Progettino luci e tapparella con IRremote e rele'

Ciao a tutti,

sto cercando di far funzionare il tutto a dovere, ma ho bisogno del vostro aiuto, non sono esperto nella programmazione e non capisco come utilizzare la funzione millis() per inserire un ritardo tra l'apertura della tapparella quindi l'attivazione di un relè e la relativa disattivazione non appena la tapparella arriva a fine corsa (giusto per non lasciare il relè alimentato).
La stessa cosa succede nella fase di discesa della tapparella, vorrei disattivare il relè dopo 10secondi di attività, ho provato maldestramente a farlo ma non ha funzionato, nello sketch che allego ho messo un "ignorantissimo" delay(10000) abbastanza inutile, visto che in quei 10secondi non posso più utilizzare il telecomando :slight_smile:

una birra a chi mi suggerisce e spiega la soluzione per sostituire delay con millis() :slight_smile:

bye!

#include <IRremote.h>

int RECV_PIN = 4; //pin ricevitore IR
int RELE1 = 2; //rele' luce 1
int RELE2 = 3; //rele' luce 2
int RELE3 = 5; //rele' alza tapparella
int RELE4 = 6; //rele' abbassa tapparella

IRrecv irrecv(RECV_PIN);
decode_results results;

void setup()
{
  pinMode(RELE1, OUTPUT);
  pinMode(RELE2, OUTPUT);
  pinMode(RELE3, OUTPUT);
  pinMode(RELE4, OUTPUT);
  digitalWrite(RELE1, HIGH);
  digitalWrite(RELE2, HIGH);
  digitalWrite(RELE3, HIGH);
  digitalWrite(RELE4, HIGH);
  
  irrecv.enableIRIn(); // avvio la ricezione IR
}

int on = 0;
unsigned long last = millis();

void loop() {
  if (irrecv.decode(&results)) {
    if (results.value == 50167935) { // tasto 1
      if (millis() - last > 250) {
        on = !on;
        digitalWrite(RELE1, on ? HIGH : LOW); //accende o spegne
      }
      last = millis();
    }

  if (results.value == 50151615) { // tasto 2
      if (millis() - last > 250) {
        on = !on;
        digitalWrite(RELE2, on ? HIGH : LOW); //accende o spegne
      }
      last = millis();
    }
  
  if (results.value == 50184255) { // tasto 3 alza tapparella
    digitalWrite(RELE3, LOW); // accende il rele'
    delay(10000); //attende il fine corsa tapparella
    digitalWrite(RELE3, HIGH); // spegne il relè'
    }
    
  if (results.value == 50143455) { // tasto 4 abbassa tapparella
    digitalWrite(RELE4, LOW);
    delay(10000); //aspetta il finecorsa
    digitalWrite(RELE4, HIGH);
    }
  
    
  if (results.value == 50153655) { //tasto rosso spegne luci
    digitalWrite(RELE1, HIGH);
    digitalWrite(RELE2, HIGH);
    }
    
    
    irrecv.resume(); // Receive the next value
  }
}

Al verificarsi dell'evento salvi in una variabile il valore di mills, a ogni ciclo lo sottrai al nuovo valore di mills per capire quanto tempo è passato.
Con un semplice if((mills() - oldmills) >= 10000) puoi sapere se sono passati 10 secondi.

millis() e mills() sono la stessa cosa? grazie per la risp faccio una prova appena torno a casa :wink:

edit: anzi, così dovrebbe andare?

ho inserito int lastmillis = 0 e la riga: if ((millis() - lastmillis) >=10000)

#include <IRremote.h>

int RECV_PIN = 4; //pin ricevitore IR
int RELE1 = 2; //rele' luce 1
int RELE2 = 3; //rele' luce 2
int RELE3 = 5; //rele' alza tapparella
int RELE4 = 6; //rele' abbassa tapparella

IRrecv irrecv(RECV_PIN);
decode_results results;

void setup()
{
  pinMode(RELE1, OUTPUT);
  pinMode(RELE2, OUTPUT);
  pinMode(RELE3, OUTPUT);
  pinMode(RELE4, OUTPUT);
  digitalWrite(RELE1, HIGH);
  digitalWrite(RELE2, HIGH);
  digitalWrite(RELE3, HIGH);
  digitalWrite(RELE4, HIGH);
  
  irrecv.enableIRIn(); // avvio la ricezione IR
}

int lastmillis = 0;
int on = 0;
unsigned long last = millis();

