Bonsoir
Je reviens sur mon projet, après avoir essayer de supprimer ce qui me paraissait inutile à mes besoins, J'ai un code défaut qui apparait sur le Void Loop
Merci de votre aide pour comprendre ce qui ne va pas
Pour votre info, je souhaite aussi utiliser ma deuxième sonde en remplacement de la sonde d'humidité, et ainsi avoir l'affichage de deux températures et de deux consignes
/*
********************************************************
AUTEUR J-M-L pour forum Arduino
http://forum.arduino.cc/index.php?topic=559714.0
Pour Arduino UNO ou Arduino MEGA (MEGA NECESSAIRE POUR LA FONCTION CARTE DS)
Code libre de droits, mention de l'origine appréciée
Librairies propriété de leurs auteurs respectifs
Sans garantie aucune de bon fonctionnement :)
********************************************************
PINS UTILISEES
--------------
0,1 = Rx,Tx - port Série pour communication USB
2 = laissée libre si besoin d'interruption
3 = pour le bus 1 wire avec une résistance de 4.7KΩ entre 5V et pin 3
4 = pin relai Chauffage (génération de chaud)
5 = pin relai Humidificateur
6 = pin relai Ventilateur (PWM utilsé pour le pilotage de cette pin)
7 = pin relai Climatiseur (génération de froid)
8 = pin bouton MODE
9 = pin bouton Chauffage
10 = pin bouton Humidificateur
11 = pin bouton Ventilateur
12 = pin bouton Climatiseur
13 = LED_BUILTIN affichage de l'état du système (éteinte quand système éteint)
48 = pin d'une LED (avec sa résistance de limitation de courant) qui sera allumée pendant le LOG
50 = SD MISO pour la communication SPI (avec la carte SD)
51 = SD MOSI pour la communication SPI (avec la carte SD)
52 = SD SCK pour la communication SPI (avec la carte SD)
53 = SD CS pour la communication SPI (avec la carte SD)
A0 = pin pour le potentiomètre de Consigne
A1
A2
A3
SDA, SCL = I2C communication (UNO = A4 (SDA) + A5 (SCL) / MEGA = 20 (SDA) + 21 (SCL))
COMPOSANTS UTILISES
-------------------
5 boutons momentannés
un LCD 2 lignes 16 caractères
une horloge DS3231
un DS18820 avec la résistance de 4.7KΩ qui va bien pour la température (le code gère plusieurs DS18820)
un Si7021 en I2C pour une l'humidité (et une autre mesure de t°). (préféré au DHT22 car plus rapide)
un "te291 level shifter" = adaptateur de tension I2C car le Si7021 ne fonctionne qu'en 3.3V
un potentiomètre à glissière ou rotatif
LIBRAIRIES UTILISEES
--------------------
LiquidCrystal_I2C https://github.com/fdebrabander/Arduino-LiquidCrystal-I2C-library
RTClib https://github.com/adafruit/RTClib
SparkFun_Si7021_Breakout_Library https://github.com/sparkfun/Si7021_Breakout (read and fix with https://github.com/sparkfun/Si7021_Breakout/issues/14)
OneButton https://github.com/mathertel/OneButton
DallasTemperature https://github.com/milesburton/Arduino-Temperature-Control-Library
SDFat https://github.com/greiman/SdFat
OneWire dernière version maintenue par Paul Stoffregen https://github.com/PaulStoffregen/OneWire
EEPROM en standard dans l'IDE
CABLAGE
-------
boutons en INPUT_PULLUP donc 1 côté vers la pin Arduino, un côté vers GND
RTC en I2C sous 5V (SDA, SCL, 5V, GND)
LCD en I2C sous 5V (SDA, SCL, 5V, GND)
Si7021 en I2C sous 3.3 V donc alimentation en 3.3V et usage du te291 level shifter pour transformer SDA et SCL de 5V en 3.3V
Potentiomètre en câblage standard (Vcc 5V, GND et broche mesure vers Pin Arduino)
Carte SD en SPI, utilise les pins standard de la carte MEGA
Vcc sous 5V, GND à GND
SD MISO <---> Arduino MEGA 50
SD MOSI <---> Arduino MEGA 51
SD SCK <---> Arduino MEGA 52
SD CS <---> Arduino MEGA 53
Pin 48 <---> ANODE LED <---> RESISTANCE 200Ω (adaptée à votre LED) <---> GND (led d'activité carte SD)
*/
// **********************************************************
// les définitions
// **********************************************************
enum : byte {automatique, manuel, param, eteint } mode = automatique; // pour le mode de fonctionnement
enum commandeAppareil : byte {MARCHE = LOW, ARRET = HIGH, INCONNUE = 0xFF}; // pour la commande des relais, relai éteint sur HIGH (inverser sinon les valeurs)
// Les PINS pour la commande des RELAIS
const byte onewireBusPin = 3; // pin 4 pour le bus 1 wire avec une résistance de 4.7KΩ entre 5V et pin 4
const byte pinChauffage = 4;
const byte pinHumidificateur = 5;
//const byte pinVentilateur = 6;
//const byte pinClimatiseur = 7;
// Les PINS pour les boutons
const byte buttonModePin = 8;
const byte boutonChauffagePin = 9;
const byte boutonHumidificateurPin = 10;
//const byte boutonVentilateurPin = 11;
//const byte boutonClimatiseurPin = 12;
// La PIN pour le potentiomètre de consigne
const byte pinConsigne = A0;
// les éléments d'affichage
const byte xClock = 0, yClock = 0;
const byte xMode = 0, yMode = 1;
const byte xVConsigne = 6, yVConsigne = 0;
const byte xTConsigne = 7, yTConsigne = 0;
const byte xRelais = 2, yRelais = 1;
const byte xHum = 12, yHum = 1;
const byte xHConsigne = 12, yHConsigne = 0;
const byte xTemp = 7, yTemp = 1;
// adresse LDC 0x27 16 caractères, 2 lignes
const byte adresseI2CLCD = 0x27;
const byte nbCol = 16;
const byte nbLignes = 2;
// Le nombre de capteurs de t° DS18820 sur le bus oneWire
const byte nbCapteursDS18820 = 2;
const int resolution = 10; // en bits --> Max 12 bit, min 9 bit (9bit prends 95ms, 10bit 187ms, 11bit 375ms et 12bit 750ms)
const unsigned long periodeTemperature = 250; // 250ms est OK pour une résolutoin en 10 bits. au minimum attendre (750 / (1 << (12 - resolution)));
const float tempTropChaudDelta = 2; // déclenchement chauffage si T° sous la consigne, arrêt au dela de la consigne + tempTropChaudDelta
const int minTemp = -30, maxTemp = 100;
/*
// gestion du SI7021 humidité (et T°)
const byte resolutionSI7021 = 0; // valeur par défaut 0 -> RH=12 bits, T° = 14 bits. dans [0..3] (cf page 25 de https://cdn.sparkfun.com/assets/learn_tutorials/4/6/7/Si7021Datasheet.pdf)
const unsigned long periodeHumidite = 1000ul; // période de mise à jour de la lecture
const int minHum = 0, maxHum = 100;
const float deltaTropHumide = 2; // gestion hysteresis
*/
// Gestion de la carte SD et du LOG
const uint8_t chipSelect = SS; // On utilise la pin par défaut pour la carte SD
const uint8_t SDActivePin = 48; // On passe cette PIN à HIGH pendant qu'on écrit sur la carte SD
const uint32_t LOG_INTERVAL_MS = 5000; // (5 * 60 * 1000UL); // 5 minutes (attention de bien mettre le UL pour ne pas faire les calculs en int mais bien en unsigned long)
const char * extensionFichierLog = ".LOG"; // L'extension utilisée pour tous nos fichiers (format .XXX -> un point et 3 caracteres max)
// **********************************************************
// Gestion EEPROM
// **********************************************************
#include <EEPROM.h>
const uint32_t motClef = 0xBEEFDEAD;
const uint16_t adresseMotClef = 0x00;
// __attribute__ ((packed)) permet de forcer la conservation de l'ordre des champs
// c'est utile pour éviter que le compilateur mette le bazar quand on en rajoute au fil du temps
struct __attribute__ ((packed)) _paramS {
int16_t tempConsigne;
int16_t humConsigne;
// int16_t ventConsigne;
// byte vitesseVentilateur; // PWM pour le ventilateur
} lesParametres;
const uint16_t adresseDesParametres = adresseMotClef + sizeof(motClef);
// **********************************************************
// Gestion du LCD
// **********************************************************
#include <LiquidCrystal_I2C.h> // https://github.com/fdebrabander/Arduino-LiquidCrystal-I2C-library
LiquidCrystal_I2C lcd( adresseI2CLCD, nbCol, nbLignes);
// les caractères fréquents
const char * degree = "\337"; // °
const char space = ' '; // espace
const char colon = ':'; // symbole pour séparer les heures des minutes (on peut aussi mettre 'h')
const char zero = '0';
const char symboleChauffageOn = 'C';
//const char symboleVentilateurOn = 'V';
const char symboleHumidificateurOn = 'H';
//const char symboleClimatiseurOn = 'F';
// caractères spéciaux pour la force du ventilateur
/*uint8_t ventilateurF_s[][8] = {
{0b00000, 0b00000, 0b00000, 0b00000, 0b10001, 0b10001, 0b01010, 0b00100},
{0b00000, 0b00000, 0b00000, 0b00000, 0b10101, 0b10001, 0b01010, 0b00100},
{0b00000, 0b00000, 0b00000, 0b00100, 0b10101, 0b10001, 0b01010, 0b00100},
{0b00000, 0b00000, 0b00100, 0b00100, 0b10101, 0b10001, 0b01010, 0b00100},
{0b00000, 0b00100, 0b00100, 0b00100, 0b10101, 0b10001, 0b01010, 0b00100},
{0b00100, 0b00100, 0b00100, 0b00100, 0b10101, 0b10001, 0b01010, 0b00100}
};
*/
// **********************************************************
// LES RELAIS DES APPAREILS DE CONTROLE DE L'ENVIRONNEMENT
// **********************************************************
boolean chauffageOn = false;
boolean humidificateurOn = false;
//boolean ventilateurOn = false;
//boolean climatiseurOn = false;
void chauffage(commandeAppareil c)
{
if ((chauffageOn ? MARCHE : ARRET) != c) { // si on change d'état
chauffageOn = (c == MARCHE);
digitalWrite(pinChauffage, c);
lcd.setCursor(xRelais, yRelais);
lcd.write(chauffageOn ? symboleChauffageOn : space);
}
}
void humidificateur(commandeAppareil c)
{
if ((humidificateurOn ? MARCHE : ARRET) != c) { // si on change d'état
humidificateurOn = (c == MARCHE);
digitalWrite(pinHumidificateur, c);
lcd.setCursor(xRelais + 1, yRelais);
lcd.write(humidificateurOn ? symboleHumidificateurOn : space);
}
}
/*void ventilateur(commandeAppareil c)
{
if ((ventilateurOn ? MARCHE : ARRET) != c) { // si on change d'état
ventilateurOn = (c == MARCHE);
if (ventilateurOn) analogWrite(pinVentilateur, lesParametres.vitesseVentilateur); // PWM
else digitalWrite(pinVentilateur, LOW);
lcd.setCursor(xRelais + 2, yRelais);
lcd.write(ventilateurOn ? symboleVentilateurOn : space);
}
}
void climatiseur(commandeAppareil c)
{
if ((climatiseurOn ? MARCHE : ARRET) != c) { // si on change d'état
climatiseurOn = (c == MARCHE);
digitalWrite(pinClimatiseur, c);
lcd.setCursor(xRelais + 3, yRelais);
lcd.write(climatiseurOn ? symboleClimatiseurOn : space);
}
}
*/
void eteindreTousLesSystemes()
{
// ici éteindre tous les relais
chauffage(ARRET);
humidificateur(ARRET);
// ventilateur(ARRET);
// climatiseur(ARRET);
}
// force l'affichage des symboles
void afficheEtatSystemes()
{
lcd.setCursor(xRelais, yRelais);
lcd.write(chauffageOn ? symboleChauffageOn : space);
lcd.write(humidificateurOn ? symboleHumidificateurOn : space);
// lcd.write(ventilateurOn ? symboleVentilateurOn : space);
// lcd.write(climatiseurOn ? symboleClimatiseurOn : space);
}
// **********************************************************
// le potentiomètre sert à modifier les consignes
// **********************************************************
void displayConsigne(boolean forceDisplay = false)
{
int16_t c;
if (forceDisplay) {
lcd.setCursor(xVConsigne, yVConsigne);
// lcd.write(lesParametres.ventConsigne);
// lcdTemperature(lesParametres.tempConsigne, xTConsigne, yTConsigne);
// lcdHumidite(lesParametres.humConsigne, xHConsigne, yHConsigne);
}
/*
// Les consignes T° et H ne sont modifiables qu'en mode param
if (mode == param) {
analogRead(pinConsigne); // double lecture pour stabiliser la mesure (au cas où d'autres lectures proches existeraient)
if ((digitalRead(boutonChauffagePin) == LOW) || (digitalRead(boutonClimatiseurPin) == LOW) ) { // il faut appuyer sur le bouton de Chauffage ou clim pour modifier la consigne T°
c = map(analogRead(pinConsigne), 0, 1023, minTemp, maxTemp);
if (c != lesParametres.tempConsigne) {
lesParametres.tempConsigne = c;
lcdTemperature(c, xTConsigne, yTConsigne);
}
} else if (digitalRead(boutonHumidificateurPin) == LOW) { // il faut appuyer sur le bouton de l'humidificateur pour modifier la consigne Humidité
c = map(analogRead(pinConsigne), 0, 1023, minHum, maxHum);
if (c != lesParametres.humConsigne) {
lesParametres.humConsigne = c;
lcdHumidite(c, xHConsigne, yHConsigne);
}
}
}
*/
/* // la vitesse du ventilateur est modifiable tout le temps (mais ne sera sauvegardée que si modifiée en mode Param)
if (digitalRead(boutonVentilateurPin) == LOW) { // il faut appuyer sur le bouton du ventilateur pour modifier la force du ventilo
byte vv = map(c = analogRead(pinConsigne), 0, 1023, 0, 255);
if (vv != lesParametres.vitesseVentilateur) {
lesParametres.vitesseVentilateur = vv;
lesParametres.ventConsigne = constrain(c / 171, 0, 5);
lcd.setCursor(xVConsigne, yVConsigne);
lcd.write(lesParametres.ventConsigne);
if (ventilateurOn) analogWrite(pinVentilateur, lesParametres.vitesseVentilateur); // met à jour le PWM
}
}
}
*/
// **********************************************************
// L'HORLOGE RTC
// **********************************************************
#include "RTClib.h" // https://github.com/adafruit/RTClib (import adafruit RTCLib library)
RTC_DS3231 rtc;
void lcdPrint2Digits(uint8_t n, const char padding = space)
{
if (n < 10) lcd.print(padding);
lcd.print(n);
}
void displayTime(boolean forceUpdate = false)
{
const unsigned long updatePeriod = 1000ul; // UL = unsigned long
static unsigned long t0 = 0;
static byte _h = 0, _m = 0;
byte h, m;
DateTime now;
if (mode == eteint) return;
if (forceUpdate) {
now = rtc.now();
_h = h = now.hour();
_m = m = now.minute();
lcd.setCursor(xClock, yClock);
lcdPrint2Digits(h); lcd.write(colon);
lcdPrint2Digits(m, zero);
t0 = millis();
} else if ((millis() - t0 >= updatePeriod) || (t0 == 0)) {
now = rtc.now();
h = now.hour();
m = now.minute();
if (_h != h) {
lcd.setCursor(xClock, yClock); lcdPrint2Digits(_h = h);
}
if (_m != m) {
lcd.setCursor(xClock + 3, yClock); lcdPrint2Digits(_m = m, zero);
}
t0 += updatePeriod;
}
}
// **********************************************************
// Gestion des DS18820 (dans ce code on n'affiche que le dernier)
// **********************************************************
#include <OneWire.h>
#include <DallasTemperature.h> // https://github.com/milesburton/Arduino-Temperature-Control-Library
OneWire oneWire(onewireBusPin);
DallasTemperature sensors(&oneWire);
DeviceAddress DS18820Address[nbCapteursDS18820];
float temperaturesDS18820[nbCapteursDS18820];
unsigned long chronoTemperatures = 0;
void lcdTemperature(int t, byte x, byte y)
{
// on sait que la température est entre -55° et 125°, donc la longeur max de la chaîne 125° = 4 caractères
char affichage[5]; // 4 carcatères + 1 pour le '\0'
char tmpBuffer[5];
// on s'assure de tenir sur 3 digits
if (t < -99) t = -99;
else if (t > 999) t = 999;
itoa(t, tmpBuffer, 10); // connvertir en chaîne, cf http://www.cplusplus.com/reference/cstdlib/itoa/?kw=itoa
strcat(tmpBuffer, degree); // ajoute le symbole '°'
memset(affichage, space, sizeof(affichage)); // on replit d'espaces
strcpy(affichage + sizeof(affichage) - strlen(tmpBuffer) - 1, tmpBuffer); // on cadre à droite
lcd.setCursor(x, y);
lcd.print(affichage);
}
void displayTemperature(boolean forceDisplay = false)
{
if (forceDisplay) {
while (millis() - chronoTemperatures < periodeTemperature); // on attend que les t° soient prêtes
}
// est-ce le moment le lire les capteurs de température?
if (millis() - chronoTemperatures >= periodeTemperature) {
float t;
for (int i = 0; i < nbCapteursDS18820; i++) {
t = sensors.getTempCByIndex(i); // lire les T°
// On n'affiche que la valeur du dernier capteur
if ((i == nbCapteursDS18820 - 1) && ((((int) t) != ((int) temperaturesDS18820[i])) || forceDisplay)) {
lcdTemperature((int) t, xTemp, yTemp);
}
temperaturesDS18820[i] = t; // mais on stocke bien la bonne valeur
}
// on relance une requete pour la prochaine fois
sensors.requestTemperatures();
chronoTemperatures = millis();
}
}
// **********************************************************
// Température et humidité du Si7021
// **********************************************************
#include "SparkFun_Si7021_Breakout_Library.h" // https://github.com/sparkfun/Si7021_Breakout
float temperatureSi7021;
float humiditeSi7021;
// instance de gestion du SI7021 temp & humidité
Weather SI7021;
unsigned long chronoHumidite = 0;
void lcdHumidite(int h, byte x, byte y)
{
// on sait que l'humidité est entre 0% et 100%, donc la longeur max de la chaîne 100% = 4 caractères
char affichage[5]; // 4 carcatères + 1 pour le '\0'
char tmpBuffer[5];
// on s'assure de tenir sur 3 digits
if (h < 0) h = 0;
else if (h > 999) h = 999; // ne devrait jamais arriver car 100 est le max
itoa(h, tmpBuffer, 10); // connvertir en chaîne, cf http://www.cplusplus.com/reference/cstdlib/itoa/?kw=itoa
strcat(tmpBuffer, "%"); // ajoute le symbole '%'
memset(affichage, space, sizeof(affichage)); // on replit d'espaces
strcpy(affichage + sizeof(affichage) - strlen(tmpBuffer) - 1, tmpBuffer); // on cadre à droite
lcd.setCursor(x, y);
lcd.print(affichage);
}
void displayHumidite(boolean forceDisplay = false)
{
if (forceDisplay) {
while (millis() - chronoHumidite < periodeHumidite);
}
// est-ce le moment le lire les capteurs de température?
if (millis() - chronoHumidite >= periodeHumidite) {
float h = SI7021.getRH(); // déclenche aussi la lecture de la T°
temperatureSi7021 = SI7021.readTemp(); // °C. la T° est mesurée avec chaque demande d'humidité donc plus rapide que de faire getTemp()
if ((((int) h) != ((int) humiditeSi7021)) || forceDisplay) {
lcdHumidite((int) h, xHum, yHum);
}
humiditeSi7021 = h;
}
}
// **********************************************************
// Gestion CARTE SD
// **********************************************************
// La carte SD
// utilise les pins standard de la carte MEGA (50, 51, 52 et 53)
#include <SPI.h>
#include "SdFat.h"
// SD card chip select pin.
#include <SPI.h>
#include "SdFat.h"
// gestion du File system
SdFat sd;
char * nomDuFichierLog()
{
// on crée un fichier par mois
static char _nomDuFichierLog[13]; // "AAAAMM.LOG"
DateTime now = rtc.now();
// Convertir les données en chaines http://www.cplusplus.com/reference/cstdlib/itoa/
itoa (now.year(), _nomDuFichierLog, 10); // initialise les 4 premiers caractères
if (now.month() < 10) { // on met un zéro
_nomDuFichierLog[4] = '0';
_nomDuFichierLog[5] = '0' + now.month();
} else {
_nomDuFichierLog[4] = '1';
_nomDuFichierLog[5] = '0' + now.month() - 10;
}
_nomDuFichierLog[6] = '\0';
strcat(_nomDuFichierLog, extensionFichierLog);
return _nomDuFichierLog;
}
void logToutesDonnees()
{
// ************************************************************************************
// ici sauvegardez les données comme vous le souhaitez
// ************************************************************************************
// éléments disponibles:
// temperaturesDS18820[] => tableau des T° lues sur les DS18820. On en a nbCapteursDS18820 (ce sont des float)
// temperatureSi7021 => la T° lue sur le Si7021 (float)
// humiditeSi7021 => l'humidité relative lue sur le Si7021 (float)
// lesParametres.tempConsigne => la température telle que fournie par l'utilisateur
// tempTropChaudDelta => une constante du programme
// humiditeMin => une constante du programme (seuil min d'humidité)
// humiditeMax => une constante du programme (seuil max d'humidité)
// chauffageOn => vrai si allumé
// humidificateurOn => vrai si allumé
// ventilateurOn => vrai si allumé
// climatiseurOn => vrai si allumé
// mode ==> une valeur de l'enum {automatique, manuel, param, eteint}
// ************************************************************************************
const char * tabulation = "\t";
const char * virgule = ", ";
static unsigned long derniereSauvegarde = 0;
if (millis() - derniereSauvegarde < LOG_INTERVAL_MS) return;
SdFile fichier;
if (fichier.open(nomDuFichierLog(), O_CREAT | O_WRITE | O_AT_END)) {
DateTime now = rtc.now();
// On ALLUME la LED d'incation d'activité SD
digitalWrite(SDActivePin, HIGH);
// On log le temps unix (nombre de secondes sur 32-bit depuis le 1/1/1970)
fichier.print(now.unixtime());
fichier.print(tabulation);
// On log la date
fichier.print(now.year());
fichier.print('/');
if (now.month() < 10) fichier.write('0');
fichier.print(now.month());
fichier.print('/');
if (now.day() < 10) fichier.write('0');
fichier.print(now.day());
// On log l'heure
fichier.print(tabulation);
if (now.hour() < 10) fichier.write('0');
fichier.print(now.hour());
fichier.print(':');
if (now.minute() < 10) fichier.write('0');
fichier.print(now.minute());
fichier.print(':');
if (now.second() < 10) fichier.write('0');
fichier.print(now.second());
// on log les T° des DS18820
if (nbCapteursDS18820 > 0) {
fichier.print(tabulation);
fichier.print(F("DS18820={"));
for (int i = 0; i < nbCapteursDS18820; i++) {
fichier.print(temperaturesDS18820[i], 1); // 1 chiffres après la virgule ensuite c'est pas vraiment significatif
if (i != nbCapteursDS18820 - 1) fichier.print(virgule);
}
fichier.print(F("}"));
}
// on log la T° et Humidité du Si7021
fichier.print(tabulation);
fichier.print(F("Si7021={"));
fichier.print(temperatureSi7021, 1); // 1 chiffres après la virgule ensuite c'est pas vraiment significatif
// on log l'humidité du Si7021
fichier.print(virgule);
fichier.print(humiditeSi7021, 1); // 1 chiffres après la virgule ensuite c'est pas vraiment significatif
fichier.print(F("}"));
// On log les consignes
fichier.print(tabulation);
fichier.print(F("Consignes={"));
fichier.print(lesParametres.tempConsigne);
fichier.print(virgule);
fichier.print(lesParametres.humConsigne);
fichier.print(virgule);
fichier.print(lesParametres.ventConsigne);
fichier.print(virgule);
fichier.print(lesParametres.vitesseVentilateur);
fichier.print(F("}"));
// On log les etats
fichier.print(tabulation);
fichier.print(F("Etats={"));
fichier.print(chauffageOn ? '1' : '0');
fichier.print(virgule);
fichier.print(humidificateurOn ? '1' : '0');
fichier.print(virgule);
fichier.print(ventilateurOn ? '1' : '0');
fichier.print(virgule);
fichier.print(climatiseurOn ? '1' : '0');
fichier.print(F("}"));
// on log le mode
fichier.print(tabulation);
fichier.print(F("Mode={"));
switch (mode) {
case automatique:
fichier.print(F("AUTO"));
break;
case manuel:
fichier.print(F("MAN"));
break;
case param:
fichier.print(F("PARAM"));
break;
case eteint:
fichier.print(F("ETEINT"));
break;
}
fichier.print(F("}"));
fichier.println();
// on ferme le fichier
if (!fichier.close()) {
Serial.println(F("Probleme Fermeture Fichier"));
}
digitalWrite(SDActivePin, LOW); // On éteint la LED d'incation d'activité SD
} else {
// if the file didn't open, print an error:
Serial.println(F("Probleme carte SD"));
}
derniereSauvegarde = millis();
}
// **********************************************************
// Les Boutons
// **********************************************************
#include <OneButton.h> // https://github.com/mathertel/OneButton
OneButton buttonMode(buttonModePin, true); // true pour le mettre en INPUT_PULLUP
OneButton boutonChauffage(boutonChauffagePin, true); // true pour le mettre en INPUT_PULLUP
OneButton boutonHumidificateur(boutonHumidificateurPin, true); // true pour le mettre en INPUT_PULLUP
OneButton boutonVentilateur(boutonVentilateurPin, true); // true pour le mettre en INPUT_PULLUP
OneButton boutonClimatiseur(boutonClimatiseurPin, true); // true pour le mettre en INPUT_PULLUP
void tickBoutons()
{
buttonMode.tick();
if (mode == manuel) {
boutonChauffage.tick();
boutonHumidificateur.tick();
boutonVentilateur.tick();
boutonClimatiseur.tick();
}
}
void displayMode()
{
lcd.setCursor(xMode, yMode);
switch (mode) {
case automatique:
lcd.print(F("A"));
digitalWrite(LED_BUILTIN, HIGH);
lcd.backlight();
displayConsigne(true);
afficheEtatSystemes();
break;
case manuel:
lcd.print(F("M"));
digitalWrite(LED_BUILTIN, HIGH);
lcd.backlight();
afficheEtatSystemes();
// efface les valeurs de consignes
lcd.setCursor(xTConsigne, yTConsigne);
for (byte i = 0; i < 4; i++) lcd.print(space);
lcd.setCursor(xHConsigne, yHConsigne);
for (byte i = 0; i < 4; i++) lcd.print(space);
break;
case param:
lcd.print(F("P"));
digitalWrite(LED_BUILTIN, HIGH);
lcd.backlight();
displayConsigne(true);
afficheEtatSystemes();
break;
case eteint:
lcd.noBacklight();
lcd.clear();
digitalWrite(LED_BUILTIN, LOW);
break;
}
}
// Les fonctions de call back, appellées quand on clique sur un des boutons
void doubleClickMode()
{
eteindreTousLesSystemes(); // quand on change de mode on éteint les systèmes mais le logging reste actif
mode = eteint;
displayMode();
}
void clickMode()
{
switch (mode) {
case automatique:
eteindreTousLesSystemes(); // quand on change de mode on éteint les systèmes
mode = manuel;
break;
case manuel:
mode = param;
break;
case param:
{
// on sauvegarde les paramètres en EEPROM s'ils ont été modifiés
_paramS temp;
if (memcmp(&temp, &lesParametres, sizeof(_paramS)) != 0) { // http://www.cplusplus.com/reference/cstring/memcmp/
EEPROM.put(adresseDesParametres, lesParametres);
}
eteindreTousLesSystemes(); // quand on change de mode on éteint les systèmes
mode = automatique;
}
break;
case eteint:
mode = automatique;
forceDisplay();
break;
}
displayMode();
}
void clickChauffage()
{
// on ne veut pas allumer en même temps le chauffage et le climatiseur
if (!chauffageOn && climatiseurOn) {
climatiseur(ARRET);
}
chauffage(chauffageOn ? ARRET : MARCHE);
}
void clickHumidificateur()
{
humidificateur(humidificateurOn ? ARRET : MARCHE);
}
void clickVentilateur()
{
ventilateur(ventilateurOn ? ARRET : MARCHE);
}
void clickClimatiseur()
{
// on ne veut pas allumer en même temps le chauffage et le climatiseur
if (chauffageOn && !climatiseurOn) {
chauffage(ARRET);
}
climatiseur(climatiseurOn ? ARRET : MARCHE);
}
// **********************************************************
// utilitaires
// **********************************************************
void forceDisplay()
{
displayTime(true);
displayConsigne(true);
displayTemperature(true);
displayHumidite(true);
displayMode();
}
// **********************************************************
void regulation()
{
if (mode == eteint) return;
// ************************************************************************************
// ici piloter les relais pour contrôler l'environnement comme vous le souhaitez
// ************************************************************************************
// éléments disponibles pour l'algo
// temperaturesDS18820[] => tableau des T° lues sur les DS18820. On en a nbCapteursDS18820 (float)
// temperatureSi7021 => la T° lue sur le Si7021 (float)
// humiditeSi7021 => l'humidité relative lue sur le Si7021 (float)
// lesParametres.tempConsigne => la température telle que fournie par l'utilisateur
// tempTropChaudDelta => une constante du programme
// humiditeMin => une constante du programme (seuil min d'humidité)
// humiditeMax => une constante du programme (seuil max d'humidité)
// chauffageOn => vrai si allumé
// humidificateurOn => vrai si allumé
// ventilateurOn => vrai si allumé
// climatiseurOn => vrai si allumé
// ************************************************************************************
// fonctions dispos pour l'algo (commande est soit MARCHE OU ARRET)
// ventilateur(commande);
// humidificateur(commande);
// chauffage(commande);
// ************************************************************************************
// A VOUS DE JOUER
// LE CODE CI DESSOUS EST VRAIMENT BASIQUE ET A TITRE D'EXEMPLE UNIQUEMENT
// ************************************************************************************
if (mode == automatique) {
commandeAppareil c = INCONNUE, h = INCONNUE, f = INCONNUE; // v = INCONNUE si vous voulez utiliser aussi le ventilo
if (temperaturesDS18820[0] < lesParametres.tempConsigne) {
// il fait trop froid, on lance le chauffage
c = MARCHE; // c pour chaud
f = ARRET; // f pour froid
} else if (temperaturesDS18820[0] > (lesParametres.tempConsigne + tempTropChaudDelta)) {
// il fait trop chaud, on lance la clim
c = ARRET;
f = MARCHE;
} else {
// entre les deux on arrête tout
c = ARRET;
f = ARRET;
}
// On gère l'humidité
if (humiditeSi7021 <= lesParametres.humConsigne) {
h = MARCHE;
}
else if (humiditeSi7021 >= lesParametres.humConsigne + deltaTropHumide ) {
h = ARRET;
}
if (f != INCONNUE) climatiseur(f);
if (c != INCONNUE) chauffage(c);
if (h != INCONNUE) humidificateur(h);
// la ventilation tourne dès qu'un appareil est en marche
if (climatiseurOn || humidificateurOn || chauffageOn) ventilateur(MARCHE);
else ventilateur(ARRET);
}
}
// **********************************************************
void etablirValeursParDefaut()
{
uint32_t lectureMotClef;
EEPROM.get(adresseMotClef, lectureMotClef);
if (lectureMotClef == motClef) {
// la mémoire a déjà été initialisée, on peut charger les paramètres
EEPROM.get(adresseDesParametres, lesParametres);
} else {
// la mémoire n'avait pas encore été initialisée
lesParametres.tempConsigne = 20;
lesParametres.humConsigne = 50;
lesParametres.ventConsigne = 2; // entre 0 (ventilateur vitess min) et 5 PWM ventilateur à 0xFF)
lesParametres.vitesseVentilateur = lesParametres.ventConsigne * 51;
EEPROM.put(adresseDesParametres, lesParametres);
EEPROM.put(adresseMotClef, motClef);
}
// **********************************************************
void setup() {
Serial.begin(115200);
pinMode(pinConsigne, INPUT);
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, LOW);
// LES RELAIS
pinMode(pinVentilateur, OUTPUT);
digitalWrite(pinVentilateur, ARRET);
pinMode(pinHumidificateur, OUTPUT);
digitalWrite(pinHumidificateur, ARRET);
pinMode(pinChauffage, OUTPUT);
digitalWrite(pinChauffage, ARRET);
pinMode(pinClimatiseur, OUTPUT);
digitalWrite(pinClimatiseur, ARRET);
// L'INDICATEUR DE CARTE SD
pinMode(SDActivePin, OUTPUT);
digitalWrite(SDActivePin, LOW);
// on définit les consignes en lisant l'EEPROM
etablirValeursParDefaut();
// initialiser the LCD
lcd.begin();
lcd.backlight();
// et créer nos caractères
for (byte i = 0; i <= 5; i++) lcd.createChar(i, ventilateurF_s[i]);
// initialiser l'horloge
if (! rtc.begin()) {
Serial.print(F("RTC introuvable!"));
while (1); // can't go further
}
// si l'horloge n'est pas à jour, décommenter, compiler et uploader. puis commenter et recharger à nouveau le code
//rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
// on initialise les capteurs de températures
sensors.begin();
for (byte i = 0; i < nbCapteursDS18820; i++) {
sensors.getAddress(DS18820Address[i], i);
sensors.setResolution(DS18820Address[i], resolution);
}
sensors.setWaitForConversion(false); // on travaillera en asynchrone, on n'attend pas les lectures
sensors.requestTemperatures(); // on lance une demande de lecture qui sera prête plus tard
chronoTemperatures = millis();
/*
// on initialise le capteur d'humidité
SI7021.begin();
SI7021.changeResolution(resolutionSI7021); // c'est normalement la valeur par défaut RH=12 bits, T° = 14 bits
// on attend un peu l'initialisation de tous les capteurs
delay(100);
*/
// état initial tout éteint
eteindreTousLesSystemes();
// On affiche tout
forceDisplay();
// Initialise a la plus haute vitesse possible sous 50MHz
// Essayez une vitesse plus basse si vous avez des "SPI errors"
if (!sd.begin(chipSelect, SD_SCK_MHZ(50))) {
sd.initErrorHalt();
}
// On attache une fonction comme callBack en cas de click
buttonMode.attachClick(clickMode);
buttonMode.attachDoubleClick(doubleClickMode);
boutonChauffage.attachClick(clickChauffage);
boutonHumidificateur.attachClick(clickHumidificateur);
boutonVentilateur.attachClick(clickVentilateur);
boutonClimatiseur.attachClick(clickClimatiseur);
}
}
void loop() {
displayTime(); // on vérifie s'il faut mettre à jour l'heure
tickBoutons(); // test des boutons - certains capateurs sont lents, pour la réactivité
displayTemperature(); // on vérifie si on peut mettre à jour les T°
tickBoutons(); // test des boutons - certains capateurs sont lents, pour la réactivité
displayConsigne(); // on vérifie s'il faut mettre à jour les consignes
tickBoutons(); // test des boutons - certains capateurs sont lents, pour la réactivité
displayHumidite(); // on vérifie s'il faut mettre à jour l'humidité
tickBoutons(); // test des boutons - certains capateurs sont lents, pour la réactivité
regulation(); // on déclenche une étapde de régulation
tickBoutons(); // test des boutons - certains capateurs sont lents, pour la réactivité
logToutesDonnees(); // on écrit (si le moment est venu) dans notre fichier de logs
}