[DHT11] Checksum error

Bonsoir à tous,

J'essaye depuis quelques jours d'utiliser un capteur d'humidité DHT11 sur mon projet qui utilise une carte arduino Nano.
J'ai cherché quelques tutos et celui qui est le plus à jour est celui ci : Mesure de température et d'humidité avec un capteur DHT11 • AranaCorp

J'ai comme indiqué, ajouté à ma librairie les .h et .cpp. Puis téléversé le programme. J'ai branché mon capteur sur le pi 4 (qui est également connecté à un écran LCD 16*2). L'alimentation est sur le 5v.

Une fois compilé j'ouvre le moniteur et tout se passe bien pour le début. Puis j'obtiens uniquement des "Checksum error". Sauf parfois une mesure qui passe et qui donne une valeur tout à fait acceptable, ce qui semble écarter une erreur de branchement.

Je viens vers vous parce-que bien que j'ai cherché, je ne comprends pas ce que veut dire cette erreur.

J'ai localisé ceci dans le cpp :

  // WRITE TO RIGHT VARS
        // as bits[1] and bits[3] are always zero they are omitted in formulas.
  humidity    = bits[0]; 
  temperature = bits[2]; 

  uint8_t sum = bits[0] + bits[2];  

  if (bits[4] != sum) return DHTLIB_ERROR_CHECKSUM;
  return DHTLIB_OK;