void loop() {
  if (irrecv.decode(&results)) {
    if (results.value == 50167935) { // tasto 1
      if (millis() - last > 250) {
        on = !on;
        digitalWrite(RELE1, on ? HIGH : LOW); //accende o spegne
      }
      last = millis();
    }

  if (results.value == 50151615) { // tasto 2
      if (millis() - last > 250) {
        on = !on;
        digitalWrite(RELE2, on ? HIGH : LOW); //accende o spegne
      }
      last = millis();
    }
  
  if (results.value == 50184255) { // tasto 3 alza tapparella
    digitalWrite(RELE3, LOW); // accende il rele'
    if ((millis() - lastmillis) >=10000) { //attende il fine corsa tapparella
      digitalWrite(RELE3, HIGH); // spegne il relè'
      }
    }
    
  if (results.value == 50143455) { // tasto 4 abbassa tapparella
    digitalWrite(RELE4, LOW);
    if ((millis() - lastmillis) >=10000) {
      digitalWrite(RELE4, HIGH);
      }
    }
  
    
  if (results.value == 50153655) { //tasto rosso spegne luci
    digitalWrite(RELE1, HIGH);
    digitalWrite(RELE2, HIGH);
    }
    
    
    irrecv.resume(); // Receive the next value
  }
}

ancora non funziona, il rele' non si spegne dopo 10 secondi, cosa mi sfugge? :°

Intanto dichiara unsigned long anche lastmillis, poi subito dopo la ricezione del messaggio di salita o discesa devi porre lastmillis uguale a millis, prima di fare il controllo se sono passati i 10 secondi.

Errore mio, scusa, è millis().

speriamo sia la volta buona, a pranzo torno a casa e provo questo codice:

#include <IRremote.h>

int RECV_PIN = 4; //pin ricevitore IR
int RELE1 = 2; //rele' luce 1
int RELE2 = 3; //rele' luce 2
int RELE3 = 5; //rele' alza tapparella
int RELE4 = 6; //rele' abbassa tapparella

IRrecv irrecv(RECV_PIN);
decode_results results;

void setup()
{
  pinMode(RELE1, OUTPUT);
  pinMode(RELE2, OUTPUT);
  pinMode(RELE3, OUTPUT);
  pinMode(RELE4, OUTPUT);
  digitalWrite(RELE1, HIGH);
  digitalWrite(RELE2, HIGH);
  digitalWrite(RELE3, HIGH);
  digitalWrite(RELE4, HIGH);
  
  irrecv.enableIRIn(); // avvio la ricezione IR
}

unsigned long lastmillis = 0;
int on = 0;
unsigned long last = millis();

void loop() {
  if (irrecv.decode(&results)) {
    if (results.value == 50167935) { // tasto 1
      if (millis() - last > 250) {
        on = !on;
        digitalWrite(RELE1, on ? HIGH : LOW); //accende o spegne
      }
      last = millis();
    }

  if (results.value == 50151615) { // tasto 2
      if (millis() - last > 250) {
        on = !on;
        digitalWrite(RELE2, on ? HIGH : LOW); //accende o spegne
      }
      last = millis();
    }
  
  if (results.value == 50184255) { // tasto 3 alza tapparella
    digitalWrite(RELE3, LOW); // accende il rele'
    lastmillis = millis();
    if ((millis() - lastmillis) >=10000) { //attende il fine corsa tapparella
      digitalWrite(RELE3, HIGH); // spegne il relè'
      }
    }
    
  if (results.value == 50143455) { // tasto 4 abbassa tapparella
    digitalWrite(RELE4, LOW);
    lastmillis = millis();
    if ((millis() - lastmillis) >=10000) {
      digitalWrite(RELE4, HIGH);
      }
    }
  
    
  if (results.value == 50153655) { //tasto rosso spegne luci
    digitalWrite(RELE1, HIGH);
    digitalWrite(RELE2, HIGH);
    }
    
    
    irrecv.resume(); // Receive the next value
  }
}

Sono riuscito a fare un test prima del previsto, il rele' si accende come al solito ma non ci pensa proprio a spegnersi dopo 10 secondi :confused:

Scusa ma la logica per me è errata.
Nei 10 secondi in cui il relè è attivo, tu comunque verifichi che il tasto sia ancora quello che ti è arrivato da telecomando, cosa che non è possibile.
Penso dovrai usare una porzione della loop() dove verifichi e memorizzi quale tasto è stato premuto.
Per le luci puoi anche agire subito.
Poi una successiva parte di codice (per la tapparella e i suoi rele) dove analizzi l'ultimo tasto premuto e delle variabili di stato per sapere quale "situazione" devi attivare. Una specie di macchina a stati finiti. Tenendo conto dei casi "misti" ovvero sei nei 10 secondi il cui la tapparella la abbassi e premi tapparella su. Cosa vuoi che faccia il codice in quel caso ?

P.S. cosa fa ogni rele ? Rele1 e 2 sono luci, Rele 3 e 4 per abbassare/alzare la tapparella ?

