DS3231, ed alcuni dubbi

Ciao a tutti, mi servirebbe un parere da qualcuno che abbia gia usato il DS3231 ... la domanda e' "software", e per la maggior parte dei programmatori probabilmente anche banale, ma la risposta poi mi condizionera' l'hardware, quindi dovrei risolvere il dubbio prima di terminare la parte hardware del prototipo.

Premetto che il tutto e' ancora in fase di studio, della serie, "vediamo se e' possibile farlo, prima di buttarci a farlo" ... dovrebbe trattarsi di un datalogger del tipo "a lungo termine", nel senso che dovrebbe avere la maggiore autonomia possibile, ed un minimo di possibilita' di campionare valori sul lungo periodo con intervalli di minuti o anche oltre ... per cui cercavo di scoprire se fosse possibile realizzarlo con un 328 buttato in sleep durante i periodi di non lettura ed un DS3231 come RTC, e risvegliabile ad intervalli programmabili ...

Stavo guardando il datasheet del chip, ed ho visto che il pin 3 puo essere usato per ottenere un'impulso basso a determinati intervalli che dipendono da due registri "alarm" ... la mia idea era di usare un'interrupt "falling" del 328 come "sveglia", pilotato appunto da questo pin, dato che gli interrupt dovrebbero essere indipendenti dalla condizione di sleep o deep-sleep, e riuscire a risvegliare il micro in ogni caso ... in questo modo, dovrebbe essere possibile programmare l'intervallo di lettura nei registri alarm del DS, che si occuperebbe poi di svegliare il 328 ad intervalli, questo farebbe tutte le sue letture, poi si rimetterebbe a dormire fino al prossimo impulso ... e fin qui, la cosa dovrebbe essere "relativamente" semplice (parecchio relativamente, immagino :D)

Pero', da quello che ho capito, gli allarmi possono essere impostati per avere impulsi ogni secondo, minuto, ora, giorno ... ma NON per multipli, cioe', non potrei avere una lettura ogni 10 o 30 minuti, o 2 o 5 ore, e cosi via, se mi servisse, e qui viene il dubbio ... il 328, puo usare un'ingresso interrupt come "contatore" per una variabile interna anche rimanendo per la maggior parte del tempo in sleep ? (esempio, devo fare una lettura ogni 6 ore, imposto l'allarme interno del DS in modo che mi dia un'impulso ogni ora ed una variabile di conteggio a zero, alla ricezione dell'impulso, controllo il valore della variabile, se e' 6, la azzero, faccio le mie letture, salvo su SD e torno a dormire, se e' minore, aggiungo uno e torno a dormire ... in questo modo, il tutto sarebbe "sveglio" per pochissimo tempo ogni ora, al di fuori delle letture) ... presumo di si, ma vorrei esserne certo ... inoltre, quanto potrebbe influire sul consumo medio l'operazione di aggiornamento di questa variabile ? ... anche qui, presumo piuttosto poco, dato che presumo bastino poche operazioni quindi pochissimo tempo, ma chiedere e' sempre meglio ...

Ovviamente, se non esiste un modo per avere gli impulsi gia dal DS agli intervalli voluti :wink:

Etemenanki:
... Pero', da quello che ho capito, gli allarmi possono essere impostati per avere impulsi ogni secondo, minuto, ora, giorno ... ma NON per multipli, cioe', non potrei avere una lettura ogni 10 o 30 minuti, o 2 o 5 ore, e cosi via ...

Veramente, se guardi a pagina 11 e 12 del datasheet hai una spiegazione (... che spero di aver capito dato che gli allarmi non li uso) ... puoi programmare sia un orario fisso di allarme (data/ora o solo ora) sia un allarme ripetitivo (Vd. table 2).

Per il tuo scopo, io programmerei un allarme (ora/minuti/secondi), mi sveglierei con il suo interrupt, farei quello che devo fare e programmerei il nuovo allarme (ora/minuti/secondi) prima di andare di nuovo in sleep. :wink:

