Présentation
J'ai plein d'horloges et de montres mécaniques, électriques ou électroniques mais je ne suis jamais sûr qu'elles soient à l'heure. Il me fallait donc une petite horloge de confiance. Et je voulais qu'elle fonctionne sur piles sans avoir à les changer trop souvent. Et puis, ça m'amusait...
Donc voici la présentation de cette horloge synchronisé sur le signal DCF77 ainsi que son programme qui tourne sur un processeur Texas Instrument (TI) MSP430F449 qui comme toute la série des processeurs MSP430, est réputé pour sa très faible consommation tout en étant capable de gérer en permance un afficheur LCD. Et c'est le gros avantage de cette horloge par rapport à un smartphone : pas besoin de la recharger tous les jours. Normalement, un changement de pile toutes les X années suffit (X de l'ordre de 5 à 7 ans).
Pour ceux qui ont parcouru ce site, vous avez pu voir tout une série de compteurs geiger-muller de ma conception qui utilisent ce processeur ou d'autres de la même famille et dont la consommation moyenne est de l'ordre de 20 à 60µA selon les versions.
Pour terminer cette introduction, vous trouverez pléthore d'horloges synchronisées sur le signal DCF77 à des prix très raisonnables (une vingtaine d'euro ou moins) et qui font beaucoup plus de chose que celle présentée ici. Cette horloge n'a ni réveil matin, ni réglage de l'heure (elle ne fonctionne donc que dans certains pays d'Europe) et n'a aucune autre prétention que de permettre d'expérimenter et d'avoir la satisfaction de l'avoir faite soit même.
Et vous trouverez également, outre les programmes sources, quelques réflexions sur la façon de traiter le signal DCF77.
Spécifications
Les spécifications sont les suivantes :
- Affichage permanent de l'heure sur 24 heures (heures, minutes, secondes) avec une précision raisonnable.
- Affichage de la date (année, mois, jour).
- Mise à jour de ces données à partir du signal DCF77 (une fois par jour).
- Consommation faible autorisant plusieurs années de fonctionnement sur piles.
- Indicateurs divers dont le fait que l'horloge a pu se mettre à jour ou pas depuis les dernières 24H00.
L'afficheur est le seul interface disponible (avec éventuellement, les boutons poussoirs)
Affichage de l’heure
Entre deux mise à l’heure à partir du signal DCF77, l’horloge fonctionne « en roue libre » sur sa propre base de temps interne.
Elle resynchronise sa base de temps interne et se remet à l’heure lorsqu’un signal DCF77 correct est reçu.
Affichage de la date
L’affichage de la date se fait sur l’afficheur en haut à gauche. Il affiche alternativement (chaque seconde) l’année (exemple : 2023) ou le jour et le mois (exemple : 23:08 pour le 23 août).
Cette date se resynchronise tous les jours (ou à la demande) lorsqu’un signal DCF77 correct est reçu.
Indicateurs
4 indicateurs sont présents sur l’afficheur :
- La charge des piles « Bat » (mise à jour tous les 24 heures). Il y a trois barres (4 = charge maximum, 0 = charge faible). À partir de 1 barre, il faut penser à changer les piles.
- L’indicateur clignotant « DCF77 » (une clé) indique que l’horloge n’a pas pu se mettre automatiquement à l’heure depuis plus de 24H00.
- L’indicateur « Ant » indique que l’horloge tente de recevoir un signal DCF77.
- L’indicateur « signal » (1 à 3 barres) indique que l’horloge reçoit un signal DCF77.
Matériel
Le processeur utilisé est donc un MSP430 disponible sur un petit circuit de développement conçu par Olimex. Il dispose d'un afficheur (que j'avais cassé il y a plusieurs années. Je l'ai remplacé par un autre modèle d'où les fils un peu partout pour relier l'afficheur à la carte de développement), 4 boutons poussoirs et d'autres bricoles que j'ai viré (prise V24, buzzer...).
MSP430-449STK2
Pour le module DCF77, j’en ai pris un tout fait sur Aliexpress (environ 3€ port compris en 2023). Il est donné pour avoir une consommation maximum de 85µA ce qui est assez élevé. Mais en mode « désactivé », sa consommation est imperceptible.
Module RCC02C03A
Pour ceux qui auraient du mal à trouver la spécification, voici quelques indications utiles :
- L'interface comporte 4 fils. Sur la photo, Vdd est à droite. En partant de Vdd et en allant vers la gauche, on a donc :
- Vdd = (+) de la tension d'alimentation
- Vss ou Ground = 0V de la tension alimentation
- P ou P1 (entrée) = activation (signal = 0V) ou désactivation (signal = Vdd) du module.
- T (sortie) = signal démodulé.
- Tension d'alimentation = 1,1 à 3,3V
- Consommation maximum = 85µA
Réalisation
Ci-après, la réalisation matérielle (avec l'afficheur qui n'est pas d'origine !). On y trouve la connexion du module DCF77 sur un connecteur de la carte de développement avec son alimentation, le signal d'activation sur le port GPIO P2.1 et le signal démodulé sur le port GPIO P2.0. L'autre connexion est celle du porte pile qui fournit l'alimentation de 3V.
On peut mettre tout ça dans un petit boitier imprimé en 3D, ici, en ASA (sans le capôt qui ferme le tout).
Boitier qui présente une légère rétractation des bords, problème malheureusement courant avec le ASA.
Logiciel
La partie la plus complexe mais la plus intéressante concerne le logiciel. Celui-ci est téléchargeable pour le cas (improbable) où quelqu'un voudrait réaliser cette horloge ou le cas (plus probable) où quelqu'un voudrait des tuyaux sur la programmation du MSP430.
La partie concernant l'affichage de l'heure, de la date et des indicateurs n'appelle pas d'attention particulière et je ne la détaillerai pas.
La partie réellement intéressante concerne le décodage du signal DCF77 et la gestion de la basse consommation. C'est ce qui est expliqué ci-après.
Réception du signal DCF77
La réception du signal se fait donc via un module spécialisé qui peut être activé ou non. Il n’est activé que lorsque l’horloge le demande (soit lors d’une mise à l’heure automatique à 00:00:00, soit lors d’une demande manuelle). Si au bout de 10mn, l’horloge n’a pas reçu de trame correcte, le module DCF77 est désactivé et l’horloge continue de fonctionner en roue libre. Un indicateur permet de savoir si la dernière tentative de réception à 00:00:00 a fonctionné ou pas.
Rappel sur le signal DCF77
On trouve une spécification du signal DCF77 sur le site Wikipedia. Les explications qui suivent résument les points importants de cette spécification.
Le signal DCF77 est constitué d’une porteuse à 77,5kHZ. La modulation de cette porteuse code l’information à transmettre (un bit) sous forme temporelle.
Cette modulation se retrouve sur une sortie du module spécialisée sous la forme d’un 0 (tension nulle) ou d’un 1 (tension d’alimentation du module).
- La durée d’un 0 est de 100ms
- La durée d’un 1 est de 200ms
- La durée totale de la transmission d’un bit est de 1000ms (1 seconde).
On retiendra que si on reçoit un signal à 1 pendant plus de 200ms ou si l'on reçoit un signal à 0 pendant plus de 1900ms, on a soit un gros problème de réception, soit un module en panne.
Donc, chaque seconde, on doit recevoir un signal à 1 (dont la durée donne la valeur du bit), puis après 100ms (respectivement 200ms), un signal à 0 pendant 900ms (respectivement 800ms), puis de nouveau, un signal à 1, etc.
On appelle « trame » l'ensemble des bits du signal horaire émis périodiquement.
La trame comporte 59 bits utiles véhiculés à raison d'un bit par seconde (donc 59 secondes). La 60ème seconde sert à la synchronisation et vaut 0 pendant une seconde (pas de modulation). Elle marque la fin de la trame courante et le premier front montant qui suit détermine le début de la trame suivante. Il détermine également le moment où les signaux reçus de la trame précédente peuvent être utilisés.
Dit autrement, l’heure reçue dans une trame est valide lorsqu’on reçoit le début de la trame suivante. En supposant que l'heure reçue soit 09:56, le front montant du début de la trame suivante (qui code 09:57) permettra de mettre une horloge à l'heure avec l'heure (09:56:00. Il y a un cas particulier, voir la spécification sur Wikipédia)
La durée du signal de synchronisation permet de faire sans difficulté le décodage des informations reçues afin d’être prêt à les utiliser lors de l’apparition de la trame suivante. Pour la signification des bits reçus, voir sur Wikipedia.
Stratégie de synchronisation
Une stratégie de synchronisation (trouver le début d'une trame) peut être la suivante :
- On attend un signal à 0 dont la durée est supérieure à 900ms (disons, 1000ms). Lorsqu’on le trouve, le front montant suivant (signal à 1) marque le début d’une nouvelle trame et on a réussi à se synchroniser. On notera que dans le cas d’une réception correcte, il faut parfois attendre une minute avant de recevoir le signal de synchronisation.
Cette recherche peut se faire par test d'état (déconseillé) ou en utilisant des interruptions sur fronts montants et descendants. Un front descendant déclenche une mesure de durée que l'on arrête sur le prochain front montant. Si cette durée est entre 1800ms et 1900ms, on a trouvé le début d'une trame.
Sauf que si l'on procède ainsi, ça ne fonctionne pas bien parce que le signal est très sensible au bruit et qu'il y a souvent des impulsions parasites.
Il faut donc filtrer ces parasites ce qui implique de mesurer la durée entre chaque front (front montant ou front descendant) pour savoir si l’on doit prendre en compte le signal ou pas. Mais on se heure à un autre problème qui est de savoir si l’impulsion parasite était en fait le début d’un signal valide ou pas. On doit donc aussi mesurer la temps dans le signal auquel s’est produite cette impulsion pour lever le doute.
On a bien sûr le même problème pour la détection des signaux codant les bits. Mais en supposant que l'on a trouvé le début d'une trame (je vous rassure, c'est faisable), on peut procéder plus simplement que pour le signal de synchronisation.
L'idée est d'échantillonner (par exemple, toute les millisecondes) le signal pendant une certaine durée (pendant par exemple 50ms) autour du centre supposé de sa durée.
Pour ce faire, on utilise un compteur initialisé à 0, et à chaque fois que l'on détecte un signal à 1, on fait +1 dans le compteur et pour un signal à 0, -1.
Si la somme est positive, on considère que l’on a reçu un 1 sur la période de mesure, sinon, on a reçu un 0 (pour un compteur nul, il y a une incertitude mais cela veut dire que le signal est particulièrement brouillé).
Cette approche permet d’éviter de mesurer la durée des impulsions parasites et permet de rejeter les signaux trop brouillés : Si on obtient 0 alors qu’on devait avoir 1 (par exemple lors des 100 premières milliseconde du codage d'un bit) ou un 1 alors qu'on devait avoir un 0 (pendant les 800 dernières millisecondes du codage d'un bit), le plus prudent est de reprendre toute la mesure.
Mais on peut faire encore plus simple en échantillonnant que le signal présent entre 100ms et 200ms. S’il est présent, on a un 1, sinon, un 0. Le seul inconvénient potentiel est qu’on fait moins de contrôle sur la forme du signal donc on est moins susceptible de détecter certaines erreurs dans un environnement très bruité.
Idéalement, il faudrait pouvoir détecter le front montant de chaque nouveau signal codant un bit afin d'être certain d'échantilloner au bon endroit dans le signal. Mais on se retrouve de nouveau avec le problème d'éliminer les signaux parasites comme dans le cas du signal de synchronisation.
Une autre solution consiste à disposer d'une horloge suffisamment stable et précise sur 60 secondes que l'on déclenche au début du signal de synchronisation. Puis toutes les 1000ms, on passe à l'échantillonnage du bit suivant.
C'est l'approche adoptée dans la présente implémentation et l'on utilise pour cette horloge le quartz à 8MHz disponible sur la carte de développement que l'on divise jusqu'à avoir un top toutes les millisecondes pour l'échantillonnage.
Cette méthode est très similaire à celle d’une classique réception asynchrone.
Petit test de culture réseau : indiquez le débit en baud et le débit en bits par seconde (bps) de la communication (si vous regardez les définitions que l'on trouve de bauds et bps sur le net, vous avez toutes les chances de donner une réponse fausse).
Implémentation retenue
Pour cette horloge, l’implémentation retenue est un mixte entre la détection de fronts et la mesure temporelle de la valeur du signal.
Algorithme pour la synchronisation :
- On attend un front descendant
- Lorsqu’il est trouvé, on cumule dans une variable initialisée à 0 la valeur du signal (-1 pour signal à 0, +1 pour signal à 1) et on compte le nombre de millisecondes entre le début et la fin de la mesure.
- Sur front montant, on arrête la mesure précédente. Si le cumul des valeurs est inférieur à 0, le signal était majoritairement un 0. Sinon, c’était un 1.
- Si le signal était majoritairement à 0 et si sa durée est supérieure à 1700ms, alors, on considère que le front montant est le début d’une nouvelle trame et on commence la capture du signal. Sinon, on recommence le processus.
Note : les impulsions de durée inférieure à une certaine valeur sont ignorées jusqu’à un certain points (et donc, ne génère pas systématiquement de front montant susceptibles d’arrêter la mesure).
Une fois que la synchronisation a été trouvée, le programme mesure le valeur du signal entre 140ms et 170ms de la même façon que pour la mesure de la synchronisation. Si le cumul est positif, le signal code un bit à 1. Sinon, il code un bit à 0.
Cette façon de procéder permet de filtrer les éventuels parasites sans mesures compliquées.
Décodage
Le décodage consiste à interpréter les bits reçus. Certains contrôles (parité, cohérence) permettent de valider que la trame est correcte ou pas (note : la numérotation des bits de la trame commence à 0).
Parité : elle concerne les minutes, les heures, la date.
Valeurs fixes : elles concernent le bit 0 (toujours à 0) et le bit 20 (toujours à 1).
Cohérence : certaines valeurs doivent se trouver dans des limites connues (heures, minutes, secondes, dates, jour de la semaine).
Qualité du signal
La réception du signal DCF77 peut être assez problématique. Surtout que les environnements actuels sont très bruités du fait des alimentations à découpage présentes dans de nombreux appareils ou des éclairages à LED. La simple proximité d'un appareil d'éclairage allumé peut empêcher toute réception.
Selon les fréquences et la modulation utilisée, la réception peut être meilleure à certaines heures, en particulier, la nuit.
L’afficheur indique la qualité du signal reçu en affichant de 0 à 3 barres à côté de l’antenne. L’algorithme est le suivant :
- 0 barres : on n’a pas reçu de signal depuis 3 secondes.
- 3 barres : on reçoit le signal et il n’y a pas d’impulsions parasites.
- 2 barres : on reçoit le signal et il y a 3 impulsions parasites au plus par seconde.
- 1 barre : on reçoit le signal et il y a plus de 3 impulsions parasites par seconde.
Sauf lorsqu’il n’y a pas de réception du tout (0 barre), la modification du nombre de barres est mise à jour toutes les secondes.
Une impulsion est définie ici comme parasite si sa durée est inférieure ou égale à 50ms.
Stratégie pour une basse consommation
4 mode de basse consommation sont disponibles. LPM4 est exclu d’office dans la mesure où il désactive toutes les horloges et attend un événement externe pour réveiller le processeur. Reste donc LPM0 à LPM3.
Pour une basse consommation, on doit viser une utilisation maximale de LPM3.
En roue libre, le programme est réveillé par le Watchdog (WDT) toutes les secondes pour mettre l’heure et la date à jour.
WDT peut être piloté par un oscillateur interne au processeur (moyennement précis) ou par un quartz sur XT1 (très précis).
En roue libre, la consommation de l’horloge est de l’ordre de 45µA avec XT1 et 40µA avec l'oscillateur interne. Cette consommation passe à environ 400µA en recherche de signal et à environ 650µA une fois la synchronisation trouvée quelque soit la source de l'horloge.
Du fait de la faible différence entre les deux modes, l’implémentation utilisant XT1 a été retenue moyennant une consommation moyenne supérieure de 5µA.
Le mode basse consommation LPM3 est activé dès que les différentes routines ont terminé leur traitement.
Une journée fait 1440 minutes. Chaque jour, l'horloge fonctionne en roue libre entre 99,3% (elle n'arrive pas à se synchroniser) et 99,9% du temps (elle arrive à se synchroniser en 2 minutes ou moins). La consommation est essentiellement due à l’affichage, à l’entretien de XT1 et au traitement qui doit s’exécuter la plupart du temps en moins d’1ms à 1MHz de fréquence d’horloge.
La documentation du mode LPM3 est un peu imprécise sur certains points mais des recherches sur le forum de Texas Instrument (TI) permettent de lever certaines ambiguïtés.
Ainsi, on apprend que LPM3 n’arrête pas les quartz (c’est heureux) et n’arrête pas SMCLK s’il est utilisé par un périphérique ce qui est le cas du timer A0 qui utilise XT2 (8MHz) et qui est actif lorsque l’horloge recherche le signal DCF77.
Pour le reste, il y a les nécessaires initialisations des différents périphériques pour limiter la consommation. Par défaut, ils sont désactivés. Un problème se pose néanmoins pour les GPIO.
En général, on conseille de configurer les GPIO en entrée avec une résistance de polarisation active (il y a des débats sur le niveau (bas ou haut) d'activation de ces résistances). Sauf que le MSP439F449 ne dispose pas de résistances de polarisation.
J'ai lu quelque part que TI conseillait de configurer les GPIO en sortie. Cela parait logique : sans résistances de polarisation, les entrées sont en l'air et il y a un risque de voir les GPIO commuter en permanence ce qui consomme de l'énergie.
j'ai fait plusieurs essais et pour le moment, les meilleurs résultats ont été obtenus en mettant P1 et P2 en sortie (sauf les GPIO explicitement déclarées en entrées) et les autres ports dans leur configuration par défaut à la mise sous tension sachant que la plupart d'entre-eux sont initialisés par la suite lors de la configuration de l'écran LCD.
Selon Wikipédia, les piles AA Alcalines ont une capacité de l'ordre de 2850mAh.
Si l’on utilise deux piles en série pour obtenir 3V (capacité toujours de 2850mAh), l’autonomie sera de l’ordre de 7 ans pour une consommation moyenne de 45µA.
Avec le processeur piloté uniquement par sa base de temps interne, l’autonomie serait de l’ordre de 8 ans.
Chargement du logiciel
Le logiciel a été développé en langage C avec l'environnement Code Composer Studio (Eclipse pour MSP430).
Août 2023