Modifica indesiderata di un vettore

Salve ragazzi, sto impazzendo con un programmino per gestire delle stringhe di TAG RFID e memorizzarle sulla EEPROM
Il listato è il seguente:

#include <SoftwareSerial.h>
#include <EEPROM.h>

#define rxPIN 10
#define txPIN 11

#define greenLED 8
#define redLED 9

SoftwareSerial tag(rxPIN, txPIN); //oggetto per la comunicazione seriale con il TAG reader

int numtags = 0; //Numero dei tag presenti in memoria
char* allowedTags[10]; //Vettore di tag caricati dalla EEPROM sulla RAM
char readtag[10]; //Vettore temporaneo per il caricamento dalla EEPROM
char tagValue[10]; //Valore letto dal RFID reader  
int checksumOK; //Variabile booleana per controllare lo stato del checksum dopo la lettura
                                                     
void setup() 
{
  tag.begin(9600);    //Inizializzo la porta di comunicazione sulla quale si leggerà il tag 
  Serial.begin(9600);
  pinMode(greenLED, OUTPUT);
  pinMode(redLED, OUTPUT);
  
 
  
  readfromEEPROM(); //Carica i tag dalla EEPROM
}

void loop()
{
  wait();
  checksumOK = ReadAndCheck();
  writeonEEPROM();
}


//Funzioni personalizzate
void wait()
{
  while (tag.available() < '0') //Se non ricevo TAG, rimani in attesa e fai lampeggiare i LED verde e rosso
  {
    for (int i=0; i<=50; i++)
    {
      digitalWrite(greenLED, HIGH);
      digitalWrite(redLED, HIGH);
      if (tag.read() == '2')
        return;
      delay(10);
    }
    for (int i=0; i<=50; i++)
    {
      digitalWrite(greenLED, LOW);
      digitalWrite(redLED, LOW);
      if (tag.read() == '2')
        return;
      delay(10);
    }
  }
}

int ReadAndCheck()
{
  byte val = 0;
  byte checksum = 0;   
  byte bytesRead = 0;
  byte tempByte = 0;
  byte tagBytes[6];    // Tag formato da 5 byte + 1 per il checksum
 
  while (bytesRead < 12) 
  {
    delay(15);
    val = tag.read();
    if (bytesRead < 10) // Append the first 10 bytes (0 to 9) to the raw tag value
    {
      tagValue[bytesRead] = val; 
      //Il valore inviato è in codifica ASCII. Per il controllare se la chiave è accettata, il valore rimarrà invariato. Per il calcolo del checksum il valore verrà convertito in HEX
    }
    
    //-----INIZIO CONVERSIONE IN HEX PER IL CALCOLO DEL CHECKSUM
    //val = 'F'; Considerando F tra apici ('F'), considero il valore DECIMALE della cifra (posizione nella tabella ASCII - per esempio F corrisponde a 70)
    if ((val >= '0') && (val <= '9')) 
      val = val - '0'; //conversione in base 10: val=val - il valore DECIMALE della cifra 0 derivante dalla tabella ASCII (questo perche da 0 a 9 in tabella le cifre sono sequenziali)
    else if ((val >= 'A') && (val <= 'F')) 
      val = 10 + val - 'A'; //conversione in base 10: val=val - il valore DECIMALE della cifra A derivante dalla tabella ASCII (questo perche da A a F in tabella le cifre sono sequenziali)
    
    //-----INIZIO CALCOLO DEL CHECKSUM
    //Ogni due cifre HEX, aggiungi un byte a tagBytes (RICORDA: IN HEX OGNI CIFRA PESA MEZZO BYTE!)
    if (bytesRead & 1 == 1) // & --> Operatore AND bit a bit -- Se bytesread è un numero dispari esegui il blocco IF
    { 
      //Con le istruzioni successive compongo in un byte due cifre HEX
      tagBytes[bytesRead >> 1] = (val | (tempByte << 4)); // | --> Operatore OR bit a bit
      if (bytesRead >> 1 != 5)  //Il checksum va calcolato solo sui primi 5 byte della cidifica HEX. L'ultimo byte è riservato per il checksum
        checksum ^= tagBytes[bytesRead >> 1];   // Calculate the checksum... (XOR)
    } 
    else 
      tempByte = val;                           // Se bytesread è pari, memorizzo la cifra HEX in una variabile temporanea per poi comporla nel byte tagBytes successivamente
    bytesRead++;                                // Ready to read next digit
  }
  //-----FINE CALCOLO CHECKSUM
    
  //CONTROLLO ESATTEZZA DEL CHECKSUM 
  if (bytesRead == 12) //Se la lettura è completa
  {                        
    tagValue[10] = '\0';                        // Terminatore di stringa di caratteri
    Serial.println(); //Vado a capo
    Serial.print("Tag Letto: ");
    Serial.println(tagValue); 
    Serial.print("Checksum ricevuto: ");
    Serial.println(tagBytes[5], HEX); //Stampo il valore della cella 5, in HEX, contenente il checksum trasmesso
    Serial.print("Checksum calcolato: ");
    Serial.print(checksum, HEX);
    if (tagBytes[5] == checksum)  //Se il checksum calcolato è uguale al checksum trasmesso stampa ok altrimenti stampa errore
    {
      Serial.println(" -- CHECKSUM OK."); 
      return 1;
    }
    else
    {
      Serial.println(" -- CHECKSUM ERROR.");
      return 0;
    }
  }
}

