Creare passo a passo radiosveglia con Dot Matrix

Vi aggiorno sulla situazione, ho fatto dei progressi, ho capito meglio parti del codice e sono riuscito ad implementare la visualizzazione del RTC e sensore di temperatura assieme.

Però non riesco ancora a modificare, come voglio, la visualizzazione di data e ora, pur cercando su internet, RTC by Makuna è l'unica libreria con cui riesco a gestirlo.

Mentre per migliorare la visualizzazione del display, vorrei apportare alcune modifiche.
Al posto della scritta T o Temperatura, sono riuscito ad inserire il simbolo del termometro.
Per l'umidità vorrei inserire il simbolo della goccia, ma viene visualizzato un 1, qualche consiglio?

Tra le migliorie, vorrei inserire la visualizzazione di una scritta o effetti, quando Arduino viene alimentato nuovamente.
Così mentre viene eseguito il codice e controlli, il display non resta illuminato e vuoto per i secondi necessari.
Verrebbe utile anche in futuro, quando con i pulsanti, per gestire una funzione, in primo piano esce la scritta con la funzione scelta, così da facilitare l'uso.

Scusate per le diverse domande, già in rete si trovano una miriade d'esempi, come per il DHT11, ma spesso sono totalmente diversi
Grazie

Ciao a tutti, vi aggiorno sugli sviluppi.
Riesco a gestire in modo basico il buzzer attivo, fotoresistenza, LCD e DHT11.
Visualizzo a schermo le icone del termometro e la goccia per l'umidità.

Mentre non riesco ad uscirne con RTC basato su DS1302, ogni volta c'è un problema diverso, visualizzo caratteri strani, non tiene in memoria data e ora (se premo reset) riparte da quella del programma o resta fissa quella di programmazione.
Questo provando diverse librerie, presenti sia qui nel forum, che direttamente nell'IDE.

Sinceramente ho qualche dubbio, sull'effettivo funzionamento, come posso verificarlo?
Grazie

... ma nel codice c'è ancora questo:

RtcDateTime compiled = RtcDateTime(__TIME__, __DATE__);
...
Rtc.SetDateTime(compiled);

... perché il compito è proprio quello di impostare il RTC alla data/ora in cui hai compilato l'ultima volta il programma!

La batteria di backup è carica, di tipo ricaricabile e ben collegata? Il quarzo da 32768 KHz è saldato vicinissimo al chip? i collegamenti sono come da datasheet?

... semplicemente usando uno degli esempi che è a corredo della libreria che usi.

Guglielmo

Ciao, grazie per la risposta.
Con calma mi sono ripassato il libro dei progetti di Arduino e capito meglio alcune cose, come if ed else e Tone.

Riguardo l'RTC, con l'esempio, vedo che funziona e visualizza l'ora nel monitor seriale ogni 10 secondi, quindi non avrebbe problemi.
Come libreria uso RTC by Makuna, per curiosità, che differenza c'è con le altre disponibili?

Nel mio uso finale, vorrei impostare, data e ora tramite dei pulsanti, ma in questo caso come imposto il programma per comunicare con l'RTC?

Grazie

Ciao, vi aggiorno per dirvi che più o meno riparto da zero con il progetto, perchè posso usare parecchi nuovi componenti.
Alcuni sono in prestito da un amico che usò per le sue prove, quindi mi trovo con dei sensori/moduli "doppi" nella funzionalità

Volevo un vostro parere su quali conviene usare e se impostando il programma a stati con ogni loop separato è meglio, così da avere più flessibilità futura per eventuali modifiche/aggiunte.

I componenti nuovi sono:
LM35DZ: temperatura
DS18B20: temperatura
DHT22: temperatura e umidità
SHT31: temperatura e umidità
BMP280: temperatura e barometro
BMP180: barometro a 3.3v
DS1307: rtc
DS3231: rtc con eeprom sulla schedina
Display oled 0.96" SSD1306
ADXL335: accelerometro

In più una miriade di altri componenti come condensatori, transistor, diodi, amplificatori e cavi vari

Grazie per i vostri consigli

Ciao a tutti, seguendo un po' di esempi su Internet e guide varie, sono riuscito ad impostare le prime basi per la radiosveglia, usando un LCD.
Riesco ad impostare l'ora ed attivare la sveglia, ma ho diversi problemi.

Ho modificato il programma d'esempio, togliendo i secondi da impostare nella sveglia, perchè non mi interessano, ma così facendo non riesco a disattivarla, finchè non passa un minuto.
Il mio obiettivo era quello di premere un pulsante qualsiasi, per attivare uno snooze di 5 minuti e tenendo premuto il pulsante d'attivazione per 5 secondi per spegnerla.

Ho già aggiunto la funzione di 2 pulsanti aggiuntivi per accendere la radio e una specie di meteo, dove sfruttando il barometro incorporato nel sensore e gli altri dati di temperatura, vorrei ottenere un risultato simile a quello dei barometri analogici, cioè altitudine, pressione atmosferica e previsioni a spanne.

Nel frattempo sto studiando ancora come usare il display Dot Matrix e come mettere assieme il tutto.

Vi allego il programma, per i vostri suggerimenti e migliorie
Grazie

[code]
#include <Wire.h>
#include "RTClib.h"
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27, 16,2);
RTC_DS1307 rtc;

int stato = 0;
char str[3];
char settimana[7][4] = {"dom", "lun", "mar", "mer", "gio", "ven", "sab"};
DateTime now;

int alarmh, alarmm;
bool ALARM = false;

void setup() {
  Serial.begin(9600);
  pinMode(2, INPUT);
  pinMode(3, INPUT);
  pinMode(4, INPUT);
  pinMode(5, INPUT);
  pinMode(6, OUTPUT);
  
  lcd.init();
  lcd.backlight();
  if (! rtc.begin()) {
    Serial.println("controlla rtc");
    abort();
  }
  if (! rtc.isrunning()) {
    rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
  }
}

