//---------------------------------------------------------------------------
// https://www.plcforum.it/f/topic/308039-progetto-timer-10-ore-programmabile-con-commutatore-rotativo-e-display-sette-segmenti
//---------------------------------------------------------------------------

// inclusione librerie necessarie
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

// definizione collegamenti e livelli hardware
#define PIN_SET    5  // collegamenti pulsanti
#define PIN_STASTO 4
#define PIN_RELE   2  // collegamento rele'
#define PRESSLVL   0  // livello letto a pulsanti premuti
#define ONLVL      1  // livello rele' acceso

// variabili globali
Adafruit_SSD1306 display(128, 64, &Wire, -1);
uint32_t now;         // tempo sistema in millisecondi
bool onSet = 0;       // 1 per 1 ciclo se click su set
bool onSetlpress = 0; // 1 per 1 ciclo se long press set
bool onStasto = 0;    // 1 per 1 ciclo se press start/stop
bool blink_ena = 0;   // 1 abilita lampeggio punti
bool q = 0;           // stato rele', 1 = acceso



//---------------------------------------------------------------------------
//  LIVELLO 2
//---------------------------------------------------------------------------

void stampa_punti(){
    display.setCursor(55, 16);
    display.print(":");
    display.display();}


void cancella_punti(){
    display.setCursor(55, 16);
    display.print(" ");
    display.display();}


void visu_time(uint8_t h, int8_t m){
    display.setCursor(8, 16);
    if (h < 10 ) display.print(" ");
    display.print(h);
    display.setCursor(78, 16);
    if (m < 10 ) display.print("0");
    display.print(m);
    display.display();}



//---------------------------------------------------------------------------
//  LIVELLO 1
//---------------------------------------------------------------------------

void lettura_ingressi(){
    static uint32_t t = now;     // temporizzazione 30 ms
    static uint32_t tSet;        // misura tempo puls.set
    static uint8_t  sSet = 0;    // stato processo puls.set
    static bool     mStasto = 1; // flag riconosc.fronte
    onSet = onSetlpress = onStasto = 0;
    if (now-t < 30) return;
    t = now;
    bool inp = digitalRead(PIN_SET) == PRESSLVL;
    if (0==sSet  &&  inp){
        tSet = now;
        sSet = 1;}
    else if (1==sSet  &&  (now-tSet > 1000)){
        onSetlpress = 1;
        sSet = 2;}
    else if (1==sSet  &&  !inp){
        onSet = 1;
        sSet = 0;}
    else if (2==sSet  &&  !inp)
        sSet = 0;
    inp = digitalRead(PIN_STASTO) == PRESSLVL;
    onStasto = inp && !mStasto;
    mStasto = inp;}


void elabora(){
    static uint8_t  h = 0;  // ore
    static int8_t   m = 0;  // minuti
    static uint8_t  s = 0;  // stato processo elabora
    static uint32_t t;      // temporizzazione 1 minuto
    if (0==s  &&  onSetlpress){
        h = m = 0;
        visu_time(h, m);}
    else if (0==s  &&  onSet){
        h += h < 10;
        visu_time(h, m);}
    else if (0==s  &&  onStasto  &&  h>0){
        t = now;
        q = s = blink_ena = 1;}
    else if (1==s  &&  onStasto){
        blink_ena = 0;
        h = m = q = s = 0;
        visu_time(h, m);}
    else if (1==s  &&  (now-t >= 60000)){
        t += 60000;
        m--;
        if (0==h  &&  0==m)
            q = s = blink_ena = 0;
        else if (m < 0){
            m = 59;
            h--;}
        visu_time(h, m);}}


void aggiorna_uscite(){
    digitalWrite(PIN_RELE, q ? ONLVL : !ONLVL);}


void lampeggia(){
    static uint8_t  s = 0;  // stato processo lampeggia
    static bool     sp;     // stato punti
    static uint32_t t;      // temporizzazione 500 ms
    if (0==s  &&  blink_ena){
        cancella_punti();
        sp = 0;
        s = 1;
        t = now;}
    else if (1==s  &&  !blink_ena){
        stampa_punti();
        sp = 1;
        s = 0;}
    else if (1==s  &&  (now-t >= 500)){
        t += 500;
        (sp ^= 1) ? stampa_punti() : cancella_punti();}}



//---------------------------------------------------------------------------
//  LIVELLO 0
//---------------------------------------------------------------------------

void setup(){
    pinMode(PIN_SET, INPUT_PULLUP);
    pinMode(PIN_STASTO, INPUT_PULLUP);
    pinMode(PIN_RELE, OUTPUT);
    digitalWrite(PIN_RELE, !ONLVL);
    display.begin(SSD1306_SWITCHCAPVCC, 0x3c);
    display.clearDisplay();
    display.setTextColor(1, 0);
    display.setTextSize(4, 4);
    visu_time(0, 0);
    stampa_punti();}


void loop(){
    now = millis();
    lettura_ingressi();
    elabora();
    aggiorna_uscite();
    lampeggia();}
NOCOMNCVCCGNDINLED1PWRRelay Module