Une régulation simple
par
popularité : 63%
Le but est d’automatiser le fonctionnement d’un chauffe eau solaire avec un régulateur différentiel de température.
La principale fonction du régulateur est de mettre en service une pompe de circulation lorsque les conditions de température sont atteintes et respectées.
Il y a deux capteurs de température
T1, qui indique la température dans le panneau solaire
T2, qui indique la température dans le bas du ballon d’eau chaude
Principe de fonctionnement
Lorsque T1 dépasse T2 de plus de 8°C, le circulateur est mis en route. Au bout de 10 minutes, le temps que les températures s’équilibrent sur tout le circuit, on commence à vérifier les conditions d’arrêt du circulateur. Il restera en fonctionnement tant que T1 dépassera T2 de plus de 4°C.
Le matériel nécessaire
Pour faire cette régulation de base, nous allons utiliser :
Une carte Arduino Uno avec son alimentation
Un relai 220V, commandé en 5 volts
Deux sondes de température
Une carte Arduino Uno
C’est la carte électronique que nous allons programmer et qui va commander la mise en route du régulateur.
La principale documentation francophone se trouve sur le site mon-club-elec.fr
Son prix : de 20 à 25 € plus 5 à 10 € pour l’alimentation
Un relai 220V, commandé en 5 volts
Son prix : 8 à 20 €
Deux sondes de température
Il existe plusieurs types de sonde de température :
Les capteurs résistifs, type PT100 ou PT1000 sont très utilisés dans l’industrie. Il présentent une résistance qui varie selon la température.
Les capteurs silicium analogiques qui délivrent une tension proportionnelle à la température. Le plus connu est le LM35.
Les capteurs silicium numériques qui donnent directement la température via un protocole de communication. C’est ce type de capteur, le DS18B20 pour être précis, que nous allons utiliser. Une bonne description en est faite sur le site mon-club-elec.fr. Chaque capteur possède sa propre adresse. Cette page permet de déterminer l’adresse de chaque capteur, adresse qu’il faudra connaitre pour programmer la régulation.
Son prix : de moins de 2 € nu à plus de 15 € monté dans un doigt étanche en inox (capteur câblé).
Une résistance
Une résistance de 4,7 kΩ
A titre d’exemple, le total revient à moins de 62 € port compris chez SnootLab.
Le montage
On va utiliser le port numérique 3 de l’Arduino pour lire les températures. Le port analogique 4 (A4) sera utilisé pour commander le relai.
- Schéma
- Schéma de montage d’une régulation simple.
Un des capteurs se trouvant dans les panneaux solaires, souvent sur le toit de la maison, il peut y avoir une certaine distance entre la carte Arduino qui se trouvera en général près du ballon d’eau chaude, et le capteur. La solution la moins onéreuse que j’ai trouvé pour relier les capteurs de température est d’utiliser du câble Ethernet. On en trouve à 35 € la bobine de 100 mètres. J’utilise 3 des 4 paires torsadées à raison d’une paire par patte :
la paire orange pour la masse, qui correspond au noir du capteur câblé
la paire verte pour les données, qui correspond au jaune du capteur câblé
la paire marron pour l’alimentation +5V, qui correspond au rouge du capteur câblé
- Montage DS18B20
- Câblage du capteur DS18B20
Le programme
Et voici la partie la plus redoutable. Mais vous allez voir, il n’y a rien de très sorcier.
Je n’ai pas l’intention ici de détailler la programmation d’une carte Arduino. Pour cela, vous trouverez toutes les explications et les tutoriaux sur l’excellent site francophone mon-club-elec.fr.
Le code se décompose en 4 parties, dans cet ordre :
1. Les déclarations
2. L’initialisation
3. La boucle
4. Les fonctions diverses
1. Les déclarations
C’est ici que seront déclarées les bibliothèques utilisées. L’avantage de la plateforme Arduino est qu’il existe de nombreuses bibliothèques prêtes à l’emploi. Dans le cas qui nous intéresse, c’est toute la gestion des sondes de température qui existe déjà . Il suffira de reprendre des fonctions de la bibliothèque, fonctions que nous n’auront donc pas à écrire.
On va aussi déclarer les variables globales, c’est à dire en gros, les variables toujours disponibles, ainsi que les objets.
2. L’initialisation
C’est la fonction setup()
. Cette fonction n’est exécutée qu’une seule fois au démarrage de la carte. En fait, cela sert à initialiser la carte avant de pouvoir s’en servir.
Ici, on va initialiser les broches de la carte, alimenter les capteurs de température, stopper la pompe de circulation si celle-ci est en route. Le but est de mettre l’installation dans un état que l’on va pouvoir ensuite exploiter. Il ne faut pas perdre de vue qu’on ne sait pas à priori dans quel état se trouve l’installation.
3. La boucle
Voici le cÅ“ur du programme. C’est la fonction loop()
. Une fois l’initialisation terminée, la carte va exécuter cette fonction en boucle infinie. C’est à dire que aussitôt terminée, elle est relancée.
C’est ici que vont être gérés les différents états de l’installation, et que les décisions vont se prendre en fonction des informations renvoyées par les capteurs de température.
En résumé, on commence par lire les capteurs de température, et en fonction de l’état dans lequel se trouve l’installation, une action et / ou un changement d’état peut être décidé.
A la fin, on attend un petit peu, ici une demi seconde, ce qui est très court, car les températures n’évoluent pas si vite.
4. Les fonctions diverses
Le but de ces fonctions est souvent de structurer le code de la boucle. Soit c’est un bout de code utilisé à plusieurs endroits, auquel cas il est intéressant de ne l’écrire qu’une seule fois, soit c’est juste un bout de code que l’on isole et qui aura désormais un nom. Au niveau du programme en lui même, cela ne change rien, par contre, au niveau de la lecture du code et de sa compréhension par l’auteur ou un autre développeur, cela clarifie grandement les choses.
Et voici l’intégralité du code.
- // --- Programme Arduino ---
- // Copyright finizi - Créé le 14/07/2012
- // www.DomoEnergyTICs.com
- // Code sous licence GNU GPL :
- // This program is free software: you can redistribute it and/or modify
- // it under the terms of the GNU General Public License as published by
- // the Free Software Foundation, either version 3 of the License,
- // or any later version.
- // This program is distributed in the hope that it will be useful,
- // but WITHOUT ANY WARRANTY; without even the implied warranty of
- // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- // GNU General Public License for more details.
- // You should have received a copy of the GNU General Public License
- // along with this program. If not, see <http://www.gnu.org/licenses/>.
- //
- /*
- ******************************************************************************************************************************************************
- **
- ** Utilisation des broches
- **
- ** Analogiques
- ** 4 : => Solar Relai pompe de circulation
- **
- ** Digitales
- ** 3 : => bus OneWire
- **
- ******************************************************************************************************************************************************
- */
- /*
- ******************************************************************************************************************************************************
- **
- ** Début du code
- ** . Includes
- ** . Defines
- ** . Variables globales
- ** . Objets
- **
- ******************************************************************************************************************************************************
- */
- #include <avr/wdt.h> // Pour le WatchDog
- #include <OneWire.h> // Pour les capteurs de température
- /*
- ** Déclaration des constantes et des paramètres
- */
- #define paramLongSun 600000 // en millisecondes : Durée de fonctionnement à partir de laquelle on considère que le fonctionnement est établi depuis longtemps (600000 = 10 minutes)
- #define paramDeltaTempStart 8.0 // en degrés : Ecart de température nécessaire pour la mise en route de la pompe
- #define paramDeltaTempStop 4.0 // en degrés : Ecart de température minimum pour le fonctionnement de la pompe
- #define etatInconnu 0 // L'état est inconnu. C'est la valeur par défaut. C'est donc l'état au démarrage
- #define etatArret 4 // Le circuit est plein, prêt à fonctionner. La pompe est à l'arrêt
- #define etatSoleil 5 // La pompe fonctionne et le soleil chauffe les panneaux
- #define etatLongSoleil 6 // La pompe fonctionne et le soleil chauffe les panneaux depuis plus de paramLongSoleil
- #define etatManuOff 8 // Toute l'installation est mise à l'arrêt
- #define etatManuPump 9 // La pompe de circulation est en marche forcée
- #define onewireModeLecture 0xBE // Code pour initier la lecture des capteurs OneWire
- #define onewireModeMesure 0x44 // Code pour déclencher la lecture des capteurs OneWire
- #define onewireNb 2 // Nombre de capteurs OneWire gérés
- const int pinOneWire = 3; // Broche utilisée pour lire les températures disponibles via des composant One-Wire DS18B20
- const int pinRelayPump = A4; // Commande du relai de pompe de circulation
- #define relayOn 0
- #define relayOff 255
- /*
- ** Déclaration des variables et initialisations
- */
- int etat = etatInconnu;
- int lastEtat = etatInconnu;
- float tempPanel = -99.9;
- float tempBottom = -99.0;
- // Adresses matérielles des capteurs One-Wire <== Là , il faut mettre les adresses des capteurs réellement utilisés
- static byte onewireSensorSerial[onewireNb][8] = {
- { 0x28, 0x55, 0x63, 0x02, 0x04, 0x00, 0x00, 0x06 }, // Température à l'intérieur des panneaux solaires
- { 0x28, 0x55, 0x75, 0x02, 0x04, 0x00, 0x00, 0x40 }, // Bas du ballon d'eau chaude
- };
- // Chaines d'état à afficher (certaines seront utilisées plus tard)
- const String etatsText[10] = {
- "Inconnu", // #define etatInconnu 0
- "Vide", // #define etatVide 1
- "Remplissage", // #define etatRemplissage 2
- "Vidange", // #define etatVidange 3
- "Arret", // #define etatArret 4
- "Soleil", // #define etatSoleil 5
- "SoleilLong", // #define etatLongSoleil 6
- "ClosingValve", // #define etatClosingValve 7
- "ManuOff", // #define etatManuOff 8
- "ManuPompe" // #define etatManuPump 9
- };
- const float temperatureMini = -40.0; // Température en dessous de la quelle elle n'est pas prise en compte
- const unsigned long temperatureReadInterval = 10L * 1000L; // Temps entre 2 lectures de température
- unsigned long pumpStartTime = 0; // Temps écoulé, en millisecondes, depuis le démarrage de la pompe de circulation
- unsigned long temperatureTime = 0; // Temps écoulé, en millisecondes, depuis la dernière lecture des températures
- /*
- ** Création des objets
- */
- OneWire oneWire(pinOneWire); // On défini la broche utilisée pour OneWire
- /*
- ******************************************************************************************************************************************************
- **
- ** setup ==> Fonction obligatoire d'initialisation
- **
- ******************************************************************************************************************************************************
- */
- void setup() {
- // Initialisation du WatchDog. Se déclenche au bout de 8 secondes d'inactivité
- wdt_enable(WDTO_8S);
- // Initialiser les broches pour que le relai soit inactif au démarrage
- analogWrite(pinRelayPump, relayOff);
- // Initialiser les autres broches comme broche de commande
- pinMode(pinRelayPump, OUTPUT);
- // Ouvrir tous les relais (ne plus rien alimenter)
- stopPump();
- // Effectue une première mesure pour alimenter les capteurs de température
- for (int i = 0; i <= onewireNb; i++) {
- onewireMesureTemp(onewireSensorSerial[i]);
- }
- delay(2000);
- for (int i = 0; i <= onewireNb; i++){
- onewireMesureTemp(onewireSensorSerial[i]);
- }
- delay(1000);
- etat = etatInconnu;
- lastEtat = etatInconnu;
- }
- /*
- ******************************************************************************************************************************************************
- **
- ** loop ==> Fonction obligatoire. Boucle infinie de fonctionnement
- **
- ******************************************************************************************************************************************************
- */
- void loop() {
- // Reset du watchDog : C'est reparti pour 8 secondes
- wdt_reset();
- /*************************************************************
- **
- ** Lecture de tous les capteurs
- */
- boolean temperatureRead = 0;
- if ( (temperatureTime == 0) || ( (millis() - temperatureTime > temperatureReadInterval) && (millis() >= temperatureTime) ) ) {
- temperatureTime = millis();
- /// Lecture des températures
- tempPanel = onewireMesureTemp(onewireSensorSerial[0]);
- tempBottom = onewireMesureTemp(onewireSensorSerial[4]);
- temperatureRead = true;
- }
- /*************************************************************
- **
- ** Actions à mener en fonction des mesures effectuées et de l'état en cours
- */
- switch(etat) {
- case etatManuOff: // ==> L'installation a été mise à l'arrêt manuellement
- // Ne rien faire et laisser ainsi
- break;
- case etatManuPump: // ==> La pompe est en marche forcée (mise en marche manuelle)
- // Ne rien faire et laisser ainsi
- break;
- case etatArret: // ==> la pompe est à l'arrêt
- // Vérifier si les condition de mise en route sont remplies
- if (tempPanel >= tempBottom + paramDeltaTempStart) {
- startPump();
- }
- break;
- case etatSoleil: // ==> La pome de circulation est en route de façon NON prolongée
- // Vérifier si la pompe doit être arrêtée
- if (tempPanel <= tempBottom + paramDeltaTempStop) {
- stopPump();
- etat = etatArret;
- }
- // Vérifier si le régime de croisière est atteint
- if ( (millis() - pumpStartTime > paramLongSun) && (millis() >= pumpStartTime) ) {
- pumpStartTime = 0;
- etat = etatLongSoleil;
- }
- break;
- case etatLongSoleil: // ==> La pome de circulation est en route de façon prolongée et est donc en régime de croisière
- // Vérifier si l'écart de température entre les panneaux et le bas du ballon d'eau chaude est suffisante
- if (tempPanel <= tempBottom + paramDeltaTempStop) {
- stopPump();
- etat = etatArret;
- }
- break;
- case etatInconnu: // ==> Survient normalement au démarrage
- stopPump();
- etat = etatArret;
- break;
- }
- // Enregistrer l'état pour la boucle suivante
- lastEtat = etat;
- // Attendre un peu avant de boucler (une demi seconde)
- delay(500);
- }
- /*
- ******************************************************************************************************************************************************
- **
- ** Fonctions diverses
- **
- ******************************************************************************************************************************************************
- */
- /*
- ** Fonction pour arrêter la pompe de circulation. L'installation devient alors à l'arrêt
- */
- void stopPump() {
- analogWrite(pinRelayPump, relayOff);
- pumpStartTime = 0;
- etat = etatArret;
- }
- /*
- ** Fonction pour démarrer la pompe de circulation. L'installation devient alors en fonctionnement
- */
- boolean startPump() {
- analogWrite(pinRelayPump, relayOn);
- pumpStartTime = millis();
- etat = etatSoleil;
- return(true);
- }
- /*
- ** Fonction pour lire une température sur le capteur dont l'adresse est en paramètre
- */
- float onewireMesureTemp(byte addr[8]) {
- byte data[12]; // Tableau de 12 octets pour lecture des 9 registres de RAM et des 3 registres d'EEPROM du capteur One Wire
- int tempet = 0; // variable pour resultat brute de la mesure
- float tempetf = 0.0; // variable pour resultat à virgule de la mesure
- oneWire.reset();
- oneWire.select(addr);
- oneWire.write(onewireModeMesure, 1); //
- oneWire.reset();
- oneWire.select(addr);
- oneWire.write(onewireModeLecture); // Récupération des valeurs de la RAM du capteur
- // Lire les 9 octets de la RAM (appelé Scratchpad)
- for ( int i = 0; i < 9; i++) { // 9 octets de RAM stockés dans 9 octets
- data[i] = oneWire.read(); // lecture de l'octet de rang i stocké dans tableau data
- }
- tempetf = ((data[1] << 8) | data[0]) * 0.0625;
- return (tempetf);
- }
Pour aller plus loin
Voilà , les bases sont posées.
Ce petit code à fait tourner pendant 2 mois une installation solaire thermique. Ce n’est qu’un début car il manque beaucoup de choses. Il est en effet assez frustrant de ne pas pouvoir surveiller et contrôler cette installation autrement qu’en débranchant l’alimentation.
Un autre article montrera comment la vidange antigel a été mise en place et comment l’installation a été reliée au réseau local pour sa surveillance et son contrôle...
Commentaires forum ferme