Go Down

Topic: besoin d'aide pour programme arduino gestion de température avec log (Read 7077 times) previous topic - next topic

osaka

Balise [quote][/quote] pour citer quelqu'un.  :smiley-mr-green:


si on supprime le delay (6000) cela vas ré effectue une recherche de temp quand ? une seule fois non ?


Pourquoi une seule fois ?
Comme barbu l'a dit la fonction loop peux être considéré comme une boucle infinie donc chaque instruction ce trouvant dans celle-ci est évalué constamment ... en boucle . (la boucle tu ne la vois pas c'est l'ide qui ce charge "d'adapter" ton code avant compil).

Voici le vrai visage du code final, ton code sera "incrusté" dedans, regarde bien où ce situe setup() et loop().
Code: [Select]

#include <Arduino.h>

int main(void)
{
init();

#if defined(USBCON)
USB.attach();
#endif

setup();
   
for (;;) {
loop();
if (serialEventRun) serialEventRun();
}
       
return 0;
}


Maintenant si tu si tu regardes le lien BlinkWithoutDelay tu verras comment il est possible d'effectuer un traitement dans un délai choisis lors d'un passage dans cette boucle infinie sans bloquer le reste du code comme le fait la fonction delay().


jhonnyy

Bonjour a tous que pensez vous de mon code?

logiquement il lit la température et active le chaffage si la température est tro basse il réeffectue cette tache toutes les 10 Min!!!!
cela est Ok?
le programme peux etre plus réduit ?

Code: [Select]
#include <OneWire.h> // Inclusion de la librairie OneWire

#define DS18B20 0x28     // Adresse 1-Wire du DS18B20
#define BROCHE_ONEWIRE 7 // Broche utilisée pour le bus 1-Wire

OneWire ds(BROCHE_ONEWIRE); // Création de l'objet OneWire ds

// Fonction récupérant la température depuis le DS18B20
// Retourne true si tout va bien, ou false en cas d'erreur
boolean getTemperature(float *temp){
  byte data[9], addr[8];
  // data : Données lues depuis le scratchpad
  // addr : adresse du module 1-Wire détecté

  if (!ds.search(addr)) { // Recherche un module 1-Wire
    ds.reset_search();    // Réinitialise la recherche de module
    return false;         // Retourne une erreur
  }
   
  if (OneWire::crc8(addr, 7) != addr[7]) // Vérifie que l'adresse a été correctement reçue
    return false;                        // Si le message est corrompu on retourne une erreur

  if (addr[0] != DS18B20) // Vérifie qu'il s'agit bien d'un DS18B20
    return false;         // Si ce n'est pas le cas on retourne une erreur

  ds.reset();             // On reset le bus 1-Wire
  ds.select(addr);        // On sélectionne le DS18B20
   
  ds.write(0x44, 1);      // On lance une prise de mesure de température
  delay(800);             // Et on attend la fin de la mesure
   
  ds.reset();             // On reset le bus 1-Wire
  ds.select(addr);        // On sélectionne le DS18B20
  ds.write(0xBE);         // On envoie une demande de lecture du scratchpad

  for (byte i = 0; i < 9; i++) // On lit le scratchpad
    data[i] = ds.read();       // Et on stock les octets reçus
   
  // Calcul de la température en degré Celsius
  *temp = ((data[1] << 8) | data[0]) * 0.0625;
   
  // Pas d'erreur
  return true;
}

// Déclaration des pins
    const int relay = 13;       // pin sortie relais

// variables
// Valeurs à déterminer
  unsigned long currentMillis = millis();
//Intervale de 10Min
long intervalchauffage = 600000;
long previousMillis = 0;

    int tmin = 10;            // t° min // Valeur réelle en °C

    int tmax = 25;            // T° max // valeur réelle en °C

    int t = 0;


void setup() {

  digitalWrite(relay, LOW);
  Serial.begin(9600); // Initialisation du port série


}
void loop() {
//boucle avec fonction de temps pour la lecture de la température et action du relay chauffage
if(currentMillis - previousMillis > intervalchauffage) {
    previousMillis = currentMillis;
  /* --- Affiche la temperature dans le moniteur serial ---*/
 
    float temp; // je n'aime pas trop les variables flotantes mais bon passons ...
   
  // Lit la température ambiante à ~1Hz
  if(getTemperature(&temp)) {
     
    // Affiche la température
    Serial.print("Temperature : ");
    Serial.print(temp);
    Serial.write(176); // caractère °
    Serial.write('C');
    Serial.println();
}
  /*-----------------------------------------------------*/
  /*--- Comparaison et enclenchement du relais ---*/
  // Lecture t°:
  t = temp;
  //Comparaison :
  if (t < tmin) {
    while (t < tmax){digitalWrite(relay, HIGH); };
                  }
   else {digitalWrite(relay, LOW);}
   
   /*-------------------------------------------*/
}
}


Thanks

barbudor

#18
May 05, 2012, 11:25 pm Last Edit: May 05, 2012, 11:31 pm by barbudor Reason: 1
Bonsoir

Je ne vais pas commenter sur la partie de lecture du DS18B20 mais uniquement sur le coeur du code.
Il y a de très bonnes choses d'autres un plus ... étranges ;)

Code: [Select]
unsigned long currentMillis = millis();
Il est très étonnant que ce code compile, mais c'est pourtant le cas (j'ai essayé).
Tu déclares une variable et tu l'initialises avec la valeur de la date au moment de cette initialisation.
Ce veut dire que tu met dans currentMillis la valeur retournée par millis() une fois et une seule.
Voir plus bas l'impact sur le reste de ton code.

