Più lavori con un solo sketch?

Salve a tutti, sto riscontrando un problema con arduino mega, devo fare un plastico di casa domotica.

Sono partito dall'automazione del cancello, fin qui sono riuscito con lo sketch, ma quando devo effettuare due operazioni diverse frà di loro come si fa?
Ho quindi aggiunto un crepuscolare allo sketch, con fotoresistenza e un led, (per l'accensione luci giardino) ma come giusto sia, lo sketch viene eseguito cosi come è scritto, come risolvo ed eseguo le due operazioni in contemporanea?
(quando lo sketch va avanti con l'apertura e poi chiusura del cancello, il valore della fotoresistenza non viene più rilevato ovviamente - e ugual situazione, al contrario quando è nel breve lasso di tempo del delay di pausa del crepuscolare non esegue l'apertura del cancello tramite pulsante come è giusto che sia)

Allego quindi lo sketch

const int pulsante=5; //pulsante apertura cancello
const int finecorsa1=6; //finecorsa di chiusura
const int finecorsa2=7; //finecorsa d'apertura
const int IN1=8;
const int IN2=9;
const int IN3=10;
const int IN4=11;
int luce; //valore fotoresistenza

const char tab1[] =
{
  0x01, 0x03, 0x02, 0x06, 0x04, 0x0c, 0x08, 0x09
};

const char tab2[] =
{
  0x01, 0x09, 0x08, 0x0c, 0x04, 0x06, 0x02, 0x03
};

enum tipo_stato {CancelloChiuso=0, CancelloAperto=1};
tipo_stato stato=CancelloChiuso;


void setup() 
{
  pinMode(pulsante, INPUT);
  digitalWrite(pulsante, HIGH); //resistenza di pullup interna
  pinMode(finecorsa1, INPUT);
  digitalWrite(finecorsa1, HIGH); //resistenza di pullup interna
  pinMode(finecorsa2, INPUT);
  digitalWrite(finecorsa2, HIGH); //resistenza di pullup interna
  pinMode(IN1, OUTPUT);
  pinMode(IN2, OUTPUT);
  pinMode(IN3, OUTPUT);
  pinMode(IN4, OUTPUT);
  Serial.begin(9600);
  pinMode(53, OUTPUT); //led illuminazione giardino
}

void loop() {
  // ---- inizio crepuscolare ---- //
  luce = analogRead(A3);
  if(luce < 50)
    digitalWrite(53,HIGH);
  else
    digitalWrite(53,LOW);
  Serial.println(luce);
  delay(500);
  // ---- fine crepuscolare ---- //

  // ---- inizio cancello ---- //
  switch(stato)
  {
    case CancelloChiuso:
    if(digitalRead(pulsante)==LOW && digitalRead(finecorsa1)==LOW && digitalRead(finecorsa2)==HIGH)
    {
      stato=CancelloAperto;
      AvvioMotore();
    }
    else
    {
      StopMotore();
    }
    break;
    case CancelloAperto:
    if(digitalRead(finecorsa1)==HIGH && digitalRead(finecorsa2)==LOW)
    {
      delay(5000);
      stato=CancelloChiuso;
      AvvioMotore();
    }
    break;
  }
  // ---- fine cancello ---- //
}

void AvvioMotore()
{
  for (int j = 0; j < 1 ; j)
  {
    if (stato==0)
    {
      for (int i = 0; i < 8; i++)
      {
        digitalWrite(IN1, ((tab1[i] & 0x01) == 0x01 ? true : false));
        digitalWrite(IN2, ((tab1[i] & 0x02) == 0x02 ? true : false));
        digitalWrite(IN3, ((tab1[i] & 0x04) == 0x04 ? true : false));
        digitalWrite(IN4, ((tab1[i] & 0x08) == 0x08 ? true : false));
        delay(1);
      }
    }
    else
    {
      for (int i = 0; i < 8 ; i++)
      {
        digitalWrite(IN1, ((tab2[i] & 0x01) == 0x01 ? true : false));
        digitalWrite(IN2, ((tab2[i] & 0x02) == 0x02 ? true : false));
        digitalWrite(IN3, ((tab2[i] & 0x04) == 0x04 ? true : false));
        digitalWrite(IN4, ((tab2[i] & 0x08) == 0x08 ? true : false));
        delay(1);
      }
    }
    
    if(digitalRead(finecorsa1)==LOW && stato==0)
    {
      StopMotore();
      break;
    }

    if(digitalRead(finecorsa2)==LOW && stato==1)
    {
      StopMotore();
      break;
    }
    
  }
  
}

void StopMotore()
{
  digitalWrite(IN1, 0);
  digitalWrite(IN2, 0);
  digitalWrite(IN3, 0);
  digitalWrite(IN4, 0);
}

(ho bisogno di una mano pure con la riga 79, il ciclo for in loop che non so come rimuoverlo per avere comunque un loop)

Test_Domotica.ino (2.77 KB)

Vedo che hai una conoscenza più che basilare del linguaggio C. Lo deduco dalle enumerazioni e dall'operatore ternario.
Premetto che forse il tutto si poteva fare in maniera diversa e più semplice, sia a livello hardware "mi pare hai usato motori passo passo", e quindi anche a livello software.

Di solito in un sistema domotico si usano più schede arduino, una per ogni scopo, secondo me dovresti usare un arduino uno per il cancello e un altro per gli altri scopi, se un compito è "bloccante" ha cioè dei cicli o dei delay(), conviene dedicargli una scheda a parte, se invece deve compiere più operazioni ma senza "perdere molto tempo" all'ora un unico arduino potrebbe gestire più cose, come ad esempio accendere luci crepuscolare e anche l'irrigazione.

I due arduino potrebbero comunicare tra loro tramite seriale, o se si hanno molti arduino si potrebbe usare un Master e il protocollo I2C.

torn24:
... se un compito è "bloccante" ha cioè dei cicli o dei delay(), conviene dedicargli una scheda a parte ...

... mi sa che anche tu dovresti studiare un po' di più ::slight_smile:

>Salvatore765: ... per organizzare più attività NON devi mai fermare il codice ... studiati come si usa la millis(), prima QUI, poi QUI ed infine leggi anche QUI e QUI ... vedrai che ti sarà tutto più chiaro :wink:

Guglielmo

Sicuramente devo e voglio imparare di più, ma il tuo commento non è costruttivo, senza voler essere scortese :slight_smile:

So usare millis() al posto di un delay(), e mi evita la sospensione di un programma per un intervallo di tempo, ma se io avessi un ciclo "loop" che richiede tempo, è un po un "pastroccio" implementarlo con una millis(), dove su un sistema operativo si risolverebbe con un thread.

Forse in questo caso il problema è solo il delay(), quindi risolve con una millis(), ma dove sarebbe necessario "fare più compiti contemporaneamente" un thread, la soluzione di una scheda da 5 euro , mi sembra conveniente e pratica....

torn24:
ma se io avessi un ciclo "loop" che richiede tempo, è un po un "pastroccio" implementarlo con una millis(), dove su un sistema operativo si risolverebbe con un thread.

Il ciclo loop non deve mai durare più di una manciata di ms, già 20 ms possono essere troppi, questo perché all'interno della loop devi solo eseguire le operazioni di polling ed eventuali calcoli.
Se vuoi fare più cose in quasi real time devi usare uno scheduler, qui uno molto semplice, e molto efficiente, che ho realizzato per Arduino utilizzando il timer del watch dog, ovvero non impegna risorse.

torn24:
Sicuramente devo e voglio imparare di più, ma il tuo commento non è costruttivo, senza voler essere scortese :slight_smile:

... certo che lo è ... se avessi STUDIATO attentamente i link che ho messo ! Ed avresti anche capito dove sbagli ... ::slight_smile:

Guglielmo

... non solo, con un po' di **spirito d'iniziativa :smiling_imp: ** , sempre sul sito di Leo (quello dei primi due link che ho messo), guardando un po' qua e la tra le tante cose che ha sviluppato per Arduino, si trova :

● Looper, uno schedulatore software per Arduino ... QUI

● Nuovo looper 1.0 ... QUI

● leOS, un semplice SO per Arduino ... QUI

● leOS2 ... QUI

● Nuove versioni del leOS e del leOS2 ... QUI

● leOS 1.2.0 e leOS2 2.3.0 ... QUI

... ce n'è per tutti i gusti !!!

Guglielmo

ah ... concludo la carrelata, segnalando che, con una piccola ricerca qui sul forum :smiling_imp: , si sarebbe trovata anche un'altra semplice soluzione presentata da Astrobee alcuni anni fa ... QUESTO thread.

Per gli interessati, vi è inoltre una lunga disquisizione filosofica sui vari sistemi di scheduling in QUESTO thread.

Guglielmo

Ho dato un'occhiata a tutti i link da voi dati, vi ringrazio, tutto materiale interessante!
Ora sorge un'altro problema, non sono soluzioni "veloci" e "semplici" da applicare per un principiante, credo che il millis sia più semplice, però anche con quest'ultimo non è uscito fuori ciò che volevo dallo sketch, ho cambiato il contesto, ho momentaneamente eliminato il crepuscolare ed aggiunto semplicemente il lampeggiante del cancello, quindi dovrebbe lampeggiare durante l'apertura e la chiusura, due compiti diversi frà la gestione del cancello e la gestione della lampada. (poi più avanti quando riesco a capire dove sbaglio aggiungerò ovviamente tutto ciò che mi serve per gestire il plastico per intero, se necessario aggiungerò qualche altro arduino, ho già da parte 4 wemos d1r2 necessari per il collegamento wifi e gestione da remoto e un arduino geekcreit)

Qui lo sketch attuale, non va in conflitto nulla, però il lampeggiante non funziona come dovrebbe

// ---- inizio cancello ---- //
//comandi
const int pulsante=5; //pulsante apertura cancello
const int finecorsa1=6; //finecorsa di chiusura
const int finecorsa2=7; //finecorsa d'apertura

//motore passo passo
const int IN1=8;
const int IN2=9;
const int IN3=10;
const int IN4=11;
const char tab1[] =
{
  0x01, 0x03, 0x02, 0x06, 0x04, 0x0c, 0x08, 0x09
};
const char tab2[] =
{
  0x01, 0x09, 0x08, 0x0c, 0x04, 0x06, 0x02, 0x03
};

//lampeggiante
const int Lampeggiante =  12; //lampeggiante cancello
int StatoLamp = LOW; //stato iniziale lampeggiante
unsigned long previousMillis = 0; //ultima commutazione del lampeggiante
const long intervalLamp = 1000; //intervallo di commutazione lampeggiante

//stato del cancello
enum tipo_stato {CancelloChiuso=0, CancelloAperto=1};
tipo_stato stato=CancelloChiuso;

unsigned long previousMillis1 = 0;
unsigned long interval1 = 16; //===questo intervallo, piccolo per quanto può essere, non potrebbe causare inconvenienti sul risultato finale del cancello?===//
// ---- fine cancello ---- //

void setup() 
{
  pinMode(pulsante, INPUT);
  digitalWrite(pulsante, HIGH); //resistenza di pullup interna
  pinMode(finecorsa1, INPUT);
  digitalWrite(finecorsa1, HIGH); //resistenza di pullup interna
  pinMode(finecorsa2, INPUT);
  digitalWrite(finecorsa2, HIGH); //resistenza di pullup interna
  pinMode(IN1, OUTPUT);
  pinMode(IN2, OUTPUT);
  pinMode(IN3, OUTPUT);
  pinMode(IN4, OUTPUT);
  Serial.begin(9600);
  pinMode(Lampeggiante, OUTPUT); //lampeggiante cancello
}

void GestioneCancello()
{
  unsigned long currentMillis1 = millis();
  if (currentMillis1 - previousMillis1 >= interval1)
  {
    previousMillis1 = currentMillis1;
    LampCancello();
    switch(stato)
    {
      case CancelloChiuso:
      if(digitalRead(pulsante)==LOW && digitalRead(finecorsa1)==LOW && digitalRead(finecorsa2)==HIGH)
      {
        stato=CancelloAperto;
        AvvioMotore();
      }
      else
      {
        StopMotore();
      }
      break;

      case CancelloAperto:
      if(digitalRead(finecorsa1)==HIGH && digitalRead(finecorsa2)==LOW)
      {
        delay(5000);
        stato=CancelloChiuso;
        AvvioMotore();
      }
      break;
    }
  }
}

void LampCancello()
{
  unsigned long currentMilli = millis();
  if (currentMilli - previousMillis >= intervalLamp)
  {
    previousMillis = currentMilli;
    if(digitalRead(finecorsa1)==HIGH && digitalRead(finecorsa2)==HIGH)
    {
      if (StatoLamp == LOW)
      {
        StatoLamp = HIGH;
      }
      else
      {
        StatoLamp = LOW;
      }
      digitalWrite(Lampeggiante, StatoLamp);
    }
  }
}

void AvvioMotore()
{
  for (int j = 0; j < 1 ; j)
  {
    if (stato==0)
    {
      for (int i = 0; i < 8; i++)
      {
        digitalWrite(IN1, ((tab1[i] & 0x01) == 0x01 ? true : false));
        digitalWrite(IN2, ((tab1[i] & 0x02) == 0x02 ? true : false));
        digitalWrite(IN3, ((tab1[i] & 0x04) == 0x04 ? true : false));
        digitalWrite(IN4, ((tab1[i] & 0x08) == 0x08 ? true : false));
        delay(1);
      }
    }
    else
    {
      for (int i = 0; i < 8; i++)
      {
        digitalWrite(IN1, ((tab2[i] & 0x01) == 0x01 ? true : false));
        digitalWrite(IN2, ((tab2[i] & 0x02) == 0x02 ? true : false));
        digitalWrite(IN3, ((tab2[i] & 0x04) == 0x04 ? true : false));
        digitalWrite(IN4, ((tab2[i] & 0x08) == 0x08 ? true : false));
        delay(1);
      }
    }
    
    if(digitalRead(finecorsa1)==LOW && stato==0)
    {
      StopMotore();
      break;
    }

    if(digitalRead(finecorsa2)==LOW && stato==1)
    {
      StopMotore();
      break;
    }
    
  }
  
}

void StopMotore()
{
  digitalWrite(IN1, 0);
  digitalWrite(IN2, 0);
  digitalWrite(IN3, 0);
  digitalWrite(IN4, 0);
}

Grazie per le vostre risposte e chiarimenti

Salvatore

Mah ... io ti suggerisco una strada più semplice, l'uso di una flag che semplicemente indica se ci deve essere lampeggio o meno (flag che metti a TRUE quando il cancello è in movimento ed a FALSE quando è fermo) ed una banale funzione, che richiami SEMPRE nel loop() che:

  1. verifica la FLAG lampeggio
  2. se FALSE ritorna immediatamente
  3. se TRUE effettua il codice del lampeggio (quello che sfrutta la millis())

... pulito e veloce.

Guglielmo

P.S.: .... ricordo che è cosa già discussa su questo forum parecchio tempo fa ... magari prova a fare qualche ricerca.

ho trovato qualche discussione al riguardo, ho seguito e adattato lo sketch, però ancora il lampeggiatore di blocca durante il movimento del motore passo passo

// ---- inizio cancello ---- //
//comandi
const int pulsante=5; //pulsante apertura cancello
const int finecorsa1=6; //finecorsa di chiusura
const int finecorsa2=7; //finecorsa d'apertura

//motore passo passo
const int IN1=8;
const int IN2=9;
const int IN3=10;
const int IN4=11;
const char tab1[] =
{
  0x01, 0x03, 0x02, 0x06, 0x04, 0x0c, 0x08, 0x09
};
const char tab2[] =
{
  0x01, 0x09, 0x08, 0x0c, 0x04, 0x06, 0x02, 0x03
};

//lampeggiante
const unsigned long tempo_commutazione = 500;
unsigned long tempo = 0;
byte flag = false;
byte Lamp = LOW;
byte Lamp_pin = 12;
unsigned long previousMillis1 = 0;
unsigned long interval1 = 16;

//stato del cancello
enum tipo_stato {CancelloChiuso=0, CancelloAperto=1};
tipo_stato stato=CancelloChiuso;

// ---- fine cancello ---- //

void setup() 
{
  delay(1000);
  pinMode(pulsante, INPUT);
  digitalWrite(pulsante, HIGH); //resistenza di pullup interna
  pinMode(finecorsa1, INPUT);
  digitalWrite(finecorsa1, HIGH); //resistenza di pullup interna
  pinMode(finecorsa2, INPUT);
  digitalWrite(finecorsa2, HIGH); //resistenza di pullup interna
  pinMode(IN1, OUTPUT);
  pinMode(IN2, OUTPUT);
  pinMode(IN3, OUTPUT);
  pinMode(IN4, OUTPUT);
  Serial.begin(9600);
  pinMode(Lamp_pin, OUTPUT); //lampeggiante cancello
  flag = false;
}

void loop() {
  LampCancello();
  if(digitalRead(finecorsa1)==HIGH && digitalRead(finecorsa2)==HIGH)
  {
    flag = true;
  }
  else
  {
    flag = false;
  }
  GestioneCancello();
}

void GestioneCancello()
{
  if (millis() - previousMillis1 > interval1)
  {
    previousMillis1 = millis();
    switch(stato)
    {
      case CancelloChiuso:
      if(digitalRead(pulsante)==LOW && digitalRead(finecorsa1)==LOW && digitalRead(finecorsa2)==HIGH)
      {
        stato=CancelloAperto;
        AvvioMotore();
      }
      else
      {
        StopMotore();
      }
      break;

      case CancelloAperto:
      if(digitalRead(finecorsa1)==HIGH && digitalRead(finecorsa2)==LOW)
      {
        delay(2000);
        stato=CancelloChiuso;
        AvvioMotore();
      }
      break;
    }
  }
}

void LampCancello()
{
  if(!flag) return;
  if (millis() - tempo > tempo_commutazione)
  {
    tempo = millis();
    digitalWrite(Lamp_pin, Lamp);
    Lamp = ~Lamp;
  }
}

void AvvioMotore()
{
  for (int j = 0; j < 1 ; j)
  {
    if (stato==0)
    {
      for (int i = 0; i < 8; i++)
      {
        digitalWrite(IN1, ((tab1[i] & 0x01) == 0x01 ? true : false));
        digitalWrite(IN2, ((tab1[i] & 0x02) == 0x02 ? true : false));
        digitalWrite(IN3, ((tab1[i] & 0x04) == 0x04 ? true : false));
        digitalWrite(IN4, ((tab1[i] & 0x08) == 0x08 ? true : false));
        delay(1);
      }
    }
    else
    {
      for (int i = 0; i < 8; i++)
      {
        digitalWrite(IN1, ((tab2[i] & 0x01) == 0x01 ? true : false));
        digitalWrite(IN2, ((tab2[i] & 0x02) == 0x02 ? true : false));
        digitalWrite(IN3, ((tab2[i] & 0x04) == 0x04 ? true : false));
        digitalWrite(IN4, ((tab2[i] & 0x08) == 0x08 ? true : false));
        delay(1);
      }
    }
    
    if(digitalRead(finecorsa1)==LOW && stato==0)
    {
      StopMotore();
      break;
    }

    if(digitalRead(finecorsa2)==LOW && stato==1)
    {
      StopMotore();
      break;
    }
    
  }
  
}

void StopMotore()
{
  digitalWrite(IN1, 0);
  digitalWrite(IN2, 0);
  digitalWrite(IN3, 0);
  digitalWrite(IN4, 0);
}

... per forza, se fai delle funzioni che NON ritornano il controllo al loop() per un tempo X ... tutto si ferma per quel tempo X !

Se vuoi usare più cose contemporaneamente DEVI scrivere tutte le funzioni in modo non bloccante ...
... probabilmente il modo più semplice (si fa per dire) è l'uso di una "macchina a stati finiti" + l'uso di millis()

Purtroppo capisco che ... non è cosa da "iniziandi" e che ci dovrai sbattere parecchio la testa ... ::slight_smile:

Guglielmo

Salvatore765:
però ancora il lampeggiatore di blocca durante il movimento del motore passo passo

Seguendo la logica del cancello, bisogna scomporre ulteriormente in altri stati anche le parti che adesso attendono con delay. In sostanza tutti i delay devono sparire, sostituiti da diversi altri stati che testano millis. Anche il comando motore dovrà diventare uno switch a stati.

Claudio_F:
Seguendo la logica del cancello, bisogna scomporre ulteriormente in altri stati anche le parti che adesso attendono con delay. In sostanza tutti i delay devono sparire, sostituiti da diversi altri stati che testano millis. Anche il comando motore dovrà diventare uno switch a stati.

aah ora inizio a capire!

Una domanda... è normale che il tempo_attesa non equivale a 10 secondi ma a circa 6? ugual cosa se setto tempo_attesa a 3000, non sono 3 secondi ma molto meno?

unsigned long attesa = 0;
const unsigned long tempo_attesa = 10000;
if(millis() - attesa >= tempo_attesa)
{
stato=CancelloChiuso;
AvvioMotore();
attesa=millis();
}

Salvatore765:
Una domanda... è normale che il tempo_attesa non equivale a 10 secondi ma a circa 6? ugual cosa se setto tempo_attesa a 3000, non sono 3 secondi ma molto meno?

NO, non è assolutamente normale ... con che scheda stai lavorando ? Originale o clone cinese ?

Guglielmo

gpb01:
NO, non è assolutamente normale ... con che scheda stai lavorando ? Originale o clone cinese ?

Guglielmo

è un mega 2560 non originale, credo che però questo problema nel mio caso non è grave, basta aumentare questo millis un pò di più, o magari trovare il suo valore

Piccola altra domanda..
posso pure togliere questo delay o devo per forza sostituirlo con uno switch a stati?

for (int i = 0; i < 8; i++)
{
digitalWrite(IN1, ((tab1 & 0x01) == 0x01 ? true : false));
_ digitalWrite(IN2, ((tab1 & 0x02) == 0x02 ? true : false));_
_ digitalWrite(IN3, ((tab1 & 0x04) == 0x04 ? true : false));
digitalWrite(IN4, ((tab1 & 0x08) == 0x08 ? true : false));
* delay(1);
}*_

Salvatore765:

     unsigned long attesa = 0;

Questo è sbagliato, la variabile attesa deve partire dal valore attuale ritornato da millis(), che potrebbe in quel momento essere anche molto maggiore di zero (e quindi la condizione si verifica prima del previsto).

Per la seconda domanda... se resta li ad ogni "passaggio" blocca tutto per un secondo.

Claudio_F:
Questo è sbagliato, la variabile attesa deve partire dal valore attuale ritornato da millis(), che potrebbe in quel momento essere anche molto maggiore di zero (e quindi la condizione si verifica prima del previsto).

Per la seconda domanda... se resta li ad ogni "passaggio" blocca tutto per un secondo.

Ho capito il concetto, però non capisco, non è già il valore attuale ritornato da millis()?

unsigned long attesa = 0;
...
...
...
if(millis() - attesa >= tempo_attesa)
{
attesa=millis(); //valore attuale ritornato da millis()?

stato=CancelloChiuso;
AvvioMotore();
}

Faccio una premessa, hai voluto usare un motore passo passo, ma nello specifico progetto non è strettamente necessario, quindi ti sei complicato le cose ma potevi evitare con altro tipo di motore.

Per muovere il motore passo passo impieghi del tempo e "blocchi" il programma, MA nel ciclo for del motore passo passo, potresti mettere le chiamate a funzione che sono presenti nel loop(), di conseguenza muovendo il motore eseguirebbe anche le altre operazioni.

1)Organizzi tutto quello che c'è da svolgere in funzioni, nel loop() richiami solo le funzioni

  1. Quando azioni il motore passo passo tramite ciclo for, inserisci nel for anche le chiamate
    a funzione per svolgere altre operazione, esempio lampeggio di un led con apposita funzione, lettura
    sensori con apposita funzione ecc..

