temporizzazioni luce scale

ciao, ho intenzione di temporizzare le luci delle scale tramite una scheda arduino che utilizzo anche per altro, quindi sto cercando di fare un codice non bloccante.
a banco sembra funzionare (non ho rilevato bug) però non è ancora integrato nel resto del codice.
volevo chiedervi se cè un modo per semplificare il codice (per non intralciare il resto del codice) pur mantenendo le caratteristiche principali ovvero:
1 pressione accende le luci > poi si spegne dopo tot secondi
1 pressione durante il tempo di accensione > mi resetta il timer
2 pressioni consecutive > blocca la luce su on
1 pressione dopo lo stato di blocco > spegne le luci

ora mi funziona ma mi sembra un codice esagerato :slightly_frowning_face:

#define pulsante 5
#define luce 6 //relè
byte stato;
byte clic = 0;
byte statopulsante = 1;
byte statopulsanteprecedente = 0;
int doppioclic = 2000; //durata doppio clic
int timerluce = 10000; //durata luce
unsigned long tempopuls; //variabile per doppio clic
unsigned long iniziotimer; //variabile per tempo luce


void setup() {
  pinMode (pulsante, INPUT_PULLUP);
  pinMode (luce, OUTPUT);
  digitalWrite (luce, HIGH);
  Serial.begin(9600);
}

void loop() {
  if ((digitalRead (pulsante) == LOW) && (clic == 0)) {
    clic = 1;
    statopulsante = 0;
  }
  if ((digitalRead (pulsante) == HIGH) && (clic == 1)) {
    clic = 0;
    statopulsante = 1;
  }

  if ((statopulsante == LOW) && (stato == 0)) {  //prima accensione luce
    Serial.println ("primo if");
    tempopuls = millis();
    iniziotimer = millis();
    digitalWrite (luce, LOW);
    stato = 1;
    statopulsante = 1;
  }
  if ((statopulsante == LOW) && (stato == 1) && ((millis() - tempopuls) < doppioclic)) {  //blocco su on se faccio 2 pressioni consecutive
    Serial.println ("blocco on");
    stato = 2;
    statopulsante = 1;
  }
  if ((statopulsante == LOW) && (stato == 1) && ((millis() - tempopuls) > doppioclic)) { // reset secondi se faccio 1 pressione mentre è acceso
    Serial.println ("reset secondi");
    tempopuls = millis();
    iniziotimer = millis();
    statopulsante = 1;
  }
  if ((statopulsante == LOW) && (stato == 2)) { //spegnimento premendo il pulsante se mi trovo nello stato "on bloccato"
    Serial.println ("spegnimento manuale");
    digitalWrite (luce, HIGH);
    stato = 0;
    statopulsante = 1;
  }

  if ((stato == 1) && ((millis() - iniziotimer) > timerluce)) { //spegnimento automatico dopo superato il tempo imposto
    Serial.println ("spegnimento automatico");
    digitalWrite (luce, HIGH);
    stato = 0;
  }
  delay (50);
}

non mi pare esagerato... sono 60 righe di programma... devi solo levare

byte statopulsanteprecedente = 0;

visto che non l'hai usata e i vari print sulla seriale una volta testato...

e si riduce il tutto a

Lo sketch usa 1430 byte (4%) dello spazio disponibile per i programmi. Il massimo è 32256 byte.
Le variabili globali usano 21 byte (1%) di memoria dinamica, lasciando altri 2027 byte liberi

Se 'statopulsante' lo si setta sempre all'inizio del ciclo e si resetta solo all'istante di una pressione, si può togliere quel statopulsante = 1; da tutti i gestori degli eventi:

statopulsante = 1;

if ((digitalRead (pulsante) == LOW) && (clic == 0)) {

    clic = 1;
    statopulsante = 0;

} else if ((digitalRead (pulsante) == HIGH) && (clic == 1)) {

    clic = 0;

}

A proposito dei gestori degli eventi, questi andrebbero eseguiti in modo mutuamente esclusivo (else if), senza valutare ogni volta tutti gli if. Infatti mi pare strano che funzioni, perché una volta eseguito il codice del primo if (prima accensione luce) dovrebbe risultare vero anche il secondo, e quindi si finisce sempre subito nello stato 2.

Claudio_FF:
Se 'statopulsante' lo si setta sempre all'inizio del ciclo e si resetta solo all'istante di una pressione, si può togliere quel statopulsante = 1; da tutti i gestori degli eventi:

statopulsante = 1;

if ((digitalRead (pulsante) == LOW) && (clic == 0)) {

clic = 1;
    statopulsante = 0;

} else if ((digitalRead (pulsante) == HIGH) && (clic == 1)) {

clic = 0;

}



A proposito dei gestori degli eventi, questi andrebbero eseguiti in modo mutuamente esclusivo (else if), senza valutare ogni volta tutti gli if. Infatti mi pare strano che funzioni, perché una volta eseguito il codice del primo if (prima accensione luce) dovrebbe risultare vero anche il secondo, e quindi si finisce sempre subito nello stato 2.

statopulsanterecedente si è da eliminare,mi è rimasto dalle varie prove.