Code: [Select]
void loop() {
//boucle avec fonction de temps pour la lecture de la température et action du relay chauffage
if(currentMillis - previousMillis > intervalchauffage) {

Tu compares uniquement des variables qui ont été initialisées une fois et une seul.
Donc des constantes.
Donc le résultat est constant.
Vue la valeur de intervalchauffage, tu ne passera jamais dans le code ci-après.
Code: [Select]

previousMillis = currentMillis;

Ne sert à rien. Voir la solution après mes commentaires.
Code: [Select]

/* --- Affiche la temperature dans le moniteur serial ---*/

float temp; // je n'aime pas trop les variables flotantes mais bon passons ...

Moi non plus sur un micro 8 bit qui n'a pas d'unité de calcul flottant.... ;)
Code: [Select]


// Lit la température ambiante à ~1Hz

je comprend pas ce commentaire : tu ne viens lire la température que toutes les 60000 millisecondes donc toute les minutes, pas toute les secondes.
Code: [Select]

if(getTemperature(&temp)) {

Très bonne idée d'avoir prévu une valeur de retour booléenne pour getTemperature() au cas où ca se passe mal mais ....
Code: [Select]

// Affiche la température
Serial.print("Temperature : ");
Serial.print(temp);
Serial.write(176); // caractère °
Serial.write('C');
Serial.println();
}
/*-----------------------------------------------------*/
/*--- Comparaison et enclenchement du relais ---*/
// Lecture t°:

... ici tu continues comme si la lecture était toujours correcte. Seul l'affichage dépend de la bonne exécution de getTempérature(). C'est une bonne idée qui tourne court.
Donc cette partie devrait aussi être dans le if() au cas ou getTemperature() retourne false.
Code: [Select]

t = temp;
//Comparaison :
if (t < tmin) {
while (t < tmax) {digitalWrite(relay, HIGH); };
}
else {digitalWrite(relay, LOW); }

Un peu compliqué.
Tu n'as pas besoin de refaire le digitalWrite() pendant la durée du test.
En plus tu rentres ici dans une boucle locale dont la durée n'est pas maitrisée.
Tu risque d'y bloquer ton code ce qui va poser problème quand tu voudras y rajouter ta page web.
Code: [Select]


/*-------------------------------------------*/
}
}



Voici comment j'aurais écrit la boucle :
Tout d'abord j'ai fait l'hypothèse vu ton code que :
- Tu ne veut tester que 1 fois par minute si la température est descendue trop bas pour allumer le chauffage.
- Mais que une fois que le chauffage est allumé, tu veux vérifier plus souvent et couper le chauffage très vite si la température max est atteinte.
- En cas d'erreur de lecture de la température, on réessaye tout de suite, sinon il faudrait attente 1 minute de nouveau

Code: [Select]

#define PERIODE_LENTE       60000
#define PERIODE_RAPIDE        1000

// unsigned long currentMillis = millis(); // PLUS BESOIN
unsigned long intervalchauffage = PERIODE_LENTE;  // ATTENTION AU TYPE : On traite les millis() en unsigned long
unsigned long previousMillis = 0;  // ATTENTION AU TYPE : On traite les millis() en unsigned long

int tmin = 10;                // t° min // Valeur réelle en °C
int tmax = 25;                // T° max // valeur réelle en °C
int t = 0;

bool chauffageOn = false;


void setup() {

digitalWrite(relay, LOW);
Serial.begin(9600); // Initialisation du port série

// initialiser previousMillis pour être sur de réclencher le test la 1ère fois
 previousMillis = millis() - intervalchauffage;
}

void loop()
{
//boucle avec fonction de temps pour la lecture de la température et action du relay chauffage
// voilà comment on gère correctement le timing
// il faut à chaque fois comparer avec "maintenant" donc avec la valeur retournée par millis() à cet instant présent
if( (millis() - previousMillis) > intervalchauffage) {
previousMillis = millis();  // on mémorise la valeur de maintenant
/* --- Affiche la temperature dans le moniteur serial ---*/

float temp; // je n'aime pas trop les variables flotantes mais bon passons ...

// Lit la température ambiante à ~1Hz
if(getTemperature(&temp)) {

// Affiche la température
Serial.print("Temperature : ");
Serial.print(temp);
Serial.write(176); // caractère °
Serial.write('C');
Serial.println();
/*-----------------------------------------------------*/
/*--- Comparaison et enclenchement du relais ---*/
// Lecture t°:
t = temp;
//Comparaison :
                       if ( chauffageOn )
                       {
                              if ( t > tmax )
                               {
                                     digitalWrite(relay, LOW);
                                     chauffageOn = false;
                                     intervalchauffage = PERIODE_LENTE;
                               }
                               else
                               {
                                     intervalchauffage = PERIODE_RAPIDE;
                               }
                       }
                       else  // if ( chauffageOn )
                       {
       if (t < tmin)
                               {
                                     digitalWrite(relay, HIGH);
                                     chauffageOn = true;
                                     intervalchauffage = PERIODE_RAPIDE;
                               }
                               else
                               {
                                     intervalchauffage = PERIODE_LENTE;
                               }
                       }   // if ( chauffageOn ) else
               }
               else  // If ( getTemperature() )
               {
                       // en cas d'erreur de lecture on passe en période rapide pour venir retester rapidemment
                       intervalchauffage = PERIODE_RAPIDE;
} // If ( getTemperature() ) else

/*-------------------------------------------*/
}
}


Amélioration encore possible : compter les erreurs de lectures successives et sonner une alarme si trop d'erreurs.
Barbuduino: Arduino sur Breadboard & VinciDuino: Clone Leonardo // WR703: Mini-routeur hacké // LauchPad MSP430 et Stellaris // Panda II Arduino-like .NetMF sous VisualC#
RTFC: Read That F.....g Code / RTFD: Read That F.....g Doc / RTFDS: Read That F.....g DataSheet / RTFS: Read That F.....g Schematic / Wot da ya wanna D.I.Y. today ?

jhonnyy

merci barbudor

très intéressant tu m'apprend bcp et je t'en remercie

Quote
En cas d'erreur de lecture de la température, on réessaye tout de suite, sinon il faudrait attente 1 minute de nouveau


il est possible que la lecture est des problème ? ex:parasite sur le ds18b20?

Quote
Amélioration encore possible : compter les erreurs de lectures successives et sonner une alarme si trop d'erreurs.

Est il possible de loguer les erreur sur le serial ou la carte sd

maintenant je m'attaque au service web !!!

Il y a une partie qui est encore flou
j'ai un shield sd et network il bloque combien de ports ?

thanks
De plus comment afficher sur le web ou le port série si le relais est allumé ou non ?
une variable à crée sur la parti de comparaison ?
et l'affiché sur la partie web mais je suis vraiment pas sur!!!
Code: [Select]

