Dernière révision : septembre 2023










Projet Arduino n° 5

Philippe Notez (philippe.notez@musee-info.fr)





Sommaire

Introduction

L’électronique et l’informatique ont profondément modifié notre société. C’est certainement la révolution industrielle la plus rapide de l’histoire de l’humanité. En effet, l’ordinateur que nous connaissons aujourd’hui était tout simplement inimaginable il y a seulement une cinquantaine d’années. Et avec les Arduino, les ESP8266 ou les Raspberry Pi Pico, l'aventure est loin d'être terminée.

L’auteur ne pourra en aucun cas être tenu responsable des dommages qui résulteraient de l’utilisation des informations publiées sur ce site, sous licence Creative Commons BY-NC-SA. Toute reproduction ou modification d'un document, même partielle, est autorisée à condition que son origine et le nom de l'auteur soient clairement indiqués (BY), qu'il soit utilisé à des fins non commerciales (NC), que son mode de diffusion soit identique au document initial (SA), et que cela ne porte pas atteinte à l’auteur.

Ce document présente un projet utilisant une carte Arduino, en espérant toujours être le plus clair et précis possible. Malgré tout le soin apporté à la rédaction, l'auteur vous remercie de bien vouloir le contacter si vous relevez la moindre erreur ou omission, et vous souhaite une agréable lecture.

Si vous avez apprécié ce document, vous pouvez faire un don ici. Merci pour votre soutien.


Objectif

Mettre à jour la date et l'heure (module DS3231), définir la date et l'heure pour la marche et l'arrêt de 4 relais, afficher la date et l'heure sur un écran LCD.


Niveau




Matériel utilisé
  • un support pour Arduino Nano ou une plaque d'essai (breadboard) 170 / 400 / 830 points
  • une carte Arduino Nano
  • un module horloge temps réel DS3231 (quartz interne : moins de dérive)
  • un afficheur LCD 16 x 2
  • un potentiomètre 104 ohm (contraste afficheur)
  • une résistance 150 ohm (rétroéclairage afficheur)
  • un module 4 relais
  • des câbles Dupont
  • un câble USB pour la liaison avec l'ordinateur

Programme (sketch)

ds3231.ino
// mettre à jour la date et l'heure (module DS3231),
// définir la date et l'heure pour la marche et l'arrêt de 4 relais,
// afficher la date et l'heure sur un écran LCD

#include <Wire.h>
#include <EEPROM.h>
#include <LiquidCrystal.h>

#define RS 2
#define E 3
#define R1 9
#define R2 10
#define R3 11
#define R4 12
#define texte_erreur "Erreur sur la saisie !"
#define texte_date " (JJ/MM/AAAA) : "
#define texte_heure " (HH:MM:SS) : "
#define texte_dm "Date de marche pour le relais "
#define texte_hm "Heure de marche pour le relais "
#define texte_da "Date d'arrêt pour le relais "
#define texte_ha "Heure d'arrêt pour le relais "
#define texte_saisie_dm "Entrez la date de marche pour le relais "
#define texte_saisie_hm "Entrez l'heure de marche pour le relais "
#define texte_saisie_da "Entrez la date d'arrêt pour le relais "
#define texte_saisie_ha "Entrez l'heure d'arrêt pour le relais "

LiquidCrystal lcd(RS,E,4,5,6,7);

unsigned char tab_date[11],tab_heure[9];
unsigned char date_mr1[11],heure_mr1[9],date_ar1[11],heure_ar1[9];
unsigned char date_mr2[11],heure_mr2[9],date_ar2[11],heure_ar2[9];
unsigned char date_mr3[11],heure_mr3[9],date_ar3[11],heure_ar3[9];
unsigned char date_mr4[11],heure_mr4[9],date_ar4[11],heure_ar4[9];

