Semaforo Complesso OK-Flip Flop Semplice ( e non ci salto fuori).

docsavage:
ma questi son metodi da macellaio, non da veri programmatori

Mi sono appena reso conto che nessuno in questo forum, ma anche su i vari libri per Arduino, ha mai spiegato come si deve scrivere un programma, a partire dal fatto che usare una variabile di tipo int per definire i pin è uno spreco assurdo della ram, risorsa preziosa e limitata sulle piccole mcu, per finire col fatto che il ciclo main(), loop() su Arduino, deve essere ripetuto il maggior numero possibile di volte al secondo e che nessuna funzione deve essere bloccante e/o impegnare la cpu per più di pochi ms.
Se oggi trovo un'oretta libera da dedicare alla cosa vedo di preparare un pdf che spiega, almeno il minimo sindacale, come si deve scrivere un programma.

:confused:
nel frattempo mi dici se al mio problema esiste un metodo alternativo a quelli da macellaio.

Puso:
Potrei aggiungere ulteriori delay velocissimi in modo da far lampeggiare i led velocissimamente (cosi l'occhio umano li percepirebbe accesi) ed in mezzo ad ogni stringa infilarci la lettura del pulsante,ma per farlo dovrei scrivere uno sketch lungo come la bibbia e i vangeli assieme

Ci sei quasi, l'idea del "velocissimo spezzettato" per fare più cose assieme è corretta, ma probabilmente non l'implementazione a cui pensi. In realtà è più semplice (macchine a stati finiti), attendiamo il post di Astro per avere qualcosa di pratico su cui discutere.

Tra l'altro, se riesci a fare uno schema a relè/temporizzatori/pulsanti "classici", tradurlo in funzioni logiche equivalenti è un altro modo ancora per affrontare il problema.

In entrambi i casi il loop dovrebbe procedere a diverse migliaia di cicli completi al secondo.

Io creerei una struttura del genere

void loop(){
controllopulsanti();
controllotempo();
comandasemafori();
}

il codice deve girare sempre senza delay usando la funzione millis() per determinare lo stato di accensione delle varie luci.
Userei poi una struttura per definire i semafori e passare i parametri da una funzione all'altra.

Fare uno schema a relè/temporizzatori/pulsanti "classici", tradurlo in funzioni logiche equivalenti potrei anche riusirci,resta il fatto che il LOOP,legge le righe in fila ed una volta che è partito non posso aggiungere o toglier niente.

Anche utilizzando la struttura che consigli,resta sempre il fatto che il ciclo completo dei semafori durerebbe 20 secondi e dovrei premere il pulsante al momento giusto per fargli leggere lo stato differente.

mi sa che devo preparmi davvero ad uno sketch lungo come la divina commedia.

Non stai pensando quadrimensionalmente! (cit.)

Anche se una lampadina deve rimanere accesa 20 secondi, il loop() non deve durare 20 secondi.
Il ciclo loop() deve durare una frazione di secondo e deve essere sufficientemente breve da intercettare la pressione del pulsante.

Esempio:

void loop() {
  unsigned long currentMillis = millis();

  if (currentMillis - previousMillis >= 20000) {
    previousMillis = currentMillis;
    if (ledState == LOW) {
      ledState = HIGH;
    } else {
      ledState = LOW;
    }
    digitalWrite(ledPin, ledState);
  }

}

Il led si accende e si spegne ad intervalli di 20 secondi. il ciclo dura meno di un millisecondo.

potrebbe essere la soluzione...mo ci provo grazie per il momento

mi da errore....ho fatto copia incolla ed ho solo corretto il setup

void setup() {
pinMode(31, OUTPUT);
pinMode(33, OUTPUT);  

}



void loop() {
 unsigned long currentMillis = millis();

 if (currentMillis - previousMillis >= 20000) {
   previousMillis = currentMillis;
   if (ledState == LOW) {
     ledState = HIGH;
   } else {
     ledState = LOW;
   }
   digitalWrite(ledPin, ledState);
 }

}

Puso:
credo che anche utilizzando

if tempo>millis()....{
comanda_luci(quello che serve)
tempo=millis()+nuova attesa
}

tutto il ciclo completo dei semafori durerebbe sempre 20 secondi.

il ciclo completo certamente

Ma non la loop
Che sarebbe velocissima...

E che naturalmente interromperebbe il ciclo

perfetto prima avevo le idee confuse...adesso sto pensando seriamente di fargli leggere il pulsante quando voglio io ......con un martello

secondo me vuoi fare il passo più lungo della gamba, inizia a far lampeggiare due led con tempi diversi con millis(), poi intercetta la pressione di un pulsante e fai fare qualcosa di conseguenza ai due led, che so che rimangano accesi per 2 secondi.... una volta che hai le idee ben chiare su come gestire millis() e leggere un input lo espandi per realizzare tutto il semaforo

mi sa che hai ragione ...è meglio che ricomincio con qualcosa di più semplice....anche perche non so programmare ripeto sono alle prime armi.

anche se il semaforo mi sembrava semplice.

Puso:
mi da errore....ho fatto copia incolla

Molti esempi danno per scontato che determinati nomi presenti nel codice sono variabili o costanti che vanno definite da altre parti. In particolare previousMillis e ledState sono due variabili globali da definire all'inizio del programma, e ledPin è una costante, che va sempre definita in precedenza. Gli errori del compilatore dovrebbero permettere di capire cosa si è scritto in modo errato e in quale riga.

Quella è comunque la via giusta, il loop cicla continuamente alla massima velocità e testa continuamente il verificarsi di qualche condizione. Solo nell'istante in cui una condizione risulta vera allora si esegue quanto contenuto nell'if (e le operazioni da eseguire a loro volta non devono bloccare o durare molto tempo).

Fare uno schema a relè/temporizzatori/pulsanti "classici", tradurlo in funzioni logiche equivalenti potrei anche riusirci,resta il fatto che il LOOP,legge le righe in fila ed una volta che è partito non posso aggiungere o toglier niente.

Non ho capito cosa intendi con aggiungere/togliere. Lo schema seguente è un classico marcia/arresto, con in più un timer per l'arresto dopo tot (facciamo 5 minuti):

Questo è un esempio di istruzioni da mettere nella funzione loop, che rappresentano pari pari il circuito:

byte STA = digitalRead(STA_PIN);
byte STO = digitalRead(STO_PIN);
A = (A | STA) & !T1out & !STO;
if (!A) { T1time=millis();  T1out=0; } else if (millis() - T1time >= 300000) T1out = 1;
digitalWrite(OUT_PIN, A);

NOTA: si assume che i pulsanti premuti diano un 1 in lettura, e che la luce si accenda con un 1 in scrittura

NOTA2: STA_PIN, STO_PIN, OUT_PIN, sono costanti che indicano i pin usati, mentre A, T1time, T1out, sono variabili di lavoro definite in precedenza:

#define STA_PIN  2
#define STO_PIN  3
#define OUT_PIN  4
byte A = 0;
byte T1out = 0;
unsigned long T1time = millis();

Nonostante il tempo del processo timer sia di cinque minuti (300mila ms), il loop gira alla massima velocità e i pulsanti vengono letti continuamente (ad occhio almeno diecimila volte al secondo).

NOTA3: in un circuito reale con pulsanti/contatti meccanici bisogna anche effettuare il debounce (filtro antirimbalzo) degli ingressi.

intendo che :
lo schema elettromeccanico funziona
probabilmente ance come lo hai riportato in funzione logica funziona

pero mettiamo per ipotesi che durante il tempo in cui il timer tiene eccitato il relè, arriva un che vuole accendere una lampadina

a livello elettrotecnico baterebbe mettere in parallelo un interuttore con la lampadina e se arriva uno che la vuole accendere basta che schiaccia l'interruttore indipendentemente da cosa sta facendo il timer (non gli interessa)

a livello logico invece dovrebbe aspettare che il timer abbia finito il suo lavoro.

non so se mi sono spiegato

sorry

-pulsante-

ecco secondo me ci correbbero dei LOOP in parallelo.....mentre adesso mi sembra che ci sia un unico LOOP che funziona in serie

spero di sbagliarmi

Puso:
a livello elettrotecnico baterebbe mettere in parallelo un interuttore con la lampadina e se arriva uno che la vuole accendere basta che schiaccia l'interruttore indipendentemente da cosa sta facendo il timer (non gli interessa)

a livello logico invece dovrebbe aspettare che il timer abbia finito il suo lavoro.

No, visto che l'intera serie di istruzioni è sempre valutata/eseguita migliaia di volte al secondo, basta aggiungere una o due righe per leggere il nuovo interruttore e scrivere la nuova uscita (lo schema si può complicare a piacere con quanti elementi e timer indipendenti si vuole).

secondo me ci correbbero dei LOOP in parallelo.....mentre adesso mi sembra che ci sia un unico LOOP che funziona in serie

Quello che mi sembra sfugga è il fatto che l'esecuzione di quella serie di istruzioni dura in ogni caso pochi microsecondi (una quindicina), quindi ogni singolo componente dello schema viene virtualmente "eseguito" in parallelo a tutti gli altri ogni pochi microsecondi. La logica e i tempi del processo complessivo sono formati da innumerevoli cicli del loop principale.

NOTA: ad ogni nuovo ciclo i dati di lavoro sono rappresentati dalle letture attuali degli ingressi, e dalle variabili impostate nei cicli precedenti (stato).

anche se il semaforo mi sembrava semplice

Il semaforo monotask si, ma come in pratica in tutti i progetti "reali" ci si è trovati subito ad avere bisogno del multitasking (cooperativo), che richiede un diverso approccio/design. È abbastanza carne al fuoco tutta in una volta :wink:

Ciao Puso,

forse... e dico forse...per dimostrare la vera differenza che c'è tra usare delay() e millis() prova ad eseguire questi due sketch che ad ogni secondo scrivono su monitor quanti cicli il loop() ha eseguito in un secondo.

con delay()

unsigned long ciclo = 0;

void setup() {
  Serial.begin(9600);
}

void loop() {
  delay(1000);
  Serial.println(ciclo);
  ciclo++;
}

con millis():

unsigned long ciclo = 0;
unsigned long tempo;

void setup() {
  Serial.begin(9600);
  tempo = millis();
}

void loop() {
  if (millis() - tempo == 1000) {
    Serial.println(ciclo);
    tempo=millis();
  }
  ciclo++;
}

...se poi vuoi comunque che il pulsante premuto abbia precedenza su tutto...si deve andare di interrupt...

Puso:
mi da errore....ho fatto copia incolla ed ho solo corretto il setup

Il codice pubblicato non è completo perché lo trovi già pronto tra gli esempi dell'IDE: Blink without delay

Un pochino di masturbazione intellettuale lo vedo, ben spalmata....

Se vogliamo replicare il funzionamento di un circuito a relè e timer elettromeccanici si può fare, ma non è così che si programma arduino

Io sono quello che ne sa meno di tutti, qui, ma vedo che la strada non è quella giusta

Torno a dire che un test su millis, che legge da un array di strutture ed esegue le istruzioni codificate è un approccio modulare, semplice, espandibile