ho apportato qualche modifica al codice e tentato di fare come sul mio programma, attualmente ha due chiamate a function, leggi() e leggi2(), la prima riceve 4 numeri ASCII e li converte in un numero (senza il controllo errore, non è garantito il range 0000 a 9999 se si ricevesse dei "garbages" ), la seconda function, leggi2() invece è pensata per il comando b che da come so, usa un'unico numero e quindi aspetta solo questo. Basterà prevedere a priori la struttura di comandi in RX e creare le function necessarie, poi si aggiunge nel ciclo if...else if (o in un switch case) cosa fare al ricevere tale carattere comando.
void loop(){
if (Serial.available() )
{ ser=Serial.read();
if(ser=='a')
{
leggi();
}
else if (ser== 'b')
{
leggi_b();
}
else if (ser== 'c') //aggiungere qui altri comandi e chiamare le function corrispondenti, in questo caso, ho aggiunto un'utile chiamata a freeRam()
{
Serial.println(freeRam());
}
}
}
//*****************************************************
void leggi(){ //legge 3 caratteri numerici ASCII sulla seriale, li converte a integer
//Serial.println("OK, a premuto");
delay(50); ////<------------------questo delay è indispensabile!!
if (Serial.available()) {
a = Serial.read()-48; //viene sottratto 48 per rientrare nel range dei caratteri numerici ASCII (0=49,1=50....9=58)
b = Serial.read()-48; //senza un sistema di check errore, se il sistema ricevesse una "a" per esempio,
c = Serial.read()-48; //verrebbe calcolato come "65"... x1000 o x100 o x10 o x1, quindi errato.
d = Serial.read()-48;
delayTime = (a*1000)+(b*100)+(c*10)+(d*1); //se si deve ricevere 1, dalla seriale dovrà arrivare 0 0 0 1
Serial.println(a); //debug
Serial.println(b); //debug
Serial.println(c); //debug
Serial.println(d); //debug
Serial.println(delayTime); //debug
}
}
//******************************************************
void leggi_b(){ //questa function riceve un singolo carattere numerico, per esempio: 0=stop, 1=Forrard, 2=Reverse...
//Serial.println("OK, b premuto");
delay(5);
if (Serial.available()) {
x = Serial.read()-48;
Serial.println(x);}
}
//*******************************************************
int freeRam () {
extern int __heap_start, *__brkval;
int v;
return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
}
Ho aggiunto il comando "c" per un'utile chiamata a freeRam(), ovviamente è solo un'esempio. in questo caso, vi sono liberi 1823 bytes su 2048 bytes. Se si ottimizza occupa sicuramente meno (nel mio sketch le variabili sono tutte global).
ok, la funzione freeRam() l'ho trovata in giro, serve per conoscere grossolanamente, la quantità di RAM libera, ma va invocata in diverse parti dello sketch, tipo alla fine di un loop() o magari dentro delle functions che gestiscono molti dati locali per esempio, così ti possono dare un'idea della RAM libera durante tutta l'esecuzione dello sketch, così se in qualche parte si blocca, e sospetti sia la RAM esaurita, potresti verificare se e così o no. Mi e stata molto utile per capire che devo ottimizzare un pò, riducendo l'uso di variabili globali in favore di quelle locali (ed imparare a passarle per valore o riferimento, ma ancora non so farlo bene) o usando variabili byte invece di int se i valori da memorizzare non superano il range 0-255, infatti, spesso, mi capita di lavorare con valori che non superano 255 e non sono negativi, quindi in quel caso, le dichiaro byte, occupano meno RAM anche se global. Quelle che occupano in assoluto più bytes di RAM e FLASH sono le variabili string!.
PaoloP, grazie dello schema, molto interessante, sapevo che le MCU non hanno la RAM esterna (forse solo le CPU dei computer?) ma capisco poco, o almeno, non mi è chiaro del tutto, potresti spiegare per favore? a quanto ho visto, la prima zona è per le variabili static e global, la seconda per quelle local ecc e poi non ci ho capito quasi nulla! la function freeRam() l'ho trovata se non ricordo male, sul Reference/Playground ufficiale, e spiegava che serve ad avere un'idea della RAM libera, ma vedendo questo schema ed analizzando la function (per quel poco che ci capisco), la zona "misurata" non è sul totale della RAM, ma su una porzione di essa, ho capito bene o sto solo farneticando?
all'inizio della SRAM viene messa l'area .data, che contiene le variabili dichiarate nel programma
dopo c'è l'area .bss/.init: essa contiene le variabili non inizializzate
a seguire c'è l'HEAP, che contiene i dati per l'allocazione dinamica della memoria. L'HEAP cresce verso l'alto.
dopo l'HEAP c'è un'area vuota che funge da "materasso"
infine c'è lo STACK, collocato a partire dall'ultima locazione di memoria a crescere verso il basso, verso l'HEAP. Nello STACK ci vanno a finire non solo i punti di ritorno per i salti alle subroutine ma anche i registri di sistema durante le ISR nonché le variabili create localmente.
Sia lo STACK che l'HEAP si espandono nell'area materasso. Se queste 2 aree vengono a collidere sovrapponendosi, il micro crasha.
Grazie Leo72! la risposta più chiara e concisa che ho visto in giro per spiegare il concetto!
Quindi la function freeRam() non mi da la RAM libera di tutta quella disponibile ma solo quella compresa tra il Heap e lo STACK giusto? mi sai dire quanto è grande lo spazio .data e .bss per favore sull'arduino? dal datasheet Atmel, non mi è chiaro:
Figure 8-3. Data Memory Map
32 Registers 0x0000 - 0x001F
64 I/O Registers 0x0020 - 0x005F
160 Ext I/O Reg. 0x0060 - 0x00FF
Internal SRAM 0x0100(inizio)
(512/1024/1024/2048 x 8) 0x02FF/0x04FF/0x4FF/0x08FF (fine in base alla capacità della SRAM, l'ultimo è il 328P dell'arduino uno)
non mi è chiaro chi sia chi, ma da come vedo, i 2048 bytes sono separati dagli altri registri, vero? o sto mi sto confondendo, forse le aree .data, .bss heap e stack sono all'interno di quei 2048 bytes ed i registri sono un'altra cosa? a me sembra più logico così. Con i picaxe sapevo solo che avevo a disposizione un determinato numero di byte per dichiarare variabili e le dovevo amministrare sapientemente per far funzionare il tutto, spesso creavo forme di riciclarle (copiandole in una zona di RAM libera apposita e leggendola quando mi servivano) ma qui è più complicato. Scusate la mia ignoranza e/o confusione!! :~
Attenzione a non confondere la memoria fisica degli AVR con l'utilizzo che ne viene fatto da uno specifico compilatore, ovvero quello schema è valido esclusivamente per avr gcc, altri compilatori C e/o linguaggi usano schemi diversi.
La SRAM dedicata all'utente è al "netto" della memoria utilizzata dal micro, difatti se vedi l'indirizzo di partenza è $100, non è $00.
.data e .bss puoi saperle usando il tool avr-size. Nel link che ho messo ad un mio articolo sull'analisi dell'occupazione della memoria, spiego anche come usarlo.
barlettaag:
Scusate ma ... male che vada ... c'è il rischio di bruciare l'arduino , o semplicemente crasha e quindi basta riavviare e cambiare il codice ?
Si blocca o si resetta. Non può bruciare.
Se ti riferisci a quei video che si trovano su Youtube sono ovviamente dei montaggi
Fin' ora, l'unica cosa che so per esperienza, è che si bruciano solo se in un pin ADC/digitale (o qualsiasi a sto punto) malauguratamente gli viene alimentato a 12V!! alcuni anni fa ho avuto una doppia "disgrazia" con dei moduli Basicx BX24, avevo una breadboard alimentata con un trasformatore da parete a 12v, poi un regolatore di tensione a 5v ed i canonici condensatori e quindi avevo da un lato della breadboard la linea 12V - GND e dall'altra 5V - GND, poi dalla breadboard (lato 5V) alla scheda del modulo Bx24 che ha già onboard un regolatore tensione (5V), tutto ok per più di un paio d'anni, poi un giorno, stavo spostando uno dei fili volanti di un channel ADC, malauguratamente mi è caduto... dove? esattamente dentro uno dei pin della 12v sulla breadboard!! MANNAGGIA !!! BX24 defunto. Ne comprai un'altro e questo fece la stessa fine dopo pochi mesi, da lì ho imparato la DURA lezione, adesso ho schermata la zona delle tensioni over 5V, con tanti pin dove poteva entrarci e non fare danni. Ma proprio nella fila dei 12V doveva capitare? e su due MCU (dal costo complessivo di oltre 120 €!!) ?
Bèh, e per questo che si dice, sbagliando s'impara! e che sbaglio!! Adesso con Arduino ho fatto un'altro upgrade nella sicurezza, ho un'alimentazione a 5V sulla breadboard, quindi un rischio in meno!
Janos:
Basta non spostare i fili mentre la scheda è alimentata...
Certamente, ma se tra una selva di fili volanti, capita di far spostare uno dalla sua posizione? Purtroppo può capitare, togliere l'alimentazione ogni volta che si apporta una modifica non è sempre una scelta pratica, ma effettivamente, riduce i pericoli, per fortuna, ora il pericolo è stato eliminato alla base, le breadboard sono alimentate a 5V quindi nessun pericolo per la UNO, qualche pericolo concreto per la DUE ma per ora non me ne preoccupo molto, no ho ancora una DUE, anzi, per ora l'ho accantonata propio per la sua "diversità" di alimentazione rispetto ai canonici 5V.