void setup()
  {
  unsigned char car=0,saisie1=0,jour=0,i=0,valeur,saisie2=0;

  pinMode(R1,OUTPUT);
  digitalWrite(R1,HIGH);
  pinMode(R2,OUTPUT);
  digitalWrite(R2,HIGH);
  pinMode(R3,OUTPUT);
  digitalWrite(R3,HIGH);
  pinMode(R4,OUTPUT);
  digitalWrite(R4,HIGH);
  Wire.begin();
  lcd.begin(16,2);
  Serial.begin(9600);
  lire_ds3231();
  Serial.write(13);
  Serial.write(10);
  Serial.write("Nous sommes le ");
  Serial.write(tab_date,strlen(tab_date));
  Serial.write(", modifier (o/N) ? ");
  while (car!=13) if (Serial.available()>0)
    {
    car=Serial.read();
    if (car!=13) saisie1=car;
    }
  if (saisie1>32) Serial.write(saisie1);
  Serial.write(13);
  Serial.write(10);
  Serial.write(13);
  Serial.write(10);
  // mettre à jour la date
  if (saisie1=='o')
    {
    Serial.write("Entrez le jour de la semaine (1 = lundi, 7 = dimanche) : ");
    car=0;
    while (car!=13) if (Serial.available()>0)
      {
      car=Serial.read();
      if (car!=13) jour=car;
      }
    if ((jour<49) || (jour>55))
      {
      Serial.write(13);
      Serial.write(10);
      Serial.write(13);
      Serial.write(10);
      Serial.write(texte_erreur);
      delay(1000);
      exit(0);
      }
    Serial.write(jour);
    Serial.write(13);
    Serial.write(10);
    Serial.write(13);
    Serial.write(10);
    Serial.write("Entrez la date");
    Serial.write(texte_date);
    car=0;
    while ((car!=13) && (i<10)) if (Serial.available()>0)
      {
      car=Serial.read();
      if (car!=13) tab_date[i++]=car;
      }
    while (car!=13) car=Serial.read();
    tab_date[i]=0;
    if ((tab_date[0]==0) || (strlen(tab_date)!=10))
      {
      Serial.write(13);
      Serial.write(10);
      Serial.write(13);
      Serial.write(10);
      Serial.write(texte_erreur);
      delay(1000);
      exit(0);
      }
    Serial.write(tab_date,strlen(tab_date));
    Serial.write(13);
    Serial.write(10);
    Serial.write(13);
    Serial.write(10);
    // écrire la date
    Wire.beginTransmission(0x68); // adresse I2C du circuit DS3231 (104)
    Wire.write(0x03);             // adresse du premier registre à écrire
    Wire.write(jour-48);          // jour de la semaine
    // jour du mois
    valeur=tab_date[0]-48;
    valeur<<=4;
    valeur+=tab_date[1]-48;
    Wire.write(valeur);
    // mois
    valeur=tab_date[3]-48;
    valeur<<=4;
    valeur+=tab_date[4]-48;
    Wire.write(valeur);
    // année
    valeur=tab_date[8]-48;
    valeur<<=4;
    valeur+=tab_date[9]-48;
    Wire.write(valeur);
    Wire.write(0x10); // sortie (1 Hz)
    Wire.endTransmission();
    }
  lire_ds3231();
  Serial.write("Il est ");
  Serial.write(tab_heure,strlen(tab_heure));
  Serial.write(", modifier (o/N) ? ");
  car=0;
  while (car!=13) if (Serial.available()>0)
    {
    car=Serial.read();
    if (car!=13) saisie2=car;
    }
  if (saisie2>32) Serial.write(saisie2);
  Serial.write(13);
  Serial.write(10);
  Serial.write(13);
  Serial.write(10);
  // mettre à jour l'heure
  if (saisie2=='o')
    {
    Serial.write("Entrez l'heure");
    Serial.write(texte_heure);
    car=0;
    i=0;
    while ((car!=13) && (i<8)) if (Serial.available()>0)
      {
      car=Serial.read();
      if (car!=13) tab_heure[i++]=car;
      }
    while (car!=13) car=Serial.read();
    tab_heure[i]=0;
    if ((tab_heure[0]==0) || (strlen(tab_heure)!=8))
      {
      Serial.write(13);
      Serial.write(10);
      Serial.write(13);
      Serial.write(10);
      Serial.write(texte_erreur);
      delay(1000);
      exit(0);
      }
    Serial.write(tab_heure,strlen(tab_heure));
    Serial.write(13);
    Serial.write(10);
    Serial.write(13);
    Serial.write(10);
    // écrire l'heure
    Wire.beginTransmission(0x68); // adresse I2C du circuit DS3231 (104)
    Wire.write(0x00);             // adresse du premier registre à écrire
    // secondes
    valeur=tab_heure[6]-48;
    valeur<<=4;
    valeur+=tab_heure[7]-48;
    Wire.write(valeur);
    // minutes
    valeur=tab_heure[3]-48;
    valeur<<=4;
    valeur+=tab_heure[4]-48;
    Wire.write(valeur);
    // heures
    valeur=tab_heure[0]-48;
    valeur<<=4;
    valeur+=tab_heure[1]-48;
    Wire.write(valeur);
    Wire.endTransmission();
    }
  if ((saisie1=='o') || (saisie2=='o'))
    {
    lire_ds3231();
    Serial.write("Nous sommes le ");
    Serial.write(tab_date,strlen(tab_date));
    Serial.write(", il est ");
    Serial.write(tab_heure,strlen(tab_heure));
    Serial.write(13);
    Serial.write(10);
    Serial.write(13);
    Serial.write(10);
    }
  // charger les paramètres depuis l'EEPROM
  valeur=EEPROM[0];
  if (valeur==1) for (i=1;i<=4;i++)
    {
    Serial.write("Charger les paramètres depuis l'EEPROM (o/N) ? ");
    car=0;
    saisie1=0;
    while (car!=13) if (Serial.available()>0)
      {
      car=Serial.read();
      if (car!=13) saisie1=car;
      }
    if (saisie1>32) Serial.write(saisie1);
    Serial.write(13);
    Serial.write(10);
    Serial.write(13);
    Serial.write(10);
    if (saisie1=='o') lire_eeprom(i);
    else modif_par(i);
    }
  else for (i=1;i<=4;i++) modif_par(i);
  }

