Aiuto codice...

Ciao a tutti. Sto cercando di capire a che frequenza massima posso acquisire dei canali analogici. La mia idea era quella di acquisire un centinaio di campioni, inclusi i microsecondi e poi di salvare il tutto su una sd. Il problema comincia quando tento di richiamare i dati dagli array. Ho scritto:

for (uint8_t i = 0; i < 100; i++) {
a0*=analogRead(0);*
_ a1*=analogRead(1);_
_ a2=analogRead(2);
a3=analogRead(3);
a4=analogRead(4);
te=micros();
}
for (uint8_t a = 0; a < 10; a++) {
file.print(";");
file.print(a0[a]);
file.print(";");
file.print(a1[a]);
file.print(";");
file.print(a2[a]);
file.print(";");
file.print(a3[a]);
file.print(";");
file.println(a4[a]);
}*

La cosa strana è che se non rimuovo il secondo "for", il programma non parte neanche e non arriva neppure a leggere il for. Per fare un esempio, se scrivo: Serial.print("qualcosa") prima del secondo for o addirittura all'inizio del programma, questo non appare mai. Se invece lascio il for con i file.print, ma tolgo le variabili array (e ci metto qualunque altra cosa), funziona tutto. Cosa ho sbagliato?
Grazie e scusate l'ignoranza_

se il tuo codice è molto lungo e usi improprimante le stringhe ti si finisce la memoria.

Il codice che hai postato è il codice intero o è solo un frammento?

ciao

Il codice è solo un frammento. Il resto è la libreria fat16 che serve per utilizzare le SD. Ho pensato anche io potesse essere un problema di memoria e ho fatto diverse prove a riguardo. Ho provato a ridurre a 10 le dimensioni degli array, per esempio. E non cambia niente. Inoltre io penso che la memoria sia occupata dalla variabile, non dal suo utilizzo. A me il problema nasce dal richiamare gli array, mentre se li definisco e associo i valori, ma poi non tento di scriverli sulla sd (però rimangono in memoria), funziona tutto. Non è che ho commesso un qualche errore di sintassi o di concetto?

Per capire se hai sufficiente memoria RAM in Arduino devi sapere quanta memoria viene utilizzata dal BootLoader e dalle librerie in esso contenute quando e se le utilizzi (e sono quelle della seriale, dei tempi, ecc .. ovvero di tutte le funzioni NON stadard C++ che sono state aggiunte ad Arduino), oltre alle librerie che poi includi a livello di programma.
Oltre a questo dovresti capire quanto stack arrivi ad utilizzare, perchè: ogni volta che chiami una funzione lo usi, è usato anche quando una chiamata da interrupt interviene ma anche da chiamate di funzioni all'interno di funzioni (o classi) è un ulteriore "consumo" dello stack in ram.

Ci sono funzioni che ti possono aiutare, come ad esempio: Arduino Playground - AvailableMemory

Ma ricorda che sei vai in overflow di stack oppure, utilizzando dei puntatori (un array lo è di fatto e puoi superare il limite dimensionale assegnato senza che nessuno ti dica nulla... ) sovrascrivi locazioni già utilizzate, i risultati sono incontrollabili ed imprevedibili.

E' solo il programmatore che può tenere sotto controllo l'intera situazione, cioè: tu :wink:

Concordo anch'io sul problema di memoria , secondo me la prima cosa da fare è evitare le dichiarazioni dinamiche delle variabili all'interno della funzione , ma lavorare piu' possibile con variabili definite global ... la differenza è che non ti vanno ad intaccare lo stack e andare in overflow su quello .
Quindi nei cicli for usa variabili globali , dichiara quindi i tuoi counter all'inizio del codice e poi usalo nelle funzioni , non è una programmazione elegante ma è l'unico modo quando hai risorse limitate disponibili.
Un saluto
Roberto

Ciao a tutti.
Sto facendo ulteriori prove per capire e credo abbiate ragione che si tratta di problemi di memoria o di stack.
Ho riscritto un programma molto piu sempilce. Volevo inserire in memoria 5 array di 100 elementi (i micros e 4 canali analogici) e poi visualizzarli sulla seriale. Impossibile! Era già oltre le capacità di arduino?
L'unico modo che ho trovato è stato ridurre a 10 gli elementi delle 5 array e rimuovere il cicli for e sostituirli con il codice scritto a mano. Quindi il tutto è diventato:

int dato0[9];
int dato1[9];
int dato2[9];
int dato3[9];
int dato4[9];
unsigned long tempo[9];

