C'era una volta una piccola elettrovalvola.....

Ovvero come ti uso una UNO per comandare 12…

venghino venghino siorri e siorree a vedere come una UNO comanda 12 elettrovalvole in latch, con display IIC, ingresso analogico e seconda seriale se servisse di attaccarsi a qualche cosa ancora…

e il tutto al prezzo di un piccolo sorriso, che spero di aver già ottenuto da voi

Non mi riallaccio alla discussione originale, perchè io parlo poco; nelle discussioni altrui

ora ho messo in pratica una mia vecchia idea, che avevo abbozzato qui su questi schermi circa 2 anni fa

ovvero di leggere un ingresso per poterlo “girare” in uscita se e quando serve

cominciamo col fare una mappa dei piedini

/* mappa dei pin:
   00 Seriale HW
   01 Seriale HW
   02 Seriale Sw
   03 Seriale Sw
   04 rele' inversione
   05 prima elettrovalvola

   16 ultima elettrovalvola
   17 Analog input
   18 IIC
   19 IIC
*/

come vedete ho previsto due seriali, un ingresso analogico, una comunicazione IIC e 12 elettrovalvole

il trucco (il mio solito sporco trucco) è nel collegamento delle valvole

sono tutte su un singolo bus a due fili, inserite volta per volta da un loro specifico relè

il bus a due fili è alimentato tramite un relè a doppio scambio
in posizione di riposo il bus è in “posizione” di stop (de-energizzare la valvola)

se e solo se servisse di “energizzare” la valvola: al bisogno si scambia il relè di bus, mettendolo in posizione di “attivo”

i singoli relè di valvola sono comandati (al solito attraverso un opto) da un pulsanti al +, in parallelo al quale agisce l’associato piedino di Arduino

quindo la sequenza di azionamento è:
si scandiscono i 12 input,
se si trova un pulsante premuto (che incidentalmente ha già cominciato a far scattare il relè associato)
si scambia il pinmode del piedino e si tiene alta l’uscita (energizzato il relè) per tutto il tempo che serve

se l’azionamento fosse a spegnere non serve di fare altro, il bus è normalmente “messo a spegnere”
se invece l’azionamento fosse ad “accendere” basterà, subito dopo aver selezionato la valvola “girare” il relè di bus

attendere il giusto tempo
spegnere il relè di valvola ed eventualmente rimettere a posto il relè di bus

quindi una batteria di 12 pulsanti, se ne preme uno, anche per brevissimo tempo, e arduino completa per noi l’azione nei tempi e nei modi corretti

il tutto è fatto da una funzione

void commuta(byte i)
{
   // attiva e/o disattiva la valvola associata al piedino
   // debounce SW
   delay(10);

   if (!digitalRead(i))
   {
      return;
   }

   // OK, debounce eseguito, no false letture
   // selezioniamo la valvola
   // occhio, serve di eseguire la pinmode a uscita ALTA
   digitalWrite(i, 1);
   pinMode(i, OUTPUT);

   // ora la valvola è selezionata
   // se deve essere accesa
   if (stato[i] = !stato[i])
   {
      digitalWrite(INVERTI, 1);
   }

   // aspettiamo il tempo necessario per l'azionamento
   delay(150);
   // deselezioniamo la valvola
   pinMode(i, INPUT);
   digitalWrite(i, 0);
   // con sequenza inversa per evitare cortocircuiti nel caso il pulsante fossa ancora premuto
   // tempo di attesa per lo scatto del relè
   delay(30);
   // rimettiamo a posto il relè di inversione
   digitalWrite(INVERTI, 0);
   // tempo di attesa per lo scatto del relè
   delay(30);
}

funzione che viene chiamata al bisogno mentre si ciclano in lettura gli ingressi

void loop(void)
{
   // controllo se il piedino è alto (pulsante premuto)
   for (byte i = PRIMO; i < LAST; i++)
   {
      if (digitalRead(i))
      {
         commuta(i); // la funzione commuta attiva/disattiva la valvola associata al piedino i
      }
   }
}

naturalmente serve una setup, che contiene un trucco

void setup(void)
{
   // inizializzo i piedini
   pinMode(INVERTI, OUTPUT);

   // anche quelli delle valvole
   for (byte i = PRIMO; i < LAST; i++)
   {
      // e già che ci sono resetto anche le valvole stesse
      stato[i] = 1; // deve risultare accesa per poterla spegnere
      commuta(i);
   }
}

come vedete lancio la commuta a vuoto, per essere sicuro di avere le valvole spente

rimane solo il prembolo:

#define INVERTI 4 // piedino al quale è connesso il rele' di inversione
#define PRIMO 5 // piedino della prima valvola
#define ULTIMO 16 // piedino al quale è connessa l'ultima valvola
#define LAST ULTIMO + 1 // per gli indici dei cicli 
bool stato[ULTIMO]; // array di stati di valvole, i primi valori sono inutilizzati, ma per semplicità tengo l'indice uguale al piedino

