La curiosità è nata dal fatto che avendo una Mega con 70 pin utilizzabili, mi chiedevo se era davvero utile convertire tutti i cicli for di digital.write(x,0) e digital.read in PORTxx |= _BV(PORTxx); e PINxx
e direi proprio di si!! il tempo si dimezza quasi, un programma molto lungo, va ottimizzato al massimo, sapevo che era + veloce la manipolazione delle porte, ma non sapevo quanto
unsigned long preMillis=0;
unsigned long counter=0;
void setup(){
Serial.begin(9600);
}
void loop (){
//----------------------------------
/* accendi il led */ //44
//PORTL |= _BV(PORTL5);
/* spegni il led */ //44 questo lo fa 76.123/sec
//PORTL &= ~_BV(PORTL5);
//----------------------------------
//----------------------------------
digitalWrite(44,1);
digitalWrite(44,0);// questo lo fa 38.324/sec
//----------------------------------
counter++;
if(millis() - preMillis >= 1000)
{
preMillis = millis();
Serial.println((String)counter);
counter=0;
}
}
La lentezza della digitalWrite è rinomata. La digitalWrite esegue diversi controlli, primo fra tutti vedere se stai lavorando su un pin PWM, nel caso disattiva il corrispondente segnale ecc... Alla fine tutta 'sta roba la paghi.
però questo programma non è esattamente scevro di operazioni... incrementa un long chiama la millis (che chissà quante operazioni fa) , sottrae due long, compara... quanto impiega una funzione millis?
la seriale poi ... presumo venga gestita ad interrupt?
leo72:
La lentezza della digitalWrite è rinomata. La digitalWrite esegue diversi controlli, primo fra tutti vedere se stai lavorando su un pin PWM, nel caso disattiva il corrispondente segnale ecc... Alla fine tutta 'sta roba la paghi.
Certo che è rinomata, ma sono quei miseri 80.000 cicli a vuoto che mi lasciano perplesso, tu stesso in qualche post non ricordo quale, hai detto che vengono impegnate librerie che non vengono usate, vabbè era un appunto nulla di grave
pablos:
Bhe la seriale è l'unica istruzione che impegna il micro alla fine del secondo trascorso
si quella non mi preoccupa... però sta all'ascolto sulla seriale... questo mi preoccupa di più ma non tanto...
imho il problema è il millis... e vorrei (ma ora no posso) fare un esperimento... 80000?
capito cosa vorrei fare? quanti millis impiega ad incrementare una variabile e testare la stessa 100000 volte?
vorrei quasi scommettere che questo ciclo te lo fa in un 10-15 clock... 1 megahz... stasera provo.
Le due scritture dirette su PORTB richiedono solo 125 ns, come evidenziato nell'immagine allegata della misura sul pin 13 con un DSO, mi è toccato fare una foto al volo della schermata perché vicino al pc ho il Tektronix per il quale non tengo installato il software per scaricare le schermate.
Come si vede la frequenza per questo loop è 1.06 MHz, il periodo necessario per la sola loop, è di 875 ns - 62.5 ns = 812.5 ns = 13 cicli macchina.
Comunque no ha molto senso parlare di massima velocità della loop visto che in realtà dipende da quello che fai al suo interno a cui devi sommare 875 ns ( ~1.43 MHz) per la sua durata reale
@Astro, mi rendo conto che non è proprio a vuoto, ma tu hai un oscilloscopio eheheh io non potevo farlo se non contando approsimativamente i secondi, grazie per la prova a banco (o l'avevi già fatta )
é anche molto probabile che il mio millis che parte al reset è già abbastanza avanti, il valore di paragone che uso è comunque una costante dove lo stesso errore viene riportato ogni volta che aggiungo un pezzetto di prova.
Il mio programma su arduino 2560 è diventato quasi 2000 righe con un 60k circa occupati e ho notato tristemente che nel loop ci passa circa 23 volte al secondo cercavo di capire facendo piccoli pezzi alla volta quale fosse la procedura migliore per migliorarne le prestazioni
astrobeed:
Con cosa l'hai alimentato durante le feste ?
Sicuramente si è ingrassato il quarzo e adesso è in sovrapeso pertanto corre più lento
La UNO ha 16Mhz, la Mega 16Mhz i due sistemi internamente sono un po' diversi da gestire, nella 2560 ci sarà molto da fare prima di darmi il risultato o ci sono dei pelandroni ]:D, se facciamo confronti con schede differenti, i risultati saranno diversi
ps .. ho provato anche con 115200 è uguale il risultato 0.495 anche Serial.begin nel setup, cambia nulla
Può darsi che la mega debba fare più cose e quindi più lenta tu di quale MCU parli?
si ma continui a misurare i millisecondi mentre attivi la seriale... prima fai la differenza (e la relativa chiamata a funzione millis che non si è capito quanto dura) e poi attivi quello che vuoi e stampi quello che vuoi.
Proporrei anche un ciclo molto molto più lungo...
unsigned int cont = 0;
unsigned long tempoInizioMs;
setup(){
Serial.begin(9600); //mi aspetto molti meno interrupt/s dalla seriale
tempoInizioMs = millis();
}
loop(){
cont++;
if (!cont){ //vediamo quanto impiega a overfloodare!
Serial.println( millis()-tempoInizioMs );
tempoInizioMs = millis();
}
}
ATTENZIONE: la prima lettura non è "accettabile" perchè c'è il "salto" da setup a loop, anche questo mangia cicli. Come insegna astro (un post moolto tempo fa) anche il richiamo ciclico della funzione loop mangia cicli; confrontate il risultato con questa! (il tempo mabngiato equyivale a salvare lo stato macchina nello stack etc..
unsigned int cont = 0;
unsigned long tempoInizioMs;
setup(){
Serial.begin(9600); //mi aspetto molti meno interrupt/s dalla seriale
}
loop(){
tempoInizioMs = millis();
while(1){
cont++;
if (!cont){ //vediamo quanto impiega a overfloodare!
Serial.println( millis()-tempoInizioMs );
tempoInizioMs = millis();
}
}
}
noterete anche che sempre per il motivo a richiamo funzione, l'errore del primo calcolo sarà più piccolo quì, poichè l'esecuzione di while(1){ è molto più leggera di un richiamo a funzione.
altro test: la mega ha molti più pin "speciali" e quindi più potenziali interrupt. provate a usare noInterrupts(): però attenzione ad attivarli per usare la seriale! quindi si fa il calcolo della millis, si riattivano l'interrupt, si stampa, si fa una serial.flush() (e una delay, la flush svuota il buffer software ma non l'hardware, è un issue che ho visto su github qualche giorno fa), si ridisattivano gli interrupt, si fa tempoInizioMs = millis(); e si ricomincia.
unsigned int cont = 0;
unsigned long tempoInizioMs;
void setup(){
Serial.begin(9600); //mi aspetto molti meno interrupt/s dalla seriale
tempoInizioMs = millis();
}
void loop(){
while(1){
cont++;
if (!cont){ //vediamo quanto impiega a overfloodare!
Serial.println( millis()-tempoInizioMs );
tempoInizioMs = millis();
};
};
}
senza while 494-495ms di media.
con il while... mi stampa tutti 0... boo... adesso indagooo