-[Risolto]- pilotaggio timerato di una bobina

ciao a tutti da qualche giorno ho realizzato questo circuito. dovrebbe essere collegato ipoteticamente ad una macchina, quando giro la chiave si accende arduino e un optoisolatore rileva manda 5 v al pin zero dell'attiny85, i pin 1 e 2 sono collegati all'input rispettivi 1 e 2 del modulo a 2 relè. lo scopo di tutto è: alimento il circuito collegato ai 12v sotto chive che quando si gira la chiave, alimenterà arduino, l'optoisolatore mandeà il segnale alto al pin zero di arduino, e la bobina sarà alimentata a 12 volt.
trascorsi i 30 secondi i due relè devono commutare (arduino prenderà i 12v dalla batteria direttamente, la bobina passerà a 8v tramite un regolatore) l'optoisolatore è sempre sotto chiave. il circuito dove rimanere così fichè la macchina verrà spenta (l'optoisolatore va a livello low,) la bobina deve cambiare di stato dopo 40 secondi dallo spegnimento, e arduino deve cabiare di stato dopo 45 secondi per spegnere il circuito.

è molto ingarbugliata la spiegazione, lo so... in altre parole per semplificare il tutto:

ho uno stato di input a livello HIGH all'accensione di arduino sul pin zero
dopo 30 secondi il pin1 deve passare da 1 a 0 e il pin 2 da 0 a 1

rimane tutto così per il tempo che il pin 0 è HIGH

quando il pin 0 passa allo stato LOW

tutto resta fermo per 40 secondi

il pin 1 passa da 0 a 1

dopo altri 5 secondi il pin 2 passa da 1 a 0

si spegne tutto meccanicamente

scrivo quì sotto una bozza di listato che non sembra vedere correttamente all'accensione il pin 0 HIGH
spero possiate aiutarmi, sto diventando pazzo :slight_smile:

# define c 0 //presenza accensione chiave
# define b 1 //bobina da pilotare
# define a 2 //arduino
int val=0;
unsigned long iMillis1 = 0;
unsigned long iMillis2 = 0;
byte acceso1 = LOW;
byte acceso2 = LOW;
int TempoON1 = 6000; //40s
int TempoON2 = 5000;  //30s
int TempoON3 = 7000; //45s 
/*i tempi sono brevi per via dei vari test*/

void setup()
{pinMode(b, OUTPUT);
 pinMode(a, OUTPUT);
 pinMode(c, INPUT);
 }

void loop() {

 val = digitalRead(c);
while ( val == HIGH && acceso1 == LOW)
{ digitalWrite(b, LOW); //bobina accesa (relè input attivo basso)
acceso1 = HIGH;
iMillis1 = millis(); }
if ( acceso1 == HIGH && (millis()-iMillis1)> TempoON2)
{ digitalWrite(b, HIGH); //bobina spenta dopo TON2 (relè input attivo basso)
acceso1 = LOW; }

while ( val == HIGH && acceso2 == LOW)
{acceso2 = HIGH;
iMillis2 = millis(); }
if ( acceso2 == HIGH && (millis()-iMillis2)> TempoON2)
{ digitalWrite(a, LOW); //arduino passa dal +12 sotto chiave al +12 diretta
 acceso2 = LOW; }
 
/*ALLO SPEGNIMENTO Macchina*/

while ( val == LOW && acceso1 == LOW)
{ digitalWrite(b, HIGH); //la bobina è a riposo
acceso1 = HIGH;
iMillis1 = millis(); }
if ( acceso1 == HIGH && (millis()-iMillis1)> TempoON1)
{ digitalWrite(b, LOW); //la bobina si accende
acceso1 = LOW; }

while ( val == LOW && acceso2 == LOW)
{acceso2 = HIGH;
iMillis2 = millis(); }
if ( acceso2 == HIGH && (millis()-iMillis2)> TempoON3)
{ digitalWrite(a, HIGH); //arduino si spegne e si spegne il circuito
acceso2 = LOW;}
}