void readfromEEPROM() 
{
  numtags = EEPROM.read(0); //Nella locazione 0 è memorizzato il numero dei tag presenti in memoria
  
  Serial.print("Tag presenti in memoria: ");
  Serial.println(numtags);
  
  int i = 0, j, m;
  while (i < numtags)
  {
    m=0; //m mi serve per poter scrivere il dato sul vettore temporaneo
    for (j=((i*10)+1); j<=((i*10)+10); j++)
    {
      readtag[m] = EEPROM.read(j);
      m++;
    }
    readtag[10] = '\0';
    allowedTags[i] = readtag;
    Serial.println(i);
    Serial.println(allowedTags[i]);
    i++;
  }
}

void writeonEEPROM()
{
  int i=0, j=0, m=0;
  allowedTags[numtags] = tagValue;
  numtags++;
  EEPROM.write(0, numtags);
  while (i < numtags)
  {
    m=0;
    for (j=((i*10)+1); j<=((i*10)+10); j++)
    {
      EEPROM.write(j, allowedTags[i][m]);
      m++;
    }
    i++;
  }
}

Il problema riguarda il puntatore vettore "char* allowedTags[10]". Quando viene eseguita la funzione ReadAndCheck(), il valore delle componenti di questo vettore vengono cambiate. Per esempio se inizialmente il valore di allowedTags[0] è "58ADE3423D", dopo l'esecuzione di ReadAndCheck(), esso diventa "58ADE3423D58ADE3423D". Non riesco a capire il perchè.

Ho individuato anche la parte della funzione che crea questo problema:

//-----INIZIO CALCOLO DEL CHECKSUM
    //Ogni due cifre HEX, aggiungi un byte a tagBytes (RICORDA: IN HEX OGNI CIFRA PESA MEZZO BYTE!)
    if (bytesRead & 1 == 1) // & --> Operatore AND bit a bit -- Se bytesread è un numero dispari esegui il blocco IF
    { 
      //Con le istruzioni successive compongo in un byte due cifre HEX
      tagBytes[bytesRead >> 1] = (val | (tempByte << 4)); // | --> Operatore OR bit a bit
      if (bytesRead >> 1 != 5)  //Il checksum va calcolato solo sui primi 5 byte della cidifica HEX. L'ultimo byte è riservato per il checksum
        checksum ^= tagBytes[bytesRead >> 1];   // Calculate the checksum... (XOR)
    } 
    else 
      tempByte = val;                           // Se bytesread è pari, memorizzo la cifra HEX in una variabile temporanea per poi comporla nel byte tagBytes successivamente
    bytesRead++;

Come al solito, vi ringrazio anticipatamente per l'aiuto che, spero, mi darete :grin:

Buonanotte, ilPeppins

Di solito se modificando variabile globale (vettore tagValue) ti si modifica inaspettatamente anche un altra var.globale, quasi sicuramente hai scritto fuori da quel vettore tagValue. Sei sicuro di rimanere nei limiti del vettore tagValue?
A naso mi sembra che istruzioni tipo questa tagBytes[bytesRead >> 1] escano dai limiti, visto che byteread può arrivare a 12

Ciao, innanzitutto grazie della risposta :slight_smile:

Allora, ho provato a raddoppiare la dimensione di tagBytes, portandola a 12 ma il problema permane.
Ho parzialmente risolto definendo delle dimensioni fisse per allowedTags, dichiarando allowedTags[51][10]. (51 perchè sulla EEPROM posso memorizzare massimo 51 parole da dieci byte). La soluzione non mi piace perché 1)occupo spazio sulla RAM inutilemente; 2) non capisco perchè nella funzione readfromEEPROM() con "Serial.print(allowedTags/[i/])" riesco a stampare i le varie stringhe correttamente:

/*MONITOR SERIALE*/
Tag presenti in memoria: 6
0413BBBF23
0413BBBF23
0413BBBF23
0413BBBF23
0413BBBF23
58ADE3423D

mentre nella funzione writeonEEPROM() sono costretto ad utilizzare un ciclo for altrimenti il risultato con "Serial.print(allowedTags[0])" sarebbe questo:

/*MONITOR SERIALE*/
0413BBBF230413BBBF230413BBBF230413BBBF230413BBBF2358ADE3423D

Boh! Spero in un vostro aiuto altrimenti sarò costretto o ad utilizzare questo stratagemma o ad eliminare il controllo del checksum dal programma (visto che è quello che mi da problemi)

edit:
al momento la funzione writeonEEPROM() al momento è:

void writeonEEPROM()
{
  Serial.println(allowedTags[0]);
  /*for (int j=0; j<numtags; j++)
  {
    for (int i=0; i<10; i++)
    {
      Serial.print(allowedTags[j][i]);
    }
    Serial.println();
  }*/
}

Basta! Elimino il controllo del checksum anche se questo comporta una sconfitta personale per me! :disappointed_relieved: :disappointed_relieved:

Questo è l'ultima versione che ho compilato.

#include <SoftwareSerial.h>
#include <EEPROM.h>

#define rxPIN 10
#define txPIN 11

#define greenLED 8
#define redLED 9

SoftwareSerial tag(rxPIN, txPIN); //oggetto per la comunicazione seriale con il TAG reader

int numtags = 0; //Numero dei tag presenti in memoria
char allowedTags[51][10]; //Vettore di tag caricati dalla EEPROM sulla RAM
char readtag[10]; //Vettore temporaneo per il caricamento dalla EEPROM
char tagValue[10]; //Valore letto dal RFID reader  
int checksumOK; //Variabile booleana per controllare lo stato del checksum dopo la lettura
                                                     
void setup() 
{
  tag.begin(9600);    //Inizializzo la porta di comunicazione sulla quale si leggerà il tag 
  Serial.begin(9600);
  pinMode(greenLED, OUTPUT);
  pinMode(redLED, OUTPUT);
 
  readfromEEPROM(); //Carica i tag dalla EEPROM
}

void loop()
{
  wait();
  checksumOK = ReadAndCheck();
  writeonEEPROM();
  Serial.println();
  Serial.println();
  readfromEEPROM();
}


//Funzioni personalizzate
void wait()
{
  while (tag.available() < '0') //Se non ricevo TAG, rimani in attesa e fai lampeggiare i LED verde e rosso
  {
    for (int i=0; i<=50; i++)
    {
      digitalWrite(greenLED, HIGH);
      digitalWrite(redLED, HIGH);
      if (tag.read() == '2')
        return;
      delay(10);
    }
    for (int i=0; i<=50; i++)
    {
      digitalWrite(greenLED, LOW);
      digitalWrite(redLED, LOW);
      if (tag.read() == '2')
        return;
      delay(10);
    }
  }
}

int ReadAndCheck()
{
  byte i = 0;
  byte val = 0;
  byte checksum = 0;  
  byte bytesRead = 0;
  byte tempByte = 0;
  byte tagBytes[6];    // Tag formato da 5 byte + 1 per il checksum

  
  while (bytesRead < 12) 
  {
    delay(15);
    val = tag.read();
    if (bytesRead < 10) // Append the first 10 bytes (0 to 9) to the raw tag value
    {
      tagValue[bytesRead] = val; 
      //Il valore inviato è in codifica ASCII. Per il controllare se la chiave è accettata, il valore rimarrà invariato. Per il calcolo del checksum il valore verrà convertito in HEX
    }
  
    //-----INIZIO CONVERSIONE IN HEX PER IL CALCOLO DEL CHECKSUM
    //val = 'F'; Considerando F tra apici ('F'), considero il valore DECIMALE della cifra (posizione nella tabella ASCII - per esempio F corrisponde a 70)
    if ((val >= '0') && (val <= '9')) 
      val = val - '0'; //conversione in base 10: val=val - il valore DECIMALE della cifra 0 derivante dalla tabella ASCII (questo perche da 0 a 9 in tabella le cifre sono sequenziali)
    else if ((val >= 'A') && (val <= 'F')) 
      val = 10 + val - 'A'; //conversione in base 10: val=val - il valore DECIMALE della cifra A derivante dalla tabella ASCII (questo perche da A a F in tabella le cifre sono sequenziali)
    
    //-----INIZIO CALCOLO DEL CHECKSUM
    //Ogni due cifre HEX, aggiungi un byte a tagBytes (RICORDA: IN HEX OGNI CIFRA PESA MEZZO BYTE!)
    if (bytesRead & 1 == 1) // & --> Operatore AND bit a bit -- Se bytesread è un numero dispari esegui il blocco IF
    { 
      //Con le istruzioni successive compongo in un byte due cifre HEX
      tagBytes[bytesRead >> 1] = (val | (tempByte << 4)); // | --> Operatore OR bit a bit
      if (bytesRead >> 1 != 5)  //Il checksum va calcolato solo sui primi 5 byte della cidifica HEX. L'ultimo byte è riservato per il checksum
        checksum ^= tagBytes[bytesRead >> 1];   // Calculate the checksum... (XOR)
    } 
    else 
      tempByte = val;                           // Se bytesread è pari, memorizzo la cifra HEX in una variabile temporanea per poi comporla nel byte tagBytes successivamente
    bytesRead++;                                // Ready to read next digit
  }
  //-----FINE CALCOLO CHECKSUM
    
  //CONTROLLO ESATTEZZA DEL CHECKSUM 
  if (bytesRead == 12) //Se la lettura è completa
  {                        
    tagValue[10] = '\0';                        // Terminatore di stringa di caratteri
    Serial.println(); //Vado a capo
    Serial.print("Tag Letto: ");
    Serial.println(tagValue); 
    Serial.print("Checksum ricevuto: ");
    Serial.println(tagBytes[5], HEX); //Stampo il valore della cella 5, in HEX, contenente il checksum trasmesso
    Serial.print("Checksum calcolato: ");
    Serial.print(checksum, HEX);
    if (tagBytes[5] == checksum)  //Se il checksum calcolato è uguale al checksum trasmesso stampa ok altrimenti stampa errore
    {
      Serial.println(" -- CHECKSUM OK."); 
      return 1;
    }
    else
    {
      Serial.println(" -- CHECKSUM ERROR.");
      return 0;
    }
  }
}