Guglielmo

Per il tuo scopo, io programmerei un allarme (ora/minuti/secondi), mi sveglierei con il suo interrupt, farei quello che devo fare e programmerei il nuovo allarme (ora/minuti/secondi) prima di andare di nuovo in sleep.

Esatto, è quello che ho fatto e farei anche io.

Quando scatta l'allarme, facico quelo che deve fare e poi lo reimposto,

esempio di datalogger con ds3231

#include <avr/sleep.h>
#include "DHT.h" // Dht sensor library by Adafruit
#define DHTPIN 4
#define DHTTYPE DHT22   // DHT 22  (AM2302), AM2321
DHT dht(DHTPIN, DHTTYPE);

#include <SPI.h>
#include <SD.h>
//#include "SdFat.h"
//SdFat SD;
File myFile;
#define SD_CS_PIN 10
#define pin_mosfet 3
#define pin_led 8


#include <avr/pgmspace.h>
#include <Wire.h>
#include <RtcDS3231.h> // ***** Rtc by Makuna in Library Manager *****
RtcDS3231<TwoWire> Rtc(Wire);
#define RtcPin 2
volatile bool interuptFlag = false;
char datestring[20];


void setup() {
   pinMode(RtcPin, INPUT );
  //digitalWrite (2, HIGH);  // enable pull-up
  pinMode(pin_mosfet, OUTPUT);
  digitalWrite(pin_mosfet, LOW);
  pinMode(pin_led, OUTPUT); // Led di errore sul in D8
  digitalWrite(pin_led, LOW);
  Serial.begin(115200);
  dht.begin();
  Serial.print("Initializing SD card...");
  if (!SD.begin(SD_CS_PIN)) {
    Serial.println("initialization failed!");
    digitalWrite(pin_led, HIGH); // attiva led di allarme
    Riavvia();
    return;
  }
  Serial.println("initialization done.");
  delay(300);
  digitalWrite(pin_mosfet, HIGH);
  Rtc.Begin();
  Rtc.Enable32kHzPin(false);
  Rtc.SetSquareWavePin(DS3231SquareWavePin_ModeAlarmOne);
  imposta_allarme();
}

void imposta_allarme() {
  RtcDateTime now = Rtc.GetDateTime();
  // Imposta allarme tra 5 minuti (300 secondi )
  RtcDateTime alarmTime = now + 300 ;
  DS3231AlarmOne alarm1(
    alarmTime.Day(),
    alarmTime.Hour(),
    alarmTime.Minute(),
    alarmTime.Second(),
    DS3231AlarmOneControl_HoursMinutesSecondsMatch);
  Rtc.SetAlarmOne(alarm1);
  // throw away any old alarm state before we ran
  Rtc.LatchAlarmsTriggeredFlags();
  //  // setup external interupt
  //  attachInterrupt(0, wake, FALLING);

}

// routine di interrupt
void wake ()
{
  sleep_disable(); // cancel sleep as a precaution
  detachInterrupt(digitalPinToInterrupt(RtcPin));
  interuptFlag = true;
}

