// 1. Inclure les bibliothèques nécessaires
#include <Wire.h>
#include <RTClib.h>
#include <LiquidCrystal_I2C.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <DHT.h>
// 2. Définir les broches et les constantes
#define RELAY_PIN 3
#define ONE_WIRE_BUS 4
#define SWITCH_PIN 5
#define BUZZER_PIN 6 // Broche pour le buzzer passif (D6)
#define DHT_PIN 2 // Broche pour le DHT22 (D2)
#define DHTTYPE DHT22
// Seuils de contrôle en FAHRENHEIT (100°F pour démarrer, 105°F pour arrêter)
const float TEMP_SEUIL_MAX_F = 105.0;
const float TEMP_SEUIL_MIN_F = 100.0;
// 3. Initialiser les objets pour chaque composant
RTC_DS1307 rtc;
LiquidCrystal_I2C lcd(0x27, 20, 4); // LCD 20x4
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
DHT dht(DHT_PIN, DHTTYPE);
// Variables pour gérer la mise à jour non-блоquante avec millis()
long lastReadMillis = 0;
long lastTimeDisplayMillis = 0;
const long readInterval = 2000; // Lecture des capteurs toutes les 2 secondes
const long timeInterval = 1000; // Affichage de l'heure toutes les secondes
// Variables d'état
float currentTemperatureC = -999.0;
float currentHumidity = -1.0;
bool cycleComplete = false; // Indicateur de fin de déshydratation
// NOUVEAU: VARIABLES POUR LE CONTRÔLE NON-BLOQUANT DES BIP
long lastToneToggleMillis = 0; // Gestion non-bloquante du bip
int toneCount = 0; // Compteur de basculements (max 10 pour 5 bips ON/OFF)
const int MAX_TONE_TOGGLES = 10; // 5 x (ON + OFF) = 10 basculements
const long TONE_DURATION = 1000; // 1 seconde par état (ON ou OFF)
// VARIABLES POUR LE CONTRÔLE DE STABILITÉ (ANTI-SCINTILLEMENT)
int lastRelayStatus = -1; // Mémorise l'état HIGH/LOW du relais
int lastControlMode = -1; // Mémorise l'état HIGH/LOW du switch
// Buffer pour snprintf
char buffer[21];
// Prototype de fonctions
float celsiusToFahrenheit(float celsius);
void updateDisplay(float tempF, float hum, int switchState);
void updateTimeDisplay();
void handleEndTone(); // NOUVEAU: Fonction pour gérer le buzzer de manière non-bloquante
void setup() {
Serial.begin(9600);
sensors.begin();
dht.begin();
lcd.init();
lcd.backlight();
if (! rtc.begin()) {
Serial.println("RTC non trouvé!");
}
pinMode(RELAY_PIN, OUTPUT);
digitalWrite(RELAY_PIN, LOW);
pinMode(SWITCH_PIN, INPUT);
pinMode(BUZZER_PIN, OUTPUT);
digitalWrite(BUZZER_PIN, LOW);
lcd.setCursor(0, 0);
lcd.print("Mini Deshydratateur");
delay(2000);
lcd.clear();
}
void loop() {
int switchState = digitalRead(SWITCH_PIN);
// Gérer la séquence de bips si le cycle est terminé (non-bloquant)
if (cycleComplete) {
digitalWrite(RELAY_PIN, LOW); // Assurer que le chauffage est OFF
handleEndTone(); // Gérer les bips et l'affichage de la Ligne 4
// La boucle continue pour permettre la mise à jour de l'heure (Ligne 3)
}
// 1. Gérer la lecture des capteurs (toutes les 2 secondes)
if (millis() - lastReadMillis >= readInterval) {
lastReadMillis = millis();
sensors.requestTemperatures();
currentTemperatureC = sensors.getTempCByIndex(0);
currentHumidity = dht.readHumidity();
float currentTemperatureF = celsiusToFahrenheit(currentTemperatureC);
if (isnan(currentHumidity)) {
Serial.println("Erreur de lecture DHT!");
currentHumidity = -1.0;
}
// Mise à jour de l'affichage (Lignes 1, 2 et 4 - sauf si cycleComplete)
updateDisplay(currentTemperatureF, currentHumidity, switchState);
// 2. Logique de CONTRÔLE PRINCIPALE
// Condition d'arrêt du cycle (Humidité = 0% logique)
if (currentHumidity >= 0.0 && currentHumidity < 0.1) {
// Cette section ne s'exécute qu'une seule fois au moment de la détection
if (!cycleComplete) {
cycleComplete = true;
digitalWrite(RELAY_PIN, LOW);
// Affichage d'arrêt permanent selon les spécifications :
lcd.clear();
// Ligne 1: "CYCLE TERMINE" centré (20 chars, début à index 4)
lcd.setCursor(4, 0);
lcd.print("CYCLE TERMINE");
// Ligne 2: "Humidite: 0%"
lcd.setCursor(0, 1);
lcd.print("Humidite: 0%");
// Ligne 3: Sera mis à jour par updateTimeDisplay()
// Ligne 4: Gérée par handleEndTone()
Serial.println("!!! CYCLE COMPLETE !!!");
}
// Après le déclenchement, on revient au début de loop()
}
// Logique de contrôle thermique (Hystérésis)
// Le contrôle n'a lieu que si le cycle n'est PAS terminé.
if (!cycleComplete && switchState == HIGH) { // Mode Opérationnel (Interrupteur ON)
if (currentTemperatureF < TEMP_SEUIL_MIN_F) {
digitalWrite(RELAY_PIN, HIGH);
}
else if (currentTemperatureF >= TEMP_SEUIL_MAX_F) {
digitalWrite(RELAY_PIN, LOW);
}
} else if (!cycleComplete && switchState == LOW) { // Mode Maintenance/Arrêt (Interrupteur OFF)
digitalWrite(RELAY_PIN, LOW);
}
}
// 3. Gérer l'affichage de l'heure (toutes les secondes) (Ligne 3)
if (millis() - lastTimeDisplayMillis >= timeInterval) {
lastTimeDisplayMillis = millis();
updateTimeDisplay();
}
}
// Fonction pour gérer la séquence de bips de manière non-bloquante
void handleEndTone() {
// Si la séquence est terminée, on s'assure que le buzzer est éteint et on sort
if (toneCount >= MAX_TONE_TOGGLES) {
noTone(BUZZER_PIN);
return;
}
// Gestion de l'intervalle de temps
if (millis() - lastToneToggleMillis >= TONE_DURATION) {
lastToneToggleMillis = millis();
toneCount++; // Incrémente le compteur de basculements
lcd.setCursor(0, 3); // Ligne 4: État du Bips
if (toneCount % 2 != 0) {
// Bip ON (1, 3, 5, 7, 9ème toggle)
tone(BUZZER_PIN, 1000);
lcd.print("Bips: ON "); // Mise à jour de l'état du bip
} else {
// Bip OFF (2, 4, 6, 8, 10ème toggle)
noTone(BUZZER_PIN);
lcd.print("Bips: OFF "); // Mise à jour de l'état du bip
}
}
// Si la séquence vient de se terminer (11ème appel)
if (toneCount == MAX_TONE_TOGGLES) {
noTone(BUZZER_PIN);
lcd.setCursor(0, 3);
lcd.print("Bips: TERMINE ");
}
}
// Fonction de conversion Celsius vers Fahrenheit
float celsiusToFahrenheit(float celsius) {
return (celsius * 1.8) + 32;
}
// Fonction pour mettre à jour l'écran des capteurs et de l'état
void updateDisplay(float tempF, float hum, int switchState) {
// N'affiche pas les données de fonctionnement si le cycle est terminé
if (cycleComplete) { return; }
// Variables d'état actuelles
int currentRelayStatus = digitalRead(RELAY_PIN);
// --- LIGNE 1 (Index 0) : État du Chauffage (Anti-Scintillement) ---
if (switchState != lastControlMode || currentRelayStatus != lastRelayStatus) {
lcd.setCursor(0, 0);
if (switchState == HIGH) { // Mode AUTO
const char* heating_status = (currentRelayStatus == HIGH) ? "ON" : "OFF";
// snprintf garantit la taille max de 20
snprintf(buffer, 21, "CHAUFFAGE: %s%-8s", heating_status, "");
} else { // Mode MANUEL/Arrêt
snprintf(buffer, 21, "SYSTEME ARRETE ");
}
lcd.print(buffer);
lastControlMode = switchState;
lastRelayStatus = currentRelayStatus;
}
// --- FIN LIGNE 1 ---
// Ligne 2 (Index 1): Affichage de la Température et de l'Humidité
char tempStr[8];
char humStr[8];
dtostrf(tempF, 4, 1, tempStr);
if (hum < 0.0) {
strcpy(humStr, "--");
} else {
dtostrf(hum, 2, 0, humStr);
}
snprintf(buffer, 21, "T:%sF | H:%s%% ", tempStr, humStr);
lcd.setCursor(0, 1);
lcd.print(buffer);
// Ligne 4 (Index 3): État du Mode
const char* modeStr = (switchState == HIGH) ? "AUTOMATIQUE" : "MANUEL COUPE";
snprintf(buffer, 21, "Mode: %s ", modeStr);
lcd.setCursor(0, 3);
lcd.print(buffer);
}
// Fonction dédiée à l'affichage de l'heure (Ligne 3 - Index 2)
void updateTimeDisplay() {
// L'heure continue de se mettre à jour même si cycleComplete est vrai
DateTime now = rtc.now();
lcd.setCursor(0, 2);
snprintf(buffer, 21, "Heure: %02d:%02d:%02d ", now.hour(), now.minute(), now.second());
lcd.print(buffer);
}
Loading
ds18b20
ds18b20