Au démarrage tout se passe bien, lecture et affichage température/hygrométrie mais à la deuxième boucle, une erreur de lecture du capteur apparaît et cette erreur persiste.
J'ai beau relire le programme, je ne trouves pas.
Merci de ne se concentrer (pour le moment) que sur cette erreur.
(sauf si bien sur elle est la conséquence d'autres boulettes que j'aurais fait dans le code)
Une fois ce problème réglé, je me pencherai très volontiers sur l'art de la programmation et l'optimisation du code.
Le code est surement pourri et Il peu très certainement être optimisé.
(je ne suis pas programmeur de formation mais je ne demande qu'a apprendre).
D'avance merci.
PS:J'ai cherché sur la toile un debugger (avance pas à pas type VBA) pour analyser le déroulement du code mais sans succès.
* Connect to Android via serial Bluetooth and demonstrare the use of interrupt
Un module bluetooth serie est utilisé pour créer une connexion a un périphérique Android via une application MIT AppInentor2.
Arduino attend des commandes pour allumer des relais et donner leurs status. De plus, une interruption lui fait verifier la temperature et l'humidité d'un DHT11.
Si la temperature et/ou l'humidité sont plus haute que leur consigne, Arduino ouvre les relais concernés.
Toutes les n secondes parametrable via l'application(via la commande MSG) un rapport est envoyé a l'application.
Une simple structure de commande permet a l'application d'envoyer des parametres et valeurs a l'arduino et inversement.
Le circuit:
* Yellow led on Pin 9 via relais with 220 Ohm resistor in series
* Green led on Pin 10 via relais with 220 Ohm resistor in series
* Red led on Pin 11 via relais with 220 Ohm resistor in series
* Bleue led on Pin 12 via relais with 220 Ohm resistor in series
* the built-in led on Pin 13 is also used
* DHT11 connected to 5V, Pin digital 8 and Gnd
* HC-06 Bluetooth Wireless Serial Port Module (slave) connected as follows:
VCC <--> 5V
GND <--> GND
TXD <--> Pin 0 (Rx)
RXD <--> Pin 1 (Tx)
The Bluetooth module may interfere with PC to Arduino communication: disconnect VCC when programming the board
Adapté par mo@ sur la
base d'une création de 2014 par
Paolo Mosconi
This example code is in the public domain.
// Serial Parameters: COM11 9600 8 N 1
// \r or \n to end command line
// Bluetooth is on Pin 8 & 1 @ 9600 speed
// Command structure
// CMD VENTIL|HYGRO|POMPE|LUM=ON|OFF
// CMD TMAX|HMIN|GROW=value
// CMD MSG=value
// CMD STATUS
*/
#include <FlexiTimer2.h>
#include "DHT.h"
#define DHTPIN 8
#define DHTTYPE DHT11
#include <Wire.h>
#include "RTClib.h"
RTC_DS1307 RTC;
DHT dht(DHTPIN, DHTTYPE);
float maxTemp = 25.0; // Temperature maximum
float minTemp = 20.0; // Temperature maximum
float maxHumid = 80.0; // Humiditée minimum
float minHumid = 32.0; // Humiditée minimum
float temperature = 0.0; // lecture temperature DTH11
float humidite = 0.0; // Lecture humiditée DHT11
float maxTempSensor = (float) (maxTemp); // à definir
float minTempSensor = (float) (minTemp); // à definir
float minHumidSensor = (float) (minHumid); // a definir
float maxHumidSensor = (float) (maxHumid); // a definir
volatile float tempVal;
volatile float humidVal;
volatile int TMar=0;
volatile int CMar=0;
volatile int Grow=0;
volatile int Msg=15;
volatile boolean flagcompteur=false;
volatile boolean tempHigh = false;
volatile boolean humidLow = false;
volatile boolean statusReportT = false;
volatile boolean statusReportH = false;
String inputString = "";
String command = "";
String value = "";
boolean stringComplete = false;
char inChar;
const int led1Pin = 9; // Yellow + Relais 1 => LUMIERE
const int led2Pin = 10; // Green + Relais 2 => POMPE BAIN
const int led3Pin = 11; // Red + Relais 3 => VENTILATION
const int led4Pin = 12; // Bleue + Relais 4 => HYGRO
void setup(){
Serial.begin(9600);
dht.begin();
Wire.begin();
RTC.begin();
pinMode(led1Pin, OUTPUT);
pinMode(led2Pin, OUTPUT);
pinMode(led3Pin, OUTPUT);
pinMode(led4Pin, OUTPUT);
digitalWrite(led1Pin, HIGH);
digitalWrite(led2Pin, HIGH);
digitalWrite(led3Pin, HIGH);
digitalWrite(led4Pin, HIGH);
inputString.reserve(50);
command.reserve(50);
value.reserve(50);
// following line sets the RTC to the date & time this sketch was compiled
RTC.adjust(DateTime(__DATE__, __TIME__));
action(); //initialise lecture DHT11 et initialise les variables TempVal et HumidVal et verifie que les valeures lues sont exploitables
report();//affiche les valeurs TempVal et HumidVal et les compares a leurs consignes.
FlexiTimer2::set(Msg*1000, action); //recupere les valeurs du DHT toutes les 5 secondes et ouvre ou ferme le relais concerné si necessaire.
FlexiTimer2::start();
}
void loop(){ // enchainement des differentes fonctions conctituant le programme
serialEvent();
// "ecoute" le port serie (entrée de données venant du peripherique Android)
//Serial.println("VERIF ENTREES SERIAL");
//delay(1000);
//CheckVal();
//Serial.println("VERIF ENTREES VALIDES");
//delay(1000); // verifie que les valeurs lues sur le DHT sont exploitables.
Check(); // traite les données recues de la console Android et mets a jour les variables du programme.
//Serial.println("VERIF BLUETOOTH");
//delay(1000);
}
void action(){
Serial.println("RELEVE DHT11 ACTION");
ReadDht11();
delay(1000);
if (tempVal > maxTemp) {
digitalWrite(led3Pin, LOW);
tempHigh = true;
statusReportT =true;
}
else {
digitalWrite(led3Pin, HIGH);
tempHigh = false;
statusReportT =false;
}
if (humidVal < minHumid) {
digitalWrite(led4Pin, LOW);
humidLow = true;
statusReportH =true;
}
else {
digitalWrite(led4Pin, HIGH);
humidLow = false;
statusReportH =false;
}
}
void report(){
Serial.print("INTERVAL MESSAGE = ");
//delay(1000);
Serial.println (Msg);
statusReportT =true;
statusReportH =true;
Report_DHT ();
}
/*
SerialEvent occurs whenever a new data comes in the
hardware serial RX. This routine is run between each
time loop() runs, so using delay inside loop can delay
response. Multiple bytes of data may be available.
*/
void serialEvent() {
while (Serial.available()) {
char inChar = (char)Serial.read();
inputString += inChar;
// if the incoming character is a newline or a carriage return, set a flag
// so the main loop can do something about it:
if (inChar == '\n' || inChar == '\r') {
stringComplete = true;
}
}
}
void CheckVal(){ // verifie que les valeurs lues sur le DHT sont exploitables.
if (isnan(humidVal) || isnan(tempVal))
Serial.println( "Lecture du capteur impossible !");
}
il semble que ton sketch vienne du net.
en principe un gars qui poste un sketch est sensé mettre un sketch qui tourne bien.
cependant, dans ta loop, tu appelles serialEvent() .
cela ne se fait pas, il faut voir cette fonction comme une isr.
s'il y a une communication qui arrive sur le serial, cette fonction est exécutée, elle lit le tampon et mets la variable stringCpmplete= true.
et toi dans ta loop tu devrais uniquement tester si la variable est "true".
c'est d'ailleurs ce que tu fais dans la fonction check que tu appelles dans ta loop.
en résumé, ta loop devrait simplement appeler la fonction check.
je n'ai pas regardé le reste du code.
es tu sur de ton application sur l'android ?
as tu testé le capteur et ses branchement avec un sketch de la librairie ?
Voici comment j'ai procédé afin de suivre (essayer) tes recommandations:
Pour la partie LOOP:
Je n'appelle que la fonction Check.
void loop(){ // enchainement des differentes fonctions conctituantes du programme
//serialEvent();
// "ecoute" le port serie (entrée de données venant du peripherique Android)
//Serial.println("VERIF ENTREES SERIAL");
//delay(1000);
//CheckVal();
//Serial.println("VERIF ENTREES VALIDES");
//delay(1000); // verifie que les valeurs lues sur le DHT sont exploitables.
Check(); // traite les données recues de la console Android et mets a jour les variables du programme.
//Serial.println("VERIF BLUETOOTH");
//delay(1000);
}
Et dans la partie Check j'integre ce qu'il y avait dans le serialEvent :
void Check(){
float intValue = 0;
while (Serial.available()) {
char inChar = (char)Serial.read();
inputString += inChar;
// if the incoming character is a newline or a carriage return, set a flag
// so the main loop can do something about it:
if (inChar == '\n' || inChar == '\r') {
stringComplete = true;
}
}
.....
Cela ne règle malheureusement pas mon problème.
Première boucle OK mais la suivante (15 secondes après... ==> KO)
en pièce jointe capture du moniteur série.
EDIT :
Ci-dessous un lien vers les tutos Arduino relatif a l'utilisation du SerialEvent.
A priori il est utilisé dans la Loop (l'appel de la foncion) tout comme je l'ai fait dans mon code initial
zefram-28:
Voici comment j'ai procédé afin de suivre (essayer) tes recommandations:
Bonsoir
si ton code ne tient pas en PJ sur le forum
passe par un tiers hébergeur (ça ne garantit pas la pérennité du lien )
mais ça evite des "contorsions" pour remettre en forme/verifier, ce qui est une manip souvent rédhibitoire pour qq'un qui "passe en coup de vent"
Et dans la partie Check j'integre ce qu'il y avait dans le serialEvent :
Je pense que tu as une mauvaise compréhension de l'utilisation de serialEvent().
On ne fait pas d'appel à serialEvent(), cette fonction est appelée automatiquement à chaque itération de loop et assure la gestion du lien série en tâche de fond. Et ce n'est pas à strictement parler une ISR puisqu'elle est appelée explicitement et non en réponse à une interruption.
Edit: à la réflexion, comme c'est une fonction "normale" rien n'empêche de faire des appels directs à serialEvent(). Mais cela à peu de sens car on risque de l'appeler alors qu'il n'y a pas de données à traiter.
fdufnews:
Je pense que tu as une mauvaise compréhension de l'utilisation de serialEvent().
...
Edit: à la réflexion, comme c'est une fonction "normale" rien n'empêche de faire des appels directs à serialEvent(). Mais cela à peu de sens car on risque de l'appeler alors qu'il n'y a pas de données à traiter.
Donc a priori mon problème ne viens pas de là.
mais alors pourquoi ce fonctionnement erratique???
Il y a un truc qui me trouble dans ton code.
La fonction action() est appelée par FlexiTimer2. J'en déduit, peut-être à tort, que cela est fait sous interruption. Or dans action() il y a un appel à delay() et delay() ne fonctionne pas sous interruption.
Dans tous les cas, l'usage de delay() lorsque cela est possible, et c'est souvent le cas, doit être proscrit. Il est préférable d'utiliser millis() en association avec une petite machine à état pour gérer les actions liées au temps.
Si action() est bien appelée sous interruption, je te conseille de ne pas utiliser de Serial.print() car cela peut aussi planter Serial qui fonctionne aussi sous IT. De plus, comme le timer peut tomber n'importe quand il peut y avoir des effets de bords indésirables. Dans les fonctions appelées sous interruption, au lieu de faire des Serial.print(), il vaut mieux remonter un octet d'état qui sera exploité dans la boucle principal qui se chargera d'émettre le Serial.print().
fdufnews:
Il y a un truc qui me trouble dans ton code.
La fonction action() est appelée par FlexiTimer2. J'en déduit, peut-être à tort, que cela est fait sous interruption. Or dans action() il y a un appel à delay() et delay() ne fonctionne pas sous interruption.
Je vais virer ce delay qui n’était là que pour laisser du temps a la lecture du capteur (mais pas indispensable).
fdufnews:
Si action() est bien appelée sous interruption, je te conseille de ne pas utiliser de Serial.print() car cela peut aussi planter Serial qui fonctionne aussi sous IT. De plus, comme le timer peut tomber n'importe quand il peut y avoir des effets de bords indésirables. Dans les fonctions appelées sous interruption, au lieu de faire des Serial.print(), il vaut mieux remonter un octet d'état qui sera exploité dans la boucle principal qui se chargera d'émettre le Serial.print().
Action est bien appellé par Flexitimer2 : l'interuption les Xsecondes (parametrable).
Action ne fait que lire le capteur.
==> pas d'appel SerialEvent en cours d'interupt.
le serialEvent (exterieur au loop) est appelé par la fonction "Check" qui est dans le loop.
J’espère avoir été clair.
A priori je ne rentre pas dans les cas de figure "a éviter" que tu me décris.
peux tu tester en mettant des // devant les 4 lignes qui initialisent flexi2
FlexiTimer2::set(Msg * 1000, action); //recupere les valeurs du DHT toutes les 15 secondes et ouvre ou ferme le relais concerné si necessaire.
FlexiTimer2::start();
et
FlexiTimer2::set((Msg * 1000), report); // lance un rapport du systeme toutes maxSeconds
FlexiTimer2::start();
En invalidant les lignes FlexiTime2 je n'ai plus de plantage mais je n'ai plus les retours me disant ou en sont les valeurs réelles par rapport aux valeurs cibles.
Je n'ai donc plus le retour Arduino vers Android de ce qui se passe dans la serre.