In questo modo il ciclo for() del motore, si comporta come la funzione loop(), potendo cosi eseguire
più cose anche quando muovi il motore.

ogni volta penso "ci sono quasi" però ancora il risultato non cambia, molto interessante il looper di leo, con l'esempio 2 task riesco a far partire il motore e il lampeggio del led, però quando cerco di adattarlo allo sketch del cancello non vedo risultati positivi..

Ho praticamente rimosso per il momento pure il lampeggiatore, volevo risolvere il problema della chiusura temporizzata,(come diceva Claudio "potrebbe in quel momento essere anche molto maggiore di zero e quindi la condizione si verifica prima del previsto") credo d'aver fatto un pasticcio con millis li sotto

il mio attuale sketch, come risolvo?

// ---- inizio cancello ---- //
//comandi
const int pulsante=5; //pulsante apertura cancello
const int finecorsa1=6; //finecorsa di chiusura
const int finecorsa2=7; //finecorsa d'apertura

//motore passo passo
const int IN1=8;
const int IN2=9;
const int IN3=10;
const int IN4=11;
const char tab1[] =
{
  0x01, 0x03, 0x02, 0x06, 0x04, 0x0c, 0x08, 0x09
};
const char tab2[] =
{
  0x01, 0x09, 0x08, 0x0c, 0x04, 0x06, 0x02, 0x03
};