e volendo ci metto anche il programma completo:

// di Nelson-StandardOil
// IDE 1.8.13
// Progetto:
// Scopo: comandare il massimo di elettrovalvole con una UNO
// Data inizio lavori: 10/07/20


/* mappa dei pin:
   00 Seriale HW
   01 Seriale HW
   02 Seriale Sw
   03 Seriale Sw
   04 rele' inversione
   05 prima elettrovalvola

   16 ultima elettrovalvola
   17 Analog input
   18 IIC
   19 IIC
*/

#define INVERTI 4 // piedino al quale è connesso il rele' di inversione
#define PRIMO 5 // piedino della prima valvola
#define ULTIMO 16 // piedino al quale è connessa l'ultima valvola
#define LAST ULTIMO + 1 // per gli indici dei cicli 
bool stato[ULTIMO]; // array di stati di valvole, i primi valori sono inutilizzati, ma per semplicità tengo l'indice uguale al piedino

void setup(void)
{
   // inizializzo i piedini
   pinMode(INVERTI, OUTPUT);

   // anche quelli delle valvole
   for (byte i = PRIMO; i < LAST; i++)
   {
      // e già che ci sono resetto anche le valvole stesse
      stato[i] = 1; // deve risultare accesa per poterla spegnere
      commuta(i);
   }
}

void loop(void)
{
   // controllo se il piedino è alto (pulsante premuto)
   for (byte i = PRIMO; i < LAST; i++)
   {
      if (digitalRead(i))
      {
         commuta(i); // la funzione commuta attiva/disattiva la valvola associata al piedino i
      }
   }
}

void commuta(byte i)
{
   // attiva e/o disattiva la valvola associata al piedino
   // debounce SW
   delay(10);

   if (!digitalRead(i))
   {
      return;
   }

   // OK, debounce eseguito, no false letture
   // selezioniamo la valvola
   // occhio, serve di eseguire la pinmode a uscita ALTA
   digitalWrite(i, 1);
   pinMode(i, OUTPUT);

   // ora la valvola è selezionata
   // se deve essere accesa
   if (stato[i] = !stato[i])
   {
      digitalWrite(INVERTI, 1);
   }

   // aspettiamo il tempo necessario per l'azionamento
   delay(150);
   // deselezioniamo la valvola
   pinMode(i, INPUT);
   digitalWrite(i, 0);
   // con sequenza inversa per evitare cortocircuiti nel caso il pulsante fossa ancora premuto
   // tempo di attesa per lo scatto del relè
   delay(30);
   // rimettiamo a posto il relè di inversione
   digitalWrite(INVERTI, 0);
   // tempo di attesa per lo scatto del relè
   delay(30);
}

naturalmente non lo ho provato: non ho le valvole, ma compilare compila…

Direte voi:
ma il display?
l’analogico?
la seconda seriale?

beh, non dovrò mica fare tutto io?

ho lasciato apposta liberi i piedini…

...

beh, non dovrò mica fare tutto io?

ho lasciato apposta liberi i piedini........
[/quote]

:stuck_out_tongue: :smiley: :wink:

In particolare, una cosa che non ho fatto, e che lascio da fare a chi volesse interessarsene,
È togliere l'errore relativo alla setup
Che ho volutamente lasciato come esercizio

Standardoil:
In particolare, una cosa che non ho fatto, e che lascio da fare a chi volesse interessarsene,
È togliere l'errore relativo alla setup
Che ho volutamente lasciato come esercizio

Intendi la forzatura a spento dell'INVERTI?

Sarebbe interessante, provare ad eliminare i delay e fare tutto con millis :wink:
O in alternativa aggiungere qualche String :stuck_out_tongue:

Maurizio

Socio, ma che fai? sfidi?

guardacaso lo ho appena fatto

o meglio, ho ri-esaminato il problema ed emesso una nuova soluzione…

PS: Bravo
se capiti dalle mie parti ci facciamo un caffè e una bottiglia di “Prugna”

io lo so che il socio, qui sopra, non voleva sfidarmi

ma per un puro caso avevo affrontato il problema da un punto di vista alternativo

e quindi lascio qui la soluzione senza delay, a 5 valvole
(All American Five, un grosso Karma per chi la capisce entro oggi)

No, Guglielmo, tu non partecipi al concorso
sarebbe come ammettere “Notturno” in una premiazione di racconti di fantascienza,

tutto sta nel definire bene i termini del problema

