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

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

astrobeed,

nonostante tutto quello che si è scritto, attendiamo volentieri il Tuo PDF.

grazie
E:B:

Quello che ho intenzione di realizzare, e devo trovare il tempo per farlo, non è una soluzione al tuo problema, è una guida generale su come si deve scrivere un programma per mcu/micro.

se l'ignoranza avesse le ali......io guiderei uno stormo di somari

orso
me lo riscrivi per favore la differenza tra delay e millis.....utulizzando le uscite digitali.....se no leggo solo numeri e non capisco cosa fanno

docsavage:
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

L' OP ha detto di essere alle prime armi con la programmazione e di conoscere un po' di elettrotecnica. Gli array di strutture sono cose che secondo me arrivano tra molti mesi. D'altra parte in questo thread si è proposto di tutto, i relé simulati sono solo una delle varie possibilità, che ho usato come spunto "familiare" in quanto il punto esame in questo momento mi sembra che non sia tanto come fare qualcosa, ma come fare diverse cose contemporaneamente.

Puso:
orso
me lo riscrivi per favore la differenza tra delay e millis.....utulizzando le uscite digitali.....se no leggo solo numeri e non capisco cosa fanno

Quei numeri indicano quante volte è girato il loop principale ogni secondo trascorso. Nel primo caso la parte che scrive sulla seriale blocca tutto con delay, nel secondo no e nel loop principale si potrebbero fare altre cose "in parallelo".

Un esempio di tre LED che lampeggiano ciascuno per i fatti propri:

#define LED1_PIN  2
#define LED2_PIN  3
#define LED3_PIN  4
#define TEMPO1    500
#define TEMPO2    240
#define TEMPO3    1300


unsigned long t1 = millis();
unsigned long t2 = millis();
unsigned long t3 = millis();
unsigned long actualTime;


void setup() {
    pinMode(LED1_PIN, OUTPUT);
    pinMode(LED2_PIN, OUTPUT);
    pinMode(LED3_PIN, OUTPUT);
}


void loop() {
    actualTime = millis();
    
    if (actualTime - t1 >= TEMPO1) {
        t1 += TEMPO1;
        digitalWrite(LED1_PIN, !digitalRead(LED1_PIN));
    }

    if (actualTime - t2 >= TEMPO2) {
        t2 += TEMPO2;
        digitalWrite(LED2_PIN, !digitalRead(LED2_PIN));
    }

    if (actualTime - t3 >= TEMPO3) {
        t3 += TEMPO3;
        digitalWrite(LED3_PIN, !digitalRead(LED3_PIN));
    }
}

ciao...ci provo.

utilizzando LED integrato dell'arduino, se hai una UNO dovrebbe essere il PIN 13 e che puoi chiamare LED_BUILTIN, ed il LED della comunicazione su monitor seriale...il primo lo vedrai sempre cambiare di stato ogni mezzo secondo...l'altro, a seconda se usi millis() o delay() varia ad ogni esecuzione ciclo...quindi con delay() lo vedrai lampeggiare lento con millis() ti sembrerà sempre acceso da quante volte esegue il ciclo.

con delay():

unsigned long ciclo = 0;

void setup() {
  Serial.begin(9600);
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, LOW);
}

void loop() {
  Serial.println(ciclo);
  digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
  delay(500);
  ciclo++;
}

con milli():

unsigned long ciclo = 0;
unsigned long tempo;

void setup() {
  Serial.begin(9600);
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, LOW);
  tempo = millis();
}

void loop() {
  Serial.println(ciclo);
  if (millis() - tempo >= 500) {
    digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
    tempo = millis();
  }
  ciclo++;
}

io vedo alcune considerazioni:

il semaforo è chiaramente un oggetto che "chiama" gli array
mi spiego:
è chiaramente composto da alcune paline tra loro tutte uguali, che si comportano in modo simile ma sfasate nel tempo

quindi "descrivere" un semaforo con un array è scelta naturale

inoltre la necessità di escludere le delay dal ciclo, associata a una serie pressocche infinita di tempi di attesa fa facilmete pensare a una tabella di tempi da far rispettare alla millis

da qui leggere da una tabella una riga di configurazione del semaforo mi sembra un passo logico
riga che comprenda anche il tempo di durata della configurzione del semaforo

non è difficile, basta leggersi un poco di documentazione sugli array
gli array più semplici da capire sono le stringhe di c
e se si usano solo le lettere si può anche pensare di usare codici mnemonici