void lire_ds3231()
  {
  unsigned char date_heure[7],i=0;

  Wire.beginTransmission(0x68); // adresse I2C du circuit DS3231 (104)
  Wire.write(0x00);             // adresse du premier registre à lire
  Wire.endTransmission();       // ne pas déplacer (instruction à mettre juste après le dernier "write") !
  Wire.requestFrom(0x68,7);
  while (Wire.available()>0) date_heure[i++]=Wire.read();
  // jour du mois
  tab_date[0]=(date_heure[4]>>4)+48;
  tab_date[1]=(date_heure[4]&0x0F)+48;
  tab_date[2]='/';
  // mois
  tab_date[3]=(date_heure[5]>>4)+48;
  tab_date[4]=(date_heure[5]&0x0F)+48;
  tab_date[5]='/';
  // année
  tab_date[6]='2';
  tab_date[7]='0';
  tab_date[8]=(date_heure[6]>>4)+48;
  tab_date[9]=(date_heure[6]&0x0F)+48;
  tab_date[10]=0;
  // heures
  tab_heure[0]=(date_heure[2]>>4)+48;
  tab_heure[1]=(date_heure[2]&0x0F)+48;
  tab_heure[2]=':';
  // minutes
  tab_heure[3]=(date_heure[1]>>4)+48;
  tab_heure[4]=(date_heure[1]&0x0F)+48;
  tab_heure[5]=':';
  // secondes
  tab_heure[6]=(date_heure[0]>>4)+48;
  tab_heure[7]=(date_heure[0]&0x0F)+48;
  tab_heure[8]=0;
  }