// la descrizione di un intero gruppo valvola, pulsante uscite ingressi etc etc
struct Gruppo
{
   byte in; // il piedino di ingresso
   byte o1; // il piedino di uscita al rosso elettrovalvola
   byte o2; // il piedino di uscita al  nero elettrovalvola
   byte statob; // lo stato pre-esistente del pulsante, serve per il debounce
   byte statov; // lo stato appena cambiato della valvola,
   byte statoo; // lo stato pre-esistente della valvola, serve per confronto
   unsigned long int bounce; // ultimo tempo debounce
   unsigned long int attivo; // ultimo tempo azione
};

per poi buttare giù un po’ di numeri

// un array di gruppi valvola
Gruppo gruppi[] = { {2, 3, 4}, {5, 6, 7}, {8, 9, 10}, {11, 12, 13}, {14, 15, 16}, {17, 18, 19}};
// i numeri sono bellamente inventati
// i valori non inizializzati sono inizializzati a zero (statob statov statop bounce e attivo)
byte nugruppi = sizeof gruppi / sizeof gruppi[0];


// i tempi da rispettare
#define DEBOUNCE 50
#define DURATA 500

e quindi valvola per valvola

void loop(void)
{
   // per ogni valvola
   for (byte i = 0; i < nugruppi; i++)
   {
      scandisci(& gruppi[i]);
      // demando alla funzione scandisci() il lavoro sporco
      // la scandisci() la avevo pensata per ricevere un gruppo
      // ma un puntatore a gruppo mi risparmia memoria
   }
}

voi lo sapete o mamma, prima di andar soldato Turiddu…
scusate, una vecchia registrazione…
voi lo sapete che a me non piacciono le loop() “Venete” alla “faso tuto mi”

infatti tutto il lavoro lo fa la scandisci()

void scandisci(Gruppo * g)
{
   // esegue il controllo del pulsante, il debounce, l'azionamento della valvola e il suo rilascio
   // per il gruppo valvola puntato dal puntatore in argomento
   // bufferizzo la lettura del piedino
   bool reading = digitalRead(g->in);

   // debounce
   if (reading != g->statob)
   {
      // ingresso cambiato
      g->bounce = millis();
   }

   // aggiorno lo stato dell'ingresso
   g->statob = reading;

   if ((millis() - g->bounce) > DEBOUNCE)
   {
      g->statov = reading + 1;
      // lo stato valvola vale 1 chiusa oppure 2 aperta
      // siccome all'accensione statoo varrebbe 0 ....
   }

   if (g->statov != g->statoo)
   {
      // appena cambiato comando valvola, serve di comandare la valvola
      // ........ all'accensione la differenza tra gstatov e gstatoo è garantita
      // e quindi all'accensione si dispone automaticamente nello stato comandato
      digitalWrite(g->o1, (g->statov - 1));
      // se statov è alto alziamo la prima uscita
      digitalWrite(g->o2, !(g->statov - 1));
      // e abbassiamo la seconda
      // altrimenti l'opposto
      // comunque la valvola è comandata sempre coerentemente all'ingresso
      g->attivo = millis();
      g->statoo = g->statov;
   }

   if (g->attivo && ((millis() - g->attivo) > DURATA))
   {
      g->attivo = 0;
      // attivo zero serve anche per segnare che la valvola è già stata azionata
      digitalWrite(g->o1, 0); // stato di riposo della valvola (o del suo ponte ad H)
      digitalWrite(g->o2, 0);
   }
}

come al solito io non ho ne valvole ne arduino ne ponti ad H per collegare le valvole all’arduino ne altri ammeniccoli Hardware varii

quindi non sono sicuro sicuro che vada

primo perché manca la setup()
che però è banale da scrivere…

e poi perché non è provata, ma compilare compila

e come ispirazione basta così…

respirare, inspirare, espirare ed ispirare

Standardoil:
Socio, ma che fai? sfidi?

In realtà la sfida la avevo pensata in primis per me, ma in questo periodo non avrei il tempo di raccoglierla :frowning:

Comunque, bravo per aver già scelto e prodotto l'opzione di debellamento del delay piuttosto dell'alternativa di aggiungere qualche String :wink:

Questa sera sono troppo stanco e vedo solo una serie di caratteri incomprensibili, ma nei prossimi giorni, se mi ricordo, analizzo bene la soluzione e per ora vado sulla fiducia :stuck_out_tongue:

Maurizio

il bus a due fili è alimentato tramite un relè a doppio scambio
in posizione di riposo il bus è in "posizione" di stop (de-nergizzare la valvola)

Ci puoi fare uno schemino elettrico?

Praticamente sono 12 monostabili?...
Se è così, non capisco perché è tanto complesso: se un pulsante è premuto, genera un impulso sul relè corrispondente:

  • rileva il cambio di stato dell'ingresso (PIND/PINB)
  • cambia l'ingresso in uscita (DDRD/DDRB o pinMode)
  • arriva il relè per 30ms (tone(pin, 16, 30))
  • cambia uscita in ingresso.