Boss00:
ho uno stato di input a livello HIGH all'accensione di arduino sul pin zero

O è sbagliata la spiegazione, o è sbagliato il disegno, o tutte due le cose assieme.

Partiamo dal fatto che l'optoisolatore tiene l'ingresso a LOW e non HIGH. Continuiamo con il fatto che (dalla descrizione) la bobina inizialmente è collegata a 8V e dopo passa a 12. E proseguiamo con il fatto che in qualche punto parli di Arduino (con un pin Vin) e in qualche altro di attiny85. Un po' di confusione, che non aiuta ad aiutare mi sembra ci sia...

dopo 30 secondi il pin1 deve passare da 1 a 0 e il pin 2 da 0 a 1

Appunto qui stai dicendo che dopo 30 sec la bobina va a 12V e l'Arduino si stacca dalla batteria per andare sotto chiave, l'opposto della descrizione...

Direi di ripartire dalla descrizione lasciando fuori dalla descrizione pin e livelli, ma descrivendo esattamente solo le varie fasi di funzionamento:

-----------------------------
fase1: tutto spento

[color=orange]accendo chiave[/color]

fase2: bobina alimentata a quanto? che succede se spengo chiave?

[color=orange]passati 30 sec[/color]

fase3: autoritenuta, bobina alimentata a quanto?

[color=orange]spengo chiave[/color]

fase4: bobina alimentata a quanto? che succede se riaccendo chiave?

[color=orange]passati 40 sec[/color]

fase5: bobina alimentata a quanto? che succede se riaccendo chiave?

[color=orange]passati 5 sec[/color]

direi di nuovo fase 1
-----------------------------

È corretto?


A margine, considera che con Arduino un funzionamento lo puoi pensare in molti modi, anche a basso livello a porte logiche o relé simulati se viene più comodo rispetto a scrivere un algoritmo: esempio

ti ringrazio intanto per aver mostrato interesse al mio problema @Claudio_FF.

il mio optoisolatore al pin zero lo uso come sensore di stato, e ti assicuro che all'accensione della chiave da un livello HIGH (provato con logic pen per sicurezza). tralasciando il circuito in sè che non è fondamentale per il listato e la sua sintassi (la mia criptonite :slight_smile: ), il mio esempio semplificato che sopra citavo, facevo finta fossero collegati dei led al posto del modulo relè (ho omesso questo dettaglio scusami) che in questo caso funzionano al contrario del mio modulo relè...

ricapitolo solo la funzione che dovrebbe svolgere arduino prendendo per esempio 2 led invece delle del modulo relè, e un pulsante normalmente chiuso tra 5v e pin zero di arduino:

all'accensione di arduino ho livello HIGH al pin zero, il led1 deve accendersi subito, il led2 è spento.

trascorsi 30 secondi dopo aver acceso arduino senza fare niente.

il led1 si spegne e il led2 si accende.

tutto rimane invariato per diverse ore (in uno stato di attesa comando)

quando premo, e tengo premuto il pulsante arduino dovrà:

mantenere sempre il led2 invariato (acceso come era rimasto), dopo 40 secondi deve accendere il led1

aspettare 5 secondi e spegnere il led2 (tutto quello che viene dopo non ha importanza perchè il circuito si spegneà e se giro la chiave ancora, arduino si riaccenderà e ricomincerà tutto da capo)

chiedo ancora scusa per la mia spiegazione di prima un pò trascurata ed imprecisa. :smiley:
Grazie in anticipo

Boss00:
il mio optoisolatore al pin zero lo uso come sensore di stato, e ti assicuro che all'accensione della chiave da un livello HIGH (provato con logic pen per sicurezza)

Oh, ci credo, ma allora lo schema non è quello postato, oppure è cablato sbagliato, perché in quello schema l'optoisolatore acceso porta senza alcun dubbio il pin a zero (LOW). Ma indipendentemente da questo...

