Un paio di righe per descrivere brevemente un esperimento preparato stamattina con Arduino ed un paio di accessori.
Il problema è il seguente: capita di andare via di casa per diversi giorni (ad esempio a Natale o ad agosto), per vacanza o per altri motivi; al vostro ritorno, potreste domandarvi se è mancata o meno la corrente, e di conseguenza se quanto avevate lasciato in frigorifero o in freezer è ancora commestibile. Nel mio caso, so se è mancata perchè la sveglia del comodino lampeggia, ma non ho idea del tempo in cui sia effettivamente mancata.
Da qui, l’idea di mettere assieme un Arduino, un RTC ed uno shield con SD, per scoprire effettivamente se e per quanto tempo sia mancata la corrente quando non sono in casa. Il codice sotto riportato scrive su un file una riga di timestamp ogni 5 minuti (sfruttando l’interrupt che l’RTC lancia una volta al minuto): se la corrente viene tolta, l’Arduino si spegne e smette di scrivere su file, salvo poi riprendere al ripristino dell’alimentazione, e l’RTC avrà mantenuto nel frattempo l’orario (essendo alimentato a batteria), ed una semplice analisi del contenuto del file permetterà di scoprire l’intervallo di tempo in cui non sono stati scritti timestamp.
Non do rassicurazioni sul codice sotto riportato: test brevi hanno funzionato, ma sto ancora svolgendo un test prolungato nel tempo. L’unica particolarità del codice è che sia l’RTC che la SD comunicano attraverso SPI, utilizzando due modalità diverse (MODE3 vs. MODE0), quindi bisogna alternare le due prima di usare l’uno o l’altro dispositivo. La libreria per RTC serve solamente a semplificare la scrittura nei registri, mentre la libreria Time serve per tradurre una data ed ora in UNIX timestamp.
I collegamenti hardware dell’RTC sono molto semplici e vanno sulle connessioni standard SPI dell’Arduino Uno (CS è 10, dato che lo shield SD ha CS sul pin 8); l’uscita SQW dell’interrupt del DS3234 va al pin 2, che corrisponde ad interrupt zero per l’Arduino Uno.
#include <SPI.h> #include <ds3234.h> #include <SD.h> #include <Time.h> #define RTC_CS 10 #define SD_CS 8 #define RTC_INT 2 #define MINUTES 5 #define FNAME "logger.txt" int time_interrupt = MINUTES; File logger; void setup() { Serial.begin(115200); pinMode(RTC_INT, INPUT); pinMode(SD_CS, OUTPUT); SPI.setDataMode(SPI_MODE3); DS3234_init(RTC_CS, DS3234_INTCN); DS3234_clear_a2f(RTC_CS); set_next_alarm(); SPI.setDataMode(SPI_MODE0); attachInterrupt(0, INT0_ISR, LOW); SD.begin(SD_CS); Serial.println("Waiting for first alarm..."); } void loop() { struct ts t; tmElements_t t2; time_t time; if (time_interrupt == 0) { SPI.setDataMode(SPI_MODE3); DS3234_get(RTC_CS, &t); SPI.setDataMode(SPI_MODE0); t2.Second = t.sec; t2.Minute = t.min; t2.Hour = t.hour; t2.Wday = t.wday; t2.Day = t.mday; t2.Month = t.mon; t2.Year = t.year - 1970; time = makeTime(t2); logger = SD.open(FNAME, FILE_WRITE); if (logger) { logger.seek(logger.size()); logger.println(time); logger.close(); } time_interrupt = MINUTES; } } void set_next_alarm(void) { SPI.setDataMode(SPI_MODE3); boolean flags[4] = { 1, 1, 1, 0 }; DS3234_set_a2(RTC_CS, 0, 0, 0, flags); DS3234_set_creg(RTC_CS, DS3234_INTCN | DS3234_A2IE); SPI.setDataMode(SPI_MODE0); } void INT0_ISR(void) { detachInterrupt(0); --time_interrupt; SPI.setDataMode(SPI_MODE3); DS3234_clear_a2f(RTC_CS); SPI.setDataMode(SPI_MODE0); attachInterrupt(0, INT0_ISR, LOW); }
Leave a Reply