void loop() {
  // disable ADC
  ADCSRA = 0;

  set_sleep_mode (SLEEP_MODE_PWR_DOWN);
  sleep_enable();

  // Do not interrupt before we go to sleep, or the
  // ISR will detach interrupts and we won't wake.
  noInterrupts ();

  // will be called when pin D2 goes low
  attachInterrupt (digitalPinToInterrupt(RtcPin), wake, FALLING);
  EIFR = bit (INTF0);  // clear flag for interrupt 0

  // turn off brown-out enable in software
  // BODS must be set to one and BODSE must be set to zero within four clock cycles
  MCUCR = bit (BODS) | bit (BODSE);
  // The BODS bit is automatically cleared after three clock cycles
  MCUCR = bit (BODS);

  interrupts ();  // one cycle
  sleep_cpu ();   // one cycle
  //
  // il sistema e' in standy
  //
  digitalWrite(pin_mosfet, LOW); // attiva alimentazione
  //delay(500); // pausa per sensore DHT ( vedere di quanto si puo' ridurre )
  float h = dht.readHumidity();
  float t = dht.readTemperature();

  // Check if any reads failed and exit early (to try again).
  if (isnan(h) || isnan(t)) {
    Serial.println("Failed to read from DHT sensor!");
    // digitalWrite(pin_led, HIGH);  // attiva led di allarme
    Riavvia();

    return;
  }
  Serial.print("Humidity: ");
  Serial.print(h);
  Serial.print(" %\t");
  Serial.print("Temperature: ");
  Serial.print(t);
  Serial.println(" *C ");

  RtcDateTime now = Rtc.GetDateTime();
  // printDateTime(now);
  // Serial.println();

  if (Alarmed())
  {
    imposta_allarme();
  }

  // ************ Gestione SD

  myFile = SD.open("Data3.csv", FILE_WRITE);
  // if the file opened okay, write to it:
  if (myFile) {
    digitalWrite(pin_led, HIGH);  // attiva led OK
    Serial.println("Writing to Data3.csv...");
    myFile.print(datestring);
    myFile.print("   ");
    myFile.print(h);
    myFile.print("   ");
    myFile.println(t);
    myFile.close();
    Serial.println("done.");
    digitalWrite(pin_led, LOW);  // spegne led OK
  } else {
    // if the file didn't open, print an error:
    Serial.println("error opening Data3.csv");
    //digitalWrite(pin_led, HIGH);  // attiva led di allarme
    Riavvia();
  }

  // re-open the file for reading:
  myFile = SD.open("Data3.csv");
  if (myFile) {
    Serial.println("OK Data3.csv:");
    //        // read from the file until there's nothing else in it:
    //        while (myFile.available()) {
    //          Serial.write(myFile.read());
    //  }

    myFile.close();
  } else {
    // if the file didn't open, print an error:
    Serial.println("error opening Data3.csv");
    // digitalWrite(pin_led, HIGH);  // attiva led di allarme
    Riavvia();
  }
  delay(200); // ritardo altrimenti la SD si arrabbia
  digitalWrite(pin_mosfet, HIGH); // disabilita alimentazione

}

bool Alarmed()
{
  bool wasAlarmed = false;
  if (interuptFlag)  // check our flag that gets sets in the interupt
  {
    wasAlarmed = true;
    interuptFlag = false; // reset the flag
    // this gives us which alarms triggered and
    // then allows for others to trigger again
    DS3231AlarmFlag flag = Rtc.LatchAlarmsTriggeredFlags();

    if (flag & DS3231AlarmFlag_Alarm1)
    {
      Serial.println();
      Serial.println("allarme uno si e' attivato");
      RtcDateTime now = Rtc.GetDateTime();
      printDateTime(now);
      Serial.println();
      // Serial.println();
    }
  }
  return wasAlarmed;
}

#define countof(a) (sizeof(a) / sizeof(a[0]))

void printDateTime(const RtcDateTime& dt)
{
  //char datestring[20];
  snprintf_P(datestring,
             countof(datestring),
             PSTR("%02u/%02u/%04u %02u:%02u:%02u"),
             dt.Day(),
             dt.Month(),
             dt.Year(),
             dt.Hour(),
             dt.Minute(),
             dt.Second() );
  Serial.print(datestring);
}

void Riavvia() {
  Serial.print("      RESET     ");
  // fermare il tutto perchè c'è un problema

}

mmmm salvato e messo da parte :slight_smile:

gpb01:
... e programmerei il nuovo allarme (ora/minuti/secondi) prima di andare di nuovo in sleep. :wink:

Guglielmo

Questo non comporterebbe una maggiore complessita' a livello di software, ed un maggiore consumo a livello hardware ? ... oppure comporta talmente pochi cicli da non essere influente ? ... in questo secondo caso, sarebbe di certo la cosa migliore ...