No?...
Provo a rimettermi a dormire >:(

Tempo scaduto

All american five era il nome usato per indicare le prime radio a supereterodina a 5 valvole con valvole sviluppate allo scopo in America

Ah sì...

Il concorso per il karma era sulla citazione,
non sul comando valvole...

Per la soluzione con tone()

Mi piace(rebbe), se funzionasse
Ma
1 non è possibile generare frequenze inferiori a 31 Hz
2 serve di fare la pinmode() "dopo" aver alzato l'uscita, altrimenti per un breve periodo avremmo un corto tra pulsante premuto e uscita bassa

Comunque se Datman lo può contrarre ancora, benvenga...

Occorre però tenere conto che "deve" (e qui rispondo esplicitamente anche al mio socio) essere bloccante
Quindi delay() come se piovesse
Perché?

Siccome il bus è unico si può comandare una sola valvola alla volta

Ecco quindi che deve essere bloccante per non disturbare l'azione già cominciata

Peraltro 12 valvole su una uno con iic, un analogico e due seriali...
A qualcosa bisogna rinunciare....

Poi, dopo, ho pubblicato una differente versione a 5 valvole non bloccante

savoriano:
Ci puoi fare uno schemino elettrico?

Volentieri

Ma non ho nulla per disegnare
In effetti non ho nemmeno il pc, non qui con me, almeno

Dopo faccio schizzo con l'uso di coloranti e matrici organiche di supporto (inchiostro e carta)

Datman:
Provo a rimettermi a dormire >:(

Spero che almeno tu non soffra d'insonnia come me

Però devo dire che da quando ho traslocato a Varese sono molto migliorato

Vana speranza... :frowning:
... e, quando mi sveglio, mangio! Però devo dire che mi aiuta a riaddormentarmi, anche se p poi la bilancia mi redarguisce!

Mi sfugge il perchè debba essere bloccante.
Partiamo dall'inizio, i 12 pulsanti li leggi con il singolo ingresso analogico previsto?
Oppure sono anch'essi collegati al bus? In questo caso mi devo scervellare per capire come.
Questa cosa, se l'hai indicata, mi è sfuggita, rileggerò meglio il tutto appena ho un po' di respiro.

Sulla radio supereterodina, avevo trovato la soluzione giusta, ma ormai erano le 0:30, quindi comunque fuori tempo massimo.
In effetti, visto che facendo una rapida ricerca su internet usciva solo questo come risultato, pensavo la citazione si riferisse ad altro e quindi non ho risposto.

Maurizio

Ok
Riallosumo (allora riassumo)

Comandare 12 valvole in 'H bridge' richiede troppi pin,
Due pin per ogni valvola più il pin di ingresso
una UNO non ci sta, massimo 6 valvole, 18 pin con la seriale libera

Serve quindi un trucco:
Io ho un solo ponte ad H, oltretutto fatto a rele'

E tutte le valvole in parallelo, con un rele' di inserzione, dopo arriverà lo schema

Quindi due soli pin per valvola contando l'input più un pin per il rele che fa la funzione di ponte h
Siamo quindi a 8 valvole, 16 pin più rele di inversione e seriale fanno 19 pin, avanza spazio per un analogico

Adesso concentriamoci ancora un poco

È possibile arrivare a un solo pin per valvola?

Visto che l'input serve solo per 'cominciare', 'comandare' l'azione, posso, dopo aver sentito l'input, usare lo stesso pin come output, purché le polarità delle tensioni in gioco siano concordi
Quindi ecco 12 valvole con 13 pin e il giochino di alzare l'uscita prima di fare la pinmode

Però avendo un solo ponte ad H posso comandare una sola valvola per volta
Ecco quindi che tengo la procedura bloccante per non avere doppi azionamenti

Ok, chiarissimo.
Avevo un neurone in background che ci stava arrivando, ma il resto della truppa era troppo stanco per dargli retta.

Ora la sfida diventa un'altra, sarebbe sempre per me, ma con i limiti già descritti sopra:
Eliminare comunque i delay, per permettere alla MCU di fare comunque altro durante il comando delle elettrovalvole.
Ma sempre su questa configurazione estrema.
Cioè mantenendo la sequenzialità stretta ma senza i delay.
Una bella macchina a stati ben temporizzata.
Giusto per permettere di continuare ad usare l'analogico, l'IIC e la seconda seriale, visto che le hai previste :wink:

Maurizio

Il schema

Della versione a 12 valvole

Solo della parte di potenza

Grazie a un inganniere qui

Che mi ha fatto la bella dello schema

Ok!! Quello che non avevo capito è che tu utilizzi delle elettrovalvole bistabili!
Mi immaginavo delle elettrovalvole (non chiedermi il perché) monostabili.
Adesso è molto piu' chiaro.