Modificare ora e data RTC DS3231

Ciao a tutti. Vorrei utilizzare il modulo RTC DS3231 I2C per visualizzare l'ora su un display OLED. Purtroppo, a parte il I2C, su Arduino UNO non ho più PIN disponibili. Sarebbe possibile usare i tasti di un telecomando IR per modificare l'ora e la data? Grazie in anticipo

Possibile sarebbe anche possibile (non è semplicissimo, ma si può fare), però ... se non hai più pin, il LED ricevitore IR a cosa lo colleghi?

Guglielmo

Oops, scusami Guglielmo. Ho dimenticato di precisare che il ricevitore e relativo telecomando sono già funzionanti

Dato che sarebbe una cosa da fare "una tantum" (giusto se si scarica o cambi la pila), perché non implementi l'impostazione di data ed ora via seriale?

PS: sicuro di non avee più pin? Guarda che gli analogici puoi comunque usarli come digitali...

Ciao, grazie per la risposta. Ho usato anche quelli analogici. Ho usato ATMEGA328 in modalità standalone. La seriale posso usarla ugualmente?

Mah, dipende cosa hai collegato ai pin 0 ed 1 ... :roll_eyes:

Guglielmo

Stavo leggendo proprio in questo momento la risposta ad un argomento con il mio stesso problema. I pin 0 e 1 non li ho utilizzati. Potrei usarli per inserire 2 pulsanti con resistenza di pulldown per impostare l'ora e la data. Mi servirebbe però il codice già funzionante per settare i parametri :wink: in modo da non dover fare molte prove perchè non avrei più la comunicazione usb per programmare il micro.

Scusa, ma ... se hai la comunicazione USB, perché incasinarsi la vita? Usa quella per mandare via USB (Seriale) i comandi per regolare data/ora e quant'altro ... :roll_eyes:

Guglielmo

Sto usando un ATMEGA328 in modalità standalone

... e quindi???

... da qui risulta che hai la comunicazione USB per effettuare la programmazione :roll_eyes:

Guglielmo

Vuoi dire che posso collegare due pulsanti sui pin 0 e 1, non inizializzare la seriale, scollegare i pulsanti, compilare, ricollegarli e provare il codice. Non ci avevo proprio pensato!

Ho usato anche quelli! Però Guglielmo mi ha suggerito (se ho capito bene) di usare i pin 0 e 1.

NO, voglio dire che invii i comandi via seriale ... non mi sembra molto complicata come cosa!

Studiati QUESTA mia libreria fatta apposta!

Guglielmo

