L'orologio di Arduino: RTC DS3231

Ciao!
in questo post vedremo come interfacciare ad Arduino il molto popolare modulo RTC basato sul chip DS3231 (datasheet)


Esistono molti moduli RTC, alcuni dal costo anche elevato.
Il DS3231, nonostante il basso costo, offre una precisione valida per moltissime applicazioni.
L'errore indicato dal datasheet infatti è compreso tra 2 e 3.5ppm (in base alla temperatura ambientale).

Prendendo il dato peggiore (3.5ppm) l'errore in un giorno (86400 secondi) si calcola in questo modo:

3.5/1000000 = 0,0000035
86400 * 0,0000035 = 0,3024 secondi in un giorno.


Il modulo comunica tramite Arduino con il protocollo I2C, quindi il collegamento è quello tipico:





Per utilizzare il modulo è necessario scaricare ed installare questa libreria

Un pratico esempio di sketch per l'utilizzo è il "rtc_ds3231.ino", disponibile tra gli esempi della libreria linkata sopra

  1. #include <Wire.h>
  2. #include "ds3231.h"
  3. #define BUFF_MAX 128
  4. uint8_t Time[8];
  5. char recv[BUFF_MAX];
  6. unsigned int recv_size = 0;
  7. unsigned long prev, interval = 5000;
  8. void parse_cmd(char *cmd, int cmdsize);
  9. void setup()
  10. {
  11.     Serial.begin(9600);
  12.     Wire.begin();
  13.     DS3231_init(DS3231_CONTROL_INTCN);
  14.     memset(recv, 0, BUFF_MAX);
  15.     Serial.println("GET time");
  16. }
  17. void loop()
  18. {
  19.     char in;
  20.     char buff[BUFF_MAX];
  21.     unsigned long now = millis();
  22.     struct ts t;
  23.     // show time once in a while
  24.     if ((now - prev > interval) && (Serial.available() <= 0)) {
  25.         DS3231_get(&t);
  26.         // there is a compile time option in the library to include unixtime support
  27. #ifdef CONFIG_UNIXTIME
  28. #ifdef __AVR__
  29.         snprintf(buff, BUFF_MAX, "%d.%02d.%02d %02d:%02d:%02d %ld", t.year,
  30. #error AVR
  31. #else
  32.         snprintf(buff, BUFF_MAX, "%d.%02d.%02d %02d:%02d:%02d %d", t.year,
  33. #endif
  34.              t.mon, t.mday, t.hour, t.min, t.sec, t.unixtime);
  35. #else
  36.         snprintf(buff, BUFF_MAX, "%d.%02d.%02d %02d:%02d:%02d", t.year,
  37.              t.mon, t.mday, t.hour, t.min, t.sec);
  38. #endif
  39.         Serial.println(buff);
  40.         prev = now;
  41.     }
  42.     if (Serial.available() > 0) {
  43.         in = Serial.read();
  44.         if ((in == 10 || in == 13) && (recv_size > 0)) {
  45.             parse_cmd(recv, recv_size);
  46.             recv_size = 0;
  47.             recv[0] = 0;
  48.         } else if (in < 48 || in > 122) {;       // ignore ~[0-9A-Za-z]
  49.         } else if (recv_size > BUFF_MAX - 2) {   // drop lines that are too long
  50.             // drop
  51.             recv_size = 0;
  52.             recv[0] = 0;
  53.         } else if (recv_size < BUFF_MAX - 2) {
  54.             recv[recv_size] = in;
  55.             recv[recv_size + 1] = 0;
  56.             recv_size += 1;
  57.         }
  58.     }
  59. }
  60. void parse_cmd(char *cmd, int cmdsize)
  61. {
  62.     uint8_t i;
  63.     uint8_t reg_val;
  64.     char buff[BUFF_MAX];
  65.     struct ts t;
  66.     //snprintf(buff, BUFF_MAX, "cmd was '%s' %d\n", cmd, cmdsize);
  67.     //Serial.print(buff);
  68.     // TssmmhhWDDMMYYYY aka set time
  69.     if (cmd[0] == 84 && cmdsize == 16) {
  70.         //T355720619112011
  71.         t.sec = inp2toi(cmd, 1);
  72.         t.min = inp2toi(cmd, 3);
  73.         t.hour = inp2toi(cmd, 5);
  74.         t.wday = cmd[7] - 48;
  75.         t.mday = inp2toi(cmd, 8);
  76.         t.mon = inp2toi(cmd, 10);
  77.         t.year = inp2toi(cmd, 12) * 100 + inp2toi(cmd, 14);
  78.         DS3231_set(t);
  79.         Serial.println("OK");
  80.     } else if (cmd[0] == 49 && cmdsize == 1) {  // "1" get alarm 1
  81.         DS3231_get_a1(&buff[0], 59);
  82.         Serial.println(buff);
  83.     } else if (cmd[0] == 50 && cmdsize == 1) {  // "2" get alarm 1
  84.         DS3231_get_a2(&buff[0], 59);
  85.         Serial.println(buff);
  86.     } else if (cmd[0] == 51 && cmdsize == 1) {  // "3" get aging register
  87.         Serial.print("aging reg is ");
  88.         Serial.println(DS3231_get_aging(), DEC);
  89.     } else if (cmd[0] == 65 && cmdsize == 9) {  // "A" set alarm 1
  90.         DS3231_set_creg(DS3231_CONTROL_INTCN | DS3231_CONTROL_A1IE);
  91.         //ASSMMHHDD
  92.         for (= 0; i < 4; i++) {
  93.             Time[i] = (cmd[2 * i + 1] - 48) * 10 + cmd[2 * i + 2] - 48; // ss, mm, hh, dd
  94.         }
  95.         uint8_t flags[5] = { 0, 0, 0, 0, 0 };
  96.         DS3231_set_a1(Time[0], Time[1], Time[2], Time[3], flags);
  97.         DS3231_get_a1(&buff[0], 59);
  98.         Serial.println(buff);
  99.     } else if (cmd[0] == 66 && cmdsize == 7) {  // "B" Set Alarm 2
  100.         DS3231_set_creg(DS3231_CONTROL_INTCN | DS3231_CONTROL_A2IE);
  101.         //BMMHHDD
  102.         for (= 0; i < 4; i++) {
  103.             Time[i] = (cmd[2 * i + 1] - 48) * 10 + cmd[2 * i + 2] - 48; // mm, hh, dd
  104.         }
  105.         uint8_t flags[5] = { 0, 0, 0, 0 };
  106.         DS3231_set_a2(Time[0], Time[1], Time[2], flags);
  107.         DS3231_get_a2(&buff[0], 59);
  108.         Serial.println(buff);
  109.     } else if (cmd[0] == 67 && cmdsize == 1) {  // "C" - get temperature register
  110.         Serial.print("temperature reg is ");
  111.         Serial.println(DS3231_get_treg(), DEC);
  112.     } else if (cmd[0] == 68 && cmdsize == 1) {  // "D" - reset status register alarm flags
  113.         reg_val = DS3231_get_sreg();
  114.         reg_val &= B11111100;
  115.         DS3231_set_sreg(reg_val);
  116.     } else if (cmd[0] == 70 && cmdsize == 1) {  // "F" - custom fct
  117.         reg_val = DS3231_get_addr(0x5);
  118.         Serial.print("orig ");
  119.         Serial.print(reg_val,DEC);
  120.         Serial.print("month is ");
  121.         Serial.println(bcdtodec(reg_val & 0x1F),DEC);
  122.     } else if (cmd[0] == 71 && cmdsize == 1) {  // "G" - set aging status register
  123.         DS3231_set_aging(0);
  124.     } else if (cmd[0] == 83 && cmdsize == 1) {  // "S" - get status register
  125.         Serial.print("status reg is ");
  126.         Serial.println(DS3231_get_sreg(), DEC);
  127.     } else {
  128.         Serial.print("unknown command prefix ");
  129.         Serial.println(cmd[0]);
  130.         Serial.println(cmd[0], DEC);
  131.     }
  132. }


Ora aprite il serial monitor, vedrete una data ed ora (sbagliata),
per correggerla digitate nel serial monitor quella corretta con la seguente sintassi:

TssmmhhWDDMMYYYY

Dove:
T = comando per settare la data e ora
ss = secondi
mm = minuti
hh = ore
W = giorno della settimana (1 = lunedì)
DD = giorno
MM = mese
YYYY = anno


Questo è tutto,
per qualsiasi domanda lascia pure un commento.

Seguimi sulle mie pagine per rimanere sempre aggiornato sui nuovi post!

2 commenti:

  1. il progetto sembra non funzionare con scheda arduino Nano V.3 "exit status 1
    Errore durante la compilazione per la scheda Arduino Nano."

    RispondiElimina
    Risposte
    1. problema risolto, in pratica avevo due liberie Wire.h differenti in due cartelle diverse ....

      Elimina

Lascia un commento qui sotto, ti risponderò il prima possibile!

Altri Post