Si, stavo studiando il datasheet, ma non sembra esserci un modo per programmare il DS ad intervalli differenti da quelli fissi, ogni secondo, minuto, ora, giorno, oppure date ed ore specifiche ma sempre le stesse (tipo, le 12 di ogni giorno, ma non ogni "tot" ore diverse dalle 24 .. pero' se riprogrammare i registri dell'allarme non porta via troppe risorse, in effetti il problema lo si risolve cosi ...)

Brunello: grazie, devo studiarmi bene l'esempio, come sai io la programmazione la "mastico" ancora male ... :wink:

Etemenanki:
Questo non comporterebbe una maggiore complessita' a livello di software, ed un maggiore consumo a livello hardware ? ... oppure comporta talmente pochi cicli da non essere influente ?

... buona la seconda :smiley: :smiley: :smiley:

Ti svegli una volta ogni X ore, fai il tuo lavoro, quattro comandi per riprogrammare l'allarme e ti rimetti in sleep ...
... cosa vuoi che incidano pochi microsecondi su ore di sleep ? ? ? :wink:

Guglielmo

gpb01:
... buona la seconda :smiley: :smiley: :smiley:
...
Guglielmo

Bene, ed il primo dubbio e' chiarito, passiamo al secondo, che mi e' venuto studiandomi il datasheet (perche' se nella vita non ci sono dubbi, che vita e' ? ... :stuck_out_tongue: :D)

Leggevo nelle tabelle dei valori elettrici, che alimentando il DS con il pin VCC, l'assorbimento e' 220uA a regime e 110uA a riposo ... mentre alimentandolo solo con il VBATT, assorbe 70uA a regime e circa 3 al massimo a riposo ... ora, il datasheet dice che e' possibile alimentarlo solo con il VBATT, ma non sono presenti molte informazioni in merito, qualcuno ha gia provato ad usarlo in questo modo, e se si, ha dato problemi sul lungo periodo ?

La cosa nell'ottica di ridurre al massimo i consumi in fase di riposo ... potrei fare il "selvaggio" ed aggiungere un diodo sul GND del regolatore in modo da compensare le cadute degli altri diodi, ed usare appunto due diodi per collegare VCC e batteria al VBATT, cosi il tutto rimarrebbe alimentato dal regolatore, e la batteria interverrebbe solo a pile scariche ...

Per il resto, sto pensando di realizzare una schedina grossa circa come un portabatterie da 4 stilo, in modo di poter usare 4 alcaline, ed un MCP1700 come regolatore per i 3.3V ... l'MCP1700 ha una corrente propria di 1.6uA ed un dropout di circa 180mV, di meglio non sono riuscito a trovare, neppure sugli switching, e riesce a dare fino a 250mA, che dovrebbero essere sufficenti per un 328 e qualche sensore ... come schema preliminare riuscirei a portare fuori 4 ingressi digitali, 4 analogici, ed il bus I2C nel caso servissero sensori di quel tipo, ed userei uno degli ingressi analogici extra per leggere la tensione della batteria ed arrestare il tutto sotto una certa soglia ... un mosfet P interrompera' il positivo a tutti i connettori dei sensori, in modo da accenderli solo durante le letture ... la microSD mi sembra possa essere lasciata alimentata, in fase di inutilizzo stando ad un datasheet della Kingston dovrebbe consumare sui 10uA massimi, non pochissimo ma accettabile ... come riferimento per l'ADC un TL431B impostato di default a 1.25V, anche quello "acceso" insieme al resto quando serve ...

A proposito, dato che per la precisione dell'orario userei il DS, ha senso usare un quarzo per la MCU, o c'e' il modo di risparmiare sui consumi attivando semplicemente l'oscillatore interno o usando un risuonatore ceramico ?

Piu vado avanti a scrivere, piu mi vengono dubbi ... che bello ... :stuck_out_tongue:

Intanto che aspetto che mi arrivi un DS per fare qualche test, ho buttato giu un possibile schema di come potrebbe venire alla fine ... piazzando un po tutti i componenti in un rettangolo di 55x60, che e' piu o meno la grandezza del portabatterie (in modo da potercela incollare dietro) i componenti in 0805 che ci stanno sono all'incirca questi ... vorrei evitare di usarne di piu piccoli ...

Qualcuno potrebbe notare che, anche se c'e' il connettore con i segnali della seriale, non c'e' il solito connettore ICSP ... la cosa e' "piu o meno" voluta ... piu o meno, primo perche' mi causerebbe qualche problema con l'ingombro :P, secondo, perche' gli stessi pin dell'ICSP sono gia tutti presenti nello zoccolo della microSD, quindi pensavo di prendere una di quelle schedine tipo queste oppure disegnarmene una, ed usarla per la programmazione ICSP ... verrebbe buona per programmare in-circuit un po tutto quello che monta uno zoccolo per microSD, alla fine ... :smiley:

Ma se hai l'RTC ... ti serve veramente il quarzo? Non ti basta l'oscillatore interno? Tanto non è che ti serve tutta questa precisione nel clock e ti eviti un po' di componenti :wink:

E, se hai problemi di spazio, ti serve veramente un ATmega328P ? Non ti basta un ATtiny ?

Guglielmo

Oltretutto a 16 Mhz, mica ci arriva con quella tensione !
E ricorda che l'oscillatore interno consuma la metà della corrente rispetto a un Xtal externo

Ora non ricordo con precisione perchè è passato diverso tempo, ma avevo dei problemi con il consumo della SD. Quello che ricordo era che ( ma non sempre ) fatta una scrittura sull'SD, rimaneva un consumo alto ( 20-30 mA ) anche a file chiusi ed è per questo che la alimentavo sotto Mosfet e finito di scrivere la disabilitavo

gpb01:
Ma se hai l'RTC ... ti serve veramente il quarzo? ...

Sul disegno e' rimasta la sigla 16MHz del componente, ma pensavo di usare un 8, o al massimo 4 ... ma infatti, li dubbio era proprio quello, avendo il DS, il quarzo mi servirebbe solo per far funzionare la MCU, e dato che letture sensori e scritture su SD si potrebbero tranquillamente fare anche a velocita' minori, magari lasciando il settaggio di default ad 1MHz con l'oscillatore interno, soprattutto se come dice brunello consuma la meta' della corrente rispetto all'uso con un quarzo esterno (magari il risparmio energetico e' poco, ma tutto fa brodo :D) ... oltretutto eliminando quello ed i due condensatori, salterebbe fuori spazio extra per farci stare un piccolo connettore in piu per l'ICSP ...

Per il 328P, ho usato quello perche' cosi sono riuscito a portare fuori piu ingressi, in modo che sia possibile usarlo per diversi scopi, secondo la necessita' del momento ... senza complicarmi troppo la vita con il routing, dovrei riuscire a piazzarci 4 connettori per 4 ingressi digitali (con VCC e GND), altri 4 per 4 ingressi analogici (anche quelli con VCC e GND), e pure un 4 poli per l'I2C (gli altri che avanzano incasinerebbero molto di piu il routing) ... domani provo a vedere gli ingombri eliminando il quarzo, che anche se SMD, a montarlo e schermarlo bene si mangia parecchio spazio ...

brunello22:
... l'oscillatore interno consuma la metà della corrente rispetto a un Xtal externo

... problemi con il consumo della SD ...

A proposito della SD, leggevo tempo fa in un forum di elettronica che alcuni modelli hanno un consumo anche durante l'inutilizzo, se non vengono collegati al positivo con dei pull-up gli ingressi DAT1 e DAT2 (per quello nello schema li ho connessi) ... ma dicevano anche che la cosa succede solo con alcuni tipi di microSD, senza dare marche e modelli ... dovrei provare a cercare se ne ho in giro alcune "sacrificabili per la scenza" da qualche parte e vedere in qualche modo di testare la cosa ...

