[AIDE] probleme d'arret programme inopiné

bonjour a tous,

mon projet de gestion de chaudière avance plutôt bien.

sur mon code je suis confronté a un problème de taille.

mon programme s’arrete de maniere inopiné.

est ce que quelqu’un pourrait me donner la main?

je n’arrive pas a comprendre pourquoi je sors de la boucle loop() apres un temps indefini.

je vous joint mon sketch, si vous pouvez faire des essais et m’indiquer ce qui peut bloquer et comment arriver ale resoudre.

merci

code partie 1 (limitation du nombre de caractere sur le site

#include <dht11.h>
#include <DallasTemperature.h>
#include <OneWire.h>
#include <Time.h>
#include <SPI.h>
#include <Ethernet.h>
#include <EthernetUdp.h>



// A UDP instance to let us send and receive packets over UDP
// EthernetUDP Udp;
// la carte ethernet utilise les pattes 11,12,13 et 10 et 4
byte mac[] = {  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(192, 168, 2, 180);

EthernetUDP Udp;
unsigned int localPort = 80;  // local port to listen for UDP packets

EthernetServer server(localPort);
String readString;



#define dht11_extPIN 8
#define dht11_intPIN 7

dht11 dht11_ext;
dht11 dht11_int;

/*-----( Declare Constants and Pin Numbers )-----*/
#define ONE_WIRE_BUS_PIN 5

/*-----( Declare objects )-----*/
// Setup a oneWire instance to communicate with any OneWire devices
OneWire oneWire(ONE_WIRE_BUS_PIN);

// Pass our oneWire reference to Dallas Temperature.
DallasTemperature sensors(&oneWire);

/*-----( Declare Variables )-----*/
// Assign the addresses of your 1-Wire temp sensors.
DeviceAddress chaudiere = { 0x28, 0xFF, 0x7E, 0xA8, 0x81, 0x15, 0x01, 0xB6 };
DeviceAddress ECS = { 0x28, 0xFF, 0xFD, 0x19, 0x61, 0x15, 0x01, 0xEA };

const byte circ_chauff = 2;      // relais circulateur chauffage
const byte circ_ECS = 3;      // relais circulateur ECS
const byte bruleur = 6;      // relais marche bruleur
const byte temp_bruleur = 9; // sortie PWM pour moduler la puissance du bruleur

int consigne = 19;


int cons_chauff;

int etat_circ_chauff;
int etat_circ_ECS;
int etat_bruleur;
int etat_temp_bruleur;

byte Auto; // 0: arret    1: mode forcage normal 2: mode forcage ECS  4: Mode auto
byte Mode; // 0: mode nuit 1: mode jour
byte hiver; // 0: mode été  1: mode hiver
byte type_chauffe = 0; // 0 pas de chauffe, 1= ECS, 2 chauffage maison

int t_chaudiere;
int t_eau;
int t_exterieur;
int t_interieur;
int h_exterieur;
int h_interieur;

int i ;
byte start ;

int j = 0;

void setup()
{

  //setTime(00, 00, 00, 01, 11, 2015);
  pinMode(10, OUTPUT);
  digitalWrite(10, HIGH);
  //  passage en mode automatique au demarrage

  Auto = 4;

  // declaration entrees sorties:
  pinMode(circ_chauff, OUTPUT);
  pinMode(circ_ECS, OUTPUT);
  pinMode(bruleur, OUTPUT);

  pinMode(temp_bruleur, OUTPUT); // sortie entre 0 et 255


  // set the resolution to 10 bit (Can be 9 to 12 bits .. lower is faster)
  sensors.setResolution(chaudiere, 10);
  sensors.setResolution(ECS, 10);


  Serial.begin(9600);
  Ethernet.begin(mac);
  Udp.begin(localPort);  // demarage : UDP
  Serial.println("waiting for sync");
  setSyncProvider(getNtpTime); // lancement de la fonction
}

void loop()
{
/*
  if ((hour() == 0) && (minute() == 0) && (second() < 10))
  {
    Ethernet.begin(mac);
    Udp.begin(localPort);  // demarage : UDP
    Serial.println("waiting for sync");
    setSyncProvider(getNtpTime); // lancement de la fonction
    start = 0;
  }
  */
  if (start == 0)
  {
    Ethernet.begin(mac, ip);
    server.begin();
    start = 1;
  }


  ethernet();

  if (Auto != 0)
  {
    if (i > 10)
    {
      Serial.println(F("lecture programme"));
      Serial.println(now());
      lecture_ana();
      gestion_mode();
      gestion_type_chauffe();
      chauffage_eau();
      circulateur_chauffage();
      i = 0;
    }
    else {
      i = i + 1 ;
    }

  }

  if (Auto == 0)
  {
    digitalWrite(circ_chauff, LOW);
    digitalWrite(circ_ECS, LOW);
    digitalWrite(bruleur, LOW);
    cons_chauff = 0.0;
    analogWrite(temp_bruleur, cons_chauff); // sortie entre 0 et 255
    return;
  }
  sortie_ana();

  delay (1000);
}



/**************lecture analogique *************************/

void lecture_ana()  //mise a jour des capteurs analogique
{

  dht11_ext.read(dht11_extPIN);
  delay (1000);
  t_exterieur = ((int)dht11_ext.temperature);
  h_exterieur = ((int)dht11_ext.humidity);

  dht11_int.read(dht11_intPIN);
  delay (1000);
  t_interieur = ((int)dht11_int.temperature);
  h_interieur = ((int)dht11_int.humidity);


  sensors.requestTemperatures();
  delay (1000);
  t_eau = sensors.getTempC(ECS);
  t_chaudiere = sensors.getTempC(chaudiere);



  etat_bruleur = (digitalRead(bruleur));
  etat_circ_chauff = (digitalRead(circ_chauff));
  etat_circ_ECS = (digitalRead(circ_ECS));
  return;
}




//--------------------------------------------------------------------------------------------

void gestion_mode()
{
  if (t_exterieur >= 24)
  {
    hiver = 0;
  }
  else if ((hiver == 0) && (t_exterieur < 12))
  {
    hiver = 1;
  }


  if (((hour() > 5) && (hour() < 8)) or ((hour() > 17) && (hour() < 22)))
  {
    Mode = 1;
  }
  else
  {
    Mode = 0;
  }
  return;
}


//**********************************************************************************************/


void gestion_type_chauffe()  // gestion du type de chauffe
{

  type_chauffe = 0;
  digitalWrite(bruleur, LOW);

  if ((Auto == 2) || ((Auto == 4) && (Mode == 1 )) )
  {
    if (t_eau <= 45)
    {
      type_chauffe = 1;

      cons_chauff = 60.0;
      digitalWrite(bruleur, HIGH);

    }
    else if ((t_eau >= 55))
    {
      if (Auto == 2)
      {
        Auto = 4 ;
      }
    }
  }

  if ((Auto == 1) || ((Auto == 4) && (Mode == 1) && (hiver == 1) && (t_eau >= 55)))
  {
    type_chauffe = 2;
    regul_chauffage();
    digitalWrite(bruleur, HIGH); // regulation en faisant varier la puissance du bruleur

  }

  if (((Auto == 4) && (Mode == 0) && (hiver == 1)))
  {
    type_chauffe = 2;
    regul_chauffage();  // regulation en faisant varier la puissance du bruleur

  }

  return;
}


void chauffage_eau()
{
  if ((t_chaudiere > t_eau + 2) && (type_chauffe == 1))
  {
    digitalWrite(circ_ECS , HIGH);
  }
  else
  {
    digitalWrite(circ_ECS , LOW);
  }
  return ;
}

void regul_chauffage()
{

  cons_chauff = (1.5 * ((consigne - t_exterieur ) + 25)) - ((t_interieur - consigne) * 0.2);
  ;
  if (cons_chauff < 35.0)
  {
    cons_chauff == 35.0;
  }
  return;
}

void regul_chauffage1()
{

  if ((t_interieur < (consigne - 4)))
  {
    digitalWrite(bruleur, HIGH);
    cons_chauff == 70.0;
  }
  if (t_interieur >= (consigne - 2))
  {
    digitalWrite(bruleur, LOW);
    cons_chauff == 0.0;
  }

  return;
}


void circulateur_chauffage()
{
  if ((t_chaudiere > 45 ) && (type_chauffe != 1))
  {
    digitalWrite(circ_chauff , HIGH);
  }
  else
  {
    digitalWrite(circ_chauff , LOW);
  }
  return;
}



void sortie_ana()
{

  analogWrite(temp_bruleur, (cons_chauff * 1.2)); // ecriture d'environ 60°C
  return;
}

pour info :
j’ai 2 capteurs DHT11
2 lm35
et 3 sorties TOR.

le plus lourd du code et la page html pour le pilotage.

merci

chaudiere_DHT_eth.ino.ino (17.1 KB)

partie 2 du code:

pour info, j'ai désactiver la partie ethernet, pour faire un essai, le resultat est le meme. au bout d'un moment. je vais scanner la boucle time_t getNtpTime() alors que je ne devrais pas, et ensuite le code s'arrete.

je sais que je vais scanner la boucle car j'ai mis une info Serial.println("bug") quand je passe dans cette boucle.

je ne sais pas pourquoi j'y vais.

je ne peut pas mettre la 2eme partie du code car elle est trop grosse pour la posté, le code est en piece jointe dans le premier post

apres moult essais,

j'ai presque tout essayé ce que je pensais.

je m'aperçois que mon code s'arrette toujours au bout de 5 min.

j'ai ajouter les instructions freeram, et apparement j'ai 1100 byte de libres en permanence.

je ne comprend pas ce qui se passe.

je continue a m'auto repondre.... il semblerait que la fonction NTP get time (qui pose probleme)

soit lu toutes les 5 minutes alors que je ne le demande pas... si qq'un a une explication je suis preneur!

merci

Bonjour

Ta fonction de synchro NTP qui se déclenche de manière non maîtrisée => Ca c'est du code et tu dois pouvoir le mettre au point en ajoutant des Serial.print() pour comprendre ce qui se passe, comme tu as déjà commencé à faire.

Au delà de cet aspect, un freeze occasionnel d'un shield Ethernet est malheureusement assez classique.

J'ai été confronté à la même chose que toi. Si je réalise un sketch simple qui fait du NTP à haute fréquence (disons avec un intervalle d'une seconde entre chaque demande), l'arduino freeze assez vite, mais de manière variable selon le serveur ntp utilisé. Et même chose sur d'autres fonctions liées au shield Ethernet. Ca marche bien la plupart du temps, mais j'ai des freeze occasionnels. Pour l'instant, je n'ai pas assez de recul sur un fonctionnement en H24, mais le sujet me préoccupe.

Et quand on fait une recherche sur le net, on voit bien que le problème est loin d'être nouveau. C'est un vrai obstacle, quand on veut avoir un arduino + ethernet qui fonctionne en H24.

Du coup j'ai soulevé le capot, et suis descendu dans les librairies arduino jusqu'à la w5100.h, socket.h etc.

Mon verdict : certaines de ces libs ont été mal codées, et sont vraiment trop fragiles.

En synthèse:

Le module W5100 qui est sur le shield Ethernet, a une certaine autonomie de fonctionnement. Le dialogue avec ce module se fait via la liaison SPI. Le gros problème des librairies arduino, c'est qu'elles intègrent une certaine logique de fonctionnement (statut, compteurs, remplissage des buffers, etc.) par réplication du fonctionnement supposé du W5100. En cas de perte de synchronisation logique entre le software de ces librairies (qui s'exécute au niveau de l'arduino) et celui du W5100, on se retrouve invariablement à l'intérieur d'une boucle while infernale, dont ces librairies sont malheureusement truffées, et dont on ne ressort jamais, d'où l'impression de freeze arduino.

En ajoutant des mouchards dans ces librairies système, j'ai pu sans problème confirmer mes soupçons.

Un exemple parmi d'autres, voici pourquoi on arrive à freezer sans trop de peine dans la fonction parsePacket() :

int EthernetUDP::parsePacket() 
{ 
  // discard any remaining bytes in the last packet 
  flush(); 
  ...
void EthernetUDP::flush() 
{ 
  // could this fail (loop endlessly) if _remaining > 0 and recv in read fails? 
  // should only occur if recv fails after telling us the data is there, lets 
  // hope the w5100 always behaves :) 

  while (_remaining) 
  { 
    read(); 
  } 
}
int EthernetUDP::read() 
{ 
  uint8_t byte; 

  if ((_remaining > 0) && (recv(_sock, &byte, 1) > 0)) 
  { 
    // We read things without any problems 
    _remaining--; 
    return byte; 
  } 
  // If we get here, there's no data available 
  return -1; 
}

Et voilà CQFD : la fonction flush() boucle à l'infini, lorsqu'une quantité d'octets précédemment annoncée par le W5100 n'est pas réellement transmise, car la variable _remaining ne revient jamais à zéro.

Au passage, on appréciera le commentaire du développeur dans la fonction flush(), qui devait se douter qu'il était en train d'écrire une grosse bouse.

Des cas comme celui-ci, j'en ai identifié deux ou trois, vérifiés par des mouchards lors des freeze. Assez pour me faire une opinion sur la robustesse de ces librairies...

Ce qui reste inexpliqué, c'est pourquoi le w5100 se comporte parfois de manière non attendue par les librairies arduino. C'est peut-être lié au hardware du shield lui-même, ou bien à la version de firmware utilisée, ou encore au réseau local. Certains montages fonctionnent parfaitement, d'autres finissent par freezer.

Maintenant que faire ?

La solution la plus simple (mais la plus moche) est d'utiliser la fonction watchdog de l'arduino. Au lieu de boucler à l'infini, cela permet de rebooter le nono.

Personnellement, quand ce problème m'irritera trop, je sais que je finirai par me retrousser les manches et modifier ces librairies pour les sécuriser. Mais là pour le coup, cela a été une grosse déception sur la qualité des libs fournies par le team arduino.

sapeur3873: je vais scanner la boucle time_t getNtpTime() alors que je ne devrais pas, et ensuite le code s'arrete. je sais que je vais scanner la boucle car j'ai mis une info Serial.println("bug") quand je passe dans cette boucle. je ne sais pas pourquoi j'y vais.

il semble que ce soit fait par la lib : "Note that the loop code does not require any logic to maintain time sync. The Time library will automatically monitor NTP and sync the time as necessary. " le plus simple serait de mettre une RTC et de faire un NTP tous les jours mais pas a 0h 0mn car en cas de pb sur les variables tu boucles

j'ai des elements de reponse a apporter

normalement je ne fais le scan de la boucle ntpgettime qu'une fois par jour.

mais je ne sais pas pourquoi mon code va la scanner toutes les 5 minutes (ca doit etre un probleme d'une Library je pense).

et la fonction ntpgettime, s'associe assez mal avec un webserver sur arduino.

ce que j'ai fait qui a l'air de bein fonctionner.

si je scanne ntpgettime sans que je l'ai demander (avec un bit en memoire), je ressort directement de la fonction.

et pour que la fonction ntp gettime fonctionne lorsque je suis en mode webserver, je fais juste un reset tout les jours a 1h.

pour le moment c'est tout ce que j'ai trouver pour m'en sortir.