all'accensione di arduino ho livello HIGH al pin zero, il led1 deve accendersi subito, il led2 è spento.
trascorsi 30 secondi dopo aver acceso arduino senza fare niente.
il led1 si spegne e il led2 si accende.
tutto rimane invariato per diverse ore (in uno stato di attesa comando)
quando premo, e tengo premuto il pulsante arduino dovrà:
mantenere sempre il led2 invariato (acceso come era rimasto), dopo 40 secondi deve accendere il led1
aspettare 5 secondi e spegnere il led2 (tutto quello che viene dopo non ha importanza perchè il circuito si spegneà e se giro la chiave ancora, arduino si riaccenderà e ricomincerà tutto da capo)

Allora "astraggo anche io", dodici istruzioni in tutto senza entrare nel merito di HIGH/LOW :wink:

----------------
  accendi le1
  spegni  le2
  pausa 30s
  spegni  le1
  accendi le2
  salva tempo attuale
  finché trascorso < 40 sec:
      se ingresso attivo:
          salva tempo attuale
  accendi le1
  pausa 5s
  spegni  le2
----------------

si le funzioni che vorrei far eseguire ad arduino sono proprio quelle.
cosa c'è di sbagliato nel mio codice? l'approccio che ho utilizzato?

Boss00:
cosa c'è di sbagliato nel mio codice? l'approccio che ho utilizzato?

  1. va indentato altrimenti si legge a fatica
  2. vanno usati nomi comprensibili altrimenti si legge a fatica, ad esempio:
#define CHIAVE       0 // ingresso presenza accensione chiave
#define BOBINA       1 // uscita bobina da pilotare
#define AUTORITENUTA 2 // uscita autoritenuta alimentazione arduino

#define RL_ACCESO  LOW
#define RL_SPENTO  HIGH
  1. Vanno usati i tipi giusti, per i tempi unsigned long, in una variabile int non ci entra il valore 40000:
unsigned long TempoON1 = 6000; //40s
unsigned long TempoON2 = 5000;  //30s
unsigned long TempoON3 = 7000; //45s
  1. Letture e scritture sui pin meglio renderle chiare:
val = digitalRead(CHIAVE);

digitalWrite(BOBINA, RL_SPENTO);

digitalWrite(AUTORITENUTA, RL_ACCESO);

ecc
  1. Tutti i while sono inutili in quanto il contenuto viene eseguito una sola volta, in pratica equivalgono a semplici if.
  2. Per il resto a prima vista non capisco la logica, vedo che le variabili 'acceso1' e 'acceso2' sono usate come flag per rappresentare qualche stato. Tra l'altro essendo dei flag e non ingressi/uscite ha più senso trattarli come variabili bool true/false piuttosto che HIGH/LOW (che poi in ogni caso sempre 1 e 0 sono).

Alla fine potrebbe essere riscritto più ordinato e con i tipi dati giusti così (ma per la logica ci dovrei pensare su):

#define CHIAVE       0 // ingresso presenza accensione chiave
#define BOBINA       1 // uscita bobina da pilotare
#define AUTORITENUTA 2 // uscita autoritenuta alimentazione arduino

#define RL_ACCESO  LOW
#define RL_SPENTO  HIGH

byte val = 0;
unsigned long iMillis1 = 0;
unsigned long iMillis2 = 0;
bool acceso1 = false;
bool acceso2 = false;
const unsigned long TempoON1 = 6000; //40s
const unsigned long TempoON2 = 5000; //30s
const unsigned long TempoON3 = 7000; //45s
/*i tempi sono brevi per via dei vari test*/

void setup()
{
    pinMode(BOBINA, OUTPUT);
    pinMode(AUTORITENUTA, OUTPUT);
    pinMode(CHIAVE, INPUT);
}

