III) 2) Que montre la montre ?

À quels problèmes répond le programme ?

  1. Comment mesurer les impulsions qui nous arrivent ?
  2. Quel type d’information nous envoie-t-on ?
  3. Comment interpréter ces informations ?
  4. L’heure reçue est-elle bien l’heure exacte ?

Le but du module Arduino est de transformer une information, que l’on constate par un allumage long ou court de la diode, en heure.

1. Comment mesurer les impulsions qui nous arrivent ?

Après étude du signal reçu grâce à un oscilloscope, on obtient ceci :

photo 1(5)Les signaux sont plus ou moins larges (100 ms ou 200 ms). Δt = 1,000 seconde. On constate qu’il y a bien une modification de la tension au début de chaque seconde.

On constate bien qu’il y a à chaque seconde un nouveau signal, long ou court, dont la durée Δt ne varie pas :

photo 3(2)

On va compter le nombre de 0 et de 1, et on pourra dire si l’impulsion est longue ou si elle est courte. Le premier rôle du programme est donc de déterminer la durée des impulsions qu’il reçoit. Il va mesurer le niveau du signal à une vitesse suffisante. Ainsi, si le courant est en haut (par exemple, si la tension est de 5 Volts), il notera un 1, et s’il est en bas (par exemple, si la tension est nulle), il notera un 0. Ainsi, pour pouvoir distinguer entre 1 et 2 ms, on mesurera la tension toutes les 0,1 ms. Puis, on va regarder où est le courant tous les dixièmes de millisecondes. Comme sur le schéma  ci-contre. C’est aussi le principe utilisé par l’oscilloscope et la numérisation de la musique.

2. Quel type d’information nous envoie-t-on ?

Le début de chaque minute est signifié par une absence de signal de l’émetteur, on le remarque sur notre vidéo à la 27ème seconde ou encore sur cette photo :

photo 2(6)Le module détecte donc une série trop longue de 0. C’est le début du message codé.

Lorsque le programme reçoit un bit (0 ou un 1), il le note dans une mémoire appelée registre. Le registre sera décalé pour noter le bit suivant . Arrivé au huitième 0 ou 1 reçu, le programme va interpréter (nous expliquerons dans un second temps le sens des 0 et des 1). Après avoir interprété les 8 premiers numéros, il les efface, et fait de la place pour les 8 suivants, qu’il reçoit et interprète, jusqu’à la fin de la minute.

Il est intéressant de se figurer ce décalage des données, puis cette interprétation. On interprète, c’est-à-dire que l’on assigne les huit premiers bits à une variable, on efface, puis on passe à la suite. Cette interprétation est faite par la « librairie », que l’on détaillera plus bas. Ainsi, quand le « niveau supérieur » du programme demande l’heure, la librairie lui fournit les variables qu’elle a trouvées.

Il faut ensuite que le programme soit capable de vérifier l’exactitude des données qu’il reçoit. En effet, dans la transmission par les ondes radio, il peut y avoir un parasite industriel, un bruit, qui fausse l’information. Ainsi, après avoir trouvé l’heure une première fois, le programme la compare à l’information transmise par la minute suivante. Si les deux sont semblables, alors l’heure est juste (car on suppose qu’il ne peut pas y avoir deux fois le même parasite au même instant à exactement une minute d’intervalle). Sinon, il faut supprimer une des deux heures obtenues, et calculer encore une fois l’heure. On compare alors le nouveau résultat avec le précédent enregistré. Si ce sont les mêmes, on affiche, sinon, on recommence.

3. Comment interpréter ces informations ?

L’interprétation des 0 et des 1 reçus

Tableau du code DCF77

La figure ci-contre montre le déroulement des informations au cours d’une minute pour le code de l’émetteur DCF77

Il existe plusieurs méthode de codage des nombres. DCF77 utilise le code BCD ( binary coded decimal / décimal codé binaire).
L’information horaire et la date sont diffusées au cours des secondes 21 à 58 de chaque minute sous forme de trois groupes de signaux BCD minutes, heure et date. Chacun de ces trois groupes se termine par un signal (un bit) de parité, déterminé à l’émission, de façon à ce que le nombre de 1 à l’intérieur de chaque groupe soit toujours pair. La parité est très utile pour vérifier s’il n’y a pas eu d’erreur pendant la réception et pour ne pas afficher une valeur incorrecte.

Exemple :

À la réception, une vérification de la parité pratiquée sur chaque groupe du message pourra servir à rejeter, comme perturbé, tout message qui

Ajustement de la parité

Les 1 logiques sont représenté par des traits longs.

comporterait un nombre impair de « 1 » logiques. Les valeurs numériques qui sont diffusées à un instant donné, sont toujours valables pour la minute qui suit immédiatement celle pendant laquelle la diffusion a lieu.

Ainsi, le bip de parité permet de vérifier si le nombre de signaux envoyés est pair ou impair. Soit n le nombre de signaux envoyés (avec 0 ≤ n ≤ 7, sauf pour les années, avec 0 ≤ n ≤ 8). On cherche à savoir si n ≡ 0 [2] ou si n ≡ 1 [2].

Principe du décodage

Le microprocesseur (Arduino), pour être en mesure de traduire correctement l’information, doit détecter deux types d’information : la durée de chaque « top » et l’absence du « top » indiquant le début de la minute.

Il est donc nécessaire de « mesurer » la durée des niveaux du signal fourni par le récepteur radio. Le microprocesseur procède par échantillonnage à une fréquence de 100Hz. Le pas d’échantillonnage est donc le 1/100e de seconde. Le début du comptage est initialisé sur un changement de niveau. Si le nombre de mesures consécutives de niveau 0 Volt est compris entre 79 et 81 (sur les 100 mesures effectuées) on estime avoir reçu un « top » long ; si le nombre de mesures consécutives de niveau 0 Volt est compris entre 89 et 91 sur les 100 mesures effectuées, on estime avoir reçu un « top » court ; et enfin si ce nombre est compris entre 160 et 205, on commence une nouvelle minute. echantillonnage1

 

OrganigrammeLorsque le microprocesseur distingue la durée des « top » il devient possible de le synchroniser avec les secondes, puis de le synchroniser avec les minutes et le décodage peut commencer.

 

 

 

Description du programme :

Il faut télécharger dans le module Arduino un programme de mesure et de décodage. Notre travail a été facilité puisque des informaticiens ont publié des « bibliothèques ». Ce sont des fonctions préparées qui décodent et renvoient les valeurs souhaitées directement, de façon à pouvoir les afficher sur l’écran, pour ensuite les envoyer à un ordinateur. Les bibliothèques font partie de la programmation de haut niveau. Ainsi, nous chercherons seulement à définir ce dont nous nous servons dans notre travail.

Voici le programme, écrit en C/C++ que nous avons pu lire et télécharger dans le module.

/****************************************
Exemple d'écriture sur le display 12C 96
 ****************************************/

#include "DCF77.h"
#include "Time.h"

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define DCF_PIN 2	         // Connection pin to DCF 77 device
#define DCF_INTERRUPT 0		 // Interrupt number associated with pin

time_t time;
DCF77 DCF = DCF77 (DCF_PIN,DCF_INTERRUPT) ;

#define OLED_RESET 4
Adafruit_SSD1306 display(OLED_RESET);

void setup()   {                
  Serial.begin    (9600)             ;
  Serial.println  ("Initialisation") ;

  display.begin        (SSD1306_SWITCHCAPVCC, 0x3C) ;  // initialise le display  I2C addr 0x3C (128x32)
  DCF.Start            ()                           ;
  delay                (2000)                       ;  // 2 secondes svp
  display.clearDisplay ()                           ;   // clears the screen and buffer
  display.setTextSize  (2)                          ;
  display.setTextColor (WHITE)                      ;
  display.setCursor    (0,0)                        ;
  display.println      ("Bonjour!")                 ;
  display.display      ()                           ; 
}

void loop() {
  delay                (1000) ;
  display.clearDisplay ()     ; 
  display.setCursor    (5,0)  ;
  time_t DCFtime = DCF.getTime ()                  ; // Nouvelle heure DCF77 valide ? 
  if (DCFtime!=0)
  {
    display.println("Time is updated");
    setTime(DCFtime);
  }	
  meinberg_usb() ; 
  digitalClockDisplay();
} 

void digitalClockDisplay(){
  // Affichage de date et heure sur display
  display.setCursor    (0,2)  ;
  display.clearDisplay ()  ;    
  display.setTextSize  (1) ; 
  switch(weekday()) 
  {
    case 1: display.print ("lundi")    ; break ;
    case 2: display.print ("mardi")    ; break ;
    case 3: display.print ("mercredi") ; break ;
    case 4: display.print ("jeudi")    ; break ;
    case 5: display.print ("vendredi") ; break ;
    case 6: display.print ("samedi")   ; break ;
    case 7: display.print ("dimanche") ; break ;
  }
  display.print       (" ") ;
  display.print       (day())    ;
  display.print       (" ")      ;
  display.print       (month())  ;
  display.print       (" ")      ;
  display.print       (year())   ; 
  display.println     ("")       ; 
  display.println     ("")       ;

  display.setTextSize  (2)        ;   
  display.print        (" ")     ;
  display.print        (hour())   ;
  display_Digits       (minute()) ;
  display_Digits       (second()) ;
  display.println      ("")       ;
  display.display      ()         ;  

}  

void display_Digits(int digits){
  // Utilitaire d'affichage d'un nombre avec 2 chiffres sur le display
  display.print (":") ;
  if (digits < 10)  display.print ('0') ;
  display.print(digits);
}

void printDigits(int digits){
  // Utilitaire d'affichage d'un nombre avec 2 chiffres sur le port serie 
  Serial.print                  (":") ;
  if(digits < 10)  Serial.print ('0') ;
  Serial.print                  (digits) ;
}

void meinberg_usb()
{
  // digital clock display of the time
  Serial.print   ("D:")      ;
  Serial.print   (day())     ;
  Serial.print   (".")       ;
  Serial.print   (month())   ;
  Serial.print   (".")       ;
  Serial.print   (year())    ;  
  Serial.print   (";T:")     ; 
  Serial.print   (weekday()) ;  // Day of week 
  Serial.print   (";U:")     ; 
  Serial.print   (hour())    ;
  Serial.print   (".")       ;
  printDigits    (minute())  ;
  Serial.print   (".")       ;
  printDigits    (second())  ;  // current_bit   
  Serial.println ()          ; 
}

Dans ce programme, il y a très peu de traitement ; la majeure partie se résume à l’affichage sur l’écran des valeurs obtenues. Ces valeurs, qui semblent surgir de nulle part, proviennent des bibliothèques « DCF77.h » et « Time.h », qui sont inclues au tout début du programme. On fait appel à ces bibliothèques à trois endroits :

 time_t time;
 DCF77 DCF = DCF77 (DCF_PIN,DCF_INTERRUPT) ;
 DCF.Start () ;

 time_t DCFtime = DCF.getTime () ;

La première fonction, « time_t time; » fait appel à la bibliothèque « Time.h ». Elle retrouve le temps actuel, qu’elle stocke dans une variable « time », qui est réutilisée dans les fonctions DCF. Voici un morceau de la bibliothèque.

 int hour(); // the hour now
 int hour(time_t t); // the hour for the given time
 int hourFormat12(); // the hour now in 12 hour format
 int hourFormat12(time_t t); // the hour for the given time in 12 hour format
 uint8_t isAM(); // returns true if time now is AM
 uint8_t isAM(time_t t); // returns true the given time is AM
 uint8_t isPM(); // returns true if time now is PM
 uint8_t isPM(time_t t); // returns true the given time is PM
 int minute(); // the minute now
 int minute(time_t t); // the minute for the given time
 int second(); // the second now
 int second(time_t t); // the second for the given time
 int day(); // the day now
 int day(time_t t); // the day for the given time
 int weekday(); // the weekday now (Sunday is day 1)
 int weekday(time_t t); // the weekday for the given time
 int month(); // the month now (Jan is month 1)
 int month(time_t t); // the month for the given time
 int year(); // the full four digit year: (2009, 2010 etc)
 int year(time_t t); // the year for the given time

Toutes les variables (hour, minute, second, day, weekday, month et year) sont renseignées automatiquement par la bibliothèque  « time_t ». On voit que ces variables sont réutilisées dans l’affichage du Arduino:

void meinberg_usb()
 {
 // digital clock display of the time
 Serial.print ("D:") ;
 Serial.print (day()) ;
 Serial.print (".") ;
 Serial.print (month()) ;
 Serial.print (".") ;
 Serial.print (year()) ;
 Serial.print (";T:") ;
 Serial.print (weekday()) ; // Day of week
 Serial.print (";U:") ;
 Serial.print (hour()) ;
 Serial.print (".") ;
 printDigits (minute()) ;
 Serial.print (".") ;
 printDigits (second()) ; // current_bit
 Serial.println () ;
 }

La fonction « DCF.Start » pose un autre problème : ce n’est qu’une appellation, c’est-à-dire qu’il n’y a aucune fonction DCF.Start dans la bibliothèque « DCF77.h ». On retrouve DCF.Start dans un autre fichier, le fichier « keywords.txt ». C’est un fichier texte, où l’on retrouve tous les morceaux de commandes qui suivent « DCF. », tel que « getTime », « Start », « day », etc.
La fonction « Start » permet de lancer « l’écoute » du signal radio. Cette information est donnée dans un autre fichier texte:

Start(); // Start listening to DCF77 signal

4. L’heure reçue est-elle bien l’heure exacte ?

 

Enfin, pour la troisième fonction: time_t DCFtime = DCF.getTime ().
Il y a une vérification de la cohérence entre l’heure donnée par « time_t » et l’heure reçue par « DCF.getTime ». Si la valeur de « DCF.getTime » est nulle, la boucle « void loop() » continue à tourner, jusqu’à ce que la variable « DCF.time » s’initialise. Une fois qu’elle s’est initialisée, le programme peut commencer à régler l’affichage.

La programmation de l’affichage change selon le but souhaité, lors de l’obtention des valeurs. Ainsi, si on veut simplement afficher les valeurs sur un écran LED, on va adapter les espacements et les caractères de séparation des heures, minutes et secondes. Si on veut envoyer toutes ces variables vers un ordinateur, de manière à ce que celui-ci les traite, il faudrait transformer toutes ces données sous forme de paquets. Ensuite, il faut les envoyer par USB, comme on le fait avec l’écran. Les bibliothèques inclues au début du programme, telle que <Adafruit_GFX.h>, sont des bibliothèques d’affichage qui permettent de simplifier, encore une fois, les modifications que devrait effectuer un utilisateur de ce programme lors de l’adaptation de celui-ci au matériel utilisé.

Page suivante