void readfromEEPROM() 
{
  int i = 0, j, m;
  
  numtags = EEPROM.read(0); //Nella locazione 0 è memorizzato il numero dei tag presenti in memoria
  
  Serial.print("Tag presenti in memoria: ");
  Serial.println(numtags);
  
  while (i < numtags)
  {
    m=0; //m mi serve per poter scrivere il dato sul vettore temporaneo
    for (j=((i*10)+1); j<=((i*10)+10); j++)
    {
      readtag[m] = EEPROM.read(j);
      m++;
    }
    readtag[10] = '\0';
    memcpy(allowedTags[i], readtag, 10);
    //allowedTags[i] = readtag;
    Serial.println(allowedTags[i]);
    i++;
  }
}

void writeonEEPROM()
{
  int m=0,i=0,j=0;
  memcpy(allowedTags[numtags], tagValue, 10);
  numtags++;
  EEPROM.write(0, numtags);
  while (i < numtags)
  {
    m=0;
    for (j=((i*10)+1); j<=((i*10)+10); j++)
    {
      EEPROM.write(j, allowedTags[i][m]);
      m++;
    }
    i++;
  }
  
  /*for (int j=0; j<numtags; j++)
  {
    for (int i=0; i<10; i++)
    {
      Serial.print(allowedTags[j][i]);
    }
    Serial.println();
  }*/
}

Dopo aver inviato le informazioni tramite il TagReader (e quindi eseguito la funzione writeonEEPROM) il risultato sul monitor seriale è questo...

Tag presenti in memoria: 6
0413BBBF23
0413BBBF23
0413BBBF23
0413BBBF23
0413BBBF23
58ADE3423D

Tag Letto: 0104F5B523
Checksum ricevuto: 66
Checksum calcolato: 66 -- CHECKSUM OK.


Tag presenti in memoria: 7
0413BBBF230413BBBF230413BBBF230413BBBF230413BBBF2358ADE3423D0104F5B523
0413BBBF230413BBBF230413BBBF230413BBBF2358ADE3423D0104F5B523
0413BBBF230413BBBF230413BBBF2358ADE3423D0104F5B523
0413BBBF230413BBBF2358ADE3423D0104F5B523
0413BBBF2358ADE3423D0104F5B523
58ADE3423D0104F5B523
0104F5B523

Sono giorni che ci perdo la testa e non so più cosa fare!

mannagia, bocciati entrambi nella logica dei puntatori!!

allowedTags[i] = readtag;

così allowedTags PUNTA a readtag; se poi riutilizzi readtag.....
errore che ripeti anche in writeEEPROM
* *allowedTags[numtags] = tagValue;* *
devi usare le malloc() PER FORZA, non cercare di fare il trucco di usare le varibili temporanee al posto della readtag/tagValue globale: avrebbe funzionato con i linguaggi ad oggetti che possiedono un GarbageCollector, ma il C non è ad oggetti e il C++ NON usa un garbage collector... quindi le variabili temporanee, anche se referenziate nel tuo array, venono freeate, quindi il loro valore rimane giusto solo finchè qull'area di ram non viene riassegnata ad una altra variabile...
MA il tuo problema NON è nemmeno questo: infatti boccio ilPeppins anche nella gestione degli array
* *char tagValue[10]; //Valore letto dal RFID reader [...] tagValue[10] = '\0';                        // Terminatore di stringa di caratteri* *
tagValue ha 10 celle, da 0 a 9, usando la 11 cella (tagValue[10]) stai scrivendo fuori dall'array.
Sei molto convinto di quello che fai, tanto che lo stesso errore è presente anche su readtag
> A naso mi sembra che istruzioni tipo questa tagBytes[bytesRead >> 1] escano dai limiti, visto che byteread può arrivare a 12
nope!
prima di tutto 12 NON è analizzato
* *bytesRead < 12* *
eanche se lo fosse lui analizza solo i numeri dispari:
* *if (bytesRead & 1 == 1)* *
quindi il max numero è 11, in binario:
1011
schiftato di uno
101
che in decimale vale
5
edit: @ilPeppino mi ha preceduto, se non rimetti subito il controllo del checksum (e non sistemi i bug che sono COMUNQUE presenti e salteranno fuori dopo un paio di TAG che leggi), esco dal monitor e ti mangio vivo ]:smiley: ]:smiley:

Ciao lesto! Innanzitutto sei un grande! E io sono un fessone! ahahahah
Ti prometto che il controllo del checksum non lo eliminerò. Sono troppo orgoglioso per farlo e il tuo post mi ha ridato la carica :grin:

Purtroppo per la logica dei puntatori non posso darti torto... Ho toppato e mi devo solo fare cinque minuti di vergogna. E lo stesso si può dire per l'indirizzamento dei vettori (come uno scemo nei cicli for non commettevo errore, mentre nel terminatore di stringa si)...

Comunque per il traferimento dei vettori spero di aver risolto con memcpy.
Inoltre, correggendo il problema con l'overflow provocato dal terminatore di stringa, il programma sembra funzionare correttamente. Anche se è presto per dirlo.

Gli ultimi dubbi che ho al momento sono:
1)Come faccio ad allocare dinamicamente allowedTags nella RAM? Nel senso... è un peccato allocare una matrice 5111 senza che questa sia veramente utilizzata. Anche perchè non avrò mai, realisticamente parlando, 51 schede RFID da gestire. Vabbè, domani al massimo a mente lucida mi vedo il reference di malloc().
2)Ho provato ad eliminare readtag[11] e a scrivere allowedTags
[m] = EEPROM.read[j]; ma non funziona.*
Ti posto il codice con le correzioni al volo che ho fatto, domani inserisco gli ultimi controlli e ti faccio sapere come è andata.
Grazie ancora!!! Buonanotte :smiley:

Normalmente in C si creano delle strutct e le si alloca dinamicamente delle memoria con malloc, ma in C++ che è un linguaggio ad oggetti, ma non è java ci sono le class, che anche questo puoi allocare dinamicamente con malloc, tuttavia con class allochi spazio anche per i puntatori a funzione nella classe e quindi le dimensioni sono un pò più grandi che allocare memoria per una struttura dati semplice, cioè scusa su piccole mcu come questa il data hiding non è così importante, come non lo sono tutti gli altri paradigmi incapsulamento ecc dei linguaggi ad oggeti.

Io non ho ben chiaro la quantità dei dati e le funzioni che operano su questi, in ogni caso anche se scegli di usare una class e l'allocazione con "new" se l'oggetto viene creato dinamicamente solo una volta e mai distrutti durante tutto il corso del programma il tempo (overhead) richiesto per allocare memoria è tollerabile. Se invece devi allocare distruggere molte volte nell'arco di funzionamento del programma conviene pensare ad un altro modo per gestire la cosa, se possibile allocando dinamicamente solo handler.

Comunque, io penso che sei partito con il piede sbagliato, cioè dovresti prima pensare all'obiettivo che è: prima fallo funzionare, poi rendilo bello, poi rendilo efficiente e poi mantienilo. Quindi il CRC non è basilare per il funzionamento e quindi andrebbe introdotto dopo il 2° punto. Però tutto è giustificato dalla poca esperienza con questi linguaggi che sono tosti ma ti lasciano sempre il desiderio di insodisfazione che spinge a migliorare, si perchè le sodisfazioni poi arrivano ma richiedono molto sforzo.

Ciao.

Scusa @peppins, ieri sera avevo dato solo una occhiata di sfuggita al tuo codice. Perciò quel suggerimento era solo a naso, senza aver approfondito.
Era meglio non darlo (perchè ti può aver portato a cercare soluzioni in direzioni errate). A volte vien voglia comunque di dare aiuto :grin:

P.S. @lesto, però ci ho azzeccato che andava fuori array :smiley:

ilPeppins:
Comunque per il traferimento dei vettori spero di aver risolto con memcpy.

solo se è una matrice (e quindi lo spazio è pre-inizializzato), altrimenti stai scrivendo in area di memoria a caso se non allochi lo spazio con la alloc() e famiglia.