void loop() {
  switch (stato) {
    case 00:
      dataora();
      break;
    case 01:
      impostaOra();
      break;
    case 02:
      impostaMinuti();
      break;
    case 03:
      impostaSecondi();
      break;
    case 10:
      accendiSveglia();
      break;
      case 11:
      impostaOraSveglia();
      break;
      case 12:
      impostaMinutiSveglia();
      break;
      case 20:
      allarmeSveglia();
      break;
      case 30:
      accendiRadio();
      break;
      case 40:
      condizioniMeteo();
      break;
  }     
}

bool FIRST = true;
unsigned long t1, dt;
int ch, cm, cs;

void dataora() {
  if (FIRST) {
    lcd.clear();
    t1 = millis();
    FIRST = false;
  }

  dt = millis() - t1;
  if (dt > 500) {
    now = rtc.now();
    ch = now.hour();
    cm = now.minute();
    cs = now.second();

    
    lcd.setCursor(0,0);
    
    sprintf(str, "%02d", ch);
    lcd.print(str);
    lcd.print(":");
    sprintf(str, "%02d", cm);
    lcd.print(str);
    lcd.print(":");
    sprintf(str, "%02d", cs);
    lcd.print(str);

    lcd.setCursor(0,1);
    if (ALARM) {
      lcd.print("SVEGLIA ON");
    } else {
        lcd.print(settimana[now.dayOfTheWeek()]);
        lcd.print(" ");
        lcd.print(now.day(), DEC);
        lcd.print('/');
        lcd.print(now.month(), DEC);
        lcd.print('/');
        lcd.print(now.year(), DEC);
    }

    if ( (ch == alarmh) && (cm == alarmm)) {
      stato = 20;
      FIRST = true;
  }
    
    t1 = millis();
  }

  if (digitalRead(4)) {  //Imposta ora
    stato = 01;
    delay(300);
    FIRST = true;
  }
  if (digitalRead(5)) {   //Imposta sveglia
    stato = 10;
    delay(300);
    FIRST = true;
  }
  if (digitalRead(3)) {   //Radio
    stato = 30;
    delay(300);
    FIRST = true;
  }
  if (digitalRead(2)) {   //Meteo
    stato = 40;
    delay(300);
    FIRST = true;
  }
}

int seth = 0;

void impostaOra() {
  if (FIRST) {
    lcd.clear();
    now = rtc.now();
    seth = now.hour();
    lcd.setCursor(0,0);
    lcd.print("Imposta ora");
    FIRST = false;
  }
  lcd.setCursor(0,1);
  sprintf(str, "%02d" ,seth);
  lcd.print(str);

   if (digitalRead(5)) {
    seth++;
    if (seth >= 24) seth = 0;
    delay(200);
   }
   if (digitalRead(4)) {
    rtc.adjust(DateTime(now.year(), now.month(), now.day(), seth, now.minute(), now.second()));
    stato = 02;
    FIRST = true;
    delay(200);
   }
}

int setm = 0;

void impostaMinuti() {
  if (FIRST) {
    lcd.clear();
    now = rtc.now();
    setm = now.minute();
    lcd.setCursor(0,0);
    lcd.print("Imposta minuti");
    FIRST = false;
  }
  lcd.setCursor(0,1);
  sprintf(str, "%02d" ,setm);
  lcd.print(str);

   if (digitalRead(5)) {
    setm++;
    if (setm>= 60) setm = 0;
    delay(200);
   }
   if (digitalRead(4)) {
    rtc.adjust(DateTime(now.year(), now.month(), now.day(), now.hour(), setm, now.second()));
    stato = 03;
    FIRST = true;
    delay(200);
   }

}

int sets = 0;

void impostaSecondi() {
  if (FIRST) {
    lcd.clear();
    now = rtc.now();
    sets = now.second();
    lcd.setCursor(0,0);
    lcd.print("Imposta secondi");
    FIRST = false;
  }
  lcd.setCursor(0,1);
  sprintf(str, "%02d" ,sets);
  lcd.print(str);

   if (digitalRead(5)) {
    sets++;
    if (sets>= 60) sets = 0;
    delay(200);
   }
   if (digitalRead(4)) {
    rtc.adjust(DateTime(now.year(), now.month(), now.day(), now.hour(), now.minute(), sets));
    stato = 00;
    FIRST = true;
    delay(200);
   }
}

void accendiSveglia() {
  if (FIRST) {
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("Imposta sveglia");
    FIRST = false;
  }
  lcd.setCursor(0,1);
  if (ALARM) {
    lcd.print("ATTIVA");
  } else {
    lcd.print("SPENTA");
  }

   if (digitalRead(5)) {
    ALARM = !ALARM;
    delay(200);
   }
   if (digitalRead(4)) {
    if (!ALARM) stato = 00;
    else stato = 11;
    FIRST = true;
    delay(300);
   }
}

void impostaOraSveglia() {
  if (FIRST) {
    lcd.clear();
    now = rtc.now();
    alarmh = now.hour();
    lcd.setCursor(0,0);
    lcd.print("Ora sveglia");
    FIRST = false;
  }
  lcd.setCursor(0,1);
  sprintf(str, "%02d" ,alarmh);
  lcd.print(str);

   if (digitalRead(5)) {
    alarmh++;
    if (alarmh>= 60) alarmh = 0;
    delay(200);
   }
   if (digitalRead(4)) {
    stato = 12;
    FIRST = true;
    delay(200);
   }
}