Uhm, tanto per capirci: i pin 0 ed 1 su una UNO, di fatto sono per la comunicazione seriale, che a sua volta viene anche riportata tramite la porta USB, che a sua volta tramite il device driver il sistema operativo "vede" come una seriale fisica.
Quindi se hai i pin 0 ed uno liberi è perfetto: non collegarci nulla, ed usa la seriale per mandare un comando di impostazione data ed ora (consiglio una sola riga, terminata con '\n', e con formato fisso).
Io in un progetto simile di anni fa usai un formato di questo tipo:
*Tyyyymmgghhmmss
dove "T" lo uso come prefisso del comando "Time" (così nel caso in futuro puoi aggiungere altri comandi per fare altro), e quindi yyyy mm gg hh mm ss sono anno, mese, giorno, ore minuti, secondi.
Esempio:
*T20240927112330
Ovviamente devi accumulare tutti i caratteri ricevuti (ti consiglio di ignorare eventuali caratteri '\r') fino a che non ti arriva il terminatore '\n' , in tal caso verifichi il comando ('
' come primo carattere, poi 'T' per Time) e fai il parsing della stringa per estrarre i valori e li usi per impostare l'RTC.
Prova ad implementare questa cosa e vedrai che è molto più semplice da gestire che altre cose come usare tasti di un telecomando.

PS: se ti serve una mano posso cercare il mio vecchio progetto ed estrarti parti di codice...

Grazie!! Sarebbe davvero fantastico. Sono alle prime armi e di programmazione non conosco molto.

Ho cercato di estrarre un po' di funzioni per te utili togliendo tutto quello che non riguarda il tuo caso.
Prova a salvare in un file "proto.h" questo codice (ovviamente dagli un'occhiata per cercare di capire cosa faccio e come lo faccio):

// ---------------------------------------------
// "PROTO.H" - GESTIONE PROTOCOLLO
// ---------------------------------------------
// Nel loop() aggiungere la chiamata:
//  inputCheck();
#define MAXBUF 40
char inputBuf[MAXBUF];
byte pBuf = 0;

// Data ed ora corrente
int Year, Month, Day;
int Hour, Min, Sec;

bool argCheck(char *args, int lung) {
  if ( strlen(args) != lung ) {
    Serial.println(F("Error: invalid arguments!"));
    return false;
  }
  return true;
}

void execCommand() {
  if ( inputBuf[0] != '*') {
    Serial.println("Not a command.");
    return;
  }
  char cmd = inputBuf[1];
  if ( cmd >= 'a' ) cmd -= 32; // Conversione maiuscole
  char args[MAXBUF - 1];
  strcpy(args, inputBuf + 2);
  
  switch (cmd) {
    // ------------------------------
    // TIME
    case 'T':
      if ( args[0] == 0 ) // nessun parametro: mostra data e ora
        serialTime();
      else {
        // Imposta data ed ora. Formato:
        // aaaammgghhmmss
        // Controllo lunghezza
        if ( argCheck(args, 14) ) {
          if ( !setTime(args) ) {
            Serial.println("ERROR!");
          } else {
            Serial.println("OK");
          }
        }
      }
      break;

    default:
      // ERROR!
      Serial.println("Comando non riconosciuto!");
      break;
  }
}

void inputCheck() {
  char c = 0;
  if (Serial.available())
    c = Serial.read();
  if ( Serial.available() )
    c = Serial.read();
  if ( c > 0 ) {
    if ( c == '\n' || pBuf == MAXBUF) {
      // Fine comando
      if ( pBuf > 0 )
        execCommand();
      pBuf = 0;
    }
    else if ( c != '\r' && pBuf < MAXBUF ) {
      inputBuf[pBuf++] = c;
      inputBuf[pBuf] = 0;
    }
  }
}

void serialTime()
{
  char newt[25];
  sprintf(newt, "Time: %04d/%02d/%02d %02d:%02d:%02d",  
        Year, Month, Day, Hour, Min, Sec);
  Serial.println(newt);
}

bool setTime(const char *str) {
  if (sscanf(str, "%04d%02d%02d%02d%02d%02d", &Year, &Month, &Day, &Hour, &Min, &Sec) != 6)
    return false;
  DateTime tm(Year, Month, Day, Hour, Min, Sec);
  rtc.adjust(tm);
  return true;
}

Quindi nel tuo *.ino aggiungi in testa:
#include "proto.h"
e quindi dentro al loop() la chiamata alla funzione che acquisisce i dati ed esegue il comando:
inputCheck();
Un esempio:

#include <RTClib.h>
RTC_DS3231 rtc;
DateTime now;

#include "proto.h"

void setup() {
  Wire.begin();
  Serial.begin(9600);

  if (!rtc.begin()) {  //inizializzo l rtc
    Serial.println("Couldn't find RTC");
    while (true)
      ;
  }

  if (!rtc.lostPower()) {
    //Serial.println("RTC is NOT running, let's set the time!");
    rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
  }

  Serial.println("STARTED");
}

void loop() {
  inputCheck();
}

In questo modo se tu apri il Monitor Seriale e digiti
Io ovviamente non ho avuto tempo di provarlo, ma fammi sapere se ti funziona o meno (nel caso posta il tuo codice e descrivi cosa fa -o non fa-).

Grazie mille!! Ho dato un'occhiata veloce. Perdona la domanda banale, forse mi sfugge qualcosa, in questo modo è possibile tramite comando seriale regolare ora e data anche anche senza un pc collegato? Come inserisco i dati? Comunque ci studio un po sopra e poi ti faccio sapere. Grazie ancora :slightly_smiling_face:

Grazie per le informazioni Gugliemo. Volevo approfittare della tua grande esperienza per chiederti se esiste una guida pratica per studiare una qualsiasi libreria per riuscire quantomeno a comprenderne l'utilizzo. Grazie ancora :slightly_smiling_face:

  1. E come programmi il chip ? P.S. occhio, se dici nel primo post Arduino Uno pensiamo ad una scheda completa con usb, etc.

  2. No, pin 0 e 1 collegati al tuo pc ma tramite un convertitore usb/ttl a 4 fili tipo questo.
    Il convertitore inserito nel pc sarà una COMx specifica
    image

Ciao. Hai ragione. Era per specificare il tipo di scheda collegata alla breadboard. Terminato lo sviluppo ho spostato il micro sulla scheda autonoma. Il micro lo programmo con le schede della foto: a destra per caricare il bootloader nel caso sia vergine, oppure a sinistra infilato sopra Arduino e tolto il suo micro per caricare lo sketch.