ilPeppins:
1)Come faccio ad allocare dinamicamente allowedTags nella RAM? Nel senso... è un peccato allocare una matrice 51*11 senza che questa sia veramente utilizzata. Anche perchè non avrò mai, realisticamente parlando, 51 schede RFID da gestire. Vabbè, domani al massimo a mente lucida mi vedo il reference di malloc().

a parte che non credo un atmega328 risca ad allocare 500 e passa byte di array, se on altro per la frammentazione della memoria. E usando la gestione dinamica è ancora peggio.

ilPeppins:
2)Ho provato ad eliminare readtag[11] e a scrivere allowedTags*[m] = EEPROM.read[j]; ma non funziona.*
[/quote]
banale, che l'errore sia semplicemente le [] al posto delle () in EEPROM.read[j]??
Comunque ti stai spaccando la testa per niente!!!!
visto che le allowedtag sono hardcodate nel codice, allora anzichè metterele in EEPROM puoi salvarle in FLASH, che ha il vatntaggio che le usi esattamente come se fossero in RAM... ma NON usano RAM!!
così
* *prog_uchar allowedTags[][11] PROGMEM  = { "CODICE1", "CODICE2", "CODICE3" };* *
hai un bellissimo array che usi in modo convenzionale, ma che in realtà è nella flash!!
> però ci ho azzeccato che andava fuori array
io invece stavo andando fuori binario pensando fosse solo un problema di alloazione... ma mi sono accorto che il bug sarebbe comparso solo al secondo giro essendo le variabili globali. Questo spiega l'ordine delle mie risposte nel mio post :grin:

Comunque ti stai spaccando la testa per niente!!!!
visto che le allowedtag sono hardcodate nel codice, allora anzichè metterele in EEPROM puoi salvarle in FLASH, che ha il vatntaggio che le usi esattamente come se fossero in RAM... ma NON usano RAM!!

così
Code:

prog_uchar allowedTags[][11] PROGMEM = { "CODICE1", "CODICE2", "CODICE3" };

hai un bellissimo array che usi in modo convenzionale, ma che in realtà è nella flash!!

Ehhh, purtroppo non funonzia così: avr-libc: Data in Program Space
Poi prog_uchar non c'è più nella nuova versione di avr-libc, ma se ha ancora la vecchia fila liscio, comunque nel link sopra c'è l'esempio, dove mostra il codice sopra, facendo un raggionamento corretto, ma....: Right? WRONG!; giusto, SBAGLIATO, e mostra la soluzione sotto, dove si vede che ogni stringa contenuta nell'array deve essere dichiarata con progmem.

Ciao.

nono, attento! lui parla di PUNTATORI a stringa, quindi i puntatori sono in flash, ma le stringhe in RAM.

io ho creato una MATRICE (tanto la dimensione è fissa), che è l'esempio che sta sopra.

quindi se usi *, devi fare attenzione che la stringa puntata sia progmem, ma se usi [] il compilatore è abbastanza furbo da piazzare in FLASH

Per quanto riguarda l'errore di readtag, era il banale errore dell'una di notte! xD Ho risolto e sono riuscito ad eliminare anche una rogna in più...
Un passo alla volta XD

Utilizzare la flash invece della EEPROM sarebbe una cosa fantastica (eviterei tutte le operazioni inutili di lettura e di scrittura da e sulla EEPROM). Il problema però, rimane nel caso dovessi aggiornare il firmware. In quel caso perderei tutti i tag in memoria e quindi sarei punto e da capo. Al momento mi sa che la EEPROM è l'unica soluzione....

Rimane quindi la questione della matrice allowedTags[51][11] che viene allocata all'avvio del dispositivo. come frammentazione non ci sono problemi, perchè la ram è ancora vuota. però è sempre uno spreco di spazio. Devo ancora imparare ad usare malloc perchè con C++ e qstring mi ero abituato ad usare new e delete....

@nid69ita: Di cosa ti scusi? Ogni aiuto e suggerimento è sempre utile e ben accetto.

lesto:
nono, attento! lui parla di PUNTATORI a stringa, quindi i puntatori sono in flash, ma le stringhe in RAM.

io ho creato una MATRICE (tanto la dimensione è fissa), che è l'esempio che sta sopra.

quindi se usi *, devi fare attenzione che la stringa puntata sia progmem, ma se usi [] il compilatore è abbastanza furbo da piazzare in FLASH

Non ho capito, cosa deve fare, i puntatori i FLASH è le stringhe dell'array in RAM o tutto in FLASH?
Comunque a me questa furbizia del compilatore non torna, cioè nel mio caso non funziona.
Spiegami come funziona che la cosa mi interessa.

prog_uchar è dichiarato come typedef così:

typedef unsigned char prog_uchar PROGMEM;

prog_uchar allowedTags[][11] PROGMEM = {}