//lampeggiante
#define Lamp_pin 12
const unsigned long tempo_commutazione = 500; // qui salvo e decido quanto tempo deve restare off/on il lampeggiante
unsigned long tempo = 0; // qui salvo l'istante di tempo nel quale è cambiato lo stato del lampeggiante
byte flag_led=false;
byte stato_led=LOW;

//stato del cancello
enum tipo_stato {CancelloChiuso=0, CancelloAperto=1};
tipo_stato stato=CancelloChiuso;

unsigned long previousMillis1 = 0;

unsigned long tempo_attesa = 2000;

// ---- fine cancello ---- //



void setup() 
{
  delay(1000);
  Serial.begin(9600);
  pinMode(pulsante, INPUT_PULLUP);
  pinMode(finecorsa1, INPUT_PULLUP);
  pinMode(finecorsa2, INPUT_PULLUP);
  pinMode(IN1, OUTPUT);
  pinMode(IN2, OUTPUT);
  pinMode(IN3, OUTPUT);
  pinMode(IN4, OUTPUT);
  pinMode(Lamp_pin, OUTPUT); //lampeggiante cancello
}

void loop() {
  GestioneCancello();
}


void GestioneCancello()
{
  if(millis() - previousMillis1 >= 16)
  {
    previousMillis1 = millis();
    switch(stato)
    {
      case CancelloChiuso:
      if(digitalRead(pulsante)==LOW && digitalRead(finecorsa1)==LOW && digitalRead(finecorsa2)==HIGH)
      {
        stato=CancelloAperto;
        AvvioMotore();
      }
      else
      {
        StopMotore();
      }
      break;

      case CancelloAperto:
      if(digitalRead(finecorsa1)==HIGH && digitalRead(finecorsa2)==LOW)
      {
        unsigned long attesa;
        if(millis() - attesa >= tempo_attesa)
        {
          //delay(3000);
          stato=CancelloChiuso;
          AvvioMotore();
          attesa=millis();
        }
      }
      break;
    }
  }
}