void impostaMinutiSveglia() {
  if (FIRST) {
    lcd.clear();
    now = rtc.now();
    alarmm = now.minute();
    lcd.setCursor(0,0);
    lcd.print("Minuti sveglia");
    FIRST = false;
  }
  lcd.setCursor(0,1);
  sprintf(str, "%02d" ,alarmm);
  lcd.print(str);

   if (digitalRead(5)) {
    alarmm++;
    if (alarmm>= 60) alarmm = 0;
    delay(200);
   }
   if (digitalRead(4)) {
    stato = 00;
    FIRST = true;
    delay(200);
   }
}

int allarmeSveglia() {
  if (FIRST) {
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("SVEGLIA!!");
    FIRST = false;
  }

  tone(6, 440, 100);
  delay(100);
  if (digitalRead(4) || digitalRead(5) || digitalRead(4) || digitalRead(3)) {
    ALARM = !ALARM;
    stato = 00;
    FIRST = true;
    delay(300);
  }
}

void accendiRadio() {
  lcd.clear();
  lcd.print("RADIO IN ARRIVO!");
  delay(1000);
  stato = 00;
}

void condizioniMeteo() {
  lcd.clear();
  lcd.print("METEO IN PROVA!");
  delay(1000);
  stato = 00;
} 
[/code]

Nessun aiuto per la sveglia? :innocent:
Grazie

Ciao a tutti, nel frattempo ho migliorato alcuni passaggi nella creazione della radiosveglia, specie per la visualizzazione in una sola riga e gestione dell'illuminazione esterna per la retroilluminazione della barra con MAX7219.

Riesco a far funzionare quasi tutti i componenti in modo separato, mentre non riesco ancora con la sveglia a creare una funzione di rinvio di 5 minuti dell'allarme e disattivazione premendo un pulsante per più di 5 secondi continuativi.

Qualche dritta?
Grazie

Il tuo programma non contiene NESUN COMMENTO. Quindi ci capisci solo tu o chiunque abbia voglia di fare un "reverse engineering" e io non ne ho voglia.

Posso solo dirti che quello che vuoi fare lo puoi gestire nel loop principale usando millis(). Setti una variabile globale quando la sveglia è stata zittita, ma non disattivata. Con millis() calcoli i 5 minuti e controlli il pulssnte di disattivazione. Se Scattano i 5 minuti fai suonare di nuovo la sveglia. Se il pulsante risulta premuto, sempre con millis() verifichi che resti premuto per 5 sec e in quel caso disattivi la sveglia. Purtroppo il tuo programma è pieno di delay che allungheranno un po' i tempi da rilevare con millis().

Ciao,
P.

Ciao, grazie per il consiglio, effettivamente facendo diverse prove, ho tralasciato la parte di commenti, che viene sempre utile anche per un mio riutilizzo futuro.
Provvederò a sistemarlo.

Per la sveglia, provo a seguire il tuo esempio e vedo cosa riesco ad ottenere.
Aggiornerò il post
Grazie

Ciao a tutti, vi aggiorno sulle modifiche effettuate.
Ho commentato il programma e modificato quasi tutto per la visualizzazione su una sola riga per la futura implementazione del Dot Matrix.

Continuo ad avere problemi con la sveglia, quando premo il pulsante, non suona più ed a schermo resta attiva; se premo il pulsante per 5 secondi, continua a girare nel menù di cambio ora e non si disattiva.
Stessa cosa il posponi, anche dopo 5 minuti non suona.

Vi allego il codice, grazie mille per l'aiuto.

// Includo le librerie per RTC, OLED
#include <Wire.h>
#include "RTClib.h"
#include <U8x8lib.h>

// Assegno i nomi per RTC, OLED, sensori temperatura e RadioFM
U8X8_SSD1306_128X64_ALT0_HW_I2C oled;
RTC_DS1307 rtc;

// Imposto pulsante a 0 e dati per RTC e Sveglia
int stato = 0;
char str[3];
char settimana[7][4] = {"dom", "lun", "mar", "mer", "gio", "ven", "sab"};
DateTime now;

int alarmh, alarmm;
int alarms = 0; // Messo a 0, così non imposto i secondi della sveglia, quando scatta il minuto suona
bool ALARM = false;

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

// Imposto i PIN, in ingresso per i pulsanti e in uscita per il buzzer
  pinMode(2, INPUT);
  pinMode(3, INPUT);
  pinMode(4, INPUT);
  pinMode(5, INPUT);
  pinMode(6, OUTPUT);

// Inizializzo lo schermo OLED e imposto il font
  oled.begin();
  oled.setFont(u8x8_font_5x7_f);

// Inizializzo RTC e imposto data e ora
  if (! rtc.begin()) {
    Serial.println("Errore RTC");
    abort();
  }
  if (! rtc.isrunning()) {
    rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
  }
}

void loop() {
// In base a quale tasto premo entro nella funzione scelta
  switch (stato) {
    case 0:
      dataora();
      break;
    case 1:
      impostaOra();
      break;
    case 2:
      impostaMinuti();
      break;
    case 3:
      impostaSecondi();
      break;
    case 10:
      accendiSveglia();
      break;
    case 11:
      impostaOraSveglia();
      break;
    case 12:
      impostaMinutiSveglia();
      break;
    case 20:
      allarmeSveglia();
      break;
    case 21:
      snooze();
      break;  
    case 30:
      radioFM();
      break;
    case 40:
      meteo();
      break;
  }     
}

bool FIRST = true;
unsigned long t1, dt;
int ch, cm, cs;