#include <SPI.h>
#include <Ethernet.h>
#include <OneWire.h> // Inclusion de la librairie OneWire

#define DS18B20 0x28     // Adresse 1-Wire du DS18B20
#define BROCHE_ONEWIRE 7 // Broche utilisée pour le bus 1-Wire

OneWire ds(BROCHE_ONEWIRE); // Création de l'objet OneWire ds

// Fonction récupérant la température depuis le DS18B20
// Retourne true si tout va bien, ou false en cas d'erreur
boolean getTemperature(float *temp){
  byte data[9], addr[8];
  // data : Données lues depuis le scratchpad
  // addr : adresse du module 1-Wire détecté

  if (!ds.search(addr)) { // Recherche un module 1-Wire
    ds.reset_search();    // Réinitialise la recherche de module
    return false;         // Retourne une erreur
  }
   
  if (OneWire::crc8(addr, 7) != addr[7]) // Vérifie que l'adresse a été correctement reçue
    return false;                        // Si le message est corrompu on retourne une erreur

  if (addr[0] != DS18B20) // Vérifie qu'il s'agit bien d'un DS18B20
    return false;         // Si ce n'est pas le cas on retourne une erreur

  ds.reset();             // On reset le bus 1-Wire
  ds.select(addr);        // On sélectionne le DS18B20
   
  ds.write(0x44, 1);      // On lance une prise de mesure de température
  delay(800);             // Et on attend la fin de la mesure
   
  ds.reset();             // On reset le bus 1-Wire
  ds.select(addr);        // On sélectionne le DS18B20
  ds.write(0xBE);         // On envoie une demande de lecture du scratchpad

  for (byte i = 0; i < 9; i++) // On lit le scratchpad
    data[i] = ds.read();       // Et on stock les octets reçus
   
  // Calcul de la température en degré Celsius
  *temp = ((data[1] << 8) | data[0]) * 0.0625;
   
  // Pas d'erreur
  return true;
}

// Déclaration des pins
    const int relay = 13;       // pin sortie relais

// variables
// Valeurs à déterminer
#define PERIODE_LENTE        60000
#define PERIODE_RAPIDE        1000

unsigned long intervalchauffage = PERIODE_LENTE;  // ATTENTION AU TYPE : On traite les millis() en unsigned long
unsigned long previousMillis = 0;  // ATTENTION AU TYPE : On traite les millis() en unsigned long

int tmin = 10;                // t° min // Valeur réelle en °C
int tmax = 25;                // T° max // valeur réelle en °C
int t = 0;

bool chauffageOn = false;

// Définir l'adresse MAC et l'IP de la carte
byte mac[] = { 0x90, 0xA2, 0xDA, 0x00, 0x3D, 0x0A };
byte ip[] = { 192,168,1,20 };

// Initialisation de la bibliothèque Ethernet server
// avec l4IP définie et le port (80 par défaut en HTTP)
EthernetServer server(80);


void setup() {

digitalWrite(relay, LOW);
Serial.begin(9600); // Initialisation du port série
//Initialisation de la partie web
Ethernet.begin(mac, ip);
server.begin();
// initialiser previousMillis pour être sur de réclencher le test la 1ère fois
  previousMillis = millis() - intervalchauffage;
}

void loop()
{

//boucle avec fonction de temps pour la lecture de la température et action du relay chauffage
// voilà comment on gère correctement le timing
// il faut à chaque fois comparer avec "maintenant" donc avec la valeur retournée par millis() à cet instant présent
if( (millis() - previousMillis) > intervalchauffage) {
previousMillis = millis();  // on mémorise la valeur de maintenant
/* --- Affiche la temperature dans le moniteur serial ---*/

float temp; // je n'aime pas trop les variables flotantes mais bon passons ...

// Lit la température ambiante à ~1Hz
if(getTemperature(&temp)) {

// Affiche la température
Serial.print("Temperature : ");
Serial.print(temp);
Serial.write(176); // caractère °
Serial.write('C');
Serial.println();
/*-----------------------------------------------------*/
[u]/*--- Comparaison et enclenchement du relais ---*/
// Lecture t°:
t = temp;
//Comparaison :
                        if ( chauffageOn )
                        {
                               if ( t > tmax )
                                {
                                      digitalWrite(relay, LOW);
                                      chauffageOn = false;
                                      intervalchauffage = PERIODE_LENTE;
                                }
                                else
                                {
                                      intervalchauffage = PERIODE_RAPIDE;
                                }
                        }
                        else  // if ( chauffageOn )
                        {
        if (t < tmin)
                                {
                                      digitalWrite(relay, HIGH);
                                      chauffageOn = true;
                                      intervalchauffage = PERIODE_RAPIDE;
 
                                }
                                else
                                {
                                      intervalchauffage = PERIODE_LENTE;
                                }[/u]
                        }   // if ( chauffageOn ) else
                }
                else  // If ( getTemperature() )
                {
                        // en cas d'erreur de lecture on passe en période rapide pour venir retester rapidemment
                        intervalchauffage = PERIODE_RAPIDE;
} // If ( getTemperature() ) else

/*-------------------------------------------*/
}
// attente de clients (un navigateur web par exemple)
EthernetClient client = server.available();
if (client) {

    // une demande HTTP se termine par une ligne vide
    boolean currentLineIsBlank = true;
    while (client.connected()) {

        if (client.available()) {

            char c = client.read();
            // if you've gotten to the end of the line (received a newline
            // character) and the line is blank, the http request has ended,
            // so you can send a reply
            if (c == '\n' && currentLineIsBlank) {
            // Header HTTP usuel
            //
            client.println("HTTP/1.1 200 OK");
            client.println("Content-Type: text/html");
            client.println();

            client.print("<!doctype html><html><head><meta charset='utf-8'/><title>Serveur de température Arduino</title>");
            // script qui réactualise la page toutes les 1000 mSec
            client.print("<script type='text/javascript'>function reFresh() {  location.reload(true) } window.setInterval('reFresh()',1000); </script>");
            client.print("</head><body><html>");
            client.print("<h1 style='font-family:verdana;'>Serveur de Température - Arduino</h1>");
            client.print("<p style='font-family:arial;color:red;font-size:20px;'>La temperature relevée est de ");
            client.print(t);
            client.println(" °C.</p></body></html>");
           

        break;

    }

    if (c == '\n') {

    // you're starting a new line
    currentLineIsBlank = true;
    }
    else if (c != '\r') {

            // you've gotten a character on the current line
            currentLineIsBlank = false;

            }

        }

    }

    // on laisse du temps au navigateur web de recevoir les données
    delay(1);
    // close the connection:
    client.stop();
    }
}