e fare qualcosa del tipo:
tutto maiuscolo
prima lettera prima palina (e terza) a fare la via uno
seconda lettera seconda palina (e quarta) a fare la via due
R rosso
V verde
G giallo (col verde acceso)
P verde pedonale (rosso pedonale è semplicemente l'opposto)
B verde pedonale con buzzer acceso

terza lettera tempo di durata
A 5 secondi (sovrapposizione dei rossi)
B 15 secondi (giallo)
C 1 minuto verde sulla via a minore priorità
D 2 minuti verde sulla via a maggiore priorità

quarta lettera numero (cifra)
indica quale riga di luci sarà la prossima

in questa maniera il semoforo si puo' descrivere circa così:

0RRA1 che significa sovrapposizione rossi, 5 secondi, prossima è la riga 1
1RVC2 che significa Rosso in uno verde in due, durata un minuto, prossima la 2
2RGB3 che significa Rosso in 1, giallo in 2, tra 15 secondi cambia in 3
3RRA4 sovrapposizione dei rossi, tra 5 secondi cambia in 4
4VRD5 verde in due rosso in uno, tra minuti cambia in 5
5GRB0 giallo in uno, rosso in due tra 15 secondi cambia in 0 (ricomincia)

sembra un casino, invece ha due grandi vantaggi:

uno: si può scrivere una funzione che interpreti la stringa,
quindi la loop si limita a mandare in esecuzione la stringa
comodo in debug

due:

facile intercettare punti topici per fare cose in più

ovvero basta scrivere delle sequenze "particolari" per mandarle in esecuzione

il passaggio pedoni diventa

6PPC7 Verde pedone su due vie, rosso ovunque, tra un minuto evolve in 7
7BBB0 Verde pedone su due paline, rosso ovunque, buzzer acceso, tra 15 secondi evolve in 0
siccome zero fa parte della sequenza principale non ho bisogno d'altro per far proseguire normalmente il semaforo

anche per far intervenire il pedonale non devo fare altro che mandare in esecuzione la riga 6

e a dimostrare quello che intendobasta guardare questo esempio di loop

è corta, sono più i commenti che le righe di codice

che fa tutto il lavoro è la luci()
che imposta anche il tempo, letto dalla stringa in ingresso

Void loop() {


  // testo se abbiamo gia' raggiunto il tempo
  if (tempo > millis()) {
    // cambio stato semaforo
    luci(sequenza[stato]);
  }

  // testo se è premuto un pulsante di pedone
  if (digitalRead(pedone)) {
    // pulsante di pedone premuto
    // lo memo rizzo
    chiamata = 1;
  }
  // se chiamata eseguita e doppio rosso
  if ( chiamata && digitalRead(P1R) && digitalRead(P2R)) {

    // salvo la sequenza prossima
    stato1 = stato;
    // metto come prossima sequenza il passaggio pedoni
    stato = 6;
    // quindi allo scadere del tempo per il doppio rosso passa in pedoni, invece che in quello che doveva fare
    // considero soddisfatta la chiamata
    chiamata = 0;
    // adesso se non fcessi niente, dopo il tempo di cicalino
    // il semaforo ripartirebbe dall'inizio della sua sequenza
    // questo è garantito dal fatto che il passo 7 BBA punta al passo due
    // invece voglio che riparta da dove si era fermato prima del pedone
    // al momento non ho idee....
  }

// controllo se c'e' o no inserito il lampeggio
// non ho idee adesso
}

notare che io non interrompo il normale ciclo del semaforo

mi limito ad attendere la condizione di doppio rosso e mettere in lista di esecuzione non la normale riga successiva, ma la prima riga della sequenza pedonale

la sequenza pedonale a sua volta termina richiamando la prima riga della sequenza principale

il difficile è tutto nella luci()

Puso:
... la differenza tra delay e millis.....

Quello che secondo me dovresti cercare di capire, e' la differenza fra COSA SONO delay e millis ... perche' cosi poi la potrai sfruttare anche per altre cose, non solo per un'esempio di sketch ...

Premesso che io non sono un programmatore, cerco di darti un paio di spunti ...

Delay, e' un'istruzione (o funzione, chiamala come vuoi), a cui tu passi un certo tempo quando la invochi, e lei "aspetta" per il tempo che gli passi ... ma non fa niente altro, nel frattempo ... se ne sta' li imbambolata ad aspettare, senza leggere ingressi, senza pilotare uscite, senza incrementare cicli ne eseguire calcoli o istruzioni, aspetta e basta ... per cui, in pratica blocca completamente il funzionamento dello sketch e della MCU per tutto il tempo in cui aspetta (immagina di rimanere fermo a fare nulla con occhi ed orecchie chiuse per tutto il tempo, fregandotene di tutto quello che ti capita intorno ... quello e' un delay) ... credo che solo un'interrupt possa essere letto all'interno di un ciclo di delay ...

