Questo è il codice usato e funzionante:
#include <Wire.h>
#define CLOCK_PIN 2
#define LATCH_PIN 3
#define DATA_PIN 4
#define MIN_PULS 5
#define HOUR_PULS 6
//-----------------------------------------------------------------------------
// Variabili di lavoro globali (28 byte)
//-----------------------------------------------------------------------------
typedef struct {
uint32_t time;
byte stat;
} button_t;
button_t minPulsData = {millis(), 0}; // dati pulsante minuti
button_t hourPulsData = {millis(), 0}; // dati pulsante ora
uint32_t tempoPunti = millis(); // tempi di partenza
byte point = 1; // variabile per lampeggio punti
byte error = false; // true se errore lettura RTC
byte minuti = 0; // minuti correnti
byte ore = 0; // ore correnti
byte tabella[10] = {0xFC, 0x60, 0xDA, 0xF2, 0x66,
0xB6, 0xBE, 0xE0, 0xFE, 0xF6};
//-----------------------------------------------------------------------------
// Rileva click su tasti con debounch 60 ms e autorepeat dopo 1 s
//-----------------------------------------------------------------------------
bool click(byte pin, ::button_t* data){
uint32_t elapsed = millis() - data->time;
bool press = digitalRead(pin);
switch (data->stat)
{
case 0: // attesa pressione
if (press){ // se premuto
data->stat = 1; // passa ad antirimbalzo
data->time = millis();
}
return false;
case 1: // antirimbalzo pressione
if (!press){ // se non premuto
data->stat = 0; // ritorna ad attesa
return false;
}
if (elapsed > 60){ // primo click
data->stat = 2;
data->time = millis();
return true;
}
return false;
case 2: // attesa inizio autorepeat
if (!press){ // se non premuto
data->stat = 3;
data->time = millis();
return false;
}
if (elapsed > 1000){ // inizio autorepeat dopo 1 s
data->stat = 4;
data->time = millis();
return true; // primo autoclick
}
return false;
case 3: // antirimbalzo rilascio
if (press){ // se premuto
data->stat = 2;
data->time = millis();
return false;
}
if (elapsed > 60) // rilasciato
data->stat = 0; // torna ad attesa
return false;
case 4: // autorepeat
if (!press){ // se non premuto
data->stat = 5;
data->time = millis();
return false;
}
if (elapsed > 100){ // successivi click ogni 100 ms
data->time = millis();
return true;
}
return false;
case 5: // antirimbalzo rilascio
if (press){ // se premuto
data->stat = 4;
data->time = millis();
return false;
}
if (elapsed >= 60) // rilasciato
data->stat = 0; // torna ad attesa
return false;
}
}
//-----------------------------------------------------------------------------
byte binBCD(byte n){
return ((n / 10) << 4) | (n % 10);
}
//-----------------------------------------------------------------------------
void impostaRTC(){
Wire.beginTransmission(0x68); // <--- indirizzo RTC su bus i2c
Wire.write(0); // <--- punta al registro 0
Wire.write(0); // <--- azzera secondi RTC
Wire.write(binBCD(minuti)); // <--- imposta minuti RTC
Wire.write(binBCD(ore)); // <--- imposta ore RTC
Wire.endTransmission();
}
//-----------------------------------------------------------------------------
void avanzaOra(){
ore = (ore + 1) % 24;
}
//-----------------------------------------------------------------------------
void avanzaMinuto(){
if (++minuti == 60){
minuti = 0;
avanzaOra();
}
}
//-----------------------------------------------------------------------------
void blinkPunti(){
if (millis() - tempoPunti >= 500){
tempoPunti += 500;
point ^= 1;
}
}
//-----------------------------------------------------------------------------
byte BCDbin(byte n){
return ((n >> 4) * 10) + (n & 0x0F);
}
//-----------------------------------------------------------------------------
void leggiRTC(){
Wire.beginTransmission(0x68); // <--- indirizzo RTC su bus i2c
Wire.write(1); // <--- punta al registro 1
if (Wire.endTransmission()){ // <--- errore di connessione
error = true;
return;
}
Wire.requestFrom(0x68, 2); // <--- due registri da leggere
if (Wire.available() != 2){
error = true; // <--- errore di ricezione
return;
}
minuti = BCDbin(Wire.read());
ore = BCDbin(Wire.read());
error = false;
}
//-----------------------------------------------------------------------------
// Scrittura su display con blanking primo zero e lampeggio se errore
//-----------------------------------------------------------------------------
void visualizza(){
digitalWrite(LATCH_PIN, LOW);
if (error && !point){
shiftOut(DATA_PIN, CLOCK_PIN, LSBFIRST, 0);
shiftOut(DATA_PIN, CLOCK_PIN, LSBFIRST, 0);
shiftOut(DATA_PIN, CLOCK_PIN, LSBFIRST, 0);
shiftOut(DATA_PIN, CLOCK_PIN, LSBFIRST, 0);
}else{
shiftOut(DATA_PIN, CLOCK_PIN, LSBFIRST, tabella[minuti%10]);
shiftOut(DATA_PIN, CLOCK_PIN, LSBFIRST, tabella[minuti/10]);
shiftOut(DATA_PIN, CLOCK_PIN, LSBFIRST, tabella[ore%10]|point);
shiftOut(DATA_PIN, CLOCK_PIN, LSBFIRST, (ore/10) ? tabella[ore/10] : 0);
}
digitalWrite(LATCH_PIN, HIGH);
}
//-----------------------------------------------------------------------------
// Impostazione sistema
//-----------------------------------------------------------------------------
void setup(){
Wire.begin(); // inizializza bus i2c
pinMode(MIN_PULS, INPUT);
pinMode(HOUR_PULS, INPUT);
pinMode(LATCH_PIN, OUTPUT);
pinMode(CLOCK_PIN, OUTPUT);
pinMode(DATA_PIN, OUTPUT);
digitalWrite(CLOCK_PIN, LOW);
visualizza(); // prima scrittura su display
}
//-----------------------------------------------------------------------------
// Ciclo principale eseguito circa 800 volte al secondo
//-----------------------------------------------------------------------------
void loop(){
leggiRTC(); // lettura ora corrente da RTC
blinkPunti(); // lampeggio punti 1 Hz
if (click(MIN_PULS, &minPulsData)){ // se premuto puls.minuti
avanzaMinuto(); // regola minuti
impostaRTC();
}
if (click(HOUR_PULS, &hourPulsData)){ // se premuto puls.ore
avanzaOra(); // regola ora
impostaRTC();
}
visualizza(); // aggiorna display
}
dove e come posso inserire i tuoi suggerimenti?