void lire_eeprom(unsigned char num_relais)
  {
  unsigned char *ptr_dm,*ptr_hm,*ptr_da,*ptr_ha,i,car=0,saisie=0;
  int adr_eeprom;

  switch (num_relais)
    {
    case 1 :
      ptr_dm=&date_mr1[0];
      ptr_hm=&heure_mr1[0];
      ptr_da=&date_ar1[0];
      ptr_ha=&heure_ar1[0];
      break;
    case 2 :
      ptr_dm=&date_mr2[0];
      ptr_hm=&heure_mr2[0];
      ptr_da=&date_ar2[0];
      ptr_ha=&heure_ar2[0];
      break;
    case 3 :
      ptr_dm=&date_mr3[0];
      ptr_hm=&heure_mr3[0];
      ptr_da=&date_ar3[0];
      ptr_ha=&heure_ar3[0];
      break;
    case 4 :
      ptr_dm=&date_mr4[0];
      ptr_hm=&heure_mr4[0];
      ptr_da=&date_ar4[0];
      ptr_ha=&heure_ar4[0];
    }
  adr_eeprom=(num_relais-1)*36+1;
  // date de marche
  for (i=0;i<10;i++) ptr_dm[i]=EEPROM[adr_eeprom++];
  ptr_dm[10]=0;
  Serial.write(texte_dm);
  Serial.write(num_relais+48);
  Serial.write(texte_date);
  Serial.write(ptr_dm,strlen(ptr_dm));
  Serial.write(13);
  Serial.write(10);
  Serial.write(13);
  Serial.write(10);
  // heure de marche
  for (i=0;i<8;i++) ptr_hm[i]=EEPROM[adr_eeprom++];
  ptr_hm[8]=0;
  Serial.write(texte_hm);
  Serial.write(num_relais+48);
  Serial.write(texte_heure);
  Serial.write(ptr_hm,strlen(ptr_hm));
  Serial.write(13);
  Serial.write(10);
  Serial.write(13);
  Serial.write(10);
  // date d'arrêt
  for (i=0;i<10;i++) ptr_da[i]=EEPROM[adr_eeprom++];
  ptr_da[10]=0;
  Serial.write(texte_da);
  Serial.write(num_relais+48);
  Serial.write(texte_date);
  Serial.write(ptr_da,strlen(ptr_da));
  Serial.write(13);
  Serial.write(10);
  Serial.write(13);
  Serial.write(10);
  // heure d'arrêt
  for (i=0;i<8;i++) ptr_ha[i]=EEPROM[adr_eeprom++];
  ptr_ha[8]=0;
  Serial.write(texte_ha);
  Serial.write(num_relais+48);
  Serial.write(texte_heure);
  Serial.write(ptr_ha,strlen(ptr_ha));
  Serial.write(13);
  Serial.write(10);
  Serial.write(13);
  Serial.write(10);
  Serial.write("Modifier les paramètres (o/N) ? ");
  while (car!=13) if (Serial.available()>0)
    {
    car=Serial.read();
    if (car!=13) saisie=car;
    }
  if (saisie>32) Serial.write(saisie);
  Serial.write(13);
  Serial.write(10);
  Serial.write(13);
  Serial.write(10);
  if (saisie=='o') modif_par(num_relais);
  }

void saisir_date(unsigned char *ptr)
  {
  unsigned char car=0,i=0;

  while ((car!=13) && (i<10)) if (Serial.available()>0)
    {
    car=Serial.read();
    if (car!=13) ptr[i++]=car;
    }
  while (car!=13) car=Serial.read();
  ptr[i]=0;
  if ((ptr[0]==0) || (strlen(ptr)!=10))
    {
    Serial.write(13);
    Serial.write(10);
    Serial.write(13);
    Serial.write(10);
    Serial.write(texte_erreur);
    delay(1000);
    exit(0);
    }
  Serial.write(ptr,strlen(ptr));
  Serial.write(13);
  Serial.write(10);
  Serial.write(13);
  Serial.write(10);
  }

void saisir_heure(unsigned char *ptr)
  {
  unsigned char car=0,i=0;

  while ((car!=13) && (i<8)) if (Serial.available()>0)
    {
    car=Serial.read();
    if (car!=13) ptr[i++]=car;
    }
  while (car!=13) car=Serial.read();
  ptr[i]=0;
  if ((ptr[0]==0) || (strlen(ptr)!=8))
    {
    Serial.write(13);
    Serial.write(10);
    Serial.write(13);
    Serial.write(10);
    Serial.write(texte_erreur);
    delay(1000);
    exit(0);
    }
  Serial.write(ptr,strlen(ptr));
  Serial.write(13);
  Serial.write(10);
  Serial.write(13);
  Serial.write(10);
  }

