Bonjour !
Je dois avouer que j'aime bien tout ce qui tourne autour des horloges.
Mon premier bricolage en électronique (en 1976, ça date !) était d'ailleurs une horloge à afficheurs 7 segments à LEDs.
Du côté Arduino, après les horloges à base de DS3132 ou synchronisées par un serveur NTP (qui demandent la présence d'un réseau fournissant l'info) j'ai voulu m'attaquer à ce projet où c'est un module GPS qui donne l'heure.
Le cahier des charges est le suivant :
Par défaut (mode "auto") afficher l'heure française avec correction automatique pour l'heure d'été.
Pouvoir passer en mode "manuel" et sélectionner n'importe quel fuseau horaire de la planète entre -14 et + 12 heures par rapport à l'heure UTC, avec un pas minimal de 1/4 d'heure. (si jamais on décide d'emmener son horloge avec soi lors d'un voyage !)
Pas de correction automatique pour l'heure d'été en mode manuel.
Et tant qu'à faire avoir une possibilité d'afficher ses coordonnées géographiques et son altitude.
Le but principal de ce projet étant de "voir si ça marche" je me contenterai pour l'instant d'un antédiluvien affichage LCD à 4 lignes de 20 caractères, qui communiquera en I2C, pour "économiser" des fils.
Quitte à faire à l'avenir un truc plus léché !
Le montage est piloté par 3 boutons dont voilà le fonctionnement :
BOUTON "+" (BP1 sur le schéma) :
Appui long : passage en mode manuel (qui permet de choisir le fuseau horaire)
Appui court : si mode manuel : +1h, si mode auto pas d'effet
Double appui : si mode manuel : +1/4h, si mode auto pas d'effet
BOUTON "-" (BP2 sur le schéma) :
Appui long : passage en mode auto (mode par défaut, heure de l'Europe de l'ouest et heure d'été automatique)
Appui court : si mode manuel : -1h, si mode auto pas d'effet
Double appui : si mode manuel : -1/4h, si mode auto pas d'effet
BOUTON "Affich" (BP3 sur le schéma) :
Appui court : bascule entre affichage de heure-date et affichage de longitude-latitude-altitude
Appui long : bascule entre allumage et extinction du backlight de l'écran LCD
On trouve actuellement des petits modules GPS avec antenne intégrée ou extérieure à pas cher, j'ai pour ma part choisi un L86-M33 de chez Quectel (à antenne intégrée mais qui permet de brancher une antenne externe) pour sa petite taille et car j'ai entendu du bien sur ses qualités de réception des signaux.
C'est vraiment minuscule !
Je lui ai soudé une barrette de 6 contacts pour pouvoir le brancher soit sur une platine d'essai soit sur un câble.
Les avantages :
- les satellites GPS tournent autour de la terre (heureusement sinon ils tomberaient) et où qu'on soit, on pourra en capter.
- à priori les données d'heure et de dates sont très précises car les satellites embarquent des horloges atomiques.
L'inconvénient :
- La qualité de réception des signaux dépend de l'endroit où on se trouve. Dans une maison avec par exemple du béton armé ou une toiture métallique il y a des chances que le GPS ne capte rien, à moins qu'il ait une antenne extérieure.
Dans mon cas (maison individuelle à un étage avec planchers en bois) je capte l'heure après environ 30 secondes et elle devient vraiment précise (j'y reviendrai) dans la minute, même au rez de chaussée.
Ce projet m'a permis de creuser un peu le fonctionnement d'un GPS, et une vidéo de la sympathique chaîne Youtube de "Électro-Bidouilleur" m'a bien aidé pour éviter certains écueils :
Pour ceux que ça intéresse, comment cela marche-t-il ?
Les modules GPS utilisent majoritairement le protocole NMEA 0183 qui envoie toutes les secondes des trames formatées toujours de la même manière à travers la liaison série du GPS.
Ces trames commencent par un $ et contiennent des informations délimitées par des virgules qui seront les mêmes quelle que soit la marque du module GPS, facilitant ainsi leur exploitation.
Pour ne pas trop remplir cette page voici un document qui explique ce qui est renvoyé :
-Explication des trames GPS.zip (8,5 Ko)
Voici un exemple de ce que renvoie mon module quelques secondes après la mise sous tension :
Les 9 lignes entre les deux traits oranges sont renvoyées toutes les secondes.
On constate que même si à priori on ne capte pas encore de satellites (0 souligné en rouge) on a quand même déjà l'heure (soulignée en vert) et la date (soulignée en bleu)
J’appellerai ça plus tard le "mode dégradé", car la précision dans ce mode est d'environ 1 seconde.
Une fois qu'on capte des satellites, voici ce que renvoie le GPS :
On voit du premier coup d'oeil qu'il y a bien plus d'infos.
Se sont rajoutées la latitude et la longitude (soulignées de mauve) ainsi que l'altitude (soulignée de gris).
Le nombre de satellites captés est ici de 7. (souligné de rouge)
Il y a encore plein d'autres infos (vitesse, cap, détails sur les satellites) qui ne nous intéressent pas ici.
J’appellerai ça plus tard le "mode précis" car une fois qu'on capte des satellites l'horloge change de seconde pile-poil au bon moment.
Il faut maintenant extraire les données, soit "manuellement" par rapport au nom des trames qui nous intéressent ($GPRMC et $GPGGA) soit en étant fainéant comme moi et en utilisant une bibliothèque comme "TinyGPSPlus" disponible à GitHub - mikalhart/TinyGPSPlus: A new, customizable Arduino NMEA parsing library qui servira sur un plateau les données demandées.
Mais à ce niveau des questions se posent :
L'envoi des trames par le module GPS (par une liaison série pas très rapide à 9600 bauds par défaut) prend déjà un certain temps (dans le cas ci-dessus c'est déjà plus de 0,6 secondes), et quand je capterai encore plus de satellites (une ligne $GPGSV se rajoute tous les 4 satellites) je serai à plus de 0,8 secondes, sachant que la série de trames est envoyée toutes les secondes. Ce qui me laisse 0,2 seconde pour extraire les données et les afficher...
De quoi se créer des "bouchons" dans l'Arduino si ces 0,2 secondes ne suffisent plus pour décoder et à afficher les données !
Autre interrogation :
L'extraction des données commence une fois toutes les trames reçues, donc du temps est passé (temps variable selon la longueur des trames).
Et quand les données seront prêtes à être affichées on sera quelque part dans la seconde en cours ou même déjà à la prochaine seconde.
Ce qui n'est pas la mort, mais bon, si déjà on veut se synchroniser sur une horloge atomique, autant que ce soit précis !
C'est là qu'intervient le signal PPS (pulse per second) dont quasiment tous les modules GPS disposent, et qui est une impulsion TRÈS précise envoyée AU DÉBUT de chaque nouvelle seconde, une fois que le module GPS capte 4 satellites ou plus.
Voici un dessin (extrait de la vidéo d'Électro-Bidouilleur plus haut) qui montre ce qui se passe chaque seconde :
On a d'un côté le signal PPS en début de seconde, et en-dessous sont schématisées les trames qu'on reçoit (la zone "Acquisition").
Suit ensuite le traitement (extraction et mise en forme des données des trames reçues)
Pour être précis, on va donc pouvoir synchroniser l'affichage au front montant de la prochaine impulsion PPS.
D'où le mode "précis" de mon montage, contrairement au mode "dégradé" où l'affichage se fait immédiatement après le décodage des données sans synchronisation.
Mais attention !
Nous venons d'extraire les données de la seconde courante, et le prochain "Top affichage" sera le début de la seconde suivante, il va donc falloir incrémenter les données qu'on vient d'extraite de 1 seconde.
On peut donc ajouter 1 aux secondes mais en vérifiant qu'on est pas à la seconde 59, qui nous fera changer de minute, puis en vérifiant si on est pas à la minute 59 qui nous fera changer d'heure, etc... jusqu'à l'année !
J'ai préféré une autre approche :
Transformer les données (heures, minutes, secondes, jour, mois, années) de TinyGPSPlus en temps unix qui est un nombre sous la forme 1705843961, en fait c'est le nombre de secondes écoulées depuis le 1er janvier 1970.
Il suffit de rajouter 1 et de reconvertir ensuite le nouveau nombre obtenu en données de date et d'heure.
Là aussi la tâche va être facilitée par une bibliothèque pas toute jeune mais qui a toujours de l'intérêt :
"Time" disponible ici : GitHub - PaulStoffregen/Time: Time library for Arduino
Cette approche simplifie aussi la prise en compte de l'heure d'été ou d'hiver, il suffira d'ajouter 3600 secondes en été.
Pareil pour afficher l'heure d'autres fuseaux horaires, il suffira d'ajouter ou de soustraire autant de fois 3600 qu'il y a d'heures d'écart par rapport à l'heure UTC.
Pour accélérer l'acquisition des données, et ainsi donner du temps au Nano de faire son travail, la plupart des modules GPS peuvent être paramétrés pour n'envoyer que les trames dont on a besoin ($GPRMC et $GPGGA), en leur envoyant une commande sur leur liaison série.
Il y a aussi une autre commande pour éviter l'envoi de la trame $GPTXT, spécifique à mon module GPS.
En cherchant un peu j'ai trouvé la doc qui me donne les commandes à envoyer. Voici d'ailleurs un lien vers des documents concernant mon module Quectel L86-M33 qui m'ont aidé :
Si vous utilisez un autre module GPS, les commandes à lui envoyer pour le paramétrer seront bien sûr différentes, à ce niveau il n'y a pas de normalisation !
J'ai aussi accessoirement passé la vitesse de transmission de la liaison série du GPS de 9600 à 19200 bauds (bien que ce n'était franchement pas nécessaire après le "dégraissage" des trames), il y a aussi une commande pour ça. Je me retrouve donc avec ces infos venant du GPS tenant sur 2 lignes :
Je passe de 0,8 secondes (toutes les trames à 9600 bauds avec une quinzaine de satellites "en vue") à 75 millisecondes, ce qui laisse plus que largement le temps au Nano de travailler.
Infos en vrac :
Mon afficheur LCD associé à une liaison I2C n'étant pas très rapide, j'affiche en premier les secondes, puis les minutes et les heures, tout le reste après.
Et je ne constate aucun retard visuel par rapport à une LED que j'ai mis sur la sortie PPS du module GPS.
Le module GPS utilisé fonctionne en 3,3 V.
Cela ne pose pas de problème pour l'entrée Rx du Nano alimenté lui avec du 5 V, et qui en théorie voit les entrées à 1 dès que la tension dépasse 3V.
Par contre pour la transmission du Nano vers le GPS, j'ai fait un pont diviseur avec 2 résistances, pour transformer le 5 V en sortie du Tx du Nano en environ 3,3 V.
Dans le cas de mon module Quectel L86-M33 les broches V_BCKP et +VCC doivent obligatoirement être reliées ensemble.
A voir dans la documentation de votre module s'il est différent si c'est aussi nécessaire...
A noter aussi que le signal PPS du GPS (donné par le fabriquant pour une précision de moins de 15 nanosecondes !) pourra servir de base de temps à ceux qui ont besoin d'une grande précision, et même pas besoin de l'Arduino, puisque le module sort ce signal dès qu'il est alimenté et qu'il capte assez de satellites.
Quelques photos du montage en marche :
Au démarrage ( le "A" à droite indique qu'on est en mode "auto", donc heure française) :
Nous voici en mode "dégradé" (on a déjà l'heure mais pas encore de satellite)
Nous voilà en mode "précis" (un "P" s'affiche à droite) :
Et voilà le second écran qui donne la position :
Nous voilà en mode "manuel" sur le fuseau horaire de Taïwan :
Le montage et sa platine d'essai :
Et grande première pour moi (c'est ma première utilisation de Fritzing), l'implantation des composants et le schéma.
Et pour finir le code de ce projet :
/***************************************************************************************************
* Horloge GPS précise *
* Roland MATHIS 01/2024 *
***************************************************************************************************
Fonctionnement :
En mode auto (par défaut) , affiche l'heure UTC+1 (Europe de l'ouest) et prend en compte l'heure d'été et d'hiver
En mode manuel, permet d'afficher l'heure de n'importe quel fuseau horaire de la planète (de +11 h à -11 h),
mais sans prise en compte de l'heure d'été.
* UTILISATION DES 3 BOUTONS
*
* BOUTON + (BP1 sur le schéma) :
* Appui long : passage en mode manuel
* Appui court : si mode manuel +1h, si mode auto pas d'effet
* Double appui : si mode manuel +1/4h, si mode auto pas d'effet
*
* BOUTON - (BP2 sur le schéma):
* Appui long : passage en mode auto
* Appui court : si mode manuel -1h, si mode auto pas d'effet
* Double appui : si mode manuel -1/4h, si mode auto pas d'effet
*
* BOUTON Affich (BP3 sur le schéma):
* Appui court : bascule entre affichage de heure-date et l'affichage de longitude-latitude-altitude
* Appui long : bascule entre allumage et extinction du backlight de l'écran LCD
*/
#include <SoftwareSerial.h> // Pour gérer la liaison série avec le module GPS
#include <TinyGPSPlus.h> // Pour extraire facilement les données des trames envoyées par le GPS
#include <OneButton.h> // Pour la gestion des boutons-poussoirs
#include <LiquidCrystal_I2C.h> // Pour gérer l'afficheur LCD et sa liaison I2C (appelle wire.h)
#include <TimeLib.h> // Pour les conversions de temps au format unix et réciproquement
static const int RXPin = 2, TXPin = 3;
static const char PPS = 4;
byte nbsat; // Nombre de satellites captés
float latit, longit, altitud; // Coordonnées géographiques
bool PPS_low; // Mémorise l'état bas du signal PPS, permet de n'afficher qu'une fois au front montant de PPS
bool precis; // Mis à true lorsqu'on capte au moins 4 satellites
bool bcklght = true; // Etat du backlight de l'écran LCD
unsigned long top_PPS; // Compte les millis() à partir de chaque front montant du signal PPS
bool autoDST = true; // Quand l'horloge est en mode auto
long decal_UTC = 3600; // Décalage par rapport à l'heure UTC, +1 par défaut. Peut être négatif donc du type int
int decal_DST = 0; // Décalage pour l'heure d'été (0 en hiver, 1 en été)
bool ecran2 = false; // Pour afficher un deuxième écran
bool effac_mess = false; // Pour effacer une seule fois un texte
String JourSem[7] = {"Dimanche"," Lundi "," Mardi ","Mercredi"," Jeudi ","Vendredi"," Samedi "};
byte preci[] = // Création d'un caractère personnalisé (un "P" blanc sur fond noir)
{ B11111, B10001, B10101, B10001, B10111, B10111, B11111, B00000 };
byte mode_auto [] = // Création d'un caractère personnalisé (un "A" blanc sur fond noir)
{ B11111, B10001, B10101, B10001, B10101, B10101, B11111, B00000 };
byte heure_ete [] = // Création d'un caractère personnalisé (un "S" blanc sur fond noir)
{ B11111, B10001, B10111, B10001, B11101, B10001, B11111, B00000 };
byte e_aigu [] = // Création d'un caractère personnalisé (un "é")
{ B00010, B00100, B01110, B10001, B11111, B10000, B01110, B00000 };
OneButton btn_plus(A0, true); // Déclaration du bouton + sur l'entrée A0
OneButton btn_moins(A1, true); // Déclaration du bouton - sur l'entrée A1
OneButton btn_affich(A2, true); // Déclaration du bouton de changement d'affichage sur l'entrée A2
// Déclaration de l'objet TinyGPSPlus
TinyGPSPlus gps;
// Déclaration de la connexion série au module GPS
SoftwareSerial ss(RXPin, TXPin);
// Définition l'adresse de l'écran LCD, de la longueur et du nombre des lignes
LiquidCrystal_I2C lcd(0x27, 20, 4);
// Déclaration de la structure contenant les éléments de TimeLib
tmElements_t UTC;
void setup()
{
// Pour le fonctionnement de la librairie OneButton
// fonctions appellées par le bouton +
btn_plus.attachClick(clic_plus);
btn_plus.attachDoubleClick(clic_plus_quart);
btn_plus.attachLongPressStart(clic_long_plus);
// fonctions appellées par le bouton -
btn_moins.attachClick(clic_moins);
btn_moins.attachDoubleClick(clic_moins_quart);
btn_moins.attachLongPressStart(clic_long_moins);
// fonctions appellées par le bouton affich
btn_affich.attachClick(clic_affich);
btn_affich.attachLongPressStart(clic_long_affich);
// ******************************** INITIALISATION DU MODULE GPS ***********************************
// ************ Ces commandes ne sont valables que pour des module GPS de marque Quectel ***********
// ATTENTION : sorti d'usine le port série du GPS est paramétré à 9600, pour le premier démarrage mettre "ss.begin(9600);"
ss.begin(19200); // Initialisation de la connexion série avec module GPS à 19200 bps
// Activer cette ligne seulement au premier démarrage, pour éviter l'envoi de la trame propriétaire $GPTXT (mémorisé par le GPS)
// ss.println("$PQTXT,W,0,1*23")
// Activer cette ligne seulement au premier démarrage, passe le port série du GPS de 9600 à 19200 bauds (mémorisé par le GPS)
// ss.println("$PQBAUD,W,19200*7E");
// Envoi d'une trame au module GPS pour qu'il n'envoie que les trames $GPRMC et $GPGGA utilisées par TinyGPSPlus
// et ainsi accélérer l'acquisition (non mémorisé par le GPS)
ss.println("$PMTK314,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0*28");
pinMode(PPS, INPUT_PULLUP); // Configurer la broche PPS comme entrée
lcd.init(); // Initialisation de l'afficheur LCD
lcd.createChar(0, preci); // Assignation de preci au caractère personnalisé 0 dans la RAM de l'afficheur
lcd.createChar(1, mode_auto); // Assignation de mode_auto au caractère personnalisé 1 dans la RAM de l'afficheur
lcd.createChar(2, heure_ete); // Assignation de heure_ete au caractère personnalisé 2 dans la RAM de l'afficheur
lcd.createChar(3, e_aigu); // Assignation de degre au caractère personnalisé 3 dans la RAM de l'afficheur
// Affichage du logo d'allumage
lcd.setCursor(7, 1); lcd.print("Horloge");
lcd.setCursor(5, 2); lcd.print("GPS pr\003cise"); // "\003" écrit le caractère spécial 3 (le "é")
lcd.backlight(); // Allumer le rétroéclairage de l'écran
delay(2000); // Durée d'affichage du texte
// "Squelette" de l'affichage
lcd.clear();
lcd.setCursor(6, 0); lcd.print("--:--:--");
lcd.setCursor(5, 1); lcd.print("--/--/----");
lcd.setCursor(1, 2); lcd.print("Cherche satellites");
lcd.setCursor(0, 3); lcd.print("UTC Sat:");
}
void loop()
{
// Détection des appuis sur les boutons par OneButton
btn_plus.tick(); // Surveillance du bouton +
btn_moins.tick(); // Surveillance du bouton -
btn_affich.tick(); // Surveillance du bouton affich
// Boucle de lecture des données du GPS suivie de leur mise en forme (infos reçue 1 fois par seconde)
// et de leur affichage en mode dégradé (quand pas assez de satellites)
while (ss.available() > 0)
{
{ gps.encode(ss.read());
if (gps.date.isUpdated())
{
// Passage des variables gps.xxx renvoyées par TinyGPSPlus dans TimeLib
UTC.Day = (gps.date.day()); // Les variables sous la forme UTC.xxx sont utilisées au format
UTC.Month = (gps.date.month()); // int dans une structure définie avant le setup par TimeLib
UTC.Year = (gps.date.year())-1970; // UTC.Year est une variable qui doit commencer en 1970
UTC.Hour = (gps.time.hour());
UTC.Minute = (gps.time.minute());
UTC.Second = (gps.time.second());
latit = (gps.location.lat());
longit = (gps.location.lng());
altitud = (gps.altitude.meters());
nbsat = (gps.satellites.value());
if (autoDST) // Si on est en mode auto : Temps français (UTC+1) et vérif si heure d'été ou d'hiver)
{
if (Heure_ete(UTC.Year-30, UTC.Month, UTC.Day, UTC.Hour)) // appel à la fonction "bool Heure_ete..." qui retourne true ou false
decal_DST = 3600;
else decal_DST = 0;
}
// Adaptation de l'heure au fuseau horaire et à l'heure d'été.
// Le L derrière 3600 force un calcul au format long car (3600L*(decal_UTC+decal_DST)) peut dépasser + ou - 32767
unsigned long temps_unix_local = makeTime(UTC) + 1 + decal_UTC + decal_DST;
setTime(temps_unix_local); // Transformation du temps_unix_local en ses composantes avec TimeLib
// second(), minute(), hour(), etc...
if (millis() - top_PPS > 500) // Si pas d'impulsion PPS pendant plus d'un cycle, on passe en mode d'affichage dégradé
// valeur déterminée expérimentalement
{
precis = false;
ecrit_lcd(); ecrit_lcd_UTC(); // Affichage des infos à l'écran en mode dégradé
}
}
}
}
if (!(digitalRead(PPS))) PPS_low = true; // Met PPS_low à true dès le front descendant du signal PPS
// Pour ne permettre qu'une fois l'affichage
// Affichage des infos en mode précis, synchronisé sur le front montant du signal PPS (une fois par seconde)
if (digitalRead(PPS) && (PPS_low)) // Moment du front montant de PPS
{
top_PPS = millis(); // Début de comptage des millis à partir du front montant de PPS
precis = true; PPS_low = false;
ecrit_lcd(); ecrit_lcd_UTC(); // Affichage des données à l'écran
}
}
void ecrit_lcd() // Affichage heure, date et jour
{
if (year() != 2080 && year() != 1970) // 2080 est la date de défaut quand le GPS n'a pas de fix.
{ // 1970 est l'année par défaut dans TimeLib avant qu'il n'ait fait des calculs
if (!(ecran2)) // Affichage de l'écran de base (heures et date)
{
lcd.setCursor(12, 0);
if (second() < 10) lcd.print("0"); lcd.print(second());
lcd.setCursor(9, 0);
if (minute() < 10) lcd.print("0"); lcd.print(minute());
lcd.setCursor(6, 0);
if (hour() < 10) lcd.print("0"); lcd.print(hour());
lcd.setCursor(5, 1);
if (day() < 10) lcd.print("0"); lcd.print(day());
lcd.setCursor(8, 1);
if (month() < 10) lcd.print("0"); lcd.print(month());
lcd.setCursor(11, 1); lcd.print(year());
if (effac_mess == false) // Effacement une seule fois du message "Recherche satelittes"
{
effac_mess = true;
lcd.setCursor(1, 2); lcd.print(" ");
}
lcd.setCursor(6, 2); lcd.print(JourSem[weekday()-1]);
}
else // Affichage de l'écran avec les données de position
{ ecrit_lcd_geo(); }
}
lcd.setCursor(18, 3); lcd.print(nbsat);
if (nbsat < 10) lcd.print(" "); // Cas où nbsat passe sous 10, pour effacer les unités
// Affichage de différentes indications (mode précis, mode auto, heure d'été)
lcd.setCursor(19, 0); if (precis) lcd.write(byte(0)); else lcd.print(" ");
lcd.setCursor(19, 1); if (autoDST) lcd.write(byte(1)); else lcd.print(" ");
lcd.setCursor(19, 2); if (decal_DST == 3600) lcd.write(byte(2)); else lcd.print(" ");
}
void ecrit_lcd_UTC() // Affichage du décalage par rapport à l'heure UTC en heures et minutes
{
int h = decal_UTC / 3600; // extraction des heures du décalage (nombre entier positif ou négatif)
byte mi = abs(((decal_UTC / 3600.0) - h)*60); // extraction des minutes du décalage (nombre entier positif)
lcd.setCursor(3,3);
if (decal_UTC > 0) lcd.print("+");
if (decal_UTC < 0) lcd.print("-"); // Pour avoir un "-" aussi devant le 0 si on est entre 0 et -1 heure
if (decal_UTC != 0)
{lcd.print (abs(h));
if (mi > 0) { lcd.print(":"); lcd.print(mi); } else { lcd.print(" "); }
}
if (decal_UTC == 0) lcd.print(" "); // ne rien afficher
if (abs(decal_UTC) < 36000) { lcd.setCursor(8,3); lcd.print(" "); } // ôte le chiffre à droite quand on passe sous 10
}
void ecrit_lcd_geo() // Affichage des coordonnées géographiques
{
lcd.setCursor(10, 0); lcd.print(latit,4); lcd.print("\337"); // \337 = symbole "°" dans le charset de l'écran LCD
lcd.setCursor(10, 1); lcd.print(longit,4); lcd.print("\337");
lcd.setCursor(10, 2); lcd.print(altitud,1); lcd.print("m");
}
bool Heure_ete(byte anUTC, byte moisUTC, byte jourUTC, byte heureUTC)
//*********************************************************************************************************
// Fonction extraite du fichier "simpleRTC.ccp" d'une librairie de "Bricoleau" sur le forum Arduino ici : *
// https://forum.arduino.cc/t/partage-librairie-simplertc-ds1307-ds3231-avec-heures-ete-hiver/376814 *
// Détermine si on est en heure d'été ou en heure d'hiver en retournant true ou false *
//*********************************************************************************************************
{
//En France métropolitaine :
//Passage de l'heure d'hiver à l'heure d'été le dernier dimanche de mars à 1h00 UTC (à 2h00 locales il est 3h00)
//Passage de l'heure d'été à l'heure d'hiver le dernier dimanche d'octobre à 1h00 UTC (à 3h00 locales il est 2h00)
if (moisUTC == 3)
{
byte derDimancheMars = 31 - ((5 + anUTC + (anUTC >> 2)) % 7);
return jourUTC > derDimancheMars || (jourUTC == derDimancheMars && heureUTC != 0);
}
if (moisUTC == 10)
{
byte derDimancheOct = 31 - ((2 + anUTC + (anUTC >> 2)) % 7);
return jourUTC < derDimancheOct || (jourUTC == derDimancheOct && heureUTC == 0);
}
return 3 < moisUTC && moisUTC < 10; // true d'avril à septembre inclus
}
// *********************** Gestion des appuis sur les boutons ***********************
void clic_plus() // Fonction appelée par un appui court sur le bouton +
{ if (!autoDST && decal_UTC <= 39600) { decal_UTC += 3600; ecrit_lcd(); ecrit_lcd_UTC(); } }
void clic_plus_quart()
{ if (!autoDST && decal_UTC <= 42300) { decal_UTC += 900; ecrit_lcd(); ecrit_lcd_UTC(); } }
void clic_long_plus() // Fonction appelée par un appui long sur le bouton +
{ autoDST = false; decal_DST = 0; }
void clic_moins() // Fonction appelée par un appui court sur le bouton -
{ if (!autoDST && decal_UTC >= -46800) { decal_UTC -= 3600; ecrit_lcd(); ecrit_lcd_UTC(); } }
void clic_moins_quart()
{ if (!autoDST && decal_UTC >= -49500) { decal_UTC -= 900; ecrit_lcd(); ecrit_lcd_UTC(); } }
void clic_long_moins() // Fonction appelée par un appui long sur le bouton -
{ autoDST = true; decal_UTC = 3600; }
void clic_affich() // Fonction de bascule entre affichages appelée par un appui long sur le bouton affich
{
if (precis)
{ ecran2 = !ecran2; // n'affiche les coordonnées géographique qu'en mode précis
if (ecran2)
{
lcd.setCursor(0, 0); lcd.print("Longitude: ");
lcd.setCursor(1, 1); lcd.print("Latitude: ");
lcd.setCursor(1, 2); lcd.print("Altitude: ");
ecrit_lcd_geo();
}
else
{
lcd.setCursor(0, 0); lcd.print(" : : ");
lcd.setCursor(1, 1); lcd.print(" / / ");
lcd.setCursor(1, 2); lcd.print(" ");
ecrit_lcd();
}
}
}
void clic_long_affich() // fonction de bascule pour allumer-éteindre le backlight de l'écran
{
bcklght = !bcklght;
if (bcklght) lcd.backlight();
if (!bcklght) lcd.noBacklight();
}
Et bravo à ceux qui ont réussi à tout lire !
Roland