Go Down

Topic: Comunicazione seriale (Read 10912 times) previous topic - next topic

barlettaag

cmq.... a chi interessa , ho modificato il codice per avere lapossibilità di mettere più comandi in una sola linea di codice utilizzando il metodo che credo si chiama "ricorsivo"[chiamare la funzione nel codice della stessa funzione (in pratica chiamare se stessi)]
Quote

void leggi()
{
  if (Serial.available() )
  {
    ser=Serial.read();
    if(ser=='a')
    {
      delay(50);
      a = Serial.read()-48;
      b = Serial.read()-48;
      c = Serial.read()-48;
      d = Serial.read();
     
     
      delayTime = (a*100)+(b*10)+(c*1);
      Serial.println(a);
      Serial.println(b);
      Serial.println(c);
     
     
      Serial.println(delayTime);
      delay(50);
      if (d == ' ')
      {
        leggi(); // ricorsione
      }
    }
    else if (ser == 'b')
    {
      delay(50);
      f = Serial.read()-48;
      d = Serial.read();
      x = f;
      Serial.println(x);
      Serial.flush();
      if (d == ' ')
      {
        leggi(); // ricorsione
      }
     
    }
   
   
   
 
 
  }

in questo modo possiamo scrivere piu comandi nella stessa riga separandoli con uno " "(spazio) ... chiaramente chiameremo la funzione leggi(); nel void loop.

PaoloP

Occhio che la ricorsione brucia risorse in fretta.
Rischi di bloccare il micro se gli arriva una serie molto lunga di comandi.

barlettaag

molto lungha quanto ? (a me servono 20 caratteri....)

leo72


molto lungha quanto ? (a me servono 20 caratteri....)

Dipende da quante risorse occupa il tuo sketch nel globale. Lo stack che serve a gestire i salti ricorsivi vive nella memoria RAM, gli stessi 2048 byte che contengono tutte le variabili del tuo programma ed i buffer seriali.

#19
Mar 17, 2013, 04:55 pm Last Edit: Mar 17, 2013, 05:07 pm by hiperformance71 Reason: 1
Interessante, ma effettivamente, chiamare se stesso troppe volte potrebbe riempire la RAM disponobile se il numero di chiamate è elevato o se si sta già a corto di RAM, nei picaxe vi era un limite al numero di gosub utilizzabili altrimenti si bloccavano, immagino sia quasi la stessa cosa.

io invece lo avevo risolto creando una function ->Rx_Data() che ha una struttura pensata in base alla ricezione di di 3 cifre (char numerico ASCII) ogn' una, questa function assegna alla variabile ->Value il valore ricevuto, il programma da cui ti ho mandato degli spezzoni,  consta (per ora) di 15 comandi diversi, alcuni ricevono solo 1 numero compreso tra 000 e 999, altri ne hanno 4 numeri da 000 a 999, altri ne hanno 8 numeri da 000 a 999 ed altri ne avranno fino a 256 (una matrice di 16x16) sempre da 000 a 999 (quest'ultima parte no l'ho ancora realizzata).   E per questo che ho quel grado di complessità, come detto nei post precedenti, magari un programmatore esperto lo farebbe molto meglio di me (io sto imparando!), per me sta bene così (per ora), magari non è perfetto, ma funziona e ci capisco tutto, così in caso di ampliamenti o modifiche future, ci capirò.  

ciao.

PS. attualmente questo mio programma (non completo) occupa 700 linee di codice, compilato occupa 9700 bytes (tanti, devo "tagliare" o rischio che il resto non mi entra) e mi tiene liberi 900 bytes di RAM (troppi pochi considerando tutto quello che ci manca!) ma tieni presente che uso solo variabili global e qualche local, e un totale di 400 bytes in arrays varie, tra cui, una da 16x16.  Man mano imparerò di più, il prodotto finito sarà più efficiente e compatto.
"The only way to do great work is to love what you do. If you haven't found it yet, keep looking. Don't settle" Steve Jobs

"Se gommo tiene, io vince gara. Se gommo non tiene, io come bomba dentro montagna." Markku Alen

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.

Code: [Select]

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).

Spero sia di aiuto a qualcuno.
"The only way to do great work is to love what you do. If you haven't found it yet, keep looking. Don't settle" Steve Jobs

"Se gommo tiene, io vince gara. Se gommo non tiene, io come bomba dentro montagna." Markku Alen

barlettaag

scusa ... ma non ho capito la funzione freeRam().. che cosa fa ? come funziona ?

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!.
"The only way to do great work is to love what you do. If you haven't found it yet, keep looking. Don't settle" Steve Jobs

"Se gommo tiene, io vince gara. Se gommo non tiene, io come bomba dentro montagna." Markku Alen

PaoloP

#23
Mar 17, 2013, 08:12 pm Last Edit: Mar 17, 2013, 08:20 pm by PaoloP Reason: 1
Schema della memoria in un chip AVR.


--> http://en.wikipedia.org/wiki/Data_segment

La RAM esterna nel Atmega328 non c'è.

#24
Mar 17, 2013, 09:30 pm Last Edit: Mar 17, 2013, 09:56 pm by hiperformance71 Reason: 1
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! :smiley-red:   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?

grazie
"The only way to do great work is to love what you do. If you haven't found it yet, keep looking. Don't settle" Steve Jobs

"Se gommo tiene, io vince gara. Se gommo non tiene, io come bomba dentro montagna." Markku Alen

leo72

Ti riposto questo mio intervento passato:
Quote

La memoria SRAM viene suddivisa in 5 pezzi:
1) all'inizio della SRAM viene messa l'area .data, che contiene le variabili dichiarate nel programma
2) dopo c'è l'area .bss/.init: essa contiene le variabili non inizializzate
3) a seguire c'è l'HEAP, che contiene i dati per l'allocazione dinamica della memoria. L'HEAP cresce verso l'alto.
4) dopo l'HEAP c'è un'area vuota che funge da "materasso"
5) 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.

#26
Mar 18, 2013, 09:25 am Last Edit: Mar 18, 2013, 09:53 am by hiperformance71 Reason: 1
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!! :~




"The only way to do great work is to love what you do. If you haven't found it yet, keep looking. Don't settle" Steve Jobs

"Se gommo tiene, io vince gara. Se gommo non tiene, io come bomba dentro montagna." Markku Alen

astrobeed


Schema della memoria in un chip AVR.


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.
Scientia potentia est

leo72

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 ?

Go Up