void loop() {

    val = digitalRead(CHIAVE);

    if (val == HIGH  &&  !acceso1)
    { 
        digitalWrite(BOBINA, RL_ACCESO); //bobina accesa (relè input attivo basso)
        acceso1 = true;
        iMillis1 = millis(); 
    }

    if (acceso1  &&  (millis() - iMillis1) > TempoON2)
    { 
        digitalWrite(BOBINA, RL_SPENTO); //bobina spenta dopo TON2 (relè input attivo basso)
        acceso1 = false; 
    }

    if (val == HIGH  &&  !acceso2)
    {
        acceso2 = true;
        iMillis2 = millis(); 
    }

    if (acceso2  &&  (millis() - iMillis2) > TempoON2)
    { 
        digitalWrite(AUTORITENUTA, RL_ACCESO); //arduino passa dal +12 sotto chiave al +12 diretta
        acceso2 = false; 
    }

    /*ALLO SPEGNIMENTO Macchina*/

    if (val == LOW  &&  !acceso1)
    { 
        digitalWrite(BOBINA, RL_SPENTO); //la bobina è a riposo
        acceso1 = true;
        iMillis1 = millis(); 
    }

    if (acceso1  &&  (millis() - iMillis1) > TempoON1)
    { 
        digitalWrite(BOBINA, RL_ACCESO); //la bobina si accende
        acceso1 = false; 
    }

    if (val == LOW  &&  !acceso2)
    {
        acceso2 = true;
        iMillis2 = millis(); 
    }

    if (acceso2  &&  (millis() - iMillis2) > TempoON3)
    { 
        digitalWrite(AUTORITENUTA, RL_SPENTO); //arduino si spegne e si spegne il circuito
        acceso2 = false;
    }
}

Ah, ecco cosa non mi tornava nella logica, hai duplicato cose che potevano essere uniche, ad esempio:

  if (val == HIGH  &&  fase == 0)
    { 
        digitalWrite(BOBINA, RL_ACCESO); //bobina accesa (relè input attivo basso)
        fase = 1;
        iMillis = millis(); 
    }

    if (fase == 1  &&  (millis() - iMillis) > TempoON2)
    { 
        digitalWrite(BOBINA, RL_SPENTO); //bobina spenta dopo TON2 (relè input attivo basso)
        digitalWrite(AUTORITENUTA, RL_ACCESO); //arduino passa dal +12 sotto chiave al +12 diretta
        fase = 2; 
    }

Nota che se invece di semplici flag 'acceso1' 'acceso2' ecc usi una sola variabile 'fase' a cui dai un valore numerico crescente diventa più semplice gestire il tutto.

appena ho tutto sotto mano provo, poi ti dico la situazione. per il momento posso solo ringraziarti, cercherò di fare degli sketch più trasparenti e leggibili le prossime volte, probabilmente rende il tutto più semplice. :wink:

ho provato lo sketch che hai postato, il risultato è
la "bobina" si accende subito, e va bene.
trascorso TempoON2 si accende la "ritenuta", ma non si spegne la bobina.

cambiando di stato il pin 0 invece ho:

un ritardo sulla "bobina" allo spegnimento (che non è previsto nel listato)

la "ritenuta" rimane invariata e accesa senza spegnersi.

non capisco davvero questo comportamento strano del circuito.

al momento il collaudo lo stò facendo sia con il circuito reale, sia con un circuito su breadboard con arduino UNO, led e pulsante (modificando opportunamente i listati per i 2 circuiti) ottengo i medesimi risultati su entrambi.

qualche idea?

Il codice completo che ho postato mantiene intatta la tua logica. Il problema è che con solo due stati, alla fine del secondo si riattiva il primo. In pratica appena si rimette 'acceso1' a LOW/false, si riabilita il primo if. Lo stesso problema si trova in quelli seguenti.

Per quello suggerivo di modificare tutto come nel pezzetto di esempio postato alla fine, così si avanza da una fase all'altra senza riattivare le precedenti. Un'unica variabile che dice a che punto siamo arrivati, un solo if abilitato alla volta.

