Afficheur MAX7219 et RTC DS3231
sur STM32
J'aborde une phase cruciale de mon existence : le dernier trimestre de ma vie professionnelle.
Il m'est venu à l'idée d'afficher sur mon bureau le décompte de secondes qui va s'écouler jusqu'à ce moment tant attendu.
Une espèce de QUILLE électronique.
Un ARDUINO avec un MAX7219 + afficheur 8x7 segments ?
Oui mais c'est trop facile. Il fallait que je fasse un petit effort supplémentaire.
J'ai donc choisi cette carte : la "petite" BLUE PILL que l'on peut trouver ICI à un prix plus qu'intéressant.
Pour le même prix qu'une NANO :
Le module MAX7219 se présente sous cette forme :
Il est câblé comme suit :
Il est câblé ainsi :
Le problème est qu'il faudrait lire le code de la librairie core pour savoir comment tout cela est configuré.
Remarque : le STM32F103C8 possède un RTC interne et un oscillateur 32.768KHz est implanté sur la carte BLUE PILL.
Mais j'avais envie de jouer avec l'I2C.
Il m'est venu à l'idée d'afficher sur mon bureau le décompte de secondes qui va s'écouler jusqu'à ce moment tant attendu.
Une espèce de QUILLE électronique.
1. Le matériel
Qu'allons-nous utiliser comme matériel ?Un ARDUINO avec un MAX7219 + afficheur 8x7 segments ?
Oui mais c'est trop facile. Il fallait que je fasse un petit effort supplémentaire.
J'ai donc choisi cette carte : la "petite" BLUE PILL que l'on peut trouver ICI à un prix plus qu'intéressant.
Pour le même prix qu'une NANO :
- cœur 32bits 72MHz
- large gamme de tension d'utilisation de 2V à 3.6V
- 128Ko de mémoire flash
- 20Ko de SRAM
- RTC interne
- unité de calcul CRC, ID unique 96 bits
- deux convertisseurs A/N 1µs 12 bits (jusqu'à 10 voies)
- dontrôleur DMA 7 voies, 3 timers à usage général et 1 timer de contrôle avancé
- 37 ports E/S rapides
- interfaces de débogage fil série (SWD) et JTAG
- interfaces : deux SPI, deux I2C, trois USART, une USB et une CAN
- 50% des entrées sont tolérantes au 5V
Le module MAX7219 se présente sous cette forme :
Il est câblé comme suit :
- GND : GND
- VCC : 3.3V
- DIN : PA1
- CLK : PA2
- CS : PA3
Il est câblé ainsi :
- GND : GND
- VCC : 3.3V
- SDA : PB7
- SCL : PB6
Le problème est qu'il faudrait lire le code de la librairie core pour savoir comment tout cela est configuré.
Remarque : le STM32F103C8 possède un RTC interne et un oscillateur 32.768KHz est implanté sur la carte BLUE PILL.
Mais j'avais envie de jouer avec l'I2C.
2. Le logiciel
Mon intention est de faire tourner ce petit sketch :
#include <TimeLib.h>
#include <LedControl.h>
#include <Wire.h>
#define TIME_HEADER "T" // Header tag for serial time sync message
#define TIME_REQUEST 7 // ASCII bell character requests a time sync message
#define LED PC13
#define DS3231_I2C_ADDRESS 0x68
LedControl lc = LedControl(PA1, PA2, PA3, 1);
const unsigned long DEFAULT_TIME = 1543138573; // Nov 25 2018
byte decToBcd(byte val)
{
return ((val / 10 * 16) + (val % 10));
}
// Convert binary coded decimal to normal decimal numbers
byte bcdToDec(byte val)
{
return ((val / 16 * 10) + (val % 16));
}
void setDS3231time(int second, int minute, int hour, int wday, int day, int month, int year)
{
Serial.println("Writing DS3231: ");
Serial.print(day);
Serial.print("/");
Serial.print(month);
Serial.print("/");
Serial.print(year);
Serial.print(" ");
Serial.print(hour);
Serial.print(":");
Serial.print(minute);
Serial.print(":");
Serial.println(second);
// sets time and date data to DS3231
Wire.beginTransmission(DS3231_I2C_ADDRESS);
Wire.write(0); // set next input to start at the seconds register
Wire.write(decToBcd(second)); // set seconds
Wire.write(decToBcd(minute)); // set minutes
Wire.write(decToBcd(hour)); // set hours
Wire.write(decToBcd(wday)); // set day of week (1=Sunday, 7=Saturday)
Wire.write(decToBcd(day)); // set date (1 to 31)
Wire.write(decToBcd(month)); // set month
Wire.write(decToBcd(year-2000)); // set year (0 to 99)
Wire.endTransmission();
}
void readDS3231time(int *second, int *minute, int *hour, int *wday, int *day, int *month, int *year)
{
Serial.print("Reading DS3231: ");
Wire.beginTransmission(DS3231_I2C_ADDRESS);
Wire.write(0); // set DS3231 register pointer to 00h
Wire.endTransmission();
Wire.requestFrom(DS3231_I2C_ADDRESS, 7);
// request seven bytes of data from DS3231 starting from register 00h
*second = bcdToDec(Wire.read() & 0x7f);
*minute = bcdToDec(Wire.read());
*hour = bcdToDec(Wire.read() & 0x3f);
*wday = bcdToDec(Wire.read());
*day = bcdToDec(Wire.read());
*month = bcdToDec(Wire.read());
*year = bcdToDec(Wire.read()) + 2000;
Serial.print(*day);
Serial.print("/");
Serial.print(*month);
Serial.print("/");
Serial.print(*year);
Serial.print(" ");
Serial.print(*hour);
Serial.print(":");
Serial.print(*minute);
Serial.print(":");
Serial.println(*second);
}
void processSyncMessage() {
time_t pctime;
if (Serial.find(TIME_HEADER)) {
pctime = Serial.parseInt();
Serial.print("PC TIME: ");
Serial.println(pctime);
if ( pctime >= DEFAULT_TIME) { // check the integer is a valid time
setTime(pctime); // Sync Arduino clock to the time received on the serial port
setDS3231time(second(), minute(), hour(), weekday(), day(), month(), year());
}
}
}
time_t requestSync()
{
Serial.write(TIME_REQUEST);
return 0; // the time will be sent later in response to serial mesg
}
void setup()
{
Serial.begin(115200);
Wire.begin();
pinMode(LED, OUTPUT);
lc.shutdown(0, false);
lc.setIntensity(0, 4);
lc.clearDisplay(0);
setTime(DEFAULT_TIME);
setSyncProvider(requestSync);
}
tmElements_t t = {0, 0, 0, 6, 1, 2, 2019 - 1970};
void loop()
{
int second = 0, minute = 0, hour = 0, wday = 0, day = 0, month = 0, year = 0;
readDS3231time(&second, &minute, &hour, &wday, &day, &month, &year);
if (second > 59 || minute > 59 || hour > 23 | day > 31 || year > 2030) {
Serial.println("Invalid Time");
setDS3231time(0, 0, 0, 1, 25, 11, 2018);
}
setTime(hour, minute, second, day, month, year);
time_t retirement = makeTime(t); // convert time elements into time_t
if (Serial.available()) {
processSyncMessage();
}
lc.clearDisplay(0);
printNumber(0, retirement - now());
if (timeStatus() == timeSet) {
digitalWrite(LED, LOW); // LED on if synced
} else {
digitalWrite(LED, HIGH); // LED off if needs refresh
}
delay(1000);
}
void printNumber(int addr, long num) {
byte c;
int j;
int d;
num = abs(num);
Serial.print(":");
Serial.println(num);
d = countDigits(num);
for (j = 0; j < d; j++) {
c = num % 10; // Modulo division = remainder
num /= 10; // Divide by 10 = next digit
boolean dp = (j == 3); // Add decimal point at 3rd digit.
lc.setDigit(addr, j, c, dp);
}
}
int countDigits(long num) {
int c = 0;
if (num == 0) {
return 1;
}
while (num) {
c++;
num /= 10;
}
return c;
}
Comme vous pouvez le remarquer, la différence par rapport à un sketch ARDUINO ne saute pas aux yeux.
Ceci est normal, car je l'ai développé d'abord sur une NANO.
Seules ces deux lignes diffèrent :
Ceci est normal, car je l'ai développé d'abord sur une NANO.
Seules ces deux lignes diffèrent :
// version NANO
#define LED 13
LedControl lc = LedControl(12, 11, 10, 1);
// version STM32
#define LED PC13
LedControl lc = LedControl(PA1, PA2, PA3, 1);
3. Le chargement
Comment faire pour exécuter du code ARDUINO sur un STM32 ?Toutes les explications sont ICI.
Un petit tuto personnel pour aider pas à pas les néophytes ICI.
Le sketch utilise Wire, TimeLib et LedControl, des librairies classiques qui ne devraient à priori pas poser de problème particulier.
De plus, le Board Package "Arduino SAM Boards" utilisé pour l'installation dans l'IDE ARDUINO - qui inclut l'ARDUINO DUE - nous laisse penser que nous avons toutes les chances que cela fonctionne.
Et cela fonctionne !
1er février 00H00 :
Maintenant :
4. Mise en route
La date par défaut dans le code est la date d'aujourd'hui.Pour mettre à l'heure le montage, il faut utiliser le moniteur série de l'IDE ARDUINO ou n'importe quel autre terminal série.
Il faut envoyer la commande suivante :
TXXXXXXXXXX
La commande se compose de la lettre T suivie du timestamp (nombre de secondes écoulées depuis le 1/1/1970) correspondant à l'heure courante.
Si vous possédez une machine sous LINUX entrez la commande shell suivante :
expr `date +%s` + 3600
La commande affiche un nombre correspondant à l'heure GMT + 1H:
1543157582
Vous pouvez utiliser aussi ce site :
http://www.timestamp.fr/
Il vous faudra également ajouter 3600.
Copiez / collez le timestamp dans votre moniteur série :
T1543157582
Le sketch mettra alors votre RTC à l'heure ainsi que votre horloge système.
5. Conclusion
Ce petit exemple démontre que l'utilisation de librairies prévues pour les cartes ARDUINO est possible sur d'autres cartes.L'apport des librairies ARDUINO en matière de simplification est indéniable et permet de gagner un temps fou sur le développement logiciel.
Les développeurs ayant déjà travaillé avec les librairies STM32 de chez ST MicroElectronics savent de quoi je parle.
Cordialement
Henri
Aucun commentaire:
Enregistrer un commentaire