Millis invece di per se non "aspetta" nulla, la puoi immaginare come una variabile che contiene, ogni volta che viene "letta", il numero di millisecondi trascorsi dall'accensione della MCU fino a quel momento ... pero' nonostante non sia una funzione di attesa, la puoi usare per controllare e confrontare intervalli di tempo, senza bloccare il resto del programma, oltre che per farci altre cose che richiedono il confronto fra due o piu valori di tempo trascorso ...

be mi fa piacere che almeno per essere alle prime armi non ho richiesto uno dei soliti aiuti per avere tutto senza studiare.

vi ringrazio tutti per avermi dato un parere.

ora sto tentando di capire bene il codice mills....che se non ho capito male è un valore di 50 giorni (ovviamemte espresso in millesimi) che parte all'avvio dell LOOP.

Quindi dandogli delle condizioni puramente aritmetiche, posso fargli eseguire dei comandi per circa 50 giorni( ovviamente espresso in millesimi) oppure lo resetto non ho ancora capito come ,ma ci sto studiando e lo faccio ripartire.

Questo al contrario del DELAY che ferma il LOOP per (X) millisecondi, mi darebbe un LooP veloce ne quale posso inserire il PULSANTE DEL VECCHIETTO.

Il tutto solo stando attento che la condizione matematica di Mills non sia pù veloce dell'esecuzione di tutto il cilo di semafori.
.....GIUSTO????????.......

vi prego ditemi che è giusto se significa che non ci ho ancora capito niente.

Per il momento grazie a tutti per l'aiuto che mi state dando.

intanto non abbandono il DELAY(visto che al momento è quella che Lunica che ho capito) e provo a metterci la funzione INTERRUPT (sperando che non sia come premere il Reset).

vediam un po' se ci riesco io

millis() è solo un contatore, che conta quanti millisecondi sono passati da quando hai acceso arduino

se vuoi fare una pausa nel tuo programma il comando è e rimane delay()

ma attento quando parli di pausa

si intende una pausa vera e completa, come quando vai a dormire, per dare l'idea

se invece devi continuare a fare qualcosa, fosse solo aspettare un pulsante premuto, quella non è una pausa

qundi se devi accendere e/o spegnere a intervalli determinati E BASTA si usa la delay

se anche solo devi sorvegliare un pulsante niente delay

e come si fa?

come fai tu a casa a sapere se è ora di guardare il telegiornale?

guardi l'orologio

anche arduno guarda l'orologio

io suo orologio si chiama millis()

quindi se devi spegnere una luce all'ora definita

farai un test sull'orologio

se millis è piu' di ora_programmata accendo la luce

cche in C diventa:

if (millis()>ora_programmata){

e qui un intero blocco di programma
}

tutto il casino viene dal fatto, che esattamente come il tuo orologio fa un giro ogni 12 ore, la millis() fa un giro ogni.......

un fracco di millisecondi, circa 50 giorni

adesso devo uscire, dopo seconda puntata

Visto che il paragone di guardare l'orologio è bello mi permetto di continuare.

Cosa si fa quando si vuole fare qualcosa tra quattro ore?

  1. Si guarda l'orologio
  2. Ci si annota da qualche parte l'ora
  3. Di tanto in tanto si guarda di nuovo l'orologio per vedere quanto tempo è trascorso

Come si fa a calcolare il tempo trascorso?

Calcolando:
** **ora_attuale meno ora_di_inizio_salvata_prima** **
.

Vediamo la figura seguente (cerchio di sinistra): supponiamo ad un certo momento di voler fare qualcosa tra quattro ore, guardiamo l'ora, sono le 5, ce la scriviamo da qualche parte. Continuiamo a guardare periodicamente l'orologio. Alle 9 scopriamo che sono passate 4 ore (9-5=4).

orologiomillis.png

Ma cosa succede se passa la mezzanotte (cioè il famoso e temuto overflow di millis) ?

Assolutamente niente! Contando circolarmente con numeri interi senza segno il risultato viene sempre giusto. Nel cerchio di destra il tempo iniziale sono le 10. Ci interessa sapere quando sono passate 5 ore. Questo avviene alle 3 (3-10=5)

Su Arduino è la stessa cosa:

  1. si guarda il valore di millis() nel momento da cui vogliamo iniziare a misurare il tempo
  2. lo si annota in una variabile
  3. si controlla periodicamente il valore raggiunto da millis() per vedere se è trascorso un certo tempo