dovrebbe quindi essere un array di singoli char, e 11 è la dimensione di ogni stringa, giusto.
Poi per prenderli dalla FLASH che istruzione deve usare?

Rimane quindi la questione della matrice allowedTags[51][11] che viene allocata all'avvio del dispositivo. come frammentazione non ci sono problemi, perchè la ram è ancora vuota. però è sempre uno spreco di spazio. Devo ancora imparare ad usare malloc perchè con C++ e qstring mi ero abituato ad usare new e delete....

Puoi usare new e delete che sotto sotto chiamano malloc, sostanzialmente allochi uno spazio di memoria void che devi castare al tipo per poterlo usare. Io come detto non ho capito quali sono i dati da allocare dinamicamente, se questi a senso metterli in una struttura linked list, così li puoi aggiungere in mezzo rimuovere ecc come fa appunto QList di Qt.

Ciao.

Ciao.

Utilizzare la flash invece della EEPROM sarebbe una cosa fantastica (eviterei tutte le operazioni inutili di lettura e di scrittura da e sulla EEPROM). Il problema però, rimane nel caso dovessi aggiornare il firmware. In quel caso perderei tutti i tag in memoria e quindi sarei punto e da capo. Al momento mi sa che la EEPROM è l'unica soluzione....

no, mi sa che non ci staimo capendo. i dati in FLASH sono in SOLA LETTURA, quindi vanno inizializzati nel programma. Altrimenti per lettura/scrittura la EEPROM è obbligata

Rimane quindi la questione della matrice allowedTags[51][11] che viene allocata all'avvio del dispositivo. come frammentazione non ci sono problemi, perchè la ram è ancora vuota. però è sempre uno spreco di spazio. Devo ancora imparare ad usare malloc perchè con C++ e qstring mi ero abituato ad usare new e delete....

a parte che non credo funzioni a priori, perchè un minimo di frammentazione la hai per via delle librerie arduino. Usando malloc/alloc la cosa è anche peggio.
IMHO se la flash non ti va bene, ti conviene ogni volta fare un check con i dati in EEPROM (tanto non si rovina in lettura), così non devi tenere in memeoria tutta quella roba, e anzi, puoi riempirti la eeprom tranqillamente.

Non ho capito, cosa deve fare, i puntatori i FLASH è le stringhe dell'array in RAM o tutto in FLASH?

tutto in flash

dovrebbe quindi essere un array di singoli char, e 11 è la dimensione di ogni stringa, giusto.

un array di X elementi composti da 11 char. la differenza con l'esempio che non funziona è che nell'esempio che non funziona hai qualcosa del genere
In questo caso il compilatore sa a priori (perchè lo inizializzi a mano) sia il numero di elementi che lo spazio da essi occupato, quindi può riservare lo spazio in FLASH. O almeno così mi aspetto, magari invece bisogna comunque inizializzare lettera per lettera:

prog_uchar allowedTags[][11] PROGMEM = { {'C', 'O', 'D', 'I', 'C', 'E', '1', '\0'}, {'C', 'O', 'D', 'I', 'C', 'E', '2', '\0'}, {'C', 'O', 'D', 'I', 'C', 'E', '3', '\0'} };

@lesto
Ok, si così funziona, e che non avevi usato l'inizializzazione per singoli char prima e non ci sono arrivato subito.

Riguardo la frammentazione, tutto dipende da cosa ci fà, io uso malloc con struct a mò di oggetti che contengono anche puntatori a funzioni(se posso evito i puntatori a funzione), insomma un antenato della classe, con la programmazione modulare in C si può fare dichiarando in ogni modulo le variabili come static, per quelle comuni a tutti gli oggetti, mentre per le variabili membro li metto dentro le struct insieme alle funzioni. L'uso che ne faccio è nello scheduler dove raramente un task viene rimosso dalla linked list e allora in tal caso ci può essere deframmentazione, ma se all'inizio del programma allochi tutto il necessario durante il corso di questo non c'è frammentazione, se non quella dovuta a string di arduino ma anche li dipende che lavoro ci fai fare a string. Ma allora che senso ha allocare ram dinamicamente? così lavoro direttamente con puntatori ad oggetti di tipo struct, buona abitudine presa studiando Qt/C++. Però è anche vero che potrei appogiarmi su una variabile puntatore per estrarre il riferimento, ma per ogni ogetto una variabile in più se gli oggetti sono 10 o più, si tratta di spazio sprecato, comunque tutto opinabile fino adesso non ho avuto problemi i programmi girano senza intoppi.

Quindi se sapesse cosa sta facendo (e non lo sa) :wink: potrebbe provare ad allocare con malloc.

Ciao.

x iscrizione

