Go Down

Topic: [Risolto] Blink con millis() lettura PPM con pulseIn() Ritardi e Problemi (Read 5 times) previous topic - next topic

leo72


google ricerca "Arduino police led millis"
http://www.cmiyc.com/tutorials/arduino-example-police-lights-with-millis/
http://www.cmiyc.com/blog/2011/01/06/millis-tutorial/
http://pastebin.com/mX2HLVBN

Direi perfetto  ;)

gingardu

#16
Sep 14, 2012, 08:29 am Last Edit: Sep 14, 2012, 08:38 am by GINGARDU Reason: 1

Led 1          Led 2          Tempo
off              off              0
on               off              100
off              off               200
on               off              300
off              off              400
off              on               500
off              off               600
off              on               700

nessun altro utilizzo per millis
il resto è tutto ricezione ppm ed esecuzione

sto facendo varie prove, ma ogni cosa faccio non riesco ad uscire dalla prima istruzione, nel senso che se gli dico di lampeggiare ogni 100 ms non riesco a fargli fare una pausa di 1000 ms e poi ricominciare il ciclo di 100



un sistema abbastanza comprensibile per chi è nuovo  e questo,
non c'e molto da spiegare (anche se millis non l'ho capito bene nemmeno io)

se millis()  si trova entro un determinato tempo accende o spegne  il led

ovviamente se vuoi modificare il tempo di accensione mettiv quello che vuoi,
l'importante che alla fine del ciclo metti

if (millis()>1400) timer0_millis = 0;
questa riga appena millis () arriva  a 1400  (1,4 sec)  porta a zero millis ()
e tutto ricomincia da capo

(ovviamente al posto di 1400 devi mettere  il tempo totale del ciclo se lo modifichi i parametri di lampeggio)



ps:
sicuramente ci saranno anche altri sistemi  per ottenere lo stesso risultato


Code: [Select]
extern unsigned long timer0_millis;

void setup() {

 pinMode(12, OUTPUT);
 pinMode(13, OUTPUT);
digitalWrite(13,LOW);
digitalWrite(12,LOW);
}

void loop(){

 if (millis()>100 && millis()<200) digitalWrite(13,HIGH);
 if (millis()>200  && millis()<300) digitalWrite(13,LOW);
 
 if (millis()>400 && millis()<500) digitalWrite(13,HIGH);
 if (millis()>600  && millis()<700) digitalWrite(13,LOW);
 
 if (millis()>700 && millis()<800) digitalWrite(12,HIGH);
 if (millis()>900  && millis()<1000) digitalWrite(12,LOW);
 
 if (millis()>1100 && millis()<1200) digitalWrite(12,HIGH);
 if (millis()>1300  && millis()<1400) digitalWrite(12,LOW);

 

 if (millis()>1400) timer0_millis = 0;
}
Le cose si possono considerare facili in due casi: quando le si conosce bene o quando non le si conosce affatto...

leo72


anche se millis non l'ho capito bene nemmeno io

Cos'è che non ti è chiaro?
Cerco di riassumerti brevemente.
Millis() altro non è che una funzione che restituisce il numero di millisecondi dall'avvio dell'Arduino. E' un contatore a 32 bit che viene incrementato da una porzione di codice inserita all'interno della ISR che gestisce l'overflow del timer 0.
Chiamando millis() hai indietro un valore numerico, un contatore temporale. E' come "leggere" l'orario su un orologio che ha solo un'unità di misura, i millisecondi appunto.

Quando si fa un controllo tipo con un if sul valore di millis non si fa altro che fare un check sul valore che assume una variabile. Se tu leggi una porta analogica e devi compiere una certa operazione se la lettura è superiore ad X, fai un semplice:
if (analogRead(porta) > X) {  .... }

Con millis() fai lo stesso. Chiedi a millis() il valore del contatore di millisecondi ed agisci di conseguenza. Esempio:
if (millis() > 1000) { ....  }
Ovviamente questo codice ha poco senso perché verrà usato solo 1 volta, esattamente 1 secondo dopo l'avvio dell'Arduino. Questo perché il valore del contatore di millisecondi cresce continuamente e tu saresti un mago se tu potessi sapere in ogni istante che valore assume. Perciò si ricorre al semplice trucco di fissare una specie di "istante zero" e calcolare il tempo a partire da quell'istante. Come si fissa l'istante zero? Facendo una semplice lettura di millis() e poi aggiungengo l'intervallo desiderato. Se ad esempio vogliamo che una data azione sia eseguita ogni 5 secondi, si farà un qualcosa del genere:

Code: [Select]
unsigned long temporizzatore; //creo una variabile per contenere il valore di millis()
void setup() {
  temporizzatore = millis(); //assegno a temporizzatore il valore attuale di millis() - creo cioè l'istante zero
}

void loop() {
  if (millis() > (temporizzatore + 5000)) { //controllo se sono passati 5 secondi dal mio istante zero
    ..... //eseguo il mio codice
    temporizzatore = millis(); //ricreo nuovamente l'istante zero
  }
  ....... //altro codice
}

Così ad ogni loop controllo se sono passati 5 secondi dall'istante zero. Se sono passati, eseguo il mio compito e poi ricreo l'istante zero da cui ricontare altri 5 secondi. E così via.

gingardu

IL fatto è che, chi è  nuovo all'argomento  ha sempre tanta confuzione  chi invece ha capito una volta per tutte una certa cosa poi avra sempre piu dimistichezza,

millis()  e una cosa che inizia e poi "scappa"  all'infinito (mai si ferma),
millis () nudo e crudo  lo si puo adoperare quasi per niente

come hai scritto tu bisogna sempre costruirgli un programmino attorno
che da solo non si puo "guardare"
Le cose si possono considerare facili in due casi: quando le si conosce bene o quando non le si conosce affatto...

Michele Menniti


IL fatto è che, chi è  nuovo all'argomento  ha sempre tanta confuzione  chi invece ha capito una volta per tutte una certa cosa poi avra sempre piu dimistichezza,

millis()  e una cosa che inizia e poi "scappa"  all'infinito (mai si ferma),
millis () nudo e crudo  lo si puo adoperare quasi per niente

come hai scritto tu bisogna sempre costruirgli un programmino attorno
che da solo non si puo "guardare"

è il prezzo (piccolo) da pagare per non bloccare il processore, a volte non serve a nulla, a volte è indispensabile :) millis si ferma, anche se gli servono un bel po' di giorni....
Guida alla programmazione ISP e seriale dei micro ATMEL (Caricare bootloader e sketch):
http://www.michelemenniti.it/Arduino_burn_bootloader.php
Guida alla Programmazione ATmega328 noP:
http://www.michelemenniti.it/atmega328nop.html
Articoli su Elettronica In:
http://www.michelemenniti.it/elettronica_in.html

DriftBoy

La questione millis si è notevolmente chiarita anche se ho ancora un paio di domande:
Code: [Select]

extern unsigned long timer0_millis;

void setup() {

  pinMode(12, OUTPUT);
  pinMode(13, OUTPUT);
digitalWrite(13,LOW);
digitalWrite(12,LOW);
}

void loop(){

  if (millis()>100 && millis()<200) digitalWrite(13,HIGH);
  if (millis()>200  && millis()<300) digitalWrite(13,LOW);
 
  if (millis()>400 && millis()<500) digitalWrite(13,HIGH);
  if (millis()>600  && millis()<700) digitalWrite(13,LOW);
 
  if (millis()>700 && millis()<800) digitalWrite(12,HIGH);
  if (millis()>900  && millis()<1000) digitalWrite(12,LOW);
 
  if (millis()>1100 && millis()<1200) digitalWrite(12,HIGH);
  if (millis()>1300  && millis()<1400) digitalWrite(12,LOW);

 

  if (millis()>1400) timer0_millis = 0;
}



questo codice è giusto quello che volevo ottenere, quindi ringrazio notevolmente per la disponibilità, ma ho un dubbio:
l'istruzione timer0_millis = 0 è un istruzione propria di millis che permette di dargli un valore?

in quanto in quest'altro codice comprendo il funzionamento di temposizzatore = millis()  e cioè che ad ogni loop temporizzatore prende il valore di millis e facendo la differenza ritroviamo gli stessi valori dell'if :
Code: [Select]
unsigned long temporizzatore; //creo una variabile per contenere il valore di millis()
void setup() {
  temporizzatore = millis(); //assegno a temporizzatore il valore attuale di millis() - creo cioè l'istante zero
}

void loop() {
  if (millis() > (temporizzatore + 5000)) { //controllo se sono passati 5 secondi dal mio istante zero
    ..... //eseguo il mio codice
    temporizzatore = millis(); //ricreo nuovamente l'istante zero
  }
  ....... //altro codice
}


