se interruttore alto attiva un uscita altrimenti me ne attivi un'altra

Progetti Arduino
Avatar utente
pgv
Messaggi: 484
Iscritto il: gio 17 set 2020, 13:16
Località: Ginevra

Re: se interruttore alto attiva un uscita altrimenti me ne attivi un'altra

Messaggio da pgv »

Uno dei mie Maestri diceva sempre "se funziona quanto basta, non toccarlo che' si guasta!"
Se la soluzione e' soddisfacente, e' soddisfacente. Se pero' pensi di modificare in futuro il codice e soprattutto cambiare i ritardi, forse conviene rivedere tutto il problema con un approccio diverso.

Da quello che ho capito, stai costruendo una specie di "Sequenziatore", se succede A bisogna che B stia alto per tot tempo, poi diventi basso, se succede C aspetto 100 millisecondi poi alzo D, etc etc etc...

Che cosa ci impedisce di implementare un vero e proprio Sequenziatore allora? E' elegante, e' didattico, funziona e si puo' riciclare in tante di quelle occasioni che uno non se lo imagina nemmeno... (si tratta in effetti di un mini sistema operativo multitasking cooperativo per chi ama i paroloni).

Immagina di avere una tabella in cui ogni riga corrisponde a una funzione (diversa e senza argomenti per il momento), un contatore che ti dice tra quanti millisecondi deve essere eseguita la funzione e un numer che indica la "ricarica" del contatore, se e' 0 (o -1...) non ricarichi, se e' positivo quando il contatore arriva a zero lo fai ripartire con il numero di conteggi indicato. Per fare un esempio semplice (Blink!):

Funzione, Contatore, Ricarica
accendiLed, 500, 1000
spegniLed, 1000, 1000

Dopodiche' ogni millisecondo esegui il seguente pseudocodice (la CPU IT-Mega parla Italiano):

per ogni riga della tabella fai:
diminuisci il Contatore
se il Contatore attuale e' arrivato a zero allora:
esegui la Funzione della riga attuale
se la Ricarica e' diversa da zero allora
copia nel Contatore il valore della Ricarica
fine se
fine se
fine per

Vediam che succede. All'istante zero quando parte il programma il Led sia spento (non importa davvero ma facciamo finta che... Ho omesso tutta l'inizializzazione perche' per il momento ci complica la vita e basta).
Passa un millisecondo, la CPU esegue lo pseudocodice, e il solo risultato e' che ora i due campi Contatore contengono 499 e 999 rispettivamente.
Passa un millisecondo, ne passano due, ne passano 499 in tutto dall'inizio del programma, i due campi Contatore contengono 1 e 501.
Passa ancora un altro millisecondo e le cose si fanno eccitanti! Il primo Contatore e' arrivato a zero, per cui e' venuto il momento di <ta daah!> <rullo di tamburi> ESEGUIRE LA FUNZIONE accendiLed() <il pubblico fa la ola>. Inoltre il primo Contatore viene ricaricato col valore 1000.
Passa un altro millisecondo, niente di speciale se non che i due campi Contatore ora contengono 999 e 499 rispettivamente (non dimentichiamo che vengono diminuiti di uno tutti e due...).
Passano altri 499 millisecondi, e a questo punto c'e' una ovazione dalle tribune, perche' il secondo campo Contatore e' arrivato a zero e dobbiamo ESEGUIRE LA FUNZIONE spegniLed() <folle oceaniche acclamano>.