penso di essere vicino alla soluzione, grazie al grande aiuto che mi stai dando.
allo stato attuale funziona solo la parte iniziale del ciclo, cioè con valore alto sul pin zero di arduino esegue correttamente i comandi che volevo, ma al cambio di stato sul pin zero non succede nulla di diverso
(rimane attiva la ritenuta e rimane tutto fermo così)

dove sto sbagliando?

ho provato di spostare iMillis = millis(); da solo dopo if (val == LOW && fase == 0) per cercare di creare un punto di inzio per contare i secondi prima delle funzioni successive, il risultato è che smette di funzionare anche la prima parte :-\

metto il codice completo attuale con le modifiche suggerite da @Claudio_FF

#define CHIAVE       0 // ingresso presenza accensione chiave
#define BOBINA       1 // uscita bobina da pilotare
#define AUTORITENUTA 2 // uscita autoritenuta alimentazione arduino

#define RL_ACCESO  LOW
#define RL_SPENTO  HIGH

byte val = 0;
unsigned long iMillis = 0;
bool fase = 0;
const unsigned long TempoON1 = 6000; //40s
const unsigned long TempoON2 = 3000; //30s
const unsigned long TempoON3 = 7000; //45s
/*i tempi sono brevi per via dei vari test*/

void setup()
{
    pinMode(BOBINA, OUTPUT);
    pinMode(AUTORITENUTA, OUTPUT);
    pinMode(CHIAVE, INPUT);
}

void loop() {

    val = digitalRead(CHIAVE);

    if (val == HIGH  &&  fase == 0)
    {
        digitalWrite(BOBINA, RL_ACCESO); //bobina accesa (relè input attivo basso)
        digitalWrite(AUTORITENUTA, RL_SPENTO);
        delay(1000);
        fase = 1;
        iMillis = millis();
    }

    if (fase == 1  &&  (millis() - iMillis) > TempoON2)
    {   
        digitalWrite(BOBINA, RL_SPENTO); //bobina spenta dopo TON2 (relè input attivo basso
        digitalWrite(AUTORITENUTA, RL_ACCESO); //bobina spenta dopo TON2 (relè input attivo basso)
        fase = 2;
    }

    /*ALLO SPEGNIMENTO Macchina*/
   
 if (val == LOW  &&  fase == 2)
    {
        digitalWrite(BOBINA, RL_SPENTO); //la bobina è a riposo
        digitalWrite(AUTORITENUTA, RL_ACCESO); //arduino passa dal +12 sotto chiave al +12 diretta
        fase = 3; 
        iMillis = millis(); 
    }

    if (fase == 3  &&  (millis() - iMillis) > TempoON1)
    {
        digitalWrite(BOBINA, RL_ACCESO); //la bobina si accende
        fase = 4;
    }

    if (fase == 4  &&  (millis() - iMillis) > TempoON3)
    {
        digitalWrite(AUTORITENUTA, RL_SPENTO); //arduino si spegne e si spegne il circuito
        fase = 5;
    }
}