barbudor


il est possible que la lecture est des problème ? ex:parasite sur le ds18b20?

le code de getTemperatuer() le prévoit.
Si ce n'est pas toi qui l'a codé ainsi, quelqu'un d'autre a été prévoyant.
En programmation, tant desktop que embarqué, IL FAUT TOUJOURS PREVOIR LE PIRE

Dans ton cas tu va commander un chauffage.
Imagine que tu lises une fois une température inférieure à 10°. Tu vas donc allumer le chauffage. Et puis pendant la chauffe, un problème arrive sur la liaison avec leDS. S'il n'est pas sur la carte mais déporté par exemple, on peut imaginer que le fil se débranche ou ait été rongé par une souris (véridique). Ton code actuel va continuer à raisonner sur la dernière lecture de temp qui confirme qu'il faut continuer à chauffer.
Je ne sais ce que tu chauffe mais si c'est pour une couveuse à canard comme Infobarquee, il est presque sûr de récupérer en fin de journée les margrets cuits à point (or ca se mange plutôt rosé le canard ;)).
Donc il faut considérer les erreurs possibles vis à vis des risques possible et agir en conséquence.
pose toi la question : si je n'ai plus la température quel est le mode de fonctionnement dégrader que je dois appliquer :
- couper le chauffage
- le laisser en route en permanence
- appliquer un "PWM" de sécurité genre 1 minute en marche poru 2 minutes arrêté,
- sonner une corne de brume pour appeler les gardes côtes ....

Quote

Est il possible de loguer les erreur sur le serial ou la carte sd

Bien sur.
A ajouter dans la boucle. Tu peux logguer les lecture valides ainsi que les erreurs.

Quote

Il y a une partie qui est encore flou
j'ai un shield sd et network il bloque combien de ports ?