// stato 0 - Schermata principale dove visualizzo data/ora e se sveglia attiva
void dataora() {
  if (FIRST) {
    oled.clear();
    t1 = millis();
    FIRST = false;
  }

// Assegno i nomi ch, cm, cs per visualizzare l'RTC
  dt = millis() - t1;
  if (dt > 500) {
    now = rtc.now();
    ch = now.hour();
    cm = now.minute();
    cs = now.second();

    oled.setCursor(0,0);

// Visualizzo ora, minuti e secondi sul display
    sprintf(str, "%02d", ch);
    oled.print(str);
    oled.print(":");
    sprintf(str, "%02d", cm);
    oled.print(str);
    oled.print(":");
    sprintf(str, "%02d", cs);
    oled.print(str);

// Se la sveglia è accesa scrivo ON, se spenta visualizzo la data corrente
    oled.setCursor(0,1);
    if (ALARM) {
      oled.print("ON");
    } else {
        oled.print(settimana[now.dayOfTheWeek()]);
        oled.print(" ");
        oled.print(now.day(), DEC);
        oled.print('/');
        oled.print(now.month(), DEC);
        oled.print('/');
        oled.print(now.year(), DEC);
    }
    
// Se ora, minuti e secondi sono uguali a quelli impostati per la sveglia, allora vai allo stato 20 - void allarmeSveglia();
    if ( (ch == alarmh) && (cm == alarmm) && (cs == alarms)) {
      stato = 20;
      FIRST = true;
  }
    t1 = millis();
  }
  
// Se premo il pulsante collegato al PIN 4, vado allo stato 1 - impostaOra();
  if (digitalRead(4)) {
    stato = 1;
    delay(200);
    FIRST = true;
  }
  
// Se premo il pulsante collegato al PIN 5, vado allo stato 10 - accendiSveglia();
  if (digitalRead(5)) { 
    stato = 10;
    delay(200);
    FIRST = true;
  }
  
// Se premo il pulsante collegato al PIN 3, vado allo stato 30 - radioFM();
  if (digitalRead(3)) {
    stato = 30;
    delay(200);
    FIRST = true;
  }

// Se premo il pulsante collegato al PIN 2, vado allo stato 40 - meteo();
  if (digitalRead(2)) {   
    stato = 40;
    delay(200);
    FIRST = true;
  }
}

// Imposto la variabile seth a 0, nel void impostaOra() assegno alla variabile l'ora
int seth = 0;

// stato 1 - Qui imposto l'ora
void impostaOra() {       // Recupero l'ora dal RTC e viene assegnata a seth
  if (FIRST) {
    oled.clear();
    now = rtc.now();
    seth = now.hour();
    FIRST = false;
  }
// Visualizzo a schermo che viene modificata l'ora, minuti e secondi sono tratteggiati
  oled.setCursor(0,0);
  sprintf(str, "%02d" ,seth);
  oled.print(str);
  oled.print(" : -- : --");

// Se premo il pulsante collegato al PIN 5, aumento le ore
  if (digitalRead(5)) {
    seth++;
    if (seth >= 24) seth = 0;
    delay(200);
   }
  // Se premo il pulsante al PIN 4, salvo l'ora impostata nel RTC e vado nello stato 02 - void impostaMinuti();
  if (digitalRead(4)) {
    rtc.adjust(DateTime(now.year(), now.month(), now.day(), seth, now.minute(), now.second()));
    stato = 02;
    FIRST = true;
    delay(200);
   }
}

// Imposto la variabile setm a 0, nel void impostaMinuti() assegno alla variabile i minuti
int setm = 0;

// stato 2 - Qui imposto i minuti
void impostaMinuti() {
// Recupero i minuti dal RTC e li assegno alla variabile setm
  if (FIRST) {
    oled.clear();
    now = rtc.now();
    setm = now.minute(); 
    FIRST = false;
  }
// Visualizzo a schermo che vengono modificati i minuti, ora e secondi sono tratteggiati
  oled.setCursor(0,0);
  sprintf(str, "%02d" ,setm);
  oled.print("-- : ");
  oled.print(str);
  oled.print(" : --");

// Se premo il pulsante collegato al PIN  5, aumento i minuti, arrivato a 60 riparto da zero
   if (digitalRead(5)) {
    setm++;
    if (setm>= 60) setm = 0;
    delay(200);
   }
// Se premo il pulsante collegato al PIN 4, salvo i minuti impostati nel RTC e vado allo stato 3 - impostaSecondi()
   if (digitalRead(4)) {
    rtc.adjust(DateTime(now.year(), now.month(), now.day(), now.hour(), setm, now.second()));
    stato = 03;
    FIRST = true;
    delay(200);
   }
}
// Imposto la variabile sets a 0, nel void impostaSecondi() assegno alla variabile i secondi
int sets = 0;

// stato 3 - Qui imposto i secondi
void impostaSecondi() {
// Recupero i secondi dal RTC e li assegno alla variabile sets
  if (FIRST) {
    oled.clear();
    now = rtc.now();
    sets = now.second();
    FIRST = false;
  }
// Visualizzo a schermo che vengono modificati i secondi, ora e minuti sono tratteggiati
  oled.setCursor(0,0);
  sprintf(str, "%02d" ,sets);
  oled.print("-- : -- : ");
  oled.print(str);

// Se premo il pulsante collegato al PIN  5, aumento i secondi, se arrivano a 60, riparte da zero
  if (digitalRead(5)) {
    sets++;
    if (sets>= 60) sets = 0;
    delay(200);
   }
// Se premo il pulsante collegato al PIN 4, salvo i secondi impostati nel RTC e vado allo stato 0 - dataora()
   if (digitalRead(4)) {
    rtc.adjust(DateTime(now.year(), now.month(), now.day(), now.hour(), now.minute(), sets));
    stato = 0;
    FIRST = true;
    delay(200);
   }
}