L'unica differenza è che millis() conta da 0 a 4294967295 invece che da 0 a 11, quindi serve una variabile di tipo unsigned long per salvare il tempo di inizio.

Poi periodicamente si calcola quanto tempo è trascorso con:
** ** millis() - tempoInizio** **

Visto che il paragone di guardare l'orologio è bello...etc etc

@Claudio_FF ...mi piace +1

Grazie

Meglio non avrei saputo
E a cena ho fatto tardi....

SIETE GRANDI

a grandi linee ho quasi capito il comando MILLIS quindi ho copiato e MODIFICATO questo sketc( no mi ricordo come si scrive) molto semplice per prendere dimestichezza ed ho immaginato una situazione un po più semplice......(Scusate le descrizioni ma servono a Me per Ricordare)

int A = LOW;             //INTero ( quindi 0 o 1) A= Basso ad A assegno un valore BASSO
long B = 0;                //Devo capire la differenza tra LONG ed INT comunque a B assegno il numero 0

void setup(){

 pinMode(9, OUTPUT);              //SEMAFORO
    pinMode(4, INPUT);              //PULSANTE VECCHIETTO
 }

void loop(){

 if ((4, HIGH)&&(millis() > 2000 ))     // SE il vecchio preme il pulsante 4 (CONDIZIONE  1)  e 
                                                    Millis è MAGGIORE di 2 Secondi (CONDIZIONE 2)
 {
        B = millis();        //ASSEGNA a B il valore di MILLIS ( (50 giorni - 2secondi) X tutte le volte che ha
                                 lavorato(APPROFONDIRE)                                               
 
   if (A == LOW){        // SE (A è UGUALE ad un valore BASSO
            A = HIGH;      //ASSEGNA ad A un valore ALTO
   } 
        else                  //ALTRIMENTI
   A = LOW;               //ASSEGNA ad A un valore BASSO

   digitalWrite(9, A);    //SCRIVI sul Pin 9, il valore di A
    
}
}

ero contento perche funzionava tutto a meraviglia, finchè non ho deciso di metterci in mezzo IL MALEDETTO PULSANTE DEL VECCHIETTO e la doppia condizione && (che potrebbe essere una soluzione al mio semaforo )

...pero sta di fatto che le condizioni NON VENGONO RISPETTATE, e non capisco il perche.....sarà la maledidone del pulsante del vecchietto??

Hai un po' di confusione in linea

if (4,HIGH) non significanulla

semmai if (digitalread(4)==HIGH)

che comunque non serve, basta
if (digitalread(4))
dato ce la digitalread su un pulsante premuto vale vero di suo, senza proseguire con la condizione

poi millis()>2000 varra' vero dopo due secondi dall'accensione e per sempre (si, OK dopo 50 giorni altri due secondi di NO, ma non credo che adesso ci preoccupi)

la differenza tra int e long

int è un tipo di variabile che può contenre numeri interi tra (imparare a leggere il reference)
comunque tra -32000 e passa e + 32000 e passa

se ti servono numeri più grandi si usa long

che tiene un fracco di più (quanto? come ho detto fa fede il reference ed è necessario imparare a consultarlo)

se non ti basta ancora si usano unsigned int e unsigned long, che tengono il doppio di int e lon, ma senza il segno (solo numeri positivi)

millis è di tipo unsigned long, che vuol dire che la millis ti risponde con un numero che arriva al massimo fino al massimo della unsigned long

poi

la tua if (A==LOW) con tutto quello che segue può diventare

A=!A;

che significa: qualunque sia A, metti il suo opposto
se era 0 mette 1 (ricordati sempre che 0 è uguale a LOW e uguale a condizione NON ripettata)
se era "non 0" 0 (ricordati che qualunque cosa differente da zero viene valutata come HIGH o condizione rispettata)

in pratica il tuo programma dice:

dopo i primi 2 secondi
misura il tempo e salvalo in B (inutile visto che poi B non la usi mai)
inverti il valore di A
accendi o spegni l'uscita a seconda del valore di A
che non mi sembra essere quello che volevi fare

Sbaglio?

Puso:
sarà la maledidone del pulsante del vecchietto??

Sarà che la scaletta da percorrere è sempre la solita :wink:

Studiare:

  • tipi di variabili / rappresentazione dei dati
  • operazioni aritmetiche / logiche
  • esecuzione condizionata (if else switch)
  • cicli (for / while)
  • uso delle funzioni
  • uso degli array
  • un minimo, ma proprio minimo, di puntatori, che su Arduino in pratica servono solo per passare i valori per riferimento alle funzioni.

Trentacinque anni fa andava via un mese per ogni punto...