Non vedo errori nel codice. L'unica spiegazione è che l'ingresso non vada LOW. (vedere post #15)

ho provato anche con arduino uno e i led, medesimo risultato.
l'impressione è proprio quella, che non veda l'imput.

sono aperto anche ad usare diverse librerie se ne esistono, per creare ritardi o posticipi.
oppure essendo che deve eseguire una funzione alla volta, potrei forse anche utilizzare solo il delay... ?

È dal primo post che dico che per me c'è un problema hardware. Prova facile: leggi l'input e lo scrivi su un'uscita. Se l'input funziona l'uscita lo deve seguire paro paro.

Ma la fase 5 deve esistere o va bene che non esista?

Ciao.

nel dubbio ho provato senza la fase5, e ho provato a fare un po di modifiche nella seconda parte ma sempre con gli stessi risultati (o funziona la prima parte oppure non funziona neanche quella).

ho provato anche con questa libreria fondendola allo sketch che ho postato sopra.

il codice che viene fuori è una cosa del genere (i modi e i tempi di azionamento degli output sono stati pensati in maniera leggermente diversa solo per testare il comportamento in sè di arduino)

#include <SandTimer.h>

#define CHIAVE       0 // ingresso presenza accensione chiave
#define BOBINA       1 // uscita bobina da pilotare
#define AUTORITENUTA 2 // uscita autoritenuta alimentazione arduino

#define RL_ACCESO  LOW
#define RL_SPENTO  HIGH

byte val = 0;
bool fase = 0;

SandTimer my_timer1;
SandTimer my_timer2;
SandTimer my_timer3;

void setup(){
{
    pinMode(BOBINA, OUTPUT);
    pinMode(AUTORITENUTA, OUTPUT);
    pinMode(CHIAVE, INPUT);
}

{
digitalWrite(BOBINA, RL_ACCESO); 
digitalWrite(AUTORITENUTA, RL_SPENTO);
delay(50);
my_timer1.start(10000);
}
}
void loop() {
   
   val = digitalRead(CHIAVE);
   
  {if (my_timer1.finished() &&  val == HIGH)
      digitalWrite(BOBINA, RL_SPENTO);
      digitalWrite(AUTORITENUTA, RL_ACCESO);
    }

   if (val == LOW && fase == 0)
   {my_timer2.start(10000);
  
    if (my_timer2.finished())
      digitalWrite(BOBINA, RL_ACCESO);
      digitalWrite(AUTORITENUTA, RL_ACCESO);
      fase = 1;
   }
   if ( fase == 1)
   {my_timer3.start(5000);
  
    if (my_timer3.finished())
      digitalWrite(BOBINA, RL_SPENTO);
      digitalWrite(AUTORITENUTA, RL_SPENTO);
    }
  
}

il problema rimane, tutto funziona bene prima del cambio di stato sul pin zero di arduino.
per il test utilizzo sempre; sia il mio circuito e un' altro arduino con led e pulsante, ogniuno con i propri aggiustamenti allo sketch per via degli output diversi (con arduino uno uso i pin D2,D3,D4)

L'errore è il tipo della variabile fase, che essendo bool non può avere valori superiori a 1.

L'errore è il tipo della variabile fase, che essendo bool non può avere valori superiori a 1.

Ecco appunto, quindi fase=5 serve ad evitare si eseguire codice delle fasi da 1 a 4.

@Boss00
Troppe graffe }{, devono contare in numero pari ed essere messe nel posto giusto.

A questo punto ti consiglio di leggere qualcosa sul linguaggio C/C++ magari le basi, perché sprechi tempo che potresti usare meglio anziché fare copia ed incolla. :slight_smile:

Dal momento che il microcontroller (MCU) non può eseguire operazioni in parallelo ma solo sequenzialmente, si usa dividere la sequenza in tante fasi (quanto necessario) per poi metterle nella sequenza desiderata. La variabile fase è impiegata con tale scopo e quando si assegna alla variabile un valore non previsto (fase 5) nessuna delle fasi da 1 a 4 viene eseguita.

Ovviamente un reset o mancanza e riattivazione di alimentazione riavvia anche la sequenza.

Ciao.

Maurotec:
quindi fase=5 serve ad evitare si eseguire codice delle fasi da 1 a 4.

In questo caso (post #9) la fase 4 spegne tutto, per cui non ha importanza che 'fase' sia variata.

come ho già detto, ho provato anche senza mettere la fase 5, ma il funzionamento rimane invariato...
altri suggerimenti?

@Maurotec apprezzo i consigli, le parentesi graffe ho cercato di metterle dove ritenevo opportuno metterle :wink: , ciò non esclude che le abbia messe nei posti sbagliati.. ma ti garantisco che nell'ultimo schetch postato non le ho copiate ed incollate nemmeno una volta :slight_smile:

Boss00:
ma il funzionamento rimane invariato... altri suggerimenti?

Leggere il post #15 :slight_smile: