Quel titre !
- PIC32 : les microcontrôleurs 32bits de Microchip
- MPLAB Harmony : le framework Harmony dédié à ces microcontrôleurs
- data logger : enregistreur de données
- RTCC : Real Time Calendar/Clock
- BCD : Binary Coded Decimal
But
Coder un enregistreur de données (data logger) en utilisant l’horloge RTC d’un PIC32 via le framework MPLAB Harmony de Microchip.
L’objectif est donc d’obtenir, par exemple, un fichier texte où chaque ligne commence par la date et l’heure correspondant à un événement :
08/10/15;10:17:28;...
08/10/15;10:22:30;...
08/10/15;10:24:33;...
08/10/15;10:30:07;...
Immédiat ? Pas si sûr…
Problématique
Avec le framework Harmony, la date est récupérée avec la fonction DRV_RTCC_DateGet()
de la bibliothèque RTCC :
Or les valeurs renvoyées sont au format BCD.
Pour le jeudi 8 Octobre 2015, la variable date contient (en notation hexadécimale) 0x15100804
.
En séparant chaque groupe de 2 digits :
- 15 : l’année (2015)
- 10 : le mois (octobre)
- 08 : le jour (8)
- 04 : le numéro du jour de la semaine (0 pour dimanche, 1 pour lundi, 2 pour mardi…), ici jeudi
Comme 0x15100804
correspond à la valeur décimale 353372164
, on ne peut pas séparer l’année, le mois et le jour par de simples divisions.
Il faut extraire chaque digit hexadécimale un par un.
Solution n°1 : division et modulo
Une première solution consiste à effectuer une série de divisions en séparant à chaque fois la partie entière du reste de la division.
Par exemple en base 10 (décimale), pour obtenir tout les digits de 1587 soir 1, 5, 8 et 7 :
1587/1000 => partie entière = 1 et reste de la division = 587
587/100 => partie entière = 5 et reste de la division = 87
87/10 => partie entière = 8 et reste de la division = 7
En langage C :
void main(void) {
int date = 1587;
printf("%d ", date / 1000);
date = date % 1000;
printf("%d ", date / 100);
date = date % 100;
printf("%d ", date / 10);
date = date % 10;
printf("%d", date);
printf("\n");
}
L’exécution de ce code affiche 1 5 8 7
.
On applique le même principe à la valeur de la date en BCD mais en utilisant la base 16 (hexadécimale) :
#include <stdint.h>
void main(void) {
uint32_t date = 0x15100804;
printf("%d ", date / 0x10000000);
date = date % 0x10000000;
printf("%d ", date / 0x1000000);
date = date % 0x1000000;
printf("%d ", date / 0x100000);
date = date % 0x100000;
printf("%d ", date / 0x10000);
date = date % 0x10000;
printf("%d ", date / 0x1000);
date = date % 0x1000;
printf("%d ", date / 0x100);
date = date % 0x100;
printf("%d ", date / 0x10);
date = date % 0x10;
printf("%d" , date);
printf("\n");
}
L’exécution de ce code affiche 1 5 1 0 0 8 0 4
.
Solution n°2 : masque binaire et décalage de bits
Intéressons-nous au codage la valeur de la date 0x15100804
.
Chaque digit est un nombre hexadécimal compris entre 0 et 9. Il faut donc 4 bits pour coder chaque digit de 0000 à 1001. Avec 8 digits, la date prend 8*4 = 32 bits en mémoire (d’où le type uint32_t).
Écrivons chaque digit et son équivalent en notation binaire :
0001 0101 0001 0000 0000 1000 0000 0100
Voici la méthode à appliquer à chaque digit :
- isoler le paquet de 4 bits correspondant avec un masque binaire 1111 et un ET logique
- décaler le paquet masqué jusqu’à la dernière position à droite, soit n*4 où n est le numéro du digit (origine 0 = digit de droite)
Pour le digit n°7 (le 1 de l’année) :
+ 1111 0000 0000 0000 0000 0000 0000 0000
-----------------------------------------
0001 0000 0000 0000 0000 0000 0000 0000
Faire 28 décalages (7*4) vers la droite :
>>>>
0000 0001 0000 0000 0000 0000 0000 0000
>>>>
0000 0000 0001 0000 0000 0000 0000 0000
>>>>
0000 0000 0000 0001 0000 0000 0000 0000
>>>>
0000 0000 0000 0000 0001 0000 0000 0000
>>>>
0000 0000 0000 0000 0000 0001 0000 0000
>>>>
0000 0000 0000 0000 0000 0000 0001 0000
>>>>
0000 0000 0000 0000 0000 0000 0000 0001
La conversion du résultat en décimal donne bien 1
Pour le digit n°6 (le 5 de l’année) :
+ 0000 1111 0000 0000 0000 0000 0000 0000
-----------------------------------------
0000 0101 0000 0000 0000 0000 0000 0000
Faire 24 décalages (6*4) vers la droite :
>>>>
0000 0000 0101 0000 0000 0000 0000 0000
>>>>
0000 0000 0000 0101 0000 0000 0000 0000
>>>>
0000 0000 0000 0000 0101 0000 0000 0000
>>>>
0000 0000 0000 0000 0000 0101 0000 0000
>>>>
0000 0000 0000 0000 0000 0000 0101 0000
>>>>
0000 0000 0000 0000 0000 0000 0000 0101
La conversion du résultat en décimal donne bien 5
On répète ensuite la méthode pour chaque digit.
Voici le code C correspondant à cette méthode :
#include <stdint.h>
void main(void) {
uint32_t date = 0x15100703;
printf("%d ", (date & 0xF0000000) >> (4*7));
printf("%d ", (date & 0x0F000000) >> (4*6));
printf("%d ", (date & 0x00F00000) >> (4*5));
printf("%d ", (date & 0x000F0000) >> (4*4));
printf("%d ", (date & 0x0000F000) >> (4*3));
printf("%d ", (date & 0x00000F00) >> (4*2));
printf("%d ", (date & 0x000000F0) >> (4*1));
printf("%d", (date & 0x0000000F));
printf("\n");
}
Conclusion
Vous pouvez maintenant convertir les dates du format BCD vers un format plus approprié pour leurs manipulations.
Les codes présentés ici sont volontairement simples. À vous de les optimiser si nécessaire.
N’hésitez pas à poster un commentaire si vous connaissez une solution alternative, ou si vous voulez plus d’informations.