void setup() {
Serial.begin(9600);
Serial.print("tempo");
}

void loop()
{
tempo[0]=micros();
dato0[0]=analogRead(0);
dato1[0]=analogRead(1);
dato2[0]=analogRead(2);
dato3[0]=analogRead(3);
dato4[0]=analogRead(4);
tempo[1]=micros();
dato0[1]=analogRead(0);
dato1[1]=analogRead(1);
dato2[1]=analogRead(2);
dato3[1]=analogRead(3);
dato4[1]=analogRead(4);
...
...
dato3[9]=analogRead(3);
dato4[9]=analogRead(4);

Serial.println(tempo[0]);
Serial.println(tempo[1]);
Serial.println(tempo[2]);
Serial.println(tempo[3]);
Serial.println(tempo[4]);
Serial.println(tempo[5]);
Serial.println(tempo[6]);
Serial.println(tempo[7]);
Serial.println(tempo[8]);
Serial.println(tempo[9]);
Serial.println("------------------------------------------------------------");
}

Non mi sembra un programma tanto complesso. Possibile che non ci sia memoria sufficiente per scrivere 5 array di 100 elementi? Oppure sbaglio io qualcosa?

Inoltre ho un risultato strano. L'uscita in microsecondi è la seguente:

46203041
46248256
46248816
46249376
46249936
46250496
46251056
46251616
46252176
46252827

La cosa strana (si ripete tutte le volte) è che il primo elemento dell'array necessita oltre 40millisecondi, mentre tutti i successivi sono intorno a 0,56ms. E' normale?

5 array di 100 elementi int corrispondono esattamente a 5 * 100 * 2 byte di ram, ovvero 1000byte, praticamente quasi 1Kb (che conta 1024byte).
Ora se stai usando un ATmega168 hai a disposizione solo 1Kbyte, con l'ATmega328 ne hai a disposizione 2Kbyte (nei quali però devi comunque far stare anche le altre variabili e sopratutto lo stack!!!)

Come vedi il problema è proprio quello della memoria!

Il mio consiglio, se non ti serve la precisione di 10Bit delle conversioni A/D, è quello di ridurle a 8bit (1byte), in questo modo dimezzi l'occupazione dei tuoi array (che occuperebbero "solo" 500Byte). Per ridurre un valore a 10bit contenuto in un int (che usa 16bit) procedi in questo modo:

char valori[100]; //l'array di 100byte
valori[0] = analogRead(0) >> 2; //riduco la precisione eliminando i due bit meno significativi

L'alternativa è quella di adottare una memorietta esterna via i2C nella quale passare i dati sino a quando non li puoi scaricare all'esterno via seriale...

Aggiungo:

P.S. per la differenza nei tempi di conversione dovresti guardare di mettere le tue letture sotto interrupt con un valore di priorità superiore a quello della seriale, altrimenti può accadere in qualsiasi momento che il tuo programma venga interrotto per eseguire funzioni in background (come quelle della seriale) con conseguenti ritardi che non puoi controllare :wink:

Ciao, kokiua.
Grazie mille per la spiegazione più che esauriente.
Hai idea di quale velocità sia possibile, salvando nella memoria i2C? Io sto tentando di superare la lentezza nello scrivere sulla SD e non vorrei ritrovarmi il problema con la memoria esterna.

Per quanto riguarda invece il tempo necessario a acquisire il primo elemento dell'array, come è possibile che questo sia influenzato dalla seriale? Come vedi dal listato, il programma procede in questo modo:

  • acquisisce i 10 elementi dei 5 array
  • manda alla seriale i 10 elementi di un array (non mi serviva visualizzare anche gli altri 4).
  • ricomincia da capo.

Come è possibile che la scrittura in seriale (che è lenta) rallenti l'acquisizione del primo campione? Io capisco che tra l'ultimo campione di una serie e il primo della serie successiva passi tanto tempo (dovuto alla visualizzazione), ma non mi rendo conto di come sia possibile che tra il primo elemento dell'array e il secondo passi più tempo che tra tutti gli altri.

Grazie
Davide

Temo che il problema sia analogo... Per fare un buon lavoro l'unica è quella di adottare un µProcessore che abbia maggiore memoria (come l'Arduino Mega) o che possa indirizzare in memoria esterna, così da aggiungere in parallelo (su bus) una RAM standard magari di 16 o 32 Kbyte e oltre. In questo modo puoi archiviare alla massima velocità del sistema e scaricare comodamente a velocità inferiori.