void modif_par(unsigned char num_relais)
  {
  unsigned char *ptr_dm,*ptr_hm,*ptr_da,*ptr_ha,car=0,saisie=0,i;
  int adr_eeprom;

  switch (num_relais)
    {
    case 1 :
      ptr_dm=&date_mr1[0];
      ptr_hm=&heure_mr1[0];
      ptr_da=&date_ar1[0];
      ptr_ha=&heure_ar1[0];
      break;
    case 2 :
      ptr_dm=&date_mr2[0];
      ptr_hm=&heure_mr2[0];
      ptr_da=&date_ar2[0];
      ptr_ha=&heure_ar2[0];
      break;
    case 3 :
      ptr_dm=&date_mr3[0];
      ptr_hm=&heure_mr3[0];
      ptr_da=&date_ar3[0];
      ptr_ha=&heure_ar3[0];
      break;
    case 4 :
      ptr_dm=&date_mr4[0];
      ptr_hm=&heure_mr4[0];
      ptr_da=&date_ar4[0];
      ptr_ha=&heure_ar4[0];
    }
  // date de marche
  Serial.write(texte_saisie_dm);
  Serial.write(num_relais+48);
  Serial.write(texte_date);
  saisir_date(ptr_dm);
  // heure de marche
  Serial.write(texte_saisie_hm);
  Serial.write(num_relais+48);
  Serial.write(texte_heure);
  saisir_heure(ptr_hm);
  // date d'arrêt
  Serial.write(texte_saisie_da);
  Serial.write(num_relais+48);
  Serial.write(texte_date);
  saisir_date(ptr_da);
  // heure d'arrêt
  Serial.write(texte_saisie_ha);
  Serial.write(num_relais+48);
  Serial.write(texte_heure);
  saisir_heure(ptr_ha);
  Serial.write("Enregistrer les paramètres dans l'EEPROM (o/N) ? ");
  while (car!=13) if (Serial.available()>0)
    {
    car=Serial.read();
    if (car!=13) saisie=car;
    }
  if (saisie>32) Serial.write(saisie);
  Serial.write(13);
  Serial.write(10);
  Serial.write(13);
  Serial.write(10);
  if (saisie=='o')
    {
    // EEPROM.update(int adresse, octet) : lire, puis écrire si l'octet est différent
    // EEPROM.put(int adresse, variable) : écrire une donnée de type quelconque (utilise EEPROM.update)
    // EEPROM.get(int adresse, variable) : lire une donnée de type quelconque
    EEPROM.update(0,1);
    adr_eeprom=(num_relais-1)*36+1;
    for (i=0;i<10;i++) EEPROM.update(adr_eeprom++,ptr_dm[i]);
    for (i=0;i<8;i++) EEPROM.update(adr_eeprom++,ptr_hm[i]);
    for (i=0;i<10;i++) EEPROM.update(adr_eeprom++,ptr_da[i]);
    for (i=0;i<8;i++) EEPROM.update(adr_eeprom++,ptr_ha[i]);
    }
  }

void loop()
  {
  int test_date,test_heure;

  lire_ds3231();
  // afficher la date et l'heure sur un écran LCD
  lcd.setCursor(0,0);
  lcd.write(tab_date,strlen(tab_date));
  lcd.setCursor(0,1);
  lcd.write(tab_heure,strlen(tab_heure));
  // gérer la date et l'heure pour la marche du relais 1
  test_date=strcmp(tab_date,date_mr1);
  if (test_date==0)
    {
    test_heure=strcmp(tab_heure,heure_mr1);
    if (test_heure==0) digitalWrite(R1,LOW);
    }
  // gérer la date et l'heure pour l'arrêt du relais 1
  test_date=strcmp(tab_date,date_ar1);
  if (test_date==0)
    {
    test_heure=strcmp(tab_heure,heure_ar1);
    if (test_heure==0) digitalWrite(R1,HIGH);
    }
  // gérer la date et l'heure pour la marche du relais 2
  test_date=strcmp(tab_date,date_mr2);
  if (test_date==0)
    {
    test_heure=strcmp(tab_heure,heure_mr2);
    if (test_heure==0) digitalWrite(R2,LOW);
    }
  // gérer la date et l'heure pour l'arrêt du relais 2
  test_date=strcmp(tab_date,date_ar2);
  if (test_date==0)
    {
    test_heure=strcmp(tab_heure,heure_ar2);
    if (test_heure==0) digitalWrite(R2,HIGH);
    }
  // gérer la date et l'heure pour la marche du relais 3
  test_date=strcmp(tab_date,date_mr3);
  if (test_date==0)
    {
    test_heure=strcmp(tab_heure,heure_mr3);
    if (test_heure==0) digitalWrite(R3,LOW);
    }
  // gérer la date et l'heure pour l'arrêt du relais 3
  test_date=strcmp(tab_date,date_ar3);
  if (test_date==0)
    {
    test_heure=strcmp(tab_heure,heure_ar3);
    if (test_heure==0) digitalWrite(R3,HIGH);
    }
  // gérer la date et l'heure pour la marche du relais 4
  test_date=strcmp(tab_date,date_mr4);
  if (test_date==0)
    {
    test_heure=strcmp(tab_heure,heure_mr4);
    if (test_heure==0) digitalWrite(R4,LOW);
    }
  // gérer la date et l'heure pour l'arrêt du relais 4
  test_date=strcmp(tab_date,date_ar4);
  if (test_date==0)
    {
    test_heure=strcmp(tab_heure,heure_ar4);
    if (test_heure==0) digitalWrite(R4,HIGH);
    }
  }




Haut de page