Comme je le dit dans ma signature la dessous : READ THAT FUCKING SCHEMATIC (cloné de la phrase de Linus Torvald : Read That Fucking Code qui incite les gens à lire le code Open Source pour être sur de savoir ce qu'il fait).
Si ton shield c'est le shield officiel Arduino tu trouveras le schéma sur la page consacré ici.
On voit que les broches suivantes sont utilisées :
- D4 : chip-select de la carte SD
- D10 : chip-select du chip Ethernet W5100
- D11, D12, D23 : interface SPI (respectivement MISO, MOSI et SCLK). Celles-ci sont difficile à voir sur le schéma car pour une raison incompréhensible, le shield Ethernet ne va pas les prendre sur le connecteur shield J1 mais sur le connecteur ISP. Ceci rend le shield Ethernet incompatible avec toute carte compatible qui ne respecte pas exactement l'emplacement du connecteur ICSP !

Donc ca te laisse pas mal d'IO pour ta sonde de température, ta commande de relai (a bouger de la broche D13 maintenant car celle-ci est utilisé par le bus SPI)

Quote

De plus comment afficher sur le web ou le port série si le relais est allumé ou non ? une variable à crée sur la parti de comparaison ?
et l'affiché sur la partie web mais je suis vraiment pas sur!!!

Dans le code que je t'ai renvoyé, j'ai déjà créé une variable chauffageOn qui trace cette information. Je m'en sert pour savoir si je doit comparer la température "< tmin" ou "> tmax". Tu peux l'utiliser aussi à l'extérieur.
Pour le port série, un Serial.print() bien placé fera l'affaire.
Pour la page web, il faut que le contenu de ta page contienne une partie dynamique qui dépend de la valeur de certaines variables.

Attention, par défaut, pour que l'affichage dans le navigateur web soit mis à jour il faut que le navigateur redemande la page.
Si tu veux que cela soit affiché automatiquement, il faut donc que le navigateur fasse la demande automatiquement d'un rafraîchissement de la page sans que l'utilisateur presse F5.
Pour un rafraichissement de toute la page, il suffit d'ajouter dans l'entête de ta page :
Code: [Select]
<header>
<meta http-equiv="refresh" content="30" />
</header>

La valeur donne la période de rafraîchissement en seconde.
Comme tu ne mesures la température que toute les minutes, ça ne sert à rien de rafraîchir plus vite.

Après pour avoir un rafraîchissement plus léger, tu peux faire du JavaScript et du HTML Dynamique pour éviter l'effet de remise à zéro de la page.


Sinon, ton dernier code commence a devenir lourd.
Ne laisse plus tout dans la fonction loop() mais découpe en sous fonctions qui deviennent maintenable et lisibles.
Une fonction qui dépasse 50 lignes de code (y compris les lignes blanches et les commentaires) devient illisibles.
On se perd dans les indentations, quand on lit la fin on ne sais plus ce que fait le début , ....

Découpe ton code par exemple :
Code: [Select]
void loop()
{
  tache_lecture _temperature();
  tache_gestion chauffage();
  tache_ethernet();
}


Tu t'y retrouveras mieux, tu pourras plus facilement debugguer chaque partie individuellement.
Définis clairement les interfaces entre les taches c'est à dire les variables globales qui vont transporter l'information d'une tâche à l'autre.
J'ai donné à plusieurs personnes sur le forum déjà des exemples sur comment découper des tâches en machines d'état non bloquantes.
En attendant que j'écrive un Tuto sur le sujet, regarde mes réponses par exemple ici : http://arduino.cc/forum/index.php/topic,102491.0.html


En plus quand tu auras des problèmes et que tu feras appel à communauté,; tu auras plus facilement des réponses sur un code simple, localisé à un problème, que si tu nous balance 500 lignes de code en disant "çà marche pas".

A+
Barbuduino: Arduino sur Breadboard & VinciDuino: Clone Leonardo // WR703: Mini-routeur hacké // LauchPad MSP430 et Stellaris // Panda II Arduino-like .NetMF sous VisualC#
RTFC: Read That F.....g Code / RTFD: Read That F.....g Doc / RTFDS: Read That F.....g DataSheet / RTFS: Read That F.....g Schematic / Wot da ya wanna D.I.Y. today ?

jhonnyy

bonjour,
Désolé je n'arrive pas a comprendre la partie
Quote
void loop()
{
  tache_lecture _temperature();
  tache_gestion chauffage();
  tache_ethernet();
}


je me suis aidé de ce code
Code: [Select]
taskLoop(redLED) 

  digitalWrite(ledPinRed,HIGH); 
  delay(200); 
  digitalWrite(ledPinRed,LOW); 
  delay(200); 

 
taskLoop(greenLED) 

  digitalWrite(ledPinGreen, HIGH); 
  delay(500); 
  digitalWrite(ledPinGreen, LOW);  // set the LED off 
  delay(500); 

 
// Fonctions habituelles 
 
void setup()     
{                 
  // Initialisation des deux sorties pour les leds 
  pinMode(ledPinRed, OUTPUT); 
  pinMode(ledPinGreen, OUTPUT); 
   
  // Création des deux tâches 
  createTaskLoop(redLED, NORMAL_PRIORITY); 
  createTaskLoop(greenLED, NORMAL_PRIORITY); 

 
void loop()                       

  // Deux tâches en parallèle pendant 2 secondes 
  resumeTask(greenLED); 
  resumeTask(redLED); 
  delay(2000); 
  // Puis seulement la verte pendant 2 secondes   
  suspendTask(redLED); 
  delay(2000); 
  // Puis seulement la rouge 
  resumeTask(redLED); 
  suspendTask(greenLED); 
  delay(2000); 
  // et on recommence (loop) 


je vous pas comment appelé la tache_lecture _temperature();
il faut la renseigner avant un peux comme mon

l.13 boolean getTemperature(float *temp){

non ?
et oui Read That Fucking Code
Je pensait avoir une remarque comme celle ci  :)

jhonnyy

c Bon j'ai comprit Merci dite moi si mon code est comme voulou mais logiquement c bon

séparé les taches c'est mieux pour l'arduino ?

pour nous humain je comprend mais aussi pour "lui"!!!

Code: [Select]

#include <SPI.h>
#include <Ethernet.h>
#include <OneWire.h> // Inclusion de la librairie OneWire

#define DS18B20 0x28     // Adresse 1-Wire du DS18B20
#define BROCHE_ONEWIRE 7 // Broche utilisée pour le bus 1-Wire
// variables
// Valeurs à déterminer
#define PERIODE_LENTE        60000
#define PERIODE_RAPIDE        1000
unsigned long intervalchauffage = PERIODE_LENTE;  // ATTENTION AU TYPE : On traite les millis() en unsigned long
unsigned long previousMillis = 0;  // ATTENTION AU TYPE : On traite les millis() en unsigned long
OneWire ds(BROCHE_ONEWIRE); // Création de l'objet OneWire ds

int tmin = 10;                // t° min // Valeur réelle en °C
int tmax = 25;                // T° max // valeur réelle en °C
int t = 0;
bool chauffageOn = false;
// Déclaration des pins
    const int relay = 13;       // pin sortie relais


// Fonction récupérant la température depuis le DS18B20
// Retourne true si tout va bien, ou false en cas d'erreur
boolean getTemperature(float *temp){
  byte data[9], addr[8];
  // data : Données lues depuis le scratchpad
  // addr : adresse du module 1-Wire détecté

  if (!ds.search(addr)) { // Recherche un module 1-Wire
    ds.reset_search();    // Réinitialise la recherche de module
    return false;         // Retourne une erreur
  }
   
  if (OneWire::crc8(addr, 7) != addr[7]) // Vérifie que l'adresse a été correctement reçue
    return false;                        // Si le message est corrompu on retourne une erreur

  if (addr[0] != DS18B20) // Vérifie qu'il s'agit bien d'un DS18B20
    return false;         // Si ce n'est pas le cas on retourne une erreur

  ds.reset();             // On reset le bus 1-Wire
  ds.select(addr);        // On sélectionne le DS18B20
   
  ds.write(0x44, 1);      // On lance une prise de mesure de température
  delay(800);             // Et on attend la fin de la mesure
   
  ds.reset();             // On reset le bus 1-Wire
  ds.select(addr);        // On sélectionne le DS18B20
  ds.write(0xBE);         // On envoie une demande de lecture du scratchpad

  for (byte i = 0; i < 9; i++) // On lit le scratchpad
    data[i] = ds.read();       // Et on stock les octets reçus
   
  // Calcul de la température en degré Celsius
  *temp = ((data[1] << 8) | data[0]) * 0.0625;
   
  // Pas d'erreur
  return true;
}



// Définir l'adresse MAC et l'IP de la carte
byte mac[] = { 0x90, 0xA2, 0xDA, 0x00, 0x3D, 0x0A };
byte ip[] = { 192,168,1,20 };

// Initialisation de la bibliothèque Ethernet server
// avec l4IP définie et le port (80 par défaut en HTTP)
EthernetServer server(80);
void temperature(){

//boucle avec fonction de temps pour la lecture de la température et action du relay chauffage
// voilà comment on gère correctement le timing
// il faut à chaque fois comparer avec "maintenant" donc avec la valeur retournée par millis() à cet instant présent
if( (millis() - previousMillis) > intervalchauffage) {
previousMillis = millis();  // on mémorise la valeur de maintenant
/* --- Affiche la temperature dans le moniteur serial ---*/

float temp; // je n'aime pas trop les variables flotantes mais bon passons ...

// Lit la température ambiante à ~1Hz
if(getTemperature(&temp)) {

// Affiche la température
Serial.print("Temperature : ");
Serial.print(temp);
Serial.write(176); // caractère °
Serial.write('C');
Serial.println();
/*-----------------------------------------------------*/
/*--- Comparaison et enclenchement du relais ---*/
// Lecture t°:
t = temp;
//Comparaison :
                        if ( chauffageOn )
                        {
                               if ( t > tmax )
                                {
                                      digitalWrite(relay, LOW);
                                      chauffageOn = false;
                                      intervalchauffage = PERIODE_LENTE;
                                }
                                else
                                {
                                      intervalchauffage = PERIODE_RAPIDE;
                                }
                        }
                        else  // if ( chauffageOn )
                        {
        if (t < tmin)
                                {
                                      digitalWrite(relay, HIGH);
                                      chauffageOn = true;
                                      intervalchauffage = PERIODE_RAPIDE;
 
                                }
                                else
                                {
                                      intervalchauffage = PERIODE_LENTE;
                                }
                        }   // if ( chauffageOn ) else
                }
                else  // If ( getTemperature() )
                {
                        // en cas d'erreur de lecture on passe en période rapide pour venir retester rapidemment
                        intervalchauffage = PERIODE_RAPIDE;
} // If ( getTemperature() ) else

/*-------------------------------------------*/
}

}
void reseau(){
EthernetClient client = server.available();
if (client) {

    // une demande HTTP se termine par une ligne vide
    boolean currentLineIsBlank = true;
    while (client.connected()) {

        if (client.available()) {

            char c = client.read();
            // if you've gotten to the end of the line (received a newline
            // character) and the line is blank, the http request has ended,
            // so you can send a reply
            if (c == '\n' && currentLineIsBlank) {
            // Header HTTP usuel
            //
            client.println("HTTP/1.1 200 OK");
            client.println("Content-Type: text/html");
            client.println();

            client.print("<!doctype html><html><head><meta charset='utf-8'/><title>Serveur de température Arduino</title>");
            // script qui réactualise la page toutes les 1000 mSec
            client.print("<script type='text/javascript'>function reFresh() {  location.reload(true) } window.setInterval('reFresh()',1000); </script>");
            client.print("</head><body><html>");
            client.print("<h1 style='font-family:verdana;'>Serveur de Température - Arduino</h1>");
            client.print("<p style='font-family:arial;color:red;font-size:20px;'>La temperature relevée est de ");
            client.print(t);
            client.println(" °C.</p></body></html>");
           

        break;

    }

    if (c == '\n') {

    // you're starting a new line
    currentLineIsBlank = true;
    }
    else if (c != '\r') {

            // you've gotten a character on the current line
            currentLineIsBlank = false;

            }

        }

    }

    // on laisse du temps au navigateur web de recevoir les données
    delay(1);
    // close the connection:
    client.stop();
    }
}

void setup() {

digitalWrite(relay, LOW);
Serial.begin(9600); // Initialisation du port série
//Initialisation de la partie web
Ethernet.begin(mac, ip);
server.begin();
// initialiser previousMillis pour être sur de réclencher le test la 1ère fois
  previousMillis = millis() - intervalchauffage;
}

void loop()
{
temperature();
reseau();
}


barbudor

#23
May 06, 2012, 06:13 pm Last Edit: May 06, 2012, 06:16 pm by barbudor Reason: 1
Ca me semble bon à première lecture.

Le premier exemple que tu était aller chercher concerne l'utilisation de DuinOS un noyau multi-tâche qui est une extension à l'environnement Arduino. Pas besoin d'aller chercher cela pour ce genre d'opérations simples.

Encore 2 remarques :
- Tu utilise toujours la broche 13 pour le relai ce qui est incompatible avec l'usage du shield Ethernet car la broche 13 fait partie de l'interface SPI utilisée par le shield Ethernet et la carte SD.

- Attention à la mémoire. Tu utilise de nombreuses chaines de caractères pour définir ta page HTML. Les mécanismes du processeur ATmega font que les chaînes de caractères, bien qu'étant des constantes, sont des données et sont recopiées avant setup() de la mémoire FLASH dans la RAM.
Or si la FLASH est assez confortable (32KO), la RAM est beaucoup plus petite (2KO).
Il existe heureusement des techniques qui permettent de laisser les chaînes de caractères.

Le principe est :
1) De rajouter #include "pgmspace.h"
2) D'encapsuler toutes les chaines de caractères que tu va utiliser avec xxx.print par PSTR("ma chaîne") comme par exemple :