void LampCancello()
{
  if(!flag_led) return;
  if (millis() - tempo >= tempo_commutazione)
  {
    tempo = millis();
    digitalWrite(Lamp_pin, stato_led);
    stato_led = ~stato_led;
  }
}

void AvvioMotore()
{
  for (int j = 0; j < 1 ; j)
  {
    if (stato==0)
    {
      for (int i = 0; i < 8; i++)
      {
        //if(millis() - timer >= 1)
        //{
        digitalWrite(IN1, ((tab1[i] & 0x01) == 0x01 ? true : false));
        digitalWrite(IN2, ((tab1[i] & 0x02) == 0x02 ? true : false));
        digitalWrite(IN3, ((tab1[i] & 0x04) == 0x04 ? true : false));
        digitalWrite(IN4, ((tab1[i] & 0x08) == 0x08 ? true : false));
        delay(1);
    //timer=millis();
        //}
      }
    }
    else
    {
      for (int i = 0; i < 8; i++)
      {
        //if(millis() - timer2 >= 1)
        //{
        digitalWrite(IN1, ((tab2[i] & 0x01) == 0x01 ? true : false));
        digitalWrite(IN2, ((tab2[i] & 0x02) == 0x02 ? true : false));
        digitalWrite(IN3, ((tab2[i] & 0x04) == 0x04 ? true : false));
        digitalWrite(IN4, ((tab2[i] & 0x08) == 0x08 ? true : false));
        delay(1);
    //timer2=millis();
        //}
      }
    }
    
    if(digitalRead(finecorsa1)==LOW && stato==0)
    {
      StopMotore();
      break;
    }

    if(digitalRead(finecorsa2)==LOW && stato==1)
    {
      StopMotore();
      break;
    }
    
  }
  
}

void StopMotore()
{
  digitalWrite(IN1, 0);
  digitalWrite(IN2, 0);
  digitalWrite(IN3, 0);
  digitalWrite(IN4, 0);
}