Avendo un valore numerico di 4 o 5 cifre, dovendo mutiplexare dei display a 7 segmenti, qual è il sistema più veloce per dividerlo in cifre? Ho fatto come segue, ma si può fare senza divisioni? Trasformando il valore in stringa, dividendo e ritrasformando in numeri è più veloce o più lento?
Fallo a rovescio: scrivi dalla cifra 5 alla cifra 1, ogni volta dividendo e facendo modulo solo di 10, se lo fai in un ciclo for con tre righe te la cavi. Fai lo stesso numero di divisioni ma tutte per lo stesso divisore, forse il compilatore ottimizza, comunque passare per le stringhe certamente rallenta di molto, ammennocchè non ti servano direttamente i caratteri invece delle cifre
Ma se devi visualizzare solo numeri interi non ha molto senso trasformare in stringa.
Io l'ho fatto ma avevo altre necessità come ad esempio visualizzare il nome di parametri composto da 3 caratteri, es: StP, CtS ecc, dovevo sia visualizzare interi con e senza segno oltre a numeri con la virgola in quel caso ho dovuto fare in modo che il buffer del display accettasse solo codici corrispondenti a simboli visualizzabili e mi pare avessi solo 4 digit. Sicuramente è più rapido e meno costoso non usare conversioni da numero a stringhe.
Non so... dalle cifre ai caratteri c'è di messo solo una tabella, non una divisione!
Sto facendo delle prove. Il programma che ho pubblicato impiega 148us.
Purtroppo mi sono messo a combattere con un 328p che anni fa avevo impostato per errore su clock esterno e che ora ho recuperato mandandogli 16MHz esterni e sono rimasto indietro con l'esperimento!
unsigned long int n = 12345;
unsigned long int x = n;
char a[(sizeof x) + 1] = {0};
void setup(void)
{
for (int i = 0; i < sizeof n; i++)
{
a[i] = ' ';
}
// il lavoro vero:
{
// ambiente locale per le variabili
int i = sizeof x;
while (x && i) // così garantisce anche la soppressione degli zeri superflui
{
a[i] = x % 10;
x = x / 10;
i--; // conteggio delle cifre
}
}
// fine del lavoro vero
}
void loop(void)
{
}
la parte di scomposizione è tra le righe "lavoro vero"
Speravo che ci fosse qualche metodo geniale per farlo...
Ho usato il modulo e funziona. Ho dovuto armeggiare un po' con il multiplexer, perché faceva battimento con i 100ms di misura dell'interrupt, pur avendo inserito l'mpx() anche durante quei 100ms di attesa. Tra poco vi faccio vedere il risultato.
Quei 4µs non mi convincevano, così ho voluto misurare col frequenzimetro:
// 150052.4 Hz (6.66 µs ciclo base senza operazioni)
L010:
digitalWrite(13, 1);
digitalWrite(13, 0);
goto L010;
// 8611.4 Hz (116 µs procedura Datman)
L010:
digitalWrite(13, 1);
cifra[1] = y / 10000;
y = y % 10000;
cifra[2] = y / 1000;
y = y % 1000;
cifra[3] = y / 100;
y = y % 100;
cifra[4] = y / 10;
cifra[5] = y % 10;
digitalWrite(13, 0);
goto L010;
// 22820.1 Hz (43.8 µs procedura mia)
L010:
digitalWrite(13, 1);
cifra[5] = y % 10;
y = y / 10;
cifra[4] = y % 10;
y = y / 10;
cifra[3] = y % 10;
y = y / 10;
cifra[2] = y % 10;
cifra[1] = y / 10;
digitalWrite(13, 0);
goto L010;
Al netto del tempo del ciclo base abbiamo 109.4 µs procedura Datman e 37 µs la mia, però non mi spiego perché con lo stesso identico numero di divisioni e moduli si ottengano risultati così differenti.
Risultati troppo diversi, ho rifatto le misure generando un'onda quadra invece di impulsi e adesso corrispondono alle tue, probabilmente il frequenzimetro con segnali troppo asimmetrici si perdeva qualcosa.
// 13.01 µs (tolta la durata delle digital read/write)
L010:
cifra[5]=x%10;
x=x/10;
cifra[4]=x%10;
x=x/10;
cifra[3]=x%10;
x=x/10;
cifra[2]=x%10;
cifra[1]=x/10;
digitalWrite(13, !digitalRead(13));
goto L010;
// 37.91 µs (tolta la durata delle digital read/write)
L010:
cifra[1]=x/10000;
x=x%10000;
cifra[2]=x/1000;
x=x%1000;
cifra[3]=x/100;
x=x%100;
cifra[4]=x/10;
cifra[5]=x%10;
digitalWrite(13, !digitalRead(13));
goto L010;
// 99.64 µs (tolta la durata delle digital read/write)
L010:
sprintf(cifra2, "%d", x);
digitalWrite(13, !digitalRead(13));
goto L010;