/**************************************************************************/ /* BIBLIOTHEQUES*/ /**************************************************************************/ /*I2C*/ #include /**************************************************************************/ /*Horloge RTC DS3231-DS1307-DS1302*/ #include #include /**************************************************************************/ /*Eran LCD 1602 en I2C*/ #include /**************************************************************************/ /*Détecteur de temérature / humidité DHT11*/ #include /**************************************************************************/ /* Librairie carte SD*/ #include #include /**************************************************************************/ /*Déclaration écran LCD I2C */ #define LCDADDR 0x27 #define NBCOLS 16 #define NBLIGS 2 LiquidCrystal_I2C lcd(LCDADDR,NBCOLS,NBLIGS); /**************************************************************************/ /*Variables SDCARD */ Sd2Card card; SdVolume volume; SdFile root; /*Détection pour permettre le déroulement du programme sans SDCARD */ bool SDCARD_present=true; /*PIN de connexion CS */ const byte chipSelect = 10; /**************************************************************************/ /** Broche "DATA" du capteur DHT11 */ const byte DHT_PIN = 9; SimpleDHT11 dht11(DHT_PIN); //Déclaration object sond eDHT 11 avec sa broche /**************************************************************************/ /*Ligne a afficher à l'écran*/ char myStg[16]; /**************************************************************************/ /*Broche MHZ14A, OFFSET ET VARIABLES DE TRAVAIL*/ const byte MHZ14A_PWM_PIN = 8; const byte MHZ14A_ANA_PIN = 3; const int CO2_OFFSET = 0; /**************************************************************************/ /* Periode de mesure*/ const long samplePeriodCO2 = 60000L; const long samplePeriodDHT = 10000L; long lastSampleTimeCO2 = 0; long lastSampleTimeDHT = 0; /*Initialisation*/ byte temp = 0; byte humid = 0; unsigned int co2 = 0; byte old_temp = -1; byte old_humid = -1; unsigned int old_co2 = -1; /**************************************************************************/ /**Structure des variables date / heure **/ tmElements_t tm; /*date-heure retournée par l'horloge RTC*/ tmElements_t tm_compil; /*date-heure du programme exécutable */ /**************************************************************************/ /*Nombre de valeurs de co2 à prendre ,numero de la valeur prise et valeur actuelle*/ #define PRE_HEAT_TIME 60000 /***************************************************************************/ /* Lors de la création d'un fichier sur la carte, faire en sorte qu'il ait */ /* la bonne date-heure de création */ /***************************************************************************/ void dateTime(uint16_t* date, uint16_t* time) { char timestamp[30]; int yy,mm,dd,hh,mn,ss; tmElements_t dateheure; RTC.read(dateheure); yy= tmYearToCalendar(dateheure.Year); mm= dateheure.Month; dd= dateheure.Day; hh= dateheure.Hour; mn= dateheure.Minute; ss= dateheure.Second; sprintf(timestamp, "%02d:%02d:%02d %2d/%2d/%2d \n", hh, mn, ss,dd, mm,yy); *date = FAT_DATE(yy, mm, dd); *time = FAT_TIME(hh, mn, ss); } /***************************************************************************/ /*Créer / ajouter une ligne au fichier sur la SDCARD */ /***************************************************************************/ bool EcrireLigne(tmElements_t dateheure, int valco2,byte vtemp,byte vhumid) { /*Ligne a écrire sur la sdcard*/ char myLine[32]; char filename[32]; if (!SDCARD_present) { Serial.println(F("SDCard absente")); /*true = volontaire*/ return true; } if (!SD.begin(chipSelect)) { Serial.println(F("Couldn't open SDCARD")); return false; } sprintf(filename, "%04d%02d%02d.CSV", tmYearToCalendar(dateheure.Year), dateheure.Month, dateheure.Day); Serial.print("Filename : "); Serial.println(filename); /*Ecriture réelle toutes les 5 minutes*/ if (tm.Minute%5==0) { File logFile = SD.open(filename, FILE_WRITE); delay(100); if (!logFile) { Serial.println(F("Couldn't open log file")); lcd.setCursor(0,1); lcd.print("SDCARD LOG ERROR"); delay(1000); return false; } else { Serial.println(F("Writing to ")); /*Serial.print("Filename : ");*/ Serial.println(filename); sprintf(myLine, "%04d-%02d-%02d %02d:%02d:%02d;%04d;%03d;%02d", tmYearToCalendar(dateheure.Year), dateheure.Month, dateheure.Day, dateheure.Hour, dateheure.Minute, dateheure.Second, valco2, vtemp, vhumid); /*Serial.println(myLine);*/ logFile.println(myLine); logFile.close(); } } return true; } /***********************************************************************************/ /*Initialisation et vérification SDCARD, fournit SDCARD_present : variable globale */ /***********************************************************************************/ bool InitSDCard() { Serial.println(F("Init SDCard")); // we'll use the initialization code from the utility libraries // since we're just testing if the card is working! clearLCD(1,0,15); lcd.setCursor (0, 1); lcd.print(F("Init SDCard")); if (!card.init(SPI_HALF_SPEED, chipSelect)) { Serial.println(F("No Card.")); SDCARD_present = false; } else { Serial.println(F("SDCARD OK")); //Vérification du format: accepté : FAT16 / FAT 32 if (!volume.init(card)) { Serial.println(F("Bad format")); SDCARD_present = false; } } if (!SDCARD_present) { lcd.setCursor (12, 1); lcd.print(F("Fail")); } else { lcd.setCursor (14, 1); lcd.print(F("Ok")); // set date time callback function SdFile::dateTimeCallback(dateTime); } } /***************************************************************************/ /*Lire l'heure de création du programme */ /***************************************************************************/ bool getTime(const char *str) { int Hour, Min, Sec; if (sscanf(str, "%d:%d:%d", &Hour, &Min, &Sec) != 3) return false; tm_compil.Hour = Hour; tm_compil.Minute = Min; tm_compil.Second = Sec; return true; } /***************************************************************************/ /*Lire la date de création du programme */ bool getDate(const char *str) { char Month[12]; int Day, Year; uint8_t monthIndex; const char *monthName[12] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; if (sscanf(str, "%s %d %d", Month, &Day, &Year) != 3) return false; for (monthIndex = 0; monthIndex < 12; monthIndex++) { if (strcmp(Month, monthName[monthIndex]) == 0) break; } if (monthIndex >= 12) return false; tm_compil.Day = Day; tm_compil.Month = monthIndex + 1; tm_compil.Year = CalendarYrToTm(Year); return true; } /*************************************************************************/ /*Lecture unitaire sonde CO2 en Analogique*/ /*Filtrage des valeurs incohérentes */ int read_ANA_MHZ14A(byte sensorPin,byte nbeval, byte delais) { int ppm = 10000; int v0; int millivolt=10000; /*char tbs[16];*/ for (byte i=0;i0) delay(delais); } /* sprintf(tbs,"%2d mV ",millivolt); Serial.print(tbs); */ ppm = CO2_OFFSET + int(millivolt * 2.925 - 1201); return ppm; } /*************************************************************************/ /*Lecture unitaire sonde CO2 en PWM*/ int Read_PWM_MHZ14A(byte sensorpin) { byte tentative=0; unsigned long th, tl, ppm_pwm = 0; do { th = pulseIn(sensorpin, HIGH, 1004000) / 1000; tl = 1004 - th; ppm_pwm = CO2_OFFSET + 5000 * (th - 2) / (th + tl - 4); tentative++; } while (th == 0 && tentative<100); return ppm_pwm; } /**************************************************************************/ /*Voir s'il faut mettre à jour l'horloge RTC et si oui le faire*/ bool UpdateRTC() { /**************************************************************************/ /* Variables locales de date-heure de compilation et d'horloge RTC */ char stcompil[15]; char strtc[15]; /*Variabes indiquant si on a du remettre à jour l'horloge RTC*/ bool parse = false; bool config = false; /*Obtenir la date et l'heure auxquelles ce programme a été compilé*/ if (getDate(__DATE__) && getTime(__TIME__) && RTC.read(tm)) { parse = true; /*et mettre à jour le module RTC avec cette date/heure si celle-ci est > la date du RTC*/ sprintf(strtc, "%04d%02d%02d%02d%02d", tmYearToCalendar(tm.Year), tm.Month, tm.Day, tm.Hour, tm.Minute, tm.Second); sprintf(stcompil, "%04d%02d%02d%02d%02d", tmYearToCalendar(tm_compil.Year), tm_compil.Month, tm_compil.Day, tm_compil.Hour, tm_compil.Minute, tm_compil.Second); /* Serial.println(F("Heure RTC actuelle : ")); sprintf(myStg, "%02d/%02d/%04d %02d:%02d", tm.Day, tm.Month, tmYearToCalendar(tm.Year), tm.Hour, tm.Minute, tm.Second); Serial.println(myStg); Serial.println(F("Heure de compilation : ")); sprintf(myStg, "%02d/%02d/%04d %02d:%02d", tm_compil.Day, tm_compil.Month, tmYearToCalendar(tm_compil.Year), tm_compil.Hour, tm_compil.Minute, tm_compil.Second); Serial.println(myStg); Serial.print("Compil : "); Serial.println(stcompil); Serial.print("RTC : "); Serial.println(strtc); */ /*Serial.println(strcmp(stcompil,strtc),DEC);*/ if (strcmp(stcompil,strtc)>0) { /*Serial.println(F("Mise à l'heure nécessaire"));*/ if (RTC.write(tm_compil)) { Serial.println(F("Mise à l'heure réussie")); config = true; } else { Serial.println(F("Echec de la mise à l'heure")); } } else { config = true; } } return config; } /**************************************************************************/ /*Affiche la date et l'heure*/ /**************************************************************************/ void print_dateheure() { clearLCD(0,0,15); lcd.setCursor(0, 0); if (RTC.read(tm)) { sprintf(myStg, "%02d/%02d/%04d %02d:%02d", tm.Day, tm.Month, tmYearToCalendar(tm.Year), tm.Hour, tm.Minute, tm.Second); /*Serial.print(myStg);*/ /*Serial.print(" ");*/ lcd.print(myStg); clearLCD(1,0,15); lcd.setCursor(0, 1); lcd.print("Please wait"); } else { if (RTC.chipPresent()) { Serial.println(F("RTC is stopped")); lcd.print(F("RTC is stopped")); } else { Serial.println(F("RTC read error!")); lcd.print(F("RTC error")); } } } /****************************************************************************/ /*Afficher la partie heure */ /****************************************************************************/ void print_heure() { if (tm.Day<=31) { sprintf(myStg, "%02d:%02d", tm.Hour, tm.Minute); } else { sprintf(myStg, "%s", "Error"); } lcd.setCursor(11, 1); lcd.print(myStg); } /**************************************************************************/ /*Effacer une ligne de l'écran LCD de la position deb à la position fin */ /**************************************************************************/ void clearLCD(byte line,byte deb,byte fin) { lcd.setCursor(deb ,line); for(int n = deb; n <= fin; n++) // 20 indicates symbols in line. For 2x16 LCD write - 16 { lcd.print(" "); } } /**************************************************************************/ /*Affiche les valeurs (Port série + LCD*/ /**************************************************************************/ void Affiche_DHT(byte temp, byte humid) { clearLCD(0,0,15); /*Affiche Température*/ sprintf(myStg, "Temp:%dC", temp); Serial.print(myStg); Serial.print(" "); lcd.setCursor(0, 0); lcd.print(myStg); /*Affiche Humidite*/ sprintf(myStg, "Hd:%d", humid); Serial.println(myStg); lcd.setCursor(11, 0); lcd.print(myStg); } /**************************************************************************/ /*Affiche les valeurs (Port série + LCD*/ /**************************************************************************/ void Affiche_MHZ(int co2l) { clearLCD(1,0,10); /*Affiche CO2*/ lcd.setCursor(0, 1); sprintf(myStg, "CO2 :%d", co2); Serial.println(myStg); lcd.print(myStg); } /**************************************************************************/ /*Initialisation générale */ /**************************************************************************/ void setup() { /**************************************************************************/ /* Initialisation du port série */ Serial.begin(9600); while (!Serial) ; // wait for serial delay(200); /**************************************************************************/ /* Initialisation des ports du DHT11*/ pinMode(DHT_PIN, INPUT_PULLUP); /**************************************************************************/ /* Initialisation des ports du MHZ14A*/ pinMode(MHZ14A_PWM_PIN, INPUT); /**************************************************************************/ /* initialise l'écran LCD */ /**************************************************************************/ lcd.init(); lcd.backlight(); /**************************************************************************/ Serial.println(F("Starting ...")); clearLCD(0,0,15); lcd.setCursor(0, 0); lcd.print(F("Starting...")); Serial.println(F("Checking clock")); clearLCD(1,0,15); lcd.setCursor(0, 1); lcd.print(F("Checking clock")); delay(2000); UpdateRTC(); delay(2000); /**************************************************************************/ InitSDCard(); delay(2000); /**************************************************************************/ print_dateheure(); delay(5000); /**************************************************************************/ clearLCD(0,0,15); lcd.setCursor(0, 0); lcd.print(F("Temp:Wait")); clearLCD(1,0,15); lcd.setCursor(0, 1); lcd.print(F("CO2 :Wait")); /**************************************************************************/ } /**************************************************************************/ /* Boucle du programme */ /**************************************************************************/ void loop() { long maintenant = millis(); if ((maintenant > lastSampleTimeDHT + samplePeriodDHT) || (lastSampleTimeDHT == 0)) { lastSampleTimeDHT = maintenant; /*Lire l'heure sur le module RTC*/ if (!RTC.read(tm)) { Serial.print(F("RTC Clock failed check connexions")); tm.Day=100; } print_heure(); int err = SimpleDHTErrSuccess; if ((err = dht11.read(&temp, &humid, NULL)) != SimpleDHTErrSuccess) { humid = old_humid; temp = old_temp; Serial.print(F("DHT11 failed check connexions or sample time")); } else { old_temp = temp; old_humid = humid; Affiche_DHT(temp,humid); } } if ((maintenant > lastSampleTimeCO2 + samplePeriodCO2) or (lastSampleTimeCO2 == 0)) { lastSampleTimeCO2 = maintenant; //Pour utiliser la méthode analogique // unsigned int vco2=read_ANA_MHZ14A(MHZ14A_ANA_PIN,10, 10); //Pour utiliser la méthode PWM unsigned int vco2=Read_PWM_MHZ14A(MHZ14A_PWM_PIN); if (vco2>=0) { co2=vco2; } //Pré chauffage : co2 qui indique le max et démarrage il y a moins de 3 minutes, on met le message d'attente if (maintenant <=PRE_HEAT_TIME) { clearLCD(1,0,10); lcd.setCursor(0, 1); lcd.print("CO2 :Wait"); } //Sinon : on traite et affiche les données else { if (co2 < 0) { co2 = old_co2; } else { old_co2 = co2; } //Affiche les données (Serial et LCD Affiche_MHZ(co2); EcrireLigne(tm,co2,temp,humid); } } }