// stato 10 - Qui attivo la sveglia
void accendiSveglia() {
  if (FIRST) {
    oled.clear();
    oled.setCursor(0,0);
    oled.print("Sveglia: ");
    FIRST = false;
  }
// In base allo stato di ALARM, scrivo se la sveglia è attiva o spenta
  oled.setCursor(10,0);
  if (ALARM) {
    oled.print("ON ");
    } 
  else {
    oled.print("OFF");
    }
// Se premo il pulsante collegato al PIN 5, cambio lo stato attuale della sveglia
   if (digitalRead(5)) {
    ALARM = !ALARM;
    delay(200);
    }
// Premendo il pulsante del PIN 4, controllo lo stato della sveglia, se spenta vado alla schermata principale - stato 0, se accesa vado allo stato 11 - impostaOraSveglia()
   if (digitalRead(4)) {
    if (!ALARM) stato = 0;
    else stato = 11;
    FIRST = true;
    delay(300);
   }
}

// stato 11 - Qui imposto alla variabile alarmh l'ora corrente
void impostaOraSveglia() {
  if (FIRST) {
    oled.clear();
    now = rtc.now();
    alarmh = now.hour();
    FIRST = false;
  }
    oled.setCursor(0,0);
    sprintf(str, "%02d" ,alarmh);
    oled.print(str);
    oled.print(" : -- : -- A");
    
// Se premo il pulsante collegato al PIN 5, aumento le ore per la sveglia
   if (digitalRead(5)) {
    alarmh++;
    if (alarmh>= 24) alarmh = 0;
    delay(200);
    }
// Se premo il pulsante collegato al PIN 4, vado allo stato 12 - impostaMinutiSveglia()
   if (digitalRead(4)) {
    stato = 12;
    FIRST = true;
    delay(200);
    }
}

// stato 12 - Qui imposto i minuti della sveglia
void impostaMinutiSveglia() {
  if (FIRST) {
    oled.clear();
    now = rtc.now();
    alarmm = now.minute();
    FIRST = false;
    }
    oled.setCursor(0,0);
    sprintf(str, "%02d" ,alarmm);
    oled.print("-- : ");
    oled.print(str);
    oled.print(" : -- A");
    
// Se premo il pulsante collegato al PIN 5, aumento i minuti della sveglia
   if (digitalRead(5)) {
    alarmm++;
    if (alarmm>= 60) alarmm = 0;
    delay(200);
    }
// Se premo il pulsante collegato al PIN 4, torno alla schermata principale, stato 0 - dataora()
   if (digitalRead(4)) {
    stato = 0;
    FIRST = true;
    delay(200);
   }
}

// stato 20 - Si attiva quando, la data impostata per la sveglia è uguale a quella del RTC
void allarmeSveglia() {
  if (FIRST) {
    oled.clear();
    oled.setCursor(0,0);
    oled.print("SVEGLIA!!");
    FIRST = false;
  }

  tone(6, 440, 100);
  delay(100);
  
// Se premo uno dei 4 pulsanti, vado nello stato snooze
  if (digitalRead(4) || digitalRead(5) || digitalRead(3) || digitalRead(2)) {
    stato = 21;    
    FIRST = true;
    delay(300);
  }
}

// Imposto una variabile globale posponi per contare 5 minuti dal posponi della sveglia
unsigned long tp, posponi;

// Creo un bool per la lunga pressione del tasto così da spegnere la sveglia
bool svegliaoff;
bool prev_svegliaoff;
unsigned long toff;
int statopulsanteoff = LOW;

// Attivo il posponi per 5 minuti, se premo il tasto 4 per 5 secondi disattivo la sveglia
void snooze() {
  noTone(6);
  oled.clear();
  oled.setCursor(0,0);
  oled.print("POSPONI");
  if (FIRST) {
    posponi = millis() - tp;
    if (posponi >= 300000) {
    tp = millis();
    oled.clear();
    oled.setCursor(0,0);
    oled.print("SVEGLIA!!");
    FIRST = false;
    tone(6, 440, 100);
    delay(100);
  }
  if (svegliaoff = digitalRead(4)) {
    if (!prev_svegliaoff && svegliaoff) {
      toff = millis();
    }
  if (prev_svegliaoff && !svegliaoff){
    unsigned long tempotasto = millis() - toff;
    if (tempotasto > 5000) {
      stato = 0;
      FIRST = true;
      delay(300);
    }    
  }
  prev_svegliaoff = svegliaoff;
}
    stato = 0;
    FIRST = true;
    delay (300);
  }
}  

// Stato 30 - Qui gestisco la radio FM
void radioFM() {
  Serial.print("funzione radio fm");
}

// Stato 40 - Qui gestisco i sensori per la temperatura, umidità e pressione barometrica
void meteo() {
  Serial.print("funzione meteo");
} 
// stato 0 - Schermata principale dove visualizzo data/ora e se sveglia attiva
void dataora() {
  if (FIRST) {
    oled.clear();
    t1 = millis();
    FIRST = false;
  }

Questa è una definizione di funzione e come tale deve stare fuori da altre funzioni, mentre tu l'hai messa dentro la funzione loop(). Non so se è un errore di copia e incolla.

Ciao.

Ciao, grazie per la risposta
Nel void loop() ci sono solo i vari break che portano nei vari stati, perché ho chiuso il void loop() con la parentesi graffa.
Quindi avresti voglia di rispiegarmi meglio l’errore che ho fatto?

Grazie

EDIT: Ho preso parti di codice, studiato e messo assieme per cercare di capire come funziona.
Il FIRST è un bool per indicare se è la prima volta che entra in quella parte di programma, poi perché serve indicarlo devo ancora capirlo bene

Qualunque consiglio per migliorare il codice o altro è ben accetto

// Includo le librerie per RTC, OLED
#include <Wire.h>
#include "RTClib.h"
#include <U8x8lib.h>

// Assegno i nomi per RTC, OLED, sensori temperatura e RadioFM
U8X8_SSD1306_128X64_ALT0_HW_I2C oled;
RTC_DS1307 rtc;

// Imposto pulsante a 0 e dati per RTC e Sveglia
int stato = 0;
char str[3];
char settimana[7][4] = {"dom", "lun", "mar", "mer", "gio", "ven", "sab"};
DateTime now;

int alarmh, alarmm;
int alarms = 0; // Messo a 0, così non imposto i secondi della sveglia, quando scatta il minuto suona
bool ALARM = false;

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

  // Imposto i PIN, in ingresso per i pulsanti e in uscita per il buzzer
  pinMode(2, INPUT);
  pinMode(3, INPUT);
  pinMode(4, INPUT);
  pinMode(5, INPUT);
  pinMode(6, OUTPUT);

  // Inizializzo lo schermo OLED e imposto il font
  oled.begin();
  oled.setFont(u8x8_font_5x7_f);

  // Inizializzo RTC e imposto data e ora
  if (! rtc.begin()) {
    Serial.println("Errore RTC");
    abort();
  }
  if (! rtc.isrunning()) {
    rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
  }
}