Esattamente, il tasto 3 solleva la tapparella, il tasto 4 la tira giù.. Quindi devo memorizzare lo stato del relè in una variabile e stabilire alcune "regole" di quello che può accadere o meno nei 10 secondi?

Si, e soprattutto non puoi mettere la parte che alza/abbassa la tapparella nel grosso if che verifica se è arrivato un tasto, perchè durante quei 10 secondi, tasti NON ne arrivano, perciò in quella parte di codice non ci entri più.

Una variabile StatoTapparella potrebbe aiutare. Una variabile numerica che può assumere 3 stati.
K_TAPPARELLAOFF=0, K_TAPPARELLA_SU=1, K_TAPPARELLA_GIU=3

Spero di non aumentare la tua confusione. Ti dò un link a un esempio di macchina a stati finiti, in italiano, purtroppo per una cosa diversa dalla tua necessità:
http://www.lucadentella.it/2013/04/30/macchina-a-stati-finiti-e-arduino/

ok, sono un po' confuso ma ci provo :slight_smile:

gabrydark:
ok, sono un po' confuso ma ci provo :slight_smile:

Capisco. Prova a metterti nei panni dell'Arduino, prova a pensare in quali parti del programma passi durante l'utilizzo.
Non è semplice, ma capirai che alcuni parti del tuo codice precedente non vengono eseguite nel "momento" giusto.

Intanto grazie infinite per i suggerimenti, adesso cerco di studiare un po'!:slight_smile:

adesso dovrebbe andare secondo voi o sto scrivendo baggianate infinite? :slight_smile:

#include <IRremote.h>

#define relealzatappON 1
#define relealzatappOFF 0

#define releabbassatappON 1 
#define releabbassatappOFF 0

int stato_rele_alzatapp;
int stato_rele_abbassatapp;

int RECV_PIN = 4; //pin ricevitore IR
int RELE1 = 2; //rele' luce 1
int RELE2 = 3; //rele' luce 2
int RELE3 = 5; //rele' alza tapparella
int RELE4 = 6; //rele' abbassa tapparella

IRrecv irrecv(RECV_PIN);
decode_results results;

void setup()
{
  pinMode(RELE1, OUTPUT);
  pinMode(RELE2, OUTPUT);
  pinMode(RELE3, OUTPUT);
  pinMode(RELE4, OUTPUT);
  digitalWrite(RELE1, HIGH);
  digitalWrite(RELE2, HIGH);
  stato_rele_alzatapp = relealzatappOFF;
  stato_rele_abbassatapp = releabbassatappOFF;
  
  irrecv.enableIRIn(); // avvio la ricezione IR
}

unsigned long lastmillis = 0;
int on = 0;
unsigned long last = millis();

void loop() {
  if (irrecv.decode(&results)) {
    if (results.value == 50167935) { // tasto 1
      if (millis() - last > 250) {
        on = !on;
        digitalWrite(RELE1, on ? HIGH : LOW); //accende o spegne
      }
      last = millis();
    }

  if (results.value == 50151615) { // tasto 2
      if (millis() - last > 250) {
        on = !on;
        digitalWrite(RELE2, on ? HIGH : LOW); //accende o spegne
      }
      last = millis();
    }
  
  if (results.value == 50184255) { // tasto 3 alza tapparella
    digitalWrite(RELE3, LOW); // accende il rele'
    stato_rele_alzatapp = relealzatappON; 
  }
    
    
  if (results.value == 50143455) { // tasto 4 abbassa tapparella
    digitalWrite(RELE4, LOW);
    stato_rele_abbassatapp = releabbassatappON;   
  }
  
    
  if (results.value == 50153655) { //tasto rosso spegne luci
    digitalWrite(RELE1, HIGH);
    digitalWrite(RELE2, HIGH);
    }
    
    
    irrecv.resume(); // Receive the next value
  }
  
  if (stato_rele_alzatapp == relealzatappON) {
    lastmillis = millis();
    if ((millis() - lastmillis) >=10000) 
    stato_rele_alzatapp = relealzatappOFF;
    digitalWrite(RELE3, HIGH);
    }
   
   if (stato_rele_abbassatapp == releabbassatappON) {
    lastmillis = millis();
    if ((millis() - lastmillis) >=10000) 
    stato_rele_abbassatapp = releabbassatappOFF;
    digitalWrite(RELE4, HIGH);
    }
    
}

Mi pare sei sulla strada giusta.
Occhio alle parentesi graffe:

if ((millis() - lastmillis) >=10000) 
    stato_rele_alzatapp = relealzatappOFF;
    digitalWrite(RELE3, HIGH);

Qui se non metti le graffe, anche se indenti la digitalWrite, solo 1 istruzione dopo la if gli appartiene
E' come se tu avessi scritto:

if ((millis() - lastmillis) >=10000) 
{ stato_rele_alzatapp = relealzatappOFF;
}
digitalWrite(RELE3, HIGH);

Inoltre se con il tasto abbassi la tapparella e fai stato_rele_abbassatapp = releabbassatappON;
ricordati che magari la tapparella potrebbe essere nei 10 secondi di alzata e quindi devi azzerare stato_rele_alzatapp a OFF

Due consigli:

  1. la definizione dei pin puoi farla come "const byte"
    esempio const byte RELE1=2;

  2. invece di avere molti if per verificare il tasto puoi usare una forma più stringata con switch:

...
if(irrecv.decode(&results)) {
  switch(results.value) {
    case 50167935:  // tasto 1
      if (millis() - last > 250) {
        on = !on;
        digitalWrite(RELE1, on ? HIGH : LOW); //accende o spegne
      }
      last = millis();
      break;
    case 50151615: // tasto 2
      if (millis() - last > 250) {
        on = !on;
        digitalWrite(RELE2, on ? HIGH : LOW); //accende o spegne
      }
      last = millis();
      break;
    case 50184255: // tasto 3 alza tapparella
      digitalWrite(RELE3, LOW); // accende il rele'
      stato_rele_alzatapp = relealzatappON; 
      break; 
    case 50143455:  // tasto 4 abbassa tapparella
      digitalWrite(RELE4, LOW);
      stato_rele_abbassatapp = releabbassatappON;   
      break;   
    case 50153655: //tasto rosso spegne luci
      digitalWrite(RELE1, HIGH);
      digitalWrite(RELE2, HIGH);
      break;
  }  // end switch
  irrecv.resume(); // Receive the next value
}

quindi così potrebbe funzionare?

ho appena editato, i punti e virgola sono stati una svista :slight_smile:

#include <IRremote.h>

#define relealzatappON 1
#define relealzatappOFF 0

#define releabbassatappON 1 
#define releabbassatappOFF 0

int stato_rele_alzatapp;
int stato_rele_abbassatapp;

const byte RECV_PIN = 4; //pin ricevitore IR
const byte RELE1 = 2; //rele' luce 1
const byte RELE2 = 3; //rele' luce 2
const byte RELE3 = 5; //rele' alza tapparella
const byte RELE4 = 6; //rele' abbassa tapparella

IRrecv irrecv(RECV_PIN);
decode_results results;

void setup()
{
  pinMode(RELE1, OUTPUT);
  pinMode(RELE2, OUTPUT);
  pinMode(RELE3, OUTPUT);
  pinMode(RELE4, OUTPUT);
  digitalWrite(RELE1, HIGH);
  digitalWrite(RELE2, HIGH);
  stato_rele_alzatapp = relealzatappOFF;
  stato_rele_abbassatapp = releabbassatappOFF;
  
  irrecv.enableIRIn(); // avvio la ricezione IR
}

unsigned long lastmillis = 0;
int on = 0;
unsigned long last = millis();

void loop() {
  if(irrecv.decode(&results)) {
    switch(results.value) {
      case 50167935: // tasto 1 (luci)
        if (millis() - last > 250) {
          on = !on;
          digitalWrite(RELE1, on ? HIGH : LOW); //accende o spegne
        } 
        last = millis();
      break; 
  
    case 50151615: // tasto 2 (luci)
        if (millis() - last > 250) {
          on = !on;
          digitalWrite(RELE2, on ? HIGH : LOW); //accende o spegne
        } 
        last = millis();
    break;
    
    case 50184255: // tasto 3 alza tapparella
      digitalWrite(RELE3, LOW); // accende il rele'
      stato_rele_alzatapp = relealzatappON; 
    break;
    
    case 50143455: // tasto 4 abbassa tapparella
      digitalWrite(RELE4, LOW);
      stato_rele_abbassatapp = releabbassatappON;
    break;
 
    case 50153655: // tasto rosso spegne tutte le luci
      digitalWrite(RELE1, HIGH);
      digitalWrite(RELE2, HIGH);
    break;
    }
  }  
     
    irrecv.resume(); // Receive the next value
  
  if (stato_rele_alzatapp == relealzatappON) {
    lastmillis = millis();
    if ((millis() - lastmillis) >=10000) {
      stato_rele_alzatapp = relealzatappOFF;
      digitalWrite(RELE3, HIGH);
    }
  }

  if (stato_rele_abbassatapp == releabbassatappON) {
    lastmillis = millis();
    if ((millis() - lastmillis) >=10000) {
      stato_rele_abbassatapp = releabbassatappOFF;
      digitalWrite(RELE4, HIGH);
    }
  } 
      
}

NO. Questa NON toglierla: if (irrecv.decode(&results)) {

E nel case non devi mettere ; ma due punti case 50167935:

ho editato sopra, va meglio?