Etemenanki:
A proposito della SD, leggevo tempo fa in un forum di elettronica che ...

... io appoggio l'idea di Brunello ... MOSFET e togli l'alimentazione a ciò che non serve :wink:

Guglielmo

gpb01:
... io appoggio l'idea di Brunello ... MOSFET e togli l'alimentazione a ciò che non serve :wink:

Guglielmo

C'e' gia, per i sensori ... si fa presto a connetterci anche la SD :wink:

ma dicevano anche che la cosa succede solo con alcuni tipi di microSD

Questo è vero

se non vengono collegati al positivo con dei pull-up gli ingressi DAT1 e DAT2

Ecco, di questo non ero a conoscenza. Anche se poi uso solo µSD che non hanno il DAT2

Salve raga, bel 3d, soprattutto quando Etem mette a disposizione i suoi circuiti per entrare nella sua indole tecnica.
Ed è prorpio su quest'ultimo che voglio soffermarmi per un brevissimo ot:
etem perché sull'out del LD hai messo 3 ceramici da 1 uf e 3 da 0.1 uf?
io solitamente utilizzo uno al tantallio da 22uf (come suggerito da datasheet) ed 1 ceramico da 0.1uf per rimanere sul sicuro (su AMS1117)

miky-police: Perche' a volte non si riesce a fare un routing con le piste di alimentazione il piu corte possibile, cosi li distribuisco un po dappertutto sulla scheda ... un paio vicino alla MCU, un paio vicino al regolatore, un paio in fondo alla pista piu lunga che mi ritrovo del VCC ... in genere parto con una sola coppia, poi se vedo che mi tocca fare qualche giro strano con il VCC, ne aggiungo altri dove mi sembra meglio ... non ho una regola precisa, vado un po "a naso" ... per il tantalio, posso anche aggiungerlo, ma tanto il tutto va a batteria, non e' indispensabile avere tanti elettrolitici, a meno che non ci siano sensori che richiedono picchi elevati di corrente ...

ultimissima curiosità... vai sempre di coppia 1uf 0.1uf? solitamente consigliano il semplice 100nF e basta per il disaccoppiamento...

miky_police:
... solitamente consigliano il semplice 100nF e basta per il disaccoppiamento...

Si, di solito anch'io metto un paio di elettrolitici nei punti "strategici", e poi abbondo di 100n ceramici, ma qui non usando elettrolitici ho abbondato con il resto ... i ceramici si possono anche mettere da 4u7 invece che da 1u, se si trovano quelli della AVX in classe X7R, perche' sono quelli con la minore corrente di perdita (alcuni di quelli "peggiori" arrivano a 10 o 12 uA l'uno, mentre questi anche se costano un po di piu, sono sotto il uA) ... di solito ci si puo anche disinteressare di tali correnti, ma se un'apparato deve durare diversi mesi con la batteria, tocca fare attenzione anche a queste cose :wink:

Intanto ho buttato giu la versione senza quarzo, ed un'inizio di "routing possibile" ...

PROTO-LOGGER-V2-BRD.png

alto-destra, connettore I2C ed i 4 ingressi analogici, basso-sinistra i 4 digitali, in mezzo il 4 poli per la seriale ed il 6 poli per l'ICSP (dato che ho messo anche la SD dopo il mosfet, non posso piu usarla per la programmazione), due pad per saldarci i fili del portabatterie, DS con portabatteria per una 1220, piu o meno ci sta tutto ... ora devo solo far passare anche il resto delle piste :stuck_out_tongue:

PROTO-LOGGER-V2-BRD.png

... sai che manca Etem ? ... sei piazzole per la connessione ICSP :smiley: ... visto mai devi fare una modifica, vuoi riprogrammare il chip, ecc. ecc.

Guglielmo