quindi da come mi hai modificato la prima parte del codice, stato pulsante verrà resettata solo dall'if che verrà eseguito, ottima idea!

mentre non ho capito cosa intendi qui:

Claudio_FF:
A proposito dei gestori degli eventi, questi andrebbero eseguiti in modo mutuamente esclusivo (else if), senza valutare ogni volta tutti gli if. Infatti mi pare strano che funzioni, perché una volta eseguito il codice del primo if (prima accensione luce) dovrebbe risultare vero anche il secondo, e quindi si finisce sempre subito nello stato 2.

non può essere vero anche il secondo if perchè "statopulsante" viene messo a 1

acuplush:
quindi da come mi hai modificato la prima parte del codice, stato pulsante verrà resettata solo dall'if che verrà eseguito, ottima idea!

Si può ridurre ancora:

in = (digitalRead(pulsante) == LOW);

onPress = in & !clic;

clic = in;

E quindi scrivere nelle condizioni:

if (onPress && (stato == 0)) {  //prima accensione luce

non può essere vero anche il secondo if perchè "statopulsante" viene messo a 1

Ah, vero, io avevo tolto tutte quelle reimpostazioni a 1, e allora sotto si deve proseguire con else if invece che con un nuovo if.

Anche il comando della luce può essere un'unica riga finale:

  digitalWrite(luce, ((1 == stato) || (2 == stato)) ? ACCESA : SPENTA);

Solo con queste modifiche abbiamo già eliminato 11 righe...

boh, non so, tra poco comincia il film, quindi non posso provare
ma questo compila in:
Lo sketch usa 1034 byte (3%) dello spazio disponibile per i programmi. Il massimo è 32256 byte.
Le variabili globali usano 11 byte (0%) di memoria dinamica, lasciando altri 2037 byte liberi per le variabili locali. Il massimo è 2048 byte.

e credo vada:

// di Nelson "StandardOil"
// Idea da sviluppare:
// timer per luci scala
#define LUCE 6
#define PULSANTE 5
#define DURATA 600 // tempo in decimi di secondo dell'accensione
#define PASSO 5    // distanza massima tra due pressioni per bloccare la luce
int contatore; // il de-contatore di accensione luce


void setup(void)
{
    pinMode(LUCE, OUTPUT);
    pinMode(PULSANTE, INPUT_PULLUP);
}

void loop(void)
{
    if (!digitalRead(PULSANTE))
        // se leggo il pulsante
    {
        if (contatore != DURATA + 1)
        {
            // luce non bloccata
            contatore = DURATA;
            // carico il de-contatore
        }
        else
        {
            // luce era bloccata
            // la spengo
            contatore = 0;
        }

        if (contatore > DURATA - PASSO)
        {
            // siamo entro un passo di click
            // blocco acceso
            contatore = DURATA + 1;
            // contatore oltre il limite significa contatore bloccato
        }
        else
        {
            // nulla da fare, ho già ricaricato prima
        }


        while (!digitalRead(PULSANTE));

        // no falsi avviamenti, aspettiamo la fine della pressione
    }

    if (!millis() % 100) // ogni decimo di secondo
    {
        if (contatore)
        {
            contatore--;
            // de-conto il decimo di secondo
        }
    }

    digitalWrite(LUCE, contatore);
}

dopo magari faccio in tempo a commnetarlo

Grazie per queste dritte! Ovviamente siamo su un livello più alto delle mie conoscenze ma domani provo, sono proprio curioso

no, comunque non andrebbe
lo proverò certamente nel pomeriggio ma serve di cambiare queste righe

  if (contatore)
        {
            contatore--;
            // de-conto il decimo di secondo
        }

con queste:

        if (contatore)
        {
            if (contatore > DURATA)
            {
                contatore--;
                // de-conto il decimo di secondo
            }
        }

così dovrebbe andare
se provi tu fammi sapere
per Guglielmo invece:
Perchè un programma che usa una sola variabile int globale e nessuna locale alloca 11 byte di variabili globali?

probabilmente è qualche cosa che viene caricato dalle librerie incluse automaticamente....
infatti se compili un programma vuoto ti da

Lo sketch usa 444 byte (1%) dello spazio disponibile per i programmi. Il massimo è 32256 byte.
Le variabili globali usano 9 byte (0%) di memoria dinamica, lasciando altri 2039 byte liberi...

Nessun programma è realmente "vuoto" ...
... ricordatevi che voi in realtà definite (come minimo) solo due funzioni, setup() e loop(), ma che tutto il resto, anche se NON lo vedete (il main(), tutte le routines del "core", le sue variabili globali, ecc. ecc.), c'è ed occupa sia flash che SRAM.

Guglielmo

Provato, naturalmente non funziona(va)
ma una volta capito il gioco è facile da correggere, il risultato finale lo ho provato e va come deve:
Lo sketch usa 1128 byte (3%) dello spazio disponibile per i programmi. Il massimo è 32256 byte.
Le variabili globali usano 11 byte (0%) di memoria dinamica, lasciando altri 2037 byte liberi per le variabili locali. Il massimo è 2048 byte.