Code: [Select]
client.println(PSTR("HTTP/1.1 200 OK"));
client.println(PSTR("Content-Type: text/html"));


Normalement toutes les classes dérivées de Print (ou Stream) savent aller chercher les chaînes de caractères en FLASH.

Tu peux aussi gagner un peu en place et en temps d'exécution en groupant un peu plus tes chaines par exemple :
Code: [Select]

client.print(PSTR( \
"HTTP/1.1 200 OK\n"\
"Content-Type: text/html\n"\
"\n"\
"<!doctype html><html><head><meta charset='utf-8'/><title>Serveur de temp�rature Arduino</title>\n"\
"<script type='text/javascript'>function reFresh() {  location.reload(true) } window.setInterval('reFresh()',1000); </script>\n"\
"</head><body><html>\n"\
"<h1 style='font-family:verdana;'>Serveur de Temp�rature - Arduino</h1>\n"\
"<p style='font-family:arial;color:red;font-size:20px;'>La temperature relev�e est de " ) );
client.print(t);
client.println( PSTR(" �C.</p></body></html>") );


Tu remarquera l'usage du caractère \ en fin de ligne qui signifie que la ligne au sens C ne s'arrete pas à la ligne du code source.
le compilateur va donc voir l'ensemble de toutes ces lignes comme une seule ligne "logique" ce qui est indispensable pour que les chaînes de caractères se concatène.
Tu remarquera aussi que :
- le premier print() est un print() et non plus un println()
- j'ai "manuellement" ajouter les retours à la ligne par des \n en fin de chaque chaîne de caractères.

Comme cela, il peut envoyer d'un seul trait toute le début jusqu'à la température.
Barbuduino: Arduino sur Breadboard & VinciDuino: Clone Leonardo // WR703: Mini-routeur hacké // LauchPad MSP430 et Stellaris // Panda II Arduino-like .NetMF sous VisualC#
RTFC: Read That F.....g Code / RTFD: Read That F.....g Doc / RTFDS: Read That F.....g DataSheet / RTFS: Read That F.....g Schematic / Wot da ya wanna D.I.Y. today ?

jhonnyy