[color=#000000]
[/color]

Si je comprends bien d'autres forum qui n'ont pas aboutis ce serait une histoire de décimale.

Auriez-vous une idée pour m'aiguiller dans la résolution de ce problème ?

Bien cordialement

gheleguen

Checksum error = mauvais choix de bibliothèque.

Excuse moi je ne vais pas entrer dans les détails, je l'ai déjà fait plus de 20 fois et je fatigue.

C'est un problème de lenteur d'exécution de digitalRead() avec des circuit rapides.

Soit tu touves une bonne bibliothèque : il semble que maintenant Arduino et Adafruit ont repris la réalisation de Rob Tillart qui n'utilise pas digitalRead() mais dirrectement les registres et cela fonctionne au poil.

Soit (je ne l'ai tenté que dans un programme sans bibliothèque mais cela doit fonctionner avec une bibliothèque)

  1. tu charges la bibliothèque digitalFastRead()
  2. en tête de ton programme tu ajoutes ces deux lignes :
include<digitalFastRead.h>
#define digitalRead digitalFastRead

Comme cela chaque fois que le compilateur rencontrera digitalRead il le remplacera par digitalFastRead et ta bibliothèque pourrie se mettra miraculeusement à fonctionner.

L'utilisation d'un checksum ("une Somme de Contrôle") est une méthode pour sécuriser les transmissions numériques (et le DTH11 utilise ça)
Dans une transmission numérique (par câble, radio, fibre...), il peut survenir des erreurs : à cause d'un parasite, un 1 se change en 0 ou inversement. Ca peut arriver.
Alors avant d'envoyer les octets, on en fait la somme (ou quelque chose de + compliqué, ici c'est juste la somme).
Et on envoie cette somme à la fin du message.
Le récepteur fait la même chose : il somme les octets, et compare cette somme au "ckecksum" qu'il reçoit.
si pas ok -> Cheksum Error et on rejette le message.

Bonjour,

Ton tuto utilise une ancienne version de la librairie dht11 qui utilise digitalRead et qui est très juste au niveau du timing.
Utilises la dernière version de la librairie de RobTillaart

Bonsoir à vous trois,

Merci pour votre aide, en effet je ne connaissais pas cette erreur lié au digital read. Je prends note. Dans ce cas ce type d'erreur doit-être récurrente.

Voilà mon code :

/* Mesurer 2 temperatures et une humidité et les archiver en carte SD
by Guillaume Leguen
this sketch reads temperature from 2 DS18B20 sensors
and reports to Serial Monitor
cc-by-sa Guillaume Leguen
*/

#include <OneWire.h>
#include <DallasTemperature.h>
//#define onewirepin 9 // Cette fonction defini le numéro de port où sont branchés les capteurs
#include <LiquidCrystal.h> // initialize the library with the numbers of the interface pins – The numbers
#include <SPI.h> // for SD stock
#include <SD.h> // for SD stock
#include <Wire.h> // for SD stock
#include "DS3231.h" // for SD stock
#include <dht.h>

//are the pin connected in sequence from RS to DB7, c'est pour l'écran
LiquidCrystal lcd(7, 6, 5, 4, 3, 2);

RTClib RTC;
DS3231 Clock;
dht DHT;

int pinSD = 10 ;
int pinSensorsDS = 9 ;
char NomFichier[20];
char NomFichierComp[20];
int Year;
int Month;
int Date;
int Hour;
int Minute;
int Second;
int tempC;
int interval = 1;
int Minute_last;
int Date_last;
#define DHT11_PIN A3

File myFile; //deffine var File

OneWire oneWire(pinSensorsDS);
DallasTemperature sensors(&oneWire);

// Retrouver les adress OneWire grace au code de recherche des adresses

uint8_t sensor1[8] = { 0x28, 0xFF, 0x41, 0xB2, 0x90, 0x16, 0x04, 0xF5 };
uint8_t sensor2[8] = { 0x28, 0xFF, 0x49, 0x9A, 0x87, 0x16, 0x03, 0x14 };


void setup()
{
  Serial.begin (115200);
  Wire.begin(); //for DS3231 for RTC
  while (!Serial) {
   ; // wait for serial port to connect. Needed for native USB port only
   }
  delay(2000);  //afer reset Arduino, 2s to take out SD
  
  Serial.print("Initializing SD card...");
  
  Serial.print ("Initializing Temperature Control Library Version ");
  Serial.print("Initializing SD card...");
  Serial.println (DALLASTEMPLIBVERSION);
  Serial.println("DHT TEST PROGRAM ");
  Serial.print("LIBRARY VERSION: ");
  Serial.println(DHT_LIB_VERSION);

  sensors.begin (); // Initialise le capteur et défini une resolution
  sensors.setResolution(sensor1, 12);
  sensors.setResolution(sensor2, 12);

  delay(2000);
  Serial.println();
  Serial.print ("Number of Devices found on bus = ");
  Serial.println (sensors.getDeviceCount());
  Serial.print ("Getting temperatures… ");
  Serial.println ();

  // set up the LCD’s number of columns and rows:
  lcd.begin(16, 2);
  
  if (!SD.begin(pinSD)) {
   Serial.println("initialization failed!");
  }
  else {
   Serial.println("initialization done.");
  }

  DateTime now = RTC.now();
  Year = now.year();
  Month = now.month();
  Date = now.day();
  Hour = now.hour();
  Minute = now.minute();
  Second = now.second();
  tempC = Clock.getTemperature();
  
  Date_last = Date ;
  sprintf(NomFichier,"%02d%02d%02d%",now.year(),now.month(),now.day()); 
  
write_header ();
Serial.println(NomFichier);
}

void loop()
{
  update_vartime();
  
  sensors.requestTemperatures(); // Command all devices on bus to read temperature
  int chk = DHT.read11(DHT11_PIN);
  
  Serial.print(Minute);
  Serial.print("In : ");
  lcd.setCursor(0, 0);
  lcd.print ("I");
  printTemperature(sensor1);
  Serial.print("Out : ");
  lcd.print ("  ");
  lcd.print ("O");
  printTemperature(sensor2);
  lcd.print((char)223); // caractère degre
  lcd.print("C  ");
 // write_data1(sensor1);  //write data
 // write_data2(sensor2);
   // DISPLAY DATA
  Serial.print("H : ");
  Serial.print(DHT.humidity, 1);
  Serial.print(" |");
  Serial.println();
  lcd.setCursor(0, 1);
  lcd.print ("Hmdy : ");
  lcd.print (DHT.humidity,1);
  lcd.print ("%");
  delay(1000);//Important pour bonne lecture du DHT11
  
  if ((Minute % interval == 0)&(Minute_last!=Minute))
  {
    write_data1(sensor1);  //write data
    write_data2(sensor2);
    Minute_last = Minute;
  }

}

void printTemperature(DeviceAddress deviceAddress)
{

  float tempC = sensors.getTempC(deviceAddress);

  if (tempC == -127.00)
  {
  Serial.print ("Error getting temperature ");
  lcd.print ("Reading Error");
  }
  else
  {
  Serial.print (tempC);
  Serial.print ((char)176);
  Serial.print ("C | ");
  lcd.print(tempC);
  //lcd.print((char)223); // caractère degre
  //lcd.print("C  ");
  }
}


void write_data1(DeviceAddress deviceAddress)
{
 float tempC = sensors.getTempC(deviceAddress);
  myFile = SD.open(NomFichier, FILE_WRITE);

  // if the file opened okay, write to it:
  if (myFile) {
    myFile.print(Year);
    myFile.print("/");
    myFile.print(Month);
    myFile.print("/");
    myFile.print(Date);
    myFile.print(";");
    myFile.print(Hour);
    myFile.print(":");
    myFile.print(Minute);
    myFile.print(";");
    myFile.print(tempC);
    myFile.print(";");
    myFile.close();
    Serial.println("Write file successful!"); //print out COM Port
  } else {
    Serial.println("error opening txt");
  }
}


void write_data2(DeviceAddress deviceAddress)
{
 float tempC = sensors.getTempC(deviceAddress);
  myFile = SD.open(NomFichier, FILE_WRITE);

  // if the file opened okay, write to it:
  if (myFile) {
    myFile.print(tempC);
    myFile.println();
    myFile.close();
    Serial.println("Write file successful!"); //print out COM Port
  } else {
    Serial.println("error opening txt");
  }
}

void write_header()
{
  myFile = SD.open(NomFichier, FILE_WRITE);

  // if the file opened okay, write to it:
  if (myFile) {
    myFile.println("Donnees de temperatures");
    myFile.println("Serre de FSP");
    myFile.print(Year);
    myFile.print("/");
    myFile.print(Month);
    myFile.print("/");
    myFile.println(Date);
    myFile.println();
    myFile.println("Date;Time;Temp_In;Temp_Out;Humidity");
    myFile.close();
    Serial.println("Write header successful!"); //print out COM Port
  } else {
    Serial.println("error opening txt");
  }
}

void update_vartime()
{
  DateTime now = RTC.now();
  Year = now.year();
  Month = now.month();
  Date = now.day();
  Hour = now.hour();
  Minute = now.minute();
  Second = now.second();
  tempC = Clock.getTemperature();
 
  if((Date % interval == 0)&&(Date_last!=Date)) { //permets de créer un nouveau fichier à chaque changement de date.
    sprintf(NomFichier,"%02d%02d%02d%",now.year(),now.month(),now.day()); 
    Serial.print("Changement de date, nouveau fichier : ");
    Serial.println(NomFichier);
    Date_last = Date ;
    write_header ();
  }

}

Et pour info je documente mon projet ici : G.Leguen : StatSerre

Bonne soirée

gheleguen

Et c'est quoi la question ? :slight_smile:

Les DHT (au passage le DHT22 est bien plus performant en terme d'étendue et de précision de mesure -> le tuto est vraiment archaïque !) transmettent leur information codé en deux éléments binaire.
Attention ici il va falloir faire la différence entre le bit considéré comme une quantité d'information initiale et le signal électrique 1 ou 0 appellé "élément binaire".

Le circuit intégré du DHT va établir une suite de bit 0 et 1 à transmettre.
Pour cela il va faire un codage :
un bit 0 sera transmis sous la forme d'un élément binaire (eb) 0 suivi d'un eb 1. L'eb 1 étant plus court que l'eb 0
un bit 1 sera transmis sous la forme du même eb 0 suivi d'un eb 1 plus long que l'eb 0

Le travail de la bibliothèque est de retrouver la valeur des bits avant codage
Pour cela il faut déterminer si par couple l'élément binaire 1 est plus court ou plus long que l'élément binaire 0.
Comme la suite d'éléments binaires est transmise assez vite il faut que la détection court/long suive le rythme et pour cela les fonctions historiques digitalRead/Write sont trop lentes. Elles ratent des informations et la somme logique (CHECKSUM) est fausse.

Les fonctions historiques digitalW/R ne sont pas buggées. Elles sont conçues pour éviter des erreurs de débutant et pour cela elles font énormément de controles avant d'activer une sortie.
Elles sont juste lentes.
DigitalW/R prennent 64 cycles horloge, digitalFastW/R prennent seulement 2 cycles horloge mais elles ne t'empêcheront pas d'écrire un 1 sur une sortie sur laquelle tu avais déjà mis de la PWM.