// 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.