pour afficher si le chauffage est activer c bon ?
Code: [Select]
if(getTemperature(&temp)) {

// Affiche la température
Serial.print("Temperature : ");
Serial.print(temp);
Serial.write(176); // caractère °
Serial.write('C');
Serial.print("Chauffage :");
Serial.write(chauffageOn);
Serial.println();
/*-----------------------------------------------------*/
/*--- Comparaison et enclenchement du relais ---*/
// Lecture t°:
t = temp;
//Comparaison :
                        if ( chauffageOn )
                        {
                               if ( t > tmax )
                                {
                                      digitalWrite(relay_chauffage, LOW);
                                      chauffageOn = false;
                                      intervalchauffage = PERIODE_LENTE;
                                }
                                else
                                {
                                      intervalchauffage = PERIODE_RAPIDE;
                                }
                        }
                        else  // if ( chauffageOn )
                        {
        if (t < tmin)
                                {
                                      digitalWrite(relay_chauffage, HIGH);
                                      chauffageOn = true;
                                      intervalchauffage = PERIODE_RAPIDE;
 
                                }
                                else
                                {
                                      intervalchauffage = PERIODE_LENTE;
                                }
                        }   // if ( chauffageOn ) else
                }
                else  // If ( getTemperature() )
                {
                        // en cas d'erreur de lecture on passe en période rapide pour venir retester rapidemment
                        intervalchauffage = PERIODE_RAPIDE;
} // If ( getTemperature() ) else

/*-------------------------------------------*/
}

}


barbudor

#25
May 06, 2012, 10:39 pm Last Edit: May 06, 2012, 10:41 pm by barbudor Reason: 1
Les lignes sont bonnes mais je dirais qu'elles sont mal placées.
Tu affiches chauffageOn juste après avoir lut la température mais avant de faire le test sur la température et d'avoir pris ta décision.

J'afficherais chauffageOn après la fin du if, derrnière la ligne
et dans le else de getTemperature mets une alarme :
Code: [Select]

                        }   // if ( chauffageOn ) else
Serial.print("Chauffage :");
Serial.println( chauffageOn ? "marche" : "arrêt" );
                }
               else  // If ( getTemperature() )
               {
                       // en cas d'erreur de lecture on passe en période rapide pour venir retester rapidemment
                       intervalchauffage = PERIODE_RAPIDE;
                       Serial.println( "ALARME: Erreur de lecture de la température" );
} // If ( getTemperature() ) else
Barbuduino: Arduino sur Breadboard & VinciDuino: Clone Leonardo // WR703: Mini-routeur hacké // LauchPad MSP430 et Stellaris // Panda II Arduino-like .NetMF sous VisualC#
RTFC: Read That F.....g Code / RTFD: Read That F.....g Doc / RTFDS: Read That F.....g DataSheet / RTFS: Read That F.....g Schematic / Wot da ya wanna D.I.Y. today ?

jhonnyy

Bonjour,

comment le programe comprend les ligne ci dessous
je voit pas comment il peux faire ?
pas de true ou false ???

Serial.print("Chauffage :");
Serial.println( chauffageOn ? "marche" : "arrêt" );

Merci

actuellement je m'attaque a la parti ntp pour loguer la date et l'heure.

barbudor

Code: [Select]
Serial.println( chauffageOn ? "marche" : "arrêt" );

est une écriture compacte en C pour :

Code: [Select]

char *str;
if (ChauffageOn)
  str = "marche";
else
  str = "arrêt";
Serial.println( str );

Barbuduino: Arduino sur Breadboard & VinciDuino: Clone Leonardo // WR703: Mini-routeur hacké // LauchPad MSP430 et Stellaris // Panda II Arduino-like .NetMF sous VisualC#
RTFC: Read That F.....g Code / RTFD: Read That F.....g Doc / RTFDS: Read That F.....g DataSheet / RTFS: Read That F.....g Schematic / Wot da ya wanna D.I.Y. today ?


jhonnyy

je viens de "terminer" l'enregistrement sur sd

Code: [Select]
/*
* Info
*Broche utilisé par les fonctions
- D4 : chip-select de la carte SD
- D10 : chip-select du chip Ethernet W5100
- D11, D12, D13
*Broche à relier
- D1 :
- D2 :
- D3 :
- D5 : relai vmc
- D6 : Relai chauffage
- D7 : sonde de temp >> ds18b20
- D8 :
- D9 :
*/


//librairie
#include <SD.h>
#include <SPI.h>
#include <Ethernet.h>
#include <OneWire.h> // Inclusion de la librairie OneWire
//broche et variables
#define DS18B20 0x28     // Adresse 1-Wire du DS18B20
#define BROCHE_ONEWIRE 7 // Broche utilisée pour le bus 1-Wire
#define PERIODE_LENTE        60000
#define PERIODE_RAPIDE        1000
const int relay_chauffage = 6;       // pin sortie relais
const int relay_vmc = 6;
const int chipSelectsd = 4;
//Valeur a déterminé-----------------------------------------------------------------------------------------------
int tmin = 10;                // t° min // Valeur réelle en °C
int tmax = 25;                // T° max // valeur réelle en °C
int t = 0;

// Définir l'adresse MAC et l'IP de la carte
byte mac[] = { 0x90, 0xA2, 0xDA, 0x00, 0x3D, 0x0A };
byte ip[] = { 192,168,1,20 };
byte gw[] = { 192, 168, 1, 1 };
EthernetServer server(80);
unsigned long intervalchauffage = PERIODE_LENTE;  // ATTENTION AU TYPE : On traite les millis() en unsigned long
unsigned long previousMillis = 0;  // ATTENTION AU TYPE : On traite les millis() en unsigned long
unsigned long enregistrementcarte = PERIODE_LENTE;
OneWire ds(BROCHE_ONEWIRE); // Création de l'objet OneWire ds