Allora, cerco di spiegarvi bene cosa il programma deve fare, in modo da evitare incompresioni. Le idee chiare su cosa voglio creare le ho; sul come, per alcuni punti, no. In ogni caso:
All'avvio il programma carica dalla EEPROM i vari tag con la funzione readfromEEPROM(). Dopo di che controlla se deve mettersi in modalità normale (lettura e ricerca nella matrice allowedTags di tag letti dal lettore) o in modalità amministrazione (inserimento o eliminazione di tag dalla memoria). Qui siamo discutendo della modalità amministrazione, perchè su quella normale per il momento non ho problemi.
Quindi
1)Avvio di arduino
2)caricamento dalla EEPROM dei tag memorizzati. Riempimento del vettore multidimensionale allowedTags
3)Attesa di input da seriale personalizzata (SoftwareSerial)
4)All'arrivo di un nuovo TAG il programma deve calcolare il checksum e nel caso questo dovesse essere corretto, allora deve procedere alla memorizzazione, sia su allowedTags che sulla EEPROM, in modo che alla successiva accensione di Arduino, il nuovo tag sia presente.
N.B.: Nel listato memorizzato non ho ancora implementato alcun controllo sull'effettiva correttezza del checksum o sull'effettiva presenza del tag in memoria per evitare doppioni.

Quindi, la flash non la posso usare visto che è di sola lettura, il controllo direttamente dalla EEPROM perchè la lettura è possibile solo carattere per carattere e il processo di controllo sarebbe lento e laborioso. Quindi l'unico modo di procedere IMHO è quello di lavorare RUN TIME con la RAM.

@MauroTec: Come ho già detto, le mie poche conoscenze di C/C++ (purtroppo studio ingegneria elettronica e non informatica) si limitano ai comandi new e delete. Per esempio per un vettore (che il mio professore definisce ad allocazione dinamica):

int *pippo; //Dichiarazione senza allocazione
pippo = new int[100]: //allocazione di un vettore di 100 elementi
delete pippo; //disallocazione di pippo dalla memoria

malloc non l'ho mai usato, ma mi sto documentando. in ogni caso questo è ciò che ho capito

typedef struct {char data[11]} Tag;
Tag *allowedTags;
allowedTags = malloc(sizeof(Tags));

e poi????

In ogni caso ora il programma sta girando con la dichiarazione char allowedTags[51][11] senza apparenti problemi (ho gestito fino a 23 tag). Però questa soluzione non tanto mi piace. Vorrei allocare un elemento del vettore di volta in volta che aggiungo un nuovo tag alla lista.

Spero di essermi spegato abbastanza chiaramente :wink:

Ciao!!!


@PaoloP: che significa per iscrizione?

come detto new e delete sotto sotto sono delle alloc() e delle free. ma in questo modo jai frammentazione. secondo me ogni volta devi confrontare con i dati in eeprom. lento. dici? si, se per te 10 milliseconds sono tanti. non conosco la velocità di accesso alla eeprom, ma essendo random siamo nell'ordine dei microsecondi. certo non è veloce come la ram, ma moolto più veloce di in hard disk...

l'uso della ram porta via ram che su in micro del genere vale oro, oppure peggio, crei frammentazione della ram, che su un micrp con 1,5k di ram è deleterio...
lo sai che alloc e new possono ritorna re null se lallocazione di ram è fallita? questo è un check (e un limite) che spesso si sottovaluta, e su macvhine con Giga di ram ok.. ma con 1/1000000 di ram cambia tutto!!

Giusto! Su questo non posso darti assolutamente torto! Quindi durante la ricerca carico dalla EEPROM in RAM solo i dieci caratteri di un tag. faccio il confronto con il tag letto. Se i due corrispondono mi fermo, altrimenti sovrascrivo la stringa di dieci caratteri in ram con i successivi dieci caricati dalla ROM. Alla fine se la lettura di un singolo carattere dovesse impegare 1 millisec e il tag cercato fosse memorizzato in coda alla EEPROM impiegherei circa 500 millisec per completare l'operazione (direi un tempo accettabile ahahahah)

Per l'eliminazione di un tag, al massimo sposto il contenuto delle locazioni di EEPROM che rappresentano l'ultimo tag nelle locazioni che contengono il tag che voglio eliminare. In questo caso le variabili che mi servono sono: la lunghezza di ogni tag (che so che è di dieci caratteri) e quanti tag ci sono in memoria (che conoscono dalla variabile numtags, memorizzata nella locazione 0). Mi sa tanto che farò così. (In questi giorno vi posto il nuovo listato :wink: )

Cavolo programmare Micro è rognoso... non pensavo così tanto :blush:
E io che voglio fare la tesi in Elettronica Digitale.... :roll_eyes:

rognoso? ahahah no, sono diverse dai pc, ma mooolte meno grazie al fatto che un micro è mooolto più semplice. in realtà stai affrontando quel momento in cui dai programmi farlocchi "hello world" ti affacci ai programmi Veri. (notare la v maiuscola :D)