"Bravo! Sei riuscito a riscrivere Blink.ino rendendolo molto piu' complicato".
E' vero e non e' vero. Se ci fermiamo qui, e' vero, non occorreva stare a complicarsi tanto la vita per far lampeggiare un LED. Non e' vero se ce ne serviamo per estendere il lampeggiamento dei LED (e poi vedremo come possiamo fare anche di piu'). Passiamo al problema successivo:
Vogliamo far lampeggiare 50 LED, ciascuno con un suo periodo diverso, e magari qualcuno con un duty cycle (frazione del tempo in cui stanno accesi) diverso dal 50%. Se dobbiamo farlo con applicazioni sagge della delay() diventiamo matti, ma possiamo estendere la nostra tabellina precedente e vederne il vero valore...

accendiLed1, 500, 1000 // non e' cambiata, questo LED si accende dopo mezzo secondo e lampeggia a 0.5 Hz
spegniLed1, 1000, 1000 // neppure questa
accendiLed2, 0, 500 // questo LED si accende SUBITO e lampeggia a 1 Hz
spegniLed2, 250, 500 // con un duty cycle del 50%
accendiLed3, 100, 500 // questo LED si accende dopo 100 millisecondi e lampeggia a 1 Hz
spegniLed3, 350, 500 // anche questo con un duty cycle del 50%
accendiLed4, 100, 500 // questo si accende insieme al precedente e lampeggia anche lui a 1 Hz
spegniLed4, 200, 500 // ma ha un duty cycle solamente del 20% - acceso 100 ms e spento 400 ms
eccetera eccetera eccetera
accendiLed50, 100, 500 // anche l'ultimo LED si accende insieme al 3 e al 4 e lampeggia a 1 Hz
spegniLed50, 500, 500 // ma ha un duty cycle dell'80% - 400 ms acceso, 100 ms spento

Farlo a botte di delay() e' forse possibile ma di una noiosita' esiziale e soprattutto sarebbe difficilissimo modificare anche uno solo dei lampeggiamenti, mentre con il nostro Sequenziatore basta modificare una riga della tabellina (al costo di avere 100 funzioni diverse - per ora).

Ma non basta!

Finora abbiamo eseguito solamente task ripetitivi. E se volessimo invece eseguire un task una volta sola, ma in dipendenza da un ingresso e con un ritardo ben definito a partire dal momento in cui decidiamo che deve partire? Aggiungiamo in coda alla nostra tabellina una nuova riga. Per esempio, se volessimo accendere il LED51 (e' un Arduino Grandino e ha tantissimi pin) 150 millisecondi dopo l'arrivo di un "HIGH" sull'ingresso1 e farlo spegnere dopo 150 ulteriori millisecondi, basta aggiungere dopo l'ultima riga occupata della tabellina le due righe seguenti:

accendiLED51, 150, -1 // Il -1 ci ricorda che non deve essere ricaricato
spegniLED51, 300, -1 // come sopra

nel momento in cui il nostro ingresso1 passa da LOW a HIGH. Occorrera' poi una ulteriore tabellina con dei flag che memorizzano i valori precedenti degli ingressi se ci interessa rivelare un cambiamento di livello. Con gli ingressi e' possibile tutta una serie di giochini interessanti ma li vedremo casomai in un'altra puntata.

Fin qui abbiamo costruito un sistema operativo rudimentale ma che ci permette di mettere in esecuzione delle funzioni sia ripetitivamente, con un periodo e una fase ben determinati, sia "one-shot" a seguito di eventi esterni o interni. Resta la palla di avere una caterva di funzioni diverse pero'.. Ma se siamo un po' furbi possiamo imbrogliare e scrivere soltanto una funzione per ogni "tipologia" di azione, al costo di una colonna addizionale (o piu', secondo il caso specifico) in cui mettere un parametro (o piu' d'uno se necessario, per esempio se vogliamo attivare un'uscita PWM dovremo specificare il Pin e il Duty Cycle della PWM. Se vogliamo leggere un ingresso analogico possiamo indicare il Pin e lasciare posto nella tabellina per il valore letto...). La nuova tabellina avra' quindi i campi seguenti:

Funzione, Parametro1, (Parametro2, Parametro3,...) Fase (il valore iniziale del Contatore), Periodo (la Ricarica del Contatore).

Per riscrivere ancora una volta Blink.ino, riempiremmo la tabella con i valori seguenti:

accendiLed, 13, 500, 1000 // Aspetta 500 millisecondi, accendi il LED attaccato al Pin 13, e ripeti ogni 1000 ms
spegniLed, 13, 1000, 1000 // Aspetta 1000 millisecondi, spegni il LED attaccato al Pin 13, e ripeti ogni 1000 ms

Se fossimo colti da un attacco di pigrizia fulminante potremmo anche fare a meno di scrivere qualchesivoglia funzione e riempire la tabellina con quanto segue:

digitalWrite, 13, HIGH, 500, 1000 // Partendo dal presupposto che il LED sia collegato in mod che un'uscita HIGH lo accende
digitalWrite, 13, LOW, 1000, 1000 // vedi sopra

Io preferisco il livello di astrazione precedente, cosi' basta cambiare HIGH a LOW e LOW a HIGH debtro le funzioni accendiLed() e spegniLed() se cambiamo le connessioni dei LED, ma si tratta di questioni di gusto e non funzionali.

Alla domanda "ma come facciamo ad aggiornare la tabellina ogni millisecondo", ammicco e silenziosamente punto il dito al programma precedente, quello che si agganciava alla ISR del Timer0 per eseguire del codice ogni millisecondo (circa)... Se l'aggiornamento dei contatori nella tabellina viene fatto all'interno della ISR, la tabellina "si aggiorna da sola". Se e funzioni da chiamare si limitano ad accendere e spegnere LED (uscite) allora possono perfino essere chiamate dalla ISR. Funzioni piu' complicate e lunghe e' meglio siano chiamate dentro loop().
RoccoCostruzioni
Messaggi: 51
Iscritto il: mer 9 set 2020, 21:16

Re: se interruttore alto attiva un uscita altrimenti me ne attivi un'altra

Messaggio da RoccoCostruzioni »

allora PGV ti spiego a cosa mi serve ledPinTIMERON e ledPinTIMEROFF.
sto realizzando un alimentatore in AC con un trasformatore isolatore e un variac, per varie necessità sto dotando di un timer che se lo attivi chiude un relè e allo scadere del tempo lo stesso relè si diseccita, sfruttando il suo contatto NO e C ho pensato di pilotare timerPin per poi uscire con le due uscite ledPinTIMERON e ledPinTIMEROFF per pilotare altri due relè che a loro volta con l'impulso detto prima di 100mS mi comandano pulsON e pulsOFF che sono due pulsanti per attivare o disattivare l'uscita.
pensandoci bene al posto di due relè ausigliari si può fare questo all'interno del codice mantenendo ovviamente, a prescindere di come si trova timerPin, le due funzionalità di pulsON e pulsOFF?
Avatar utente
pgv
Messaggi: 484
Iscritto il: gio 17 set 2020, 13:16
Località: Ginevra

Re: se interruttore alto attiva un uscita altrimenti me ne attivi un'altra

Messaggio da pgv »

Fermo restando che e' intesa come critica costruttiva e non negativa della tua implementazione, ma trattandosi di AC non sarebbe meglio servirsi di qualcosa tipo la famiglia Finder 81.01? A me Finder ha sempre dato grandi soddisfazioni.
https://findernet-cms-s3.s3.eu-west-1.a ... 01EN-1.pdf
Il caso 3c mi sembra quello appropriato: il relay e' alimentato (U) e l'impulso su S fa chiudere i contatti. La "sparizione" di S fa partire il timer interno e dopo un intervallo T (tra 0.1 secondi e 10 ore) i contatti si riaprono. Se durante l'intervallo T ricompare il segnale in ingresso S, il temporizzatore si ferma e riparte da zero quando scompare di nuovo S.
<occhiali!>
Penso che avrei dovuto scrivere caso DE, il segnale di accensione e non quello di spengimento fanno partire il temporizzatore
</occhiali!>
Pulito, (moderatamente) economico (qui in CH lo ho trovato a circa 35 Euro, non e' regalato ma il relay porta 16A), a norma CE...

A parte questo, penso che a colpi di tabellina si possa implementare tutto quanto il tuo sistema e nemmeno soffrendo troppo. Vediamo caso per caso:

Codice: Seleziona tutto

  int reading1 = digitalRead (releSS);
  if (reading1 == HIGH) {
    digitalWrite (ledSS, HIGH);
  } else {
    digitalWrite (ledSS, HIGH);
    delay (500);
    digitalWrite (ledSS, LOW);
    delay (500);
  }

lo possiamo tradurre in qualche riga (assumendo di avere scritto una funzione aggiungiAllaTabellina() che fa quel che suggerisce il suo nome):

Codice: Seleziona tutto

if (digitalRead(releSS) == HIGH) {
  aggiungiAllaTabellina(accendiLed, ledSS, 1, -1);	// Al prossimo millisecondo si accendera', una volta sola
  } else {
  aggiungiAllaTabellina(accendiLed, ledSS, 1, -1);	// come sopra
  aggiungiAllaTabellina(spegniLed, ledSS, 501, -1);	// spegnilo 500 millisecondi dopo
  }
Devo pero' dire che non capisco bene che effetto tu voglia ottenere. Chiariremo le specifiche tecniche in seguito... Secondo me qui c'e' un errore concettuale e tu vuoi effettuare queste azioni sul fronte di salita dell'ingresso, ma mi saprai dire. Prossima attivazione temporizzata di LED:

Codice: Seleziona tutto

  if (digitalRead (pulsON) == HIGH) {
    delay (100);
    digitalWrite (ledPinON, HIGH);
    digitalWrite (ledPinOFF, LOW);
  }
che possiamo tradurre nelle seguenti istruzioni:

Codice: Seleziona tutto

  if (digitalRead (pulsON) == HIGH) {
    aggiungiAllaTabellina(accendiLed, ledPinON, 100, -1);	// Accendiamo questo LED dopo 100 ms
    aggiungiAllaTabellina(spegniLed, ledPinOFF, 100, -1);	// Questo invece lo spengiamo
Proseguiamo con la traduzione del tuo codice originale in una serie di inserzioni di task nella tabella. Nota che la funzione aggiungiAllaTabellina() deve essere abbastanza furba da "riciclare" lo spazio occupato da funzioni che non sono piu' in attesa di essere eseguite in quanto a "botta unica" e avendo gia' tirato il loro colpo. Inoltre, dovremmo controllare (con un valore di ritorno) che e' effettivamente riuscita ad aggiungere il Task e che non e' rimasta senza posto libero nella Tabellina. Verra'...

Codice: Seleziona tutto

  if (digitalRead (pulsOFF) == HIGH) {
    delay (100);
    digitalWrite (ledPinOFF, HIGH);
    digitalWrite (ledPinON, LOW);
  }
che diventerebbe

Codice: Seleziona tutto

  if (digitalRead (pulsOFF) == HIGH) {
    aggiungiAllaTabellina(accendiLed, ledPinOFF, 100, -1);	// Accendiamo questo LED dopo 100 ms
    aggiungiAllaTabellina(spegniLed, ledPinON, 100, -1);	// Questo invece lo spengiamo
  }  
Ora viene un pezzetto di codice piu' complicato ma non troppo:

Codice: Seleziona tutto

  if (digitalRead (pulsI) == HIGH) {
    delay (100);
    digitalWrite (array1[cont1], LOW); //spengo led corrente
    cont1 = cont1 + 1; //incremento contatore led corrente
    if (cont1 >= maxArray1) //se il contatore è al massimo
    {
      cont1 = maxArray1;
    }
    digitalWrite (array1[cont1], HIGH); //accendi il nuovo led corrente
    while (digitalRead (pulsI) == HIGH); //attendi il rilascio di BUTTON1
    delay (100);
  }
Che possiamo tradurre con:

Codice: Seleziona tutto

  if (digitalRead (pulsI) == HIGH) {
    aggiungiAllaTabellina(spegniLed, array1[cont1++], 100, -1);	// Aspetta 100 ms e poi spengi questo LED per favore
    // cont++ ha POST-incrementato il valore di cont1, ossia l'indirizzamento nell'array array1[] e' avvenuto col valore prima dell'incremento
    if (cont1 >= maxArray1) {
      cont1 = maxArray1;	// Evitiamo di sfondare l'array[]
    }
    aggiungiAllaTabellina(spegniLed, array1[cont1], 100, -1);	// Aspetta gli stessi 100 ms e poi accendi questo LED per favore
    // da notare che l'aggiunta alla Tabellina delle due funzioni e' sincrona, ci puo' essere al massimo 1 millisecondo di scarto tra i due LED
    
    // ******** // Sei sicuro di volerti bloccare qui fino a che il BUTTON1 non viene rilasciato? E poi aspettare altri 100 ms?
    while (digitalRead (pulsI) == HIGH); //attendi il rilascio di BUTTON1
    delay (100);
    // ******** //    
  }
<Esco un attimo a portare la spazzatura. A dopo>
Ultima modifica di pgv il dom 11 ott 2020, 20:32, modificato 1 volta in totale.
RoccoCostruzioni
Messaggi: 51
Iscritto il: mer 9 set 2020, 21:16

Re: se interruttore alto attiva un uscita altrimenti me ne attivi un'altra

Messaggio da RoccoCostruzioni »

certo che posso usare tutto l'hardware di questo mondo, in particolare Finder Lovato ed altri li uso da anni occupandomi di automazione ma purtroppo non sono un programmatore, ecco che, costruendomi da solo i miei strumenti di laboratorio volevo implementare la parte software e non l'hardware, ho provato con il listato di Guido e funziona alla grande e non occupa nemmeno tanto solo che riducendo all'osso l'hardware appunto secondo te come posso eliminare, seguendo la spiegazione del mio posto precedente i due relè?
RoccoCostruzioni
Messaggi: 51
Iscritto il: mer 9 set 2020, 21:16

Re: se interruttore alto attiva un uscita altrimenti me ne attivi un'altra

Messaggio da RoccoCostruzioni »

mi potresti spiegare cose intendi con tabellina?
RoccoCostruzioni
Messaggi: 51
Iscritto il: mer 9 set 2020, 21:16

Re: se interruttore alto attiva un uscita altrimenti me ne attivi un'altra

Messaggio da RoccoCostruzioni »

con questo codice

Codice: Seleziona tutto

  int reading1 = digitalRead (releSS);
  if (reading1 == HIGH) {
    digitalWrite (ledSS, HIGH);
  } else {
    digitalWrite (ledSS, HIGH);
    delay (500);
    digitalWrite (ledSS, LOW);
    delay (500);
  }
faccio si che ledSS mi lampeggi fino a quando releSS non va alto facendolo poi rimanere acceso fisso, in pratica ho aggiunto al mio progetto una resistenza da 47ohm 10W per evitare che quando accenderò questo alimentatore mi faccia saltare il magnetotermico che ho da 10A essendo il trasformatore un 1500VA, quindi quando releSS va alto mi aziona un relè che mi metterà in corto la resistenza così da portare al trasformatore di isolamento tutta la potenza necessaria, il ledSS lo applicherò sul pannello frontale come una sorta di READY cioè se lampeggia vuol dire che il trafo viene alimentato dalla resistenza viceversa quando rimane fisso vuol dire che il trafo ha piena potenza e quindi pronto per lavorare
RoccoCostruzioni
Messaggi: 51
Iscritto il: mer 9 set 2020, 21:16

Re: se interruttore alto attiva un uscita altrimenti me ne attivi un'altra

Messaggio da RoccoCostruzioni »

qui invece

Codice: Seleziona tutto

  if (digitalRead (pulsON) == HIGH) {
    delay (100);
    digitalWrite (ledPinON, HIGH);
    digitalWrite (ledPinOFF, LOW);
  }
che adesso è diventato questo perchè ho messo una sorta di interblocco

Codice: Seleziona tutto

if (digitalRead (pulsON) == HIGH and digitalRead (pulsOFF) == LOW) {
    delay (100);
    digitalWrite (ledPinON, HIGH);
    digitalWrite (ledPinOFF, LOW);
  }
e anche questo

Codice: Seleziona tutto

if (digitalRead (pulsOFF) == HIGH and digitalRead (pulsON) == LOW) {
    delay (100);
    digitalWrite (ledPinOFF, HIGH);
    digitalWrite (ledPinON, LOW);
  } 
mi servono semplicemente per poter attivare l'uscita di questo alimentatore e cioè con pulsON mi attiva l'uscita e pulsOFF me la disattiva
ledPinON e ledPinOFF mi servono per visualizzare lo stato dell'uscita e su ledPinON metterò un relè per pilotare appunto l'uscita.
Ultima modifica di RoccoCostruzioni il dom 11 ott 2020, 21:51, modificato 1 volta in totale.
RoccoCostruzioni
Messaggi: 51
Iscritto il: mer 9 set 2020, 21:16

Re: se interruttore alto attiva un uscita altrimenti me ne attivi un'altra

Messaggio da RoccoCostruzioni »

spiegami però, altrimenti non riesco a capire perchè vorresti modificare il mio codice con i codici che mi hai postato, forse ho sbagliato a scriverli e sono più eleganti quelli scritti da te? Sbaglio in qualcosa?
Io fra un po vado via mi collegherò domani sera, ho altri 40/45 minuti
Avatar utente
pgv
Messaggi: 484
Iscritto il: gio 17 set 2020, 13:16
Località: Ginevra

Re: se interruttore alto attiva un uscita altrimenti me ne attivi un'altra

Messaggio da pgv »

Non ho capito benissimo che cosa fanno i due relay ausiliari. Attaccano e staccano l'uscita mentre il primo stacca l'entrata?
Vediamo se riesco a riassumere:

1. relay in ingresso, che abilita o disabilita l'alternata e che, un tempo fisso dopo essere stato attivato, stacca comunque e indipendentemente da quante volte l'utilizzatore abbia spulsantato (oppure vogliamo far ripartire il conteggio del tempo fino allo stacco da zero ogni volta che l'utente pigia il bottone di avvio?), con indicazione dello stato su un LED;

2. un relay in uscita che collega la tensione prodotta internamente all'alimentatore alle boccole di uscita e quindi al carico. Questa deve poter essere comandata da due bottoni (attacca/stacca), e si vuole una indicazione dello stato del relay su due LED (rosso e verde per esempio).

Se questo fosse tutto (non credo di aver capito bene pero') allora in ingresso un timer tipo il Finder che dicevamo, alimentato (U) direttamente dai 110/230 VAC e fatto partire direttamente da un pulsante tra i terminali S e X (opzionalmente puoi aggiungere un pulsante di reset tra R e X che ti permette di staccare i contatti immediatamente se vuoi), in configurazione DE, dovrebbe fare l'affare per il punto 1.

Per il punto 2 sarei tentato di suggerire un Siemens serie 5TT41 (sono quelli utilizzati per accendere e spengere le lampade da piu' interruttori). Un impulso chiude i contatti un altro li riapre, risparmi un bottone. Pero' non li ho mai usati direttamente. Se disponi di una alternata sui 12 o 24 VAC, puoi anche utilizzare un relay "normale" per le uscite, collegato in modo particolare:

Un paio di Contatti col Centrale a 24 VAC e quello NA collegato alla Bobina e un pulsante NC VERDE (che si apre quando schiacci) in serie sui 24 VAC (ovviamente la coil deve poter lavorare su 12/24 VAC). Cosi' il tuo relay non chiudera' mai i contatti, A MENO CHE tu non metta anche un pulsante NA ROSSO (che si CHIUDE quando schiacci) in parallelo al paio di Contatti NA. A questo punto la tua Bobina ovviamente condurrebbe, il tuo pulsante NC VERDE condurrebbe, il solo ostacolo al passaggio di corrente sono i contatti NA del relay. Spingendo il pulsante ROSSO li cortocircuiti, e fai passare corrente nella Bobina, e i Contatti si chiudono. A questo punto anche se rilasci il pulsante VERDE la Bobina continua a condurre allegramente. Per staccare, schiacci il pulsante VERDE che apre il circuito, disattiva la Bobina e fa riaprire i Contatti. Il tuo Relay ha ovviamente almeno un altro set di Contatti di cui ti servi per collegare la tensione generata internamente alle uscite.

Per i LED, occorrerebbe una alimentazione DC, ma puoi risparmiartela utilizzando lampadine a 24 VAC. In questo caso puoi collegarne una al contatto NA e una al contatto NC del set che e' in serie con la bobina. Quando la bobina e' alimentata e il suo contatto e' chiuso si accende una, quando non e' alimentata la bobina e il suo contatto e' aperto si chiude l'altro (NC) e si accende la seconda. Magari proteggi la bobina da un eccessivo assorbimento da parte della lampadina con una resistenza in serie.
RoccoCostruzioni
Messaggi: 51
Iscritto il: mer 9 set 2020, 21:16

Re: se interruttore alto attiva un uscita altrimenti me ne attivi un'altra

Messaggio da RoccoCostruzioni »

1. relay in ingresso, che abilita o disabilita l'alternata e che, un tempo fisso dopo essere stato attivato, stacca comunque e indipendentemente da quante volte l'utilizzatore abbia spulsantato (oppure vogliamo far ripartire il conteggio del tempo fino allo stacco da zero ogni volta che l'utente pigia il bottone di avvio?), con indicazione dello stato su un LED;
a cosa ti stai riferendo a questo?

Codice: Seleziona tutto

  int reading1 = digitalRead (releSS);
  if (reading1 == HIGH) {
    digitalWrite (ledSS, HIGH);
  } else {
    digitalWrite (ledSS, HIGH);
    delay (500);
    digitalWrite (ledSS, LOW);
    delay (500);
  }
Rispondi