gestion de relais en bistable

Bonjour à tous,
Je viens vers vous car je ne comprends rien dans certaines commandes Arduino.
Petit nouveau dans l’Arduino, je viens de faire un automate pour la gestion de mes aquariums.

  • Eclairage,

  • Thermorégulation : chauffage / ventilation

  • Etc….
    J’arrive à tout faire fonctionner ou presque :

  • Si je me sers du bout de programme qui permet une gradation de la lumière, l’allumage / extinction progressif fonctionne, mais la mesure de température passe de -127°c à la valeur réelle comme en cas de faux contact (sonde ds18b20 en onewire) Par contre si je commande les leds avec un relais tout va bien (cas actuellement) je me doute donc qu’il s’agit d’un parasitage entre la sortie PWM et ma sonde de température ??? avez-vous une idée ?

  • Second soucis et c’est mon plus gros problème : je souhaite faire une électrolyse de l’eau (style Shihiro Doctor) en gros on envoie une tension continue sur 2 grilles inox espacées de qque mm (jusque-là, tout va bien). Mais c’est au niveau de la temporisation que le bas blesse. En fait il faudrait que je commande deux relais en cascade :

o Le premier me commute la tension on / off
o Le second inverse la polarité
 Ex le premier colle 1 minute toute les 5 minutes et le second commande 30 secondes +/- et 30 secondes -/+
o Pour mon cas j’ai bien compris que delay() n’est pas envisageable, mais je ne comprends pas tout entre millis(), timer(), etc

le code:

/* 
AUTOMATE AQUARIUM 100L
AUTEUR: JACKY
Date: 01/05/2019
Revision: version 1.2
---- ATTENTION RELAIS INVERSES ----
*/

#include <LiquidCrystal_I2C.h>
#include <Arduino.h>
#include <Time.h>
#include <Wire.h>
#include <DS1307RTC.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#define ONE_WIRE_BUS 2

/*
  Analog Pin A0 = Relais Chauffage
  Analog pin A1 = relais co2
  Analog pin A2 = bouton poussoir lumiere du jour
  Analog pin A3 = bouton poussoir chauffage
  Analog Pin A4 = SDA pour ds1307 et LCD en I2C
  Analog Pin A5 = SCL pour ds1307 et LCD en I2C
  Digital Pin 2 = Sonde de Temperature
  Digital Pin 9 = relais lumière
  digital pin 10 = PWM1 lumière du jour 
  Digital pin 12 = relais chihiro doctor
  digital pin 13 = relais ventilation
*/


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

int consigne = 26;
float temp = 0;
int chauffage = A0;// Relais chauffage
//int co2 = A1;// relais CO2
int BP1 = A2; // interrupteur lumière du jour
int BP2 = A3; // interrupteur Chauffage
int eclairage = 9; // relais lumière
int pwm1 = 10;// lumière du jour 1
int chihiro = 12;// Relais chihiro
int ventilation = 13;// Relais ventilation
int time;
int val_up = 0;
int val_down = 0;
long last_time1 = 0;
long last_time2 = 0;
long last_time3 = 0;

LiquidCrystal_I2C lcd(0x27,20,4);  // set the LCD address to 0x27 for a 20 chars and 4 line display


void setup()  {
  Serial.begin(9600);
  sensors.begin();
  pinMode(chauffage, OUTPUT); // met la broche chauffage en sortie (relais)
//  pinMode(co2, OUTPUT); // met la broche CO2 en sortie (relais)
  pinMode(BP1, INPUT); //met la broche en entree (bouton lumère du jour)
  digitalWrite(BP1, HIGH); // activation du pullup de la broche en entree
  pinMode(BP2, INPUT); //met la broche en entree (bouton chauffage)
  digitalWrite(BP2, HIGH); // activation du pullup de la broche en entree
  pinMode(ventilation, OUTPUT); //met la broche ventilation en sortie (relais)
  pinMode(chihiro, OUTPUT); //met la broche chihiro en sortie (relais)
 // analogWrite(pwm1, 0);
  pinMode(eclairage, OUTPUT); //met la broche eclairage en sortie (relais)
  lcd.init(); // initialise l'écran LCD 
  // message d'accueil du LCD
  lcd.backlight(); //allumage retro-éclairage ecran
  delay(10);
  lcd.print("  Gestion Aquarium");
  lcd.setCursor(0, 1);
  lcd.print("       JACKY");
  delay(2000);
  lcd.setCursor(20, 0);
  setSyncProvider(RTC.get);
  if (timeStatus() != timeSet)
    lcd.print("  RTC NON CONNECTE ");
  else
    lcd.print(" HORLOGE TEMPS REEL");
  delay(2000);
  lcd.clear();
  delay(10);
}

void loop() {
  val_up = (map (minute(), 0, 59, 0, 250));
  val_down = (map (minute(), 0, 59, 250, 0));
  time = ((hour() * 100) + minute());


  //Recuperer la temperature du DS3231*******************************
  sensors.requestTemperatures();
  temp = sensors.getTempCByIndex(0);


  //Chauffage********************************
  if((temp < 26.5) || (digitalRead(BP2)==LOW)) {     
    digitalWrite(chauffage, LOW);
  }  
  else if (temp > 27.0)
  {  
    digitalWrite(chauffage, HIGH); 

  }

 //ventilation********************************
    if((temp > 28.5) ) {
      digitalWrite(ventilation, LOW);
    }
    else if (temp < 27.5)
    {
      digitalWrite(ventilation, HIGH);
    }
  


/*//Lumière du jour ECLAIRAGE PROGRESSIF *************************************
  if (hour() == 7)  { // entre 07:00:00 et 07:59:59
    analogWrite (pwm1, val_up); // allumage progressif
  }
  else if (hour() == 19)  { // entre 19:00:00 et 19:59:59
    analogWrite (pwm1, val_down); // extinction progressive
  }
  else if ((hour() > 7,59 ) && (hour() < 19)) { // entre 08:00:00 et 18:59:59
    analogWrite(pwm1, 250);
  }
  else if ((((hour() > 0  && hour() < 8)) && (digitalRead(BP1) == LOW)) || (((hour() > 19  && hour() < 24)) && (digitalRead(BP1) == LOW)) || ((hour() == 0) && (digitalRead(BP1) == LOW))) {
    analogWrite(pwm1, 250);
  }
  else if ((((hour() > 0  && hour() < 8)) && (digitalRead(BP1) == HIGH)) || (((hour() > 19  && hour() < 24)) && (digitalRead(BP1) == HIGH)) || ((hour() == 0) && (digitalRead(BP1) == HIGH))) {
    analogWrite(pwm1, 0);
  }
*/

  //eclairage****************************
  if ((hour() >= 8 ) && (hour() <= 19) || (digitalRead(BP1)==LOW))  { // entre 08:00:00 et 19:59:59
    digitalWrite(eclairage, LOW);
  }
  else
  {
    digitalWrite(eclairage, HIGH);
  }



  //Affichage chauffage / ventilation**********************
  lcd.setCursor(20, 0);
  if (digitalRead(chauffage) == LOW)
  {
    lcd.print("  Chauffage Marche  ");
  }
  else if (digitalRead(ventilation) == LOW) 
  {
    lcd.print(" Ventilation Marche  ");
  }
  else if (digitalRead(chauffage) == HIGH)
  {
    lcd.print("      C/V Arret     ");
  }


  //Affichage heure********************************
  if ( millis() >= (last_time1 + 1000))
  {
    lcd.setCursor(2, 0);
    if ( day() < (10)) lcd.print("0");
    lcd.print(day());
    lcd.print("/");
    if ( month() < (10))  lcd.print("0");
    lcd.print(month());
    lcd.print("/");
    lcd.print(year());
    lcd.print(" ");
    if ( hour() < (10)) lcd.print("0");
    lcd.print(hour());
    printDigits(minute());
    //printDigits(second());
    last_time1 = millis();
  }


  //Affichage temperature**************************
  if ( millis() >= (last_time2 + 5000))
  {
    lcd.setCursor(0, 1);
    lcd.print(" Temperature ");
    lcd.print(temp);
    lcd.print("C   ");
    last_time2 = millis();
  }

  
/*
  //GESTION CO2**************************
  if ((hour() >= 8 ) && (hour() <= 19)) { // entre 08:00:00 et 19:59:59
    digitalWrite(co2, LOW);
  }
  else
  {
    digitalWrite(co2, HIGH);
  }


  //Affichage CO2 allumé**********************
  lcd.setCursor(20, 1);
  if (digitalRead(co2) == LOW)
  {
    lcd.print("     CO2 Marche  ");
  }
  else
  {
    lcd.print("      CO2 Arret   ");
  }
*/
}


void printDigits(int digits) {
  // utility function for digital clock display: prints preceding colon and leading 0
  lcd.print(":");
  if (digits < 10)
    lcd.print('0');
  lcd.print(digits);
}

merci pour votre aide

Vous devriez commencer par lire l'exemple blinkWithoutDelay, livré avec l'IDE (un des tous premiers exemples).
Pour aller plus loin, Programmation Automate fini / Machine à état - Tutoriels et cours - Arduino Forum, post 3 est parfait (vous n'avez pas besoin de gérer finement, avec une horloge dédiée, les delais : utiliser l'horloge du resonnateur de l'arduino suffit bien -0.01 % d'erreu- et reserver timer pour afficher l'heure exacte (une resolution de 10-4 ferait perdre/gagner 8 secondes par jour, 4 minutes par mois....)

Bonjour,
mes talents en anglais étant limités :slight_smile: je pense quand même avoir saisi le principal (blinkWithoutDelay)
par contre je n'ai pas compris, dans votre lien post 3, ce qui pouvais correspondre a mon besoin (ou j'ai mal lu)

ensuite, pourquoi utiliser l'horloge du résonateur alors que j'ai une rtc qui est présente et que j'utilise déjà?
quel est l’intérêt d'utiliser le résonateur et comment l'utiliser? ???

en fait mon soucis est uniquement (je pense) le comment faire fonctionner "milli", j'entend parler de débordement, de "ça plante au bout de 50 jours"

ma question est plutôt de savoir si, exemple:

  • je peux déclarer 3 constantes :

  • const int tempo1=300000;

  • const int tempo2=60000;

  • const int tempo3=30000;

  • a l’image de blinkWithoutDelay

  • actionner un relais toutes les 5 minutes (tempo1) pendant 1 minute (tempo2)

  • quand le premier est activé actionner le second (inverseur) 30 secondes/30 secondes (tempo3)

le tout avec la commande milli et sans perturbation pour le reste du programme ? ???

est ce réalisable sur ce modèle ? ??? ou suis-je en train de partir dans le mur ? ???

comme dit plus haut je ne comprend pas le concept du "débordement" lié au calcul (si j'ai bien compris addition dans une/des variable(s) des tempos ), ne peut on pas faire un reset de ces variables (le 1er de chaque mois a 0h00)pour éviter ce débordement ? ???

voila
merci pour vos réponses
jacky

Tout est là : arduino-tutorial-avoiding-the-overflow-issue-when-using-millis-and-micros/

Le debordement a lieu de la façon suivante: les millisecondes sont stockées en uint32_t (entier non signé à 32 bits) 210 étant voisin de 1000, vous pouvez compter confortablement ** jusqu'à 22 * 210 * 2**10 == 4 000 000 == 4E6;
or, il y a 86400 secondes par jour (en gros, 1 E5: ): ce qui vous fait 40 jours où le comptage se fait sans Annie Croche.
Maintenant, que se passe-t-il au voisinage des 50 jours fatidiques (vous n'aurez pas la patience d'attendre et moi non plus)
le test est https://github.com/esp8266/Arduino/blob/master/libraries/esp8266/examples/BlinkWithoutDelay/BlinkWithoutDelay.ino:

 if ( currentmillis- previousMillis >= interval)

au moment du debordement
currentmillis vaut environ zero
previousmillis vaut environ 4E6
la difference sera enorme, et son signe ignoré -> tout se passera bien. On peut le vérifier avec un tout petit bout de programme suivant

$ vi debord.c

 ~
$ cat debord.c && g++ debord.c && ./a.exe
#include <stdint.h>
#include <stdio.h>
uint32_t currentmillis=100, previousmillis=4000000; // in a mos des types universels, pour pouvoir tester sur pc
int main() {
  printf("cur :%x prev: %x diff %x\n", currentmillis,  previousmillis,
            currentmillis- previousmillis);
return 0;
}
cur :64 prev: 3d0900 diff ffc2f764

La difference (non signée) est effectivement énorme et le test sera vérifié; les moments inconfortables se passent bien et cessez de vous en preoccupper .

L'avantage de préférer l'horloge interne de l'arduino à une horloge externe (qu'on peut très bien reserver à des determinations précises du temps) est double:
a) ça fait un peu moins de flash (millis est très concise) et un peu moins de cycles (une transition I2C à 1000 khz -plus rapide que l'I2C des horloges, de mémoire- prend 10 microsecondes pour ramener un octet, soit 160 cycles; copier 4 octets (lourde tâche de millis) ne prend pas 8 cycles...

b) c'est un peu plus fiable (une horloge externe peut se débrancher sous l'effet de la malchance; elle peut tomber en panne)
et la perte de précision -3 millisecondes pour un delai de 30 secondes- est négligeable devant les avantages exposés plus haut.

  • je peux déclarer 3 constantes :
  • const int tempo1=300000;
  • const int tempo2=60000;
  • const int tempo3=30000;

Déclarez les plutôt comme ça, avec des types universels

        - const int32_t tempo1=300000L;

- const int32_t  tempo2=60000L;
        - const int32_t tempo3=30000L;



L'avantage est que vous ne tournerez pas en bourrique lorsque vous voudres faire des délais vraiment longs (comme vous l'avez écrit, ça peut marcher parfaitement, mais vous aurez des problèmes avec tempo2 (trop grand pour être un entier d'arduino; deviendra négatif)... et, à terme, avec tout