Voici un petit sketch pour afficher l’heure sur un écran oled avec une RTC DS3231 et un arduino mega , ce début de sketch servira pour un arrosage automatique, le programme sera développé par la suite.
Mon soucis c’est que l’heure affichée ne donne pas les minutes et les secondes avec le zéro devant ( 2 minutes au lieu de 02, idem pour les secondes).
Avez-vous une idée à me proposer ?
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <RTClib.h>
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
Adafruit_SSD1306 oled(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1); // // create SSD1306 display object connected to I2C
RTC_DS3231 rtc;
String time;
void setup() {
Serial.begin(9600);
// initialize OLED display with address 0x3C for 128x64
if (!oled.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println(F("SSD1306 allocation failed"));
while (true)
;
}
delay(2000); // wait for initializing
oled.clearDisplay(); // clear display
oled.setTextSize(1); // text size
oled.setTextColor(WHITE); // text color
oled.setCursor(0, 10); // position to display
// SETUP RTC MODULE
if (!rtc.begin()) {
Serial.println("Couldn't find RTC");
Serial.flush();
while (true)
;
}
// automatically sets the RTC to the date & time on PC this sketch was compiled
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
time.reserve(10); // to avoid fragmenting memory when using String
}
void loop() {
DateTime now = rtc.now();
time = "";
time += now.hour();
time += ':';
time += now.minute();
time += ':';
time += now.second();
oledDisplayCenter(time);
}
void oledDisplayCenter(String text) {
int16_t x1;
int16_t y1;
uint16_t width;
uint16_t height;
oled.getTextBounds(text, 0, 0, &x1, &y1, &width, &height);
// display on horizontal and vertical center
oled.clearDisplay(); // clear display
//oled.setCursor((SCREEN_WIDTH - width) / 2, (SCREEN_HEIGHT - height) / 2);
oled.setCursor (2,10);
oled.print("Heure: ");
oled.println(text); // text to display
oled.display();
}
```
Il faut tester si vous êtes inférieur à 10 et si oui mettre le 0
void loop() {
DateTime now = rtc.now();
String time = "";
if (now.hour() < 10) time += '0';
time += now.hour();
time += ':';
if (now.minute() < 10) time += '0';
time += now.minute();
time += ':';
if (now.second() < 10) time += '0';
time += now.second();
oledDisplayCenter(time);
}
C’est un peu dommage de passer la String par copie au lieu de par référence.
vérifie si la bibli que tu utilises ne propose pas des fonctions d'extraction directe des chiffres (digits) : c'est codé en BCD dans la RAM de la RTC, ce serait idiot de ne pas le faire, j'espère qu'ils y ont pensé
Ce doit être la bibliothèque de Adafruit. La doc de l'API pour la DS3231 est ici et même si en dessous la bibliothèque lit du BCD, elle ne rend pas dispo chaque digit individuellement.
Une autre solution consiste à utiliser la méthode sprintf() qui permet de formater directement les "zéros" non significatifs à gauche et séparer les champs avec le caractère ':'
void loop() {
DateTime now = rtc.now();
char l__buffer[16]; // Taille max pour accueillir la string "HH:MM:SS\0"
sprintf(l__buffer, "%02d:%02d:%02d",
now.hour(), now.minute(), now.second());
String l__time = l__buffer;
oledDisplayCenter(l__time);
}
mais je ne l'ai jamais utilisée : quand j'ai voulu découvrir le DS3231 je n'avais jamais mis en œuvre l'I2C alors j'ai écrit mes propres fonctions (au moins je sais comment ça fonctionne maintenant) pour les 2.
c'est tellement difficile de lire un octet et de le découper avec des masques et des décalages !!!
finalement, les (autres) solutions que vous évoquez (@J-M-L , @claudius01 ) sont peut-être plus à la portée de @electronn2002 ...
ce n'est pas difficile, ils le font dans leur code. Le mettre en API est un choix de design. Je pense que je ne l'aurai pas fait non plus car la valeur ajoutée semble peu importante.
Ils ont une classe vraiment plus adaptée, qui est la DateTime
cette classe sait mettre en forme la date/heure avec le format que l'on veut, cf la fonction toString()
Writes the DateTime as a string in a user-defined format.
The buffer parameter should be initialized by the caller with a string specifying the requested format. This format string may contain any of the following specifiers:
specifier
output
YYYY
the year as a 4-digit number (2000–2099)
YY
the year as a 2-digit number (00–99)
MM
the month as a 2-digit number (01–12)
MMM
the abbreviated English month name ("Jan"–"Dec")
DD
the day as a 2-digit number (01–31)
DDD
the abbreviated English day of the week ("Mon"–"Sun")
AP
either "AM" or "PM"
ap
either "am" or "pm"
hh
the hour as a 2-digit number (00–23 or 01–12)
mm
the minute as a 2-digit number (00–59)
ss
the second as a 2-digit number (00–59)
If either "AP" or "ap" is used, the "hh" specifier uses 12-hour mode (range: 01–12). Otherwise it works in 24-hour mode (range: 00–23).
The specifiers within buffer will be overwritten with the appropriate values from the DateTime. Any characters not belonging to one of the above specifiers are left as-is.
Example: The format "DDD, DD MMM YYYY hh:mm:ss" generates an output of the form "Thu, 16 Apr 2020 18:34:56.
See also
The timestamp() method provides similar functionnality, but it returns a String object and supports a limited choice of predefined formats.
Parameters
[in,out] buffer Array of char for holding the format description and the formatted DateTime. Before calling this method, the buffer should be initialized by the user with the format string. The method will overwrite the buffer with the formatted date and/or time.
Returns
A pointer to the provided buffer. This is returned for convenience, in order to enable idioms such as Serial.println(now.toString(buffer));
Bien sûr, c'est forcément plus rapide et moins couteux en mémoire, vous avez raison pour ce besoin.
Quand on développe des classes, on essaye de généraliser l'usage aussi. Avec la classe DateTime vous pouvez bien sûr représenter une date mais aussi faire des opérations entre dates pour obtenir ce qu'ils appellent un TimeSpan (un intervalle de temps).
Imaginez que vous vouliez que votre horloge représente le temps qui reste avant le 1er janvier et que vous ayez cette DS3231.
Si la "bibliothèque" n'offre que le BCD de chaque chiffre, ce sera sans doute plus long à écrire.
Ensuite, oui vous pourriez aussi envisager d'offrir les deux. Si vous regardez la fonction qui retourne l'heure de leur bibliothèque, on voit très bien qu'ils ont le BCD pour fabriquer leur instance de DateTime.
Après comme le dit @5_cylindres, si on ne veut que les digits séparément et qu'on veut faire efficace, l'accès direct aux registres de la RTC est tout ce qu'il faut.
Oui d’ailleurs je ne m’oppose ni à l’une ni à l’autre des deux approches. D’un côté c’est bien de programmer bas niveau et d’optimiser à l’octet près de l’autre RTClib offre bien plus qu’un simple affichage de l’heure.
Chaque point de vue vise des objectifs différents et est défendable.
Franchement, avec un composant aussi simple qu’un DS3231 on peut écrire soi même le code, surtout quand il ne s’agit que de simplement faire une lecture.
Le point un peu delicat est la conversion du BCD, il suffit d’ouvrir une bibliothèque et d’en extraire deux ou trois lignes de code.
L’obtention individuellement des centaines, dizaines et unités est alors trivial.
***** pas de centaine dans le DS3231 *****
dizaine = octet >> 4 ; // pour char à afficher : +48
unité = octet & 0xF ; // idem
==> temps d'exécution et taille programme négligeables