mentre timer0_millis = 0 non capisco proprio come funzioni

gingardu

#21
Sep 14, 2012, 07:11 pm Last Edit: Sep 14, 2012, 07:20 pm by GINGARDU Reason: 1

La questione millis si è notevolmente chiarita anche se ho ancora un paio di domande:
Code: [Select]

extern unsigned long timer0_millis;

void setup() {

 pinMode(12, OUTPUT);
 pinMode(13, OUTPUT);
digitalWrite(13,LOW);
digitalWrite(12,LOW);
}

void loop(){

 if (millis()>100 && millis()<200) digitalWrite(13,HIGH);
 if (millis()>200  && millis()<300) digitalWrite(13,LOW);
 
 if (millis()>400 && millis()<500) digitalWrite(13,HIGH);
 if (millis()>600  && millis()<700) digitalWrite(13,LOW);
 
 if (millis()>700 && millis()<800) digitalWrite(12,HIGH);
 if (millis()>900  && millis()<1000) digitalWrite(12,LOW);
 
 if (millis()>1100 && millis()<1200) digitalWrite(12,HIGH);
 if (millis()>1300  && millis()<1400) digitalWrite(12,LOW);

 

 if (millis()>1400) timer0_millis = 0;
}



questo codice è giusto quello che volevo ottenere, quindi ringrazio notevolmente per la disponibilità, ma ho un dubbio:
l'istruzione timer0_millis = 0 è un istruzione propria di millis che permette di dargli un valore?
mentre timer0_millis = 0 non capisco proprio come funzioni


ti rispondo per quanto riguarda uil codice che ho scritto


timer0_millis = 0  semplicemente porta il timer millis proprio a zero lo fa partire da capo
(ci deve essere anche la riga    extern unsigned long timer0_millis;     in alto nello sketc per funzionare)

non si blocca sia chiaro semplicemente riparte da capo

ecco perche ti avevo chesto se millis ()  era adoperato per qualcos'altro,

se nello sketch  che ti ho scritto aggiungi if (millis > 3000) digitalWrite (7, HIGH)

questa cosa non succederà mai perche ogni volta che millis arriva  a 1400 riparte da zero  
Le cose si possono considerare facili in due casi: quando le si conosce bene o quando non le si conosce affatto...

gingardu



millis si ferma, anche se gli servono un bel po' di giorni....


beh...   un qualsiasi cosa che incrementa sempre   prima o poi o si resetta da solo  o blocca tutto
e solo questione di tempo  (o molto tempo)  per saturare  l'harware che ha a disposizione 

Le cose si possono considerare facili in due casi: quando le si conosce bene o quando non le si conosce affatto...

Michele Menniti

#23
Sep 14, 2012, 07:41 pm Last Edit: Sep 14, 2012, 08:04 pm by Michele Menniti Reason: 1


millis si ferma, anche se gli servono un bel po' di giorni....


beh...   un qualsiasi cosa che incrementa sempre   prima o poi o si resetta da solo  o blocca tutto
e solo questione di tempo  (o molto tempo)  per saturare  l'harware che ha a disposizione  

hai invertito i quote :D
la mia affermazione è un po' più concreta; intendo dire che millis, proprio per la sua tipologia numerica a 32 bit, dura 49,7 giorni e poi va in overflow, ma credo che semplicemente si resetti il contatore, niente blocchi...
Guida alla programmazione ISP e seriale dei micro ATMEL (Caricare bootloader e sketch):
http://www.michelemenniti.it/Arduino_burn_bootloader.php
Guida alla Programmazione ATmega328 noP:
http://www.michelemenniti.it/atmega328nop.html
Articoli su Elettronica In:
http://www.michelemenniti.it/elettronica_in.html

leo72

Perché timer0_millis = 0 funziona? Per capirlo bisogna analizzare il core di Arduino. Facendolo si vede come nel file /hardware/arduino/cores/arduino/wiring.c ci sia la spiegazione. La variabile contatore agganciata al timer 0 si chiama proprio timer0_millis, ed è lei che viene incrementata. Quando si chiama la funzione millis() viene restituito il valore di timer0_millis.

Attenzione però a cambiare in corsa il valore di timer0_millis. Se ciò viene fatto mentre la routine ISR sta aggiornando il suo valore si potrebbe incorrere in un'inconsistenza del suo contenuto. Bisogna sempre prima disabilitare gli interrupt con cli() e poi ripristinarli con sei(). Quindi il codice corretto per modificare timer0_millis è:

Code: [Select]
cli();
timer0_millis = valore;
sei();

pablos

#25
Sep 14, 2012, 10:29 pm Last Edit: Sep 14, 2012, 10:32 pm by pablos Reason: 1
Sicuro GINGARDU di aver capito a pieno come funziona la funzione millis()? Dillo se non l'hai capito nessuno te magna.
Non si ferma nulla e non si inchioda nulla, puoi soltanto rischiare che al 41 esimo giorno un if risulti falso.

Tu pensa a un contatore che va da 0 a 10.000 (facciamo una cifra più piccola) che lavora da solo senza preoccuparsi di quello che hai scritto nello sketch ...

Tu ad un certo punto dici fammi un ciclo di 200 usando la funz. millis, il contatore in quell'istante si trova per esempio a 4100, la funzione cosa fa ? si copia il valore 4100 di quell'istante controlla ad ogni passaggio a che valore è il contatore, e fa passare 200 conteggi ... quando il contatore si trova a 4100+200=4300 viene eseguita l'operazione dentro al tuo IF, finito l'IF il contatore continua ad avanzare ...

che cosa succede all'overflow o quando ci siamo vicini?
Ipotizziamo che questa seconda volta tu chieda un altra pausa da 200 ma il contatore si trova in quell'istante a 9900 (manca 100 all'overflow!) il tuo IF controllerà  se 9900+200 è = al contatore corrente fammi questa cosa, peccato che non arriverà a 10.100, quindi quell'if sarà perduto.
Però per un led non credo faccia molta differenza, credo che anche osservandolo non te ne accorga nemmeno

ciao
no comment

pablos

#26
Sep 14, 2012, 11:03 pm Last Edit: Sep 14, 2012, 11:07 pm by pablos Reason: 1
Quello che dice la leggenda dell'overflow che inchioda tutto quando viene raggiunto il valore massimo tutto si ferma non è vero in se stesso poichè riparte da zero

Ma il dubbio che mi sorge è:

sapendo che la variabile long va da -2,147,483,648 a 2,147,483,647
ipotizzando che mi trovo a 2,147,483,547 (manca 100 all'overflow) quando vado a fare la somma di 1000 per verificare se sono trascorsi i millisecondi sto facendo assumere alla variabile più di 32 bit... è in questo istante che dovremmo chiederci cosa accade, poichè non può essere prevista durante la compilazione dello sketch. Questa potrebbe essere la causa del si ferma tutto, in teoria dovrebbe nascere un errore fatale :)
Dovremmo evitarlo scrivendo 1-2 righe di controllo su questo imprevisto ... bisognerebbe provare a meno che qualcuno non lo abbia già verificato

bye
no comment

Michele Menniti


Quello che dice la leggenda dell'overflow che inchioda tutto quando viene raggiunto il valore massimo tutto si ferma non è vero in se stesso poichè riparte da zero

Ma il dubbio che mi sorge è:

sapendo che la variabile long va da -2,147,483,648 a 2,147,483,647
ipotizzando che mi trovo a 2,147,483,547 (manca 100 all'overflow) quando vado a fare la somma di 1000 per verificare se sono trascorsi i millisecondi sto facendo assumere alla variabile più di 32 bit... è in questo istante che dovremmo chiederci cosa accade, poichè non può essere prevista durante la compilazione dello sketch. Questa potrebbe essere la causa del si ferma tutto, in teoria dovrebbe nascere un errore fatale :)

beh, tre righe di codice, accendi Arduino in un angolo di casa, pazienta 50 giorni e vedi che succede :smiley-sweat:
Guida alla programmazione ISP e seriale dei micro ATMEL (Caricare bootloader e sketch):
http://www.michelemenniti.it/Arduino_burn_bootloader.php
Guida alla Programmazione ATmega328 noP:
http://www.michelemenniti.it/atmega328nop.html
Articoli su Elettronica In:
http://www.michelemenniti.it/elettronica_in.html

pablos

no comment

leo72

Il contatore è di tipo unsigned long quindi va da 0 a 2^32-1, ossia da 0 a 4294967295.
Ciò che accade in prossimità dell'overflow dipende da come hai strutturato il codice. Normalmente il codice salta il check ed esegue il task quando raggiunge nuovamente il valore impostato, dopo 49 giorni.


Go Up