bool chauffageOn = false;
// Fonction récupérant la température depuis le DS18B20
// Retourne true si tout va bien, ou false en cas d'erreur
boolean getTemperature(float *temp){
  byte data[9], addr[8];
  // data : Données lues depuis le scratchpad
  // addr : adresse du module 1-Wire détecté

  if (!ds.search(addr)) { // Recherche un module 1-Wire
    ds.reset_search();    // Réinitialise la recherche de module
    return false;         // Retourne une erreur
  }
   
  if (OneWire::crc8(addr, 7) != addr[7]) // Vérifie que l'adresse a été correctement reçue
    return false;                        // Si le message est corrompu on retourne une erreur

  if (addr[0] != DS18B20) // Vérifie qu'il s'agit bien d'un DS18B20
    return false;         // Si ce n'est pas le cas on retourne une erreur

  ds.reset();             // On reset le bus 1-Wire
  ds.select(addr);        // On sélectionne le DS18B20
   
  ds.write(0x44, 1);      // On lance une prise de mesure de température
  delay(800);             // Et on attend la fin de la mesure
   
  ds.reset();             // On reset le bus 1-Wire
  ds.select(addr);        // On sélectionne le DS18B20
  ds.write(0xBE);         // On envoie une demande de lecture du scratchpad

  for (byte i = 0; i < 9; i++) // On lit le scratchpad
    data[i] = ds.read();       // Et on stock les octets reçus
   
  // Calcul de la température en degré Celsius
  *temp = ((data[1] << 8) | data[0]) * 0.0625;
   
  // Pas d'erreur
  return true;
}

void temperature(){

//boucle avec fonction de temps pour la lecture de la température et action du relay chauffage
// voilà comment on gère correctement le timing
// il faut à chaque fois comparer avec "maintenant" donc avec la valeur retournée par millis() à cet instant présent
if( (millis() - previousMillis) > intervalchauffage) {
previousMillis = millis();  // on mémorise la valeur de maintenant
/* --- Affiche la temperature dans le moniteur serial ---*/

float temp; // je n'aime pas trop les variables flotantes mais bon passons ...

// Lit la température ambiante à ~1Hz
if(getTemperature(&temp)) {

// Affiche la température
Serial.print("Temperature : ");
Serial.print(temp);
Serial.write(176); // caractère °
Serial.write('C');
Serial.println();
/*-----------------------------------------------------*/
/*--- Comparaison et enclenchement du relais ---*/
// Lecture t°:
t = temp;
//Comparaison :
                        if ( chauffageOn )
                        {
                               if ( t > tmax )
                                {
                                      digitalWrite(relay_chauffage, LOW);
                                      chauffageOn = false;
                                      intervalchauffage = PERIODE_LENTE;
                                }
                                else
                                {
                                      intervalchauffage = PERIODE_RAPIDE;
                                }
                        }
                        else  // if ( chauffageOn )
                        {
        if (t < tmin)
                                {
                                      digitalWrite(relay_chauffage, HIGH);
                                      chauffageOn = true;
                                      intervalchauffage = PERIODE_RAPIDE;
 
                                }
                                else
                                {
                                      intervalchauffage = PERIODE_LENTE;
                                }
                        }   // if ( chauffageOn ) else
Serial.print("Chauffage :");
Serial.println( chauffageOn ? "marche" : "arrêt" );
                }
                else  // If ( getTemperature() )
                {
                        // en cas d'erreur de lecture on passe en période rapide pour venir retester rapidemment
                        intervalchauffage = PERIODE_RAPIDE;
                Serial.println( "ALARME: Erreur de lecture de la température" );
} // If ( getTemperature() ) else

/*-------------------------------------------*/
}

}
void reseau(){
EthernetClient client = server.available();
if (client) {

    // une demande HTTP se termine par une ligne vide
    boolean currentLineIsBlank = true;
    while (client.connected()) {

        if (client.available()) {

            char c = client.read();
            // if you've gotten to the end of the line (received a newline
            // character) and the line is blank, the http request has ended,
            // so you can send a reply
            if (c == '\n' && currentLineIsBlank) {
            // Header HTTP usuel
            //
            client.println("HTTP/1.1 200 OK");
            client.println("Content-Type: text/html");
            client.println();

            client.print("<!doctype html><html><head><meta charset='utf-8'/><title>Serveur de température Arduino</title>");
            // script qui réactualise la page toutes les 1000 mSec
            client.print("<script type='text/javascript'>function reFresh() {  location.reload(true) } window.setInterval('reFresh()',1000); </script>");
            client.print("</head><body><html>");
            client.print("<h1 style='font-family:verdana;'>Serveur de Température - Arduino</h1>");
            client.print("<p style='font-family:arial;color:red;font-size:20px;'>La temperature relevée est de ");
            client.print(t);
            client.println(" °C.</p></body></html>");
           
        break;

    }

    if (c == '\n') {

    // you're starting a new line
    currentLineIsBlank = true;
    }
    else if (c != '\r') {

            // you've gotten a character on the current line
            currentLineIsBlank = false;

            }

        }

    }

    // on laisse du temps au navigateur web de recevoir les données
    delay(1);
    // close the connection:
    client.stop();
    }
}
void enregistrementsd() {
if( (millis() - previousMillis) > enregistrementcarte) {
previousMillis = millis();
String dataString = "";

File dataFile = SD.open("logtemp.txt", FILE_WRITE);

// if the file is available, write to it:
  if (dataFile) {
    dataFile.println(dataString);
    dataFile.close();
    // print to the serial port too:
    Serial.println(dataString);
  } 
  // if the file isn't open, pop up an error:
  else {
    Serial.println("error opening datalog.txt");
  }
}
}

void setup() {

digitalWrite(relay_chauffage, LOW);
Serial.begin(9600); // Initialisation du port série
//Initialisation de la partie web
Ethernet.begin(mac, ip);
server.begin();
// initialiser previousMillis pour être sur de réclencher le test la 1ère fois
  previousMillis = millis() - intervalchauffage;
// parti sd 
  Serial.print("Initializing SD card...");
   pinMode(10, OUTPUT);
     if (!SD.begin(chipSelectsd)) {
    Serial.println("Card failed, or not present");
    // don't do anything more:
    return;
  }
  Serial.println("card initialized.");
}

void loop()
{
temperature();
reseau();
enregistrementsd();
}


cela fonctionne mais je voudrait qu'il m'affiche l'heure par le biais d'un serveur ntp cela est possible ?

de plus mon code commence à être gros et j'ai vraiment pas fini !!!!
des astuces ?

cordialement

Go Up