void loop() {
  // In base a quale tasto premo entro nella funzione scelta
  switch (stato) {
    case 0:
      dataora();
      break;
    case 1:
      impostaOra();
      break;
    case 2:
      impostaMinuti();
      break;
    case 3:
      impostaSecondi();
      break;
    case 10:
      accendiSveglia();
      break;
    case 11:
      impostaOraSveglia();
      break;
    case 12:
      impostaMinutiSveglia();
      break;
    case 20:
      allarmeSveglia();
      break;
    case 21:
      snooze();
      break;
    case 30:
      radioFM();
      break;
    case 40:
      meteo();
      break;
  }
}

bool FIRST = true;
unsigned long t1, dt;
int ch, cm, cs;

// stato 0 - Schermata principale dove visualizzo data/ora e se sveglia attiva
void dataora() {
  if (FIRST) {
    oled.clear();
    t1 = millis();
    FIRST = false;
  }

  // Assegno i nomi ch, cm, cs per visualizzare l'RTC
  dt = millis() - t1;
  if (dt > 500) {
    now = rtc.now();
    ch = now.hour();
    cm = now.minute();
    cs = now.second();

    oled.setCursor(0, 0);

    // Visualizzo ora, minuti e secondi sul display
    sprintf(str, "%02d", ch);
    oled.print(str);
    oled.print(":");
    sprintf(str, "%02d", cm);
    oled.print(str);
    oled.print(":");
    sprintf(str, "%02d", cs);
    oled.print(str);

    // Se la sveglia è accesa scrivo ON, se spenta visualizzo la data corrente
    oled.setCursor(0, 1);
    if (ALARM) {
      oled.print("ON");
    } else {
      oled.print(settimana[now.dayOfTheWeek()]);
      oled.print(" ");
      oled.print(now.day(), DEC);
      oled.print('/');
      oled.print(now.month(), DEC);
      oled.print('/');
      oled.print(now.year(), DEC);
    }

    // Se ora, minuti e secondi sono uguali a quelli impostati per la sveglia, allora vai allo stato 20 - void allarmeSveglia();
    if ( (ch == alarmh) && (cm == alarmm) && (cs == alarms)) {
      stato = 20;
      FIRST = true;
    }
    t1 = millis();
  }

  // Se premo il pulsante collegato al PIN 4, vado allo stato 1 - impostaOra();
  if (digitalRead(4)) {
    stato = 1;
    delay(200);
    FIRST = true;
  }

  // Se premo il pulsante collegato al PIN 5, vado allo stato 10 - accendiSveglia();
  if (digitalRead(5)) {
    stato = 10;
    delay(200);
    FIRST = true;
  }

  // Se premo il pulsante collegato al PIN 3, vado allo stato 30 - radioFM();
  if (digitalRead(3)) {
    stato = 30;
    delay(200);
    FIRST = true;
  }

  // Se premo il pulsante collegato al PIN 2, vado allo stato 40 - meteo();
  if (digitalRead(2)) {
    stato = 40;
    delay(200);
    FIRST = true;
  }
}

// Imposto la variabile seth a 0, nel void impostaOra() assegno alla variabile l'ora
int seth = 0;

// stato 1 - Qui imposto l'ora
void impostaOra() {       // Recupero l'ora dal RTC e viene assegnata a seth
  if (FIRST) {
    oled.clear();
    now = rtc.now();
    seth = now.hour();
    FIRST = false;
  }
  // Visualizzo a schermo che viene modificata l'ora, minuti e secondi sono tratteggiati
  oled.setCursor(0, 0);
  sprintf(str, "%02d", seth);
  oled.print(str);
  oled.print(" : -- : --");

  // Se premo il pulsante collegato al PIN 5, aumento le ore
  if (digitalRead(5)) {
    seth++;
    if (seth >= 24) seth = 0;
    delay(200);
  }
  // Se premo il pulsante al PIN 4, salvo l'ora impostata nel RTC e vado nello stato 02 - void impostaMinuti();
  if (digitalRead(4)) {
    rtc.adjust(DateTime(now.year(), now.month(), now.day(), seth, now.minute(), now.second()));
    stato = 02;
    FIRST = true;
    delay(200);
  }
}

// Imposto la variabile setm a 0, nel void impostaMinuti() assegno alla variabile i minuti
int setm = 0;

// stato 2 - Qui imposto i minuti
void impostaMinuti() {
  // Recupero i minuti dal RTC e li assegno alla variabile setm
  if (FIRST) {
    oled.clear();
    now = rtc.now();
    setm = now.minute();
    FIRST = false;
  }
  // Visualizzo a schermo che vengono modificati i minuti, ora e secondi sono tratteggiati
  oled.setCursor(0, 0);
  sprintf(str, "%02d", setm);
  oled.print("-- : ");
  oled.print(str);
  oled.print(" : --");

  // Se premo il pulsante collegato al PIN  5, aumento i minuti, arrivato a 60 riparto da zero
  if (digitalRead(5)) {
    setm++;
    if (setm >= 60) setm = 0;
    delay(200);
  }
  // Se premo il pulsante collegato al PIN 4, salvo i minuti impostati nel RTC e vado allo stato 3 - impostaSecondi()
  if (digitalRead(4)) {
    rtc.adjust(DateTime(now.year(), now.month(), now.day(), now.hour(), setm, now.second()));
    stato = 03;
    FIRST = true;
    delay(200);
  }
}
// Imposto la variabile sets a 0, nel void impostaSecondi() assegno alla variabile i secondi
int sets = 0;

// stato 3 - Qui imposto i secondi
void impostaSecondi() {
  // Recupero i secondi dal RTC e li assegno alla variabile sets
  if (FIRST) {
    oled.clear();
    now = rtc.now();
    sets = now.second();
    FIRST = false;
  }
  // Visualizzo a schermo che vengono modificati i secondi, ora e minuti sono tratteggiati
  oled.setCursor(0, 0);
  sprintf(str, "%02d", sets);
  oled.print("-- : -- : ");
  oled.print(str);

  // Se premo il pulsante collegato al PIN  5, aumento i secondi, se arrivano a 60, riparte da zero
  if (digitalRead(5)) {
    sets++;
    if (sets >= 60) sets = 0;
    delay(200);
  }
  // Se premo il pulsante collegato al PIN 4, salvo i secondi impostati nel RTC e vado allo stato 0 - dataora()
  if (digitalRead(4)) {
    rtc.adjust(DateTime(now.year(), now.month(), now.day(), now.hour(), now.minute(), sets));
    stato = 0;
    FIRST = true;
    delay(200);
  }
}

// stato 10 - Qui attivo la sveglia
void accendiSveglia() {
  if (FIRST) {
    oled.clear();
    oled.setCursor(0, 0);
    oled.print("Sveglia: ");
    FIRST = false;
  }
  // In base allo stato di ALARM, scrivo se la sveglia è attiva o spenta
  oled.setCursor(10, 0);
  if (ALARM) {
    oled.print("ON ");
  }
  else {
    oled.print("OFF");
  }
  // Se premo il pulsante collegato al PIN 5, cambio lo stato attuale della sveglia
  if (digitalRead(5)) {
    ALARM = !ALARM;
    delay(200);
  }
  // Premendo il pulsante del PIN 4, controllo lo stato della sveglia, se spenta vado alla schermata principale - stato 0, se accesa vado allo stato 11 - impostaOraSveglia()
  if (digitalRead(4)) {
    if (!ALARM) stato = 0;
    else stato = 11;
    FIRST = true;
    delay(300);
  }
}

// stato 11 - Qui imposto alla variabile alarmh l'ora corrente
void impostaOraSveglia() {
  if (FIRST) {
    oled.clear();
    now = rtc.now();
    alarmh = now.hour();
    FIRST = false;
  }
  oled.setCursor(0, 0);
  sprintf(str, "%02d", alarmh);
  oled.print(str);
  oled.print(" : -- : -- A");

  // Se premo il pulsante collegato al PIN 5, aumento le ore per la sveglia
  if (digitalRead(5)) {
    alarmh++;
    if (alarmh >= 24) alarmh = 0;
    delay(200);
  }
  // Se premo il pulsante collegato al PIN 4, vado allo stato 12 - impostaMinutiSveglia()
  if (digitalRead(4)) {
    stato = 12;
    FIRST = true;
    delay(200);
  }
}

// stato 12 - Qui imposto i minuti della sveglia
void impostaMinutiSveglia() {
  if (FIRST) {
    oled.clear();
    now = rtc.now();
    alarmm = now.minute();
    FIRST = false;
  }
  oled.setCursor(0, 0);
  sprintf(str, "%02d", alarmm);
  oled.print("-- : ");
  oled.print(str);
  oled.print(" : -- A");

  // Se premo il pulsante collegato al PIN 5, aumento i minuti della sveglia
  if (digitalRead(5)) {
    alarmm++;
    if (alarmm >= 60) alarmm = 0;
    delay(200);
  }
  // Se premo il pulsante collegato al PIN 4, torno alla schermata principale, stato 0 - dataora()
  if (digitalRead(4)) {
    stato = 0;
    FIRST = true;
    delay(200);
  }
}

// stato 20 - Si attiva quando, la data impostata per la sveglia è uguale a quella del RTC
void allarmeSveglia() {
  if (FIRST) {
    oled.clear();
    oled.setCursor(0, 0);
    oled.print("SVEGLIA!!");
    FIRST = false;
  }

  tone(6, 440, 100);
  delay(100);

  // Se premo uno dei 4 pulsanti, vado nello stato snooze
  if (digitalRead(4) || digitalRead(5) || digitalRead(3) || digitalRead(2)) {
    stato = 21;
    FIRST = true;
    delay(300);
  }
}

// Imposto una variabile globale posponi per contare 5 minuti dal posponi della sveglia
unsigned long tp, posponi;

// Creo un bool per la lunga pressione del tasto così da spegnere la sveglia
bool svegliaoff;
bool prev_svegliaoff;
unsigned long toff;
int statopulsanteoff = LOW;

// Attivo il posponi per 5 minuti, se premo il tasto 4 per 5 secondi disattivo la sveglia
void snooze() {
  noTone(6);
  oled.clear();
  oled.setCursor(0, 0);
  oled.print("POSPONI");
  if (FIRST) {
    posponi = millis() - tp;
    if (posponi >= 300000) {
      tp = millis();
      oled.clear();
      oled.setCursor(0, 0);
      oled.print("SVEGLIA!!");
      FIRST = false;
      tone(6, 440, 100);
      delay(100);
    }
    if (svegliaoff = digitalRead(4)) {
      if (!prev_svegliaoff && svegliaoff) {
        toff = millis();
      }
      if (prev_svegliaoff && !svegliaoff) {
        unsigned long tempotasto = millis() - toff;
        if (tempotasto > 5000) {
          stato = 0;
          FIRST = true;
          delay(300);
        }
      }
      prev_svegliaoff = svegliaoff;
    }
    stato = 0;
    FIRST = true;
    delay (300);
  }
}

// Stato 30 - Qui gestisco la radio FM
void radioFM() {
  Serial.print("funzione radio fm");
}

// Stato 40 - Qui gestisco i sensori per la temperatura, umidità e pressione barometrica
void meteo() {
  Serial.print("funzione meteo");
}

Certo, l'errore è mio e la colpa è della vista e della cattiva identazione. Ora ho copiato e incollato il tuo codice nel simulatore online ho premuto Ctrl+shift+i per attivare la formattazione automatica e mi sono reso conto che l'errore che ti ho segnalato non c'è.

Il perché è presto spiegato. La funzione loop() inizia con { e termina con }. Il framework di arduino chiama la funzione loop() la quale termina e il controllo torna al framework che chiama nuovamente la funzione loop() e questo accade all'infinito. Nella funzione loop() tu hai la tua state machina basata sullo switch case, quando la variabile stato ha valore 0 (zero) viene chiamata la funzione dataora(), la quale termina e restituisce il controllo al chiamante (la funzione loop() la quale a sua volta termina e come detto prima il framework la richiama nuovamente è se la variabile stato vale ancora 0 il tutto si ripete all'infinito. Ciò non accade poiché dentro la funzione dataota() hai previsto il modo di spezzare questo ciclo assegnando alla variabile stato un valore differente da 0 a seconda di quale tasto premi. Quindi la funzione dataora() verrà chiamata e terminera molte volte al secondo e a te serve salvare il tempo in t1 solo la prima volta.

Scusa il post un poco lungo ma dovevo farmi perdonare la svista.

Qui anche grazie a un topic con la partecipazione di Claudio_FF abbiamo trovato un modo alternativo alla variabile FIRST.

Ciao.

Riguardo l’identazione, seguo quella dell’IDE, quando premo invio va a capo lui seguendo il programma
Vedendo gli esempi delle librerie, ho commentato sopra la parte di codice, che viene eseguita sotto.
Infine utilizzo la funzione copia per il forum per copiare tutto il codice.

Grazie per la spiegazione e per il link al topic, riguardo la variabile FIRST, vedrò di approfondire anche questo argomento.

Per il resto altri consigli per migliorare il codice e sistemare la funzione snooze sono ben accetti.
Grazie a tutti

Non basta, ogni tanto vai in "Strumenti -> Formattazione Automatica" (Tools -> Auto Format) e, ove occorre, ti aggiusta tutto correttamente ... solo DOPO pubblichi eventualmente sul forum. Grazie.

Guglielmo

P.S.: la "formattazine automatica" è guidata da un'apposito file di configurazione che si trova in arduino\lib, che si chiama "formatter.conf" e che usa la sintassi di AStyle. Se può servire allego quello che uso io formatter.conf.zip (669 Bytes) ... NON che sia il migiore o il più corretto, è solo quello che personamente io gradisco, ma ciascuno, seguendo le regole di AStyle, lo può adattare alle proprie preferenze.

Ah ecco, non conoscevo questa funzione integrata nell’IDE.
Grazie mille per il consiglio, ne farò sicuramente uso

Ciao!
Ho apportato delle modifiche al codice, aggiungendo la possibilità di tornare indietro con l'ora, prima andava solo avanti e aggiunto la modifica della data, perchè mi sono accorto un paio di volte che il DS1307, aveva l'ora giusta, ma la data sbagliata.

Per il posponi, ho fatto un passo avanti a metà, nel senso che non sono capace ad utilizzare millis() per farla suonare dopo 5 minuti, come consigliato da pgiagno.
Quindi ho aggirato il problema, impostando la variabile alarmm + 5, quindi riutilizzo la parte dove imposto i minuti sommando 5.
Mentre per la disattivazione premendo un pulsante a lungo, non riesco a venirne a capo, riuscite a darmi una mano?

Grazie

Ciao a tutti.
Quando ho tempo, mi dedico ad Arduino e ogni volta faccio un passetto avanti su qualche parte che compone la radiosveglia.
Sono sono riuscito a far funzionare la RDA5807M con un amplificatore PAM8403 e 2 casse da 2W, suono parecchio distrubato, ma per lo meno riesco ad ascoltare qualcosa.

Per il resto sono bloccato con la gestione dei 4 pulsanti, non riesco a venirne a capo, anche seguendo altri topic qui sul forum, insomma qualcosa non funziona e non riesco a capirlo.
Qualcuno riesce ad aiutarmi?

Grazie

Per la gestione dei pulsanti dovrai scegliere una libreria che gestisce il debounce software. Il problema che ci sono davvero tante librerie e la maggior parte sono basate sulle funzioni utente di callback.
AceButton, Button, Bounce2 ecc.

Per le migliorie sarebbe bene iniziare dal dare un nome a quasi tutto ad esempio 5 è un numero che non mi fornisce ulteriori informazioni, mentre PIN_BUZZER fornisce l'informazione principale che è quella più utile per leggere il codice e comprenderlo.

const byte PIN_BUZZER = 5;       

Ovviamente poi nel setup() scriverai:

pinMode(PIN_BUZZER, OUTPUT);

Qui nel mio blog c'è una descrizione degli Entry ed Exit state di una FSM che dovrebbe chiarirti meglio la FIRST di cui chiedevi in un post precedente.

Poi delay e cicli "bloccanti" sono out per me, poiché si può fare perché non farlo.

Ciao.