QUALCOSA DI INCREDIBILE: Problema acquisizione byte da lettore RFID

Salve,

utilizzo il seguente lettore Rfid http://www.seeedstudio.com/depot/125khz-rfid-module-uart-p-171.html?cPath=144_153 e da quanto dice il rispettivo datasheet (http://www.seeedstudio.com//depot/datasheet/RDM630-Spec..pdf), comunicando con l interfaccia seriale (pagina 4 del datasheet), il primo byte letto è il numero 2 decimale, i successivi 10 byte sono i codici ASCII delle cifre del TAG letto, i 2 successivi byte per il checksum e un ultimo con il numero 3 di default. Il mio problema riguarda i 10 caratteri letti, che dovrebbero corrispondere all'ID del tag avvicinato al lettore. Posto un esempio. Se do in pasto al lettore il tag con codice ID: 0013530444 , il lettore RFID mi riporta in seriale la seguente sequanza:

I received: 2 I received: 51 I received: 67 I received: 48 I received: 48 I received: 67 I received: 69 I received: 55 I received: 53 I received: 52 I received: 67 I received: 67 I received: 66 I received: 3

Ovviamente il primo e l'ultimo byte ricevuto mi stanno bene, perchè devono essere tali. Il terzultimo ed il penultimo sono il checksum. Ma i restanti 10, non mi convincono affatto. Per esempio, dato che l'ID del tag inizia per 0013... i primi 4 byte letti non dovrebbero essere 48,48,49,51... ?!?!? Vi posto il codice con il quale leggo i valori da un Arduino ethernet R3:

int incomingByte = 0;  

void setup() {
        Serial.begin(9600);    
}

void loop() {

        if (Serial.available() > 0) {
                incomingByte = Serial.read();
                //stampo sulla seriale di DEBUG
                Serial.print("I received: ");
                Serial.println(incomingByte, DEC);
        }
}

premetto poi che il codice di lettura l'ho trovato sul sito ufficiale di Arduino.. non so davvero da cosa possa dipendere tutto ciò!

Probabilmente non hai letto l'esempio su Wiki:

http://www.seeedstudio.com/wiki/index.php?title=Electronic_brick_-_125Khz_RFID_Card_Reader

... Note: the 10 ASCII characters grouped as 5 hex data needs to be further processed as you may find that the 5 hex data is not equal to the number marked on the tags in Decimal. Actually the tag number is equal to the later 4 bytes in decimal. For example, the card number is 62E3086CED, the corresponding number marked on the tag should be 60717296877 which is the Decimal format of E3086CED. ...

Ettore Massimo Albani

Ha perfettamente ragione! Non mi era mai capitato che il valore letto fosse differente da quella scritto all'esterno del tag... solitamente ho utilizzato altri modelli di dispositivo lettore-chiave RFID. Che dire... GRAZIE MILLE! :)

Ulteriore problema... non riesco a risalire al numero scritto fuori della card, partendo dei codici letti dalla seriale dell'arduino! Anche prendendo in considerazione i soli byte interessati al campo"data" come scritto nel datasheet, e trascurando quindi sia header, sia footer, sia il checksum, non riesco a stampare a video il codice scritto all'esterno della scheda! Qualche idea su come fare? Ho anche provato a convertire i caratteri nei rispettivi valori interi, ma nada... aiuto

La tua card ha codice 0013530444 che in hex corrisponde a 00 CE 75 4C e ricevi la sequenza:

2 => start 51 => "3" (ignorare) 67 => "C" (ignorare) 48 => "0" 48 => "0" 67 => "C" 69 => "E" 55 => "7" 53 => "5" 52 => "4" 67 => "C" 67 => "C" cheksum 66 => "B" cheksum 3 => stop

La corrispondenza c'è.

Ettore Massimo Albani

Forse mi sono spiegato male, la corrispondenza l'ho verificata, ma il mio problema è su come ricreare da codice la sequenza esadecimale e stamparla poi a video. L'ulteriore passo è, una volta letti tutti i byte, calcolare il checksum. In tutta sincerità, non so dove mettere mano al codice quando si tratta di dover raggruppare i byte hex !

Esiste una comoda funzione strtoul() che converte una stringa in un valore numerico unsigned long, mentre per il calcolo del checksum devi considerare tutti i 5 byte ricevuti ed operare su di essi uno XOR (operatore ^)

  char x = "00CE754C"; // sequenza ricevuta
  unsigned long y = 0;
  y = strtoul(x, NULL, 16);

ciao, per prima cosa grazie della dritta. Credo char x ="qwekn45n5"; si sbagliata... cioè dovrebbe essere char x[] ="qwekn45n5"; i valori conviene sempre leggerli come char o magati per il checksum ecc, farebbe comodo vederli come byte?

Scusa... sarà il caldo!

Ho sbagliato a scrivere: char x[] = "00CE754C";

Ma non capisco da dove hai tirato fuori la stringa "qwekn45n5"

ahhahaas, no vabè, era una stringa così, tanto per rendere l'idea! :grin:

Temo che il tutto abbia dell’incredibile.
Posto il codice per chiarezza

// Project 45
#define lockPin 9
//#define speakerPin 9
#define tx 3
#define rx 2
#define unlockLength 2000
#include <SoftwareSerial.h>
SoftwareSerial rfidReader = SoftwareSerial(rx, tx);
int users = 3;
char* cards[] = { // valid cards
"11308547",
"3D00251C27",
"3D0029E6BF",
};
char* names[] = { // cardholder names
"Tom Smith",
"Dick Jones",
"Harry Roberts"
};
void setup() {
pinMode (lockPin, OUTPUT);
//pinMode (speakerPin, OUTPUT);
digitalWrite(lockPin, LOW);
Serial.begin(9600);
rfidReader.begin(9600);
}
void loop()
{
        char cardNum[10]; // array to hold card number
        byte cardBytes[6]; // byte version of card number + checksum
        
        int index=0; // current digit
        byte byteIn=0; // byte read from RFID
        byte lastByte=0; // the last byte read
        byte checksum = 0; // checksum result stored here
        int i=1;
        char x[8];
        unsigned long y=0;
        //Serial.flush();
        //rfidReader.flush();
        if (rfidReader.read()==2)
        { 
          // read the RFID reader
                while(index<12) 
                { // 12 digits in unique serial number
                        byteIn = rfidReader.read(); // store value in byteIn
                        delay(100);
                        Serial.print(index);
                        Serial.print(") - Byte: ");
                        Serial.print(byteIn);
                        Serial.print(" -> Integer: ");
                        if ((byteIn==1) || (byteIn==2) || (byteIn==10) || (byteIn==13)) {return;}
                        // if STX, ETX, CR or LF break
                        if (index<10) {cardNum[index]=byteIn;} // store first 10 HEX digits only?(last 2 are checksum)
                        // convert ascii hex to integer hex value
                        if ((byteIn>='0') && (byteIn<='9')) 
                        {
                                byteIn -= '0';
                        }
                        else if ((byteIn>='A') && (byteIn<='F')) 
                        {
                                byteIn = (byteIn+10)-'A';
                        }
                        Serial.print(byteIn);
                        if(index==0||index==1)
                          Serial.print("   [IGNORATO]");
                        if(index==10||index==11)
                          Serial.print("   [CHECKSUM]");
                        Serial.println();
                        if ((index & 1) == 1) 
                        { // if odd number merge 2 4 bit digits into 8 bit byte
                                cardBytes[index/2]= (byteIn | (lastByte<<4)); // move the last digit 4 bits?left and add new digit
                                if (index<10) {checksum ^= cardBytes[index/2];} // tot up the checksum value
                        }
                        lastByte=byteIn; // store the last byte read
                        index++; // increment the index
                        if (index==12) {cardNum[10] = '\0';} // if we have reached the end of all digits?add a null terminator
                }
                //rfidReader.flush();    // togliendo questo commento, al passaggio successivo mantengo l'errore nella stringa
                Serial.println(cardNum); // print the card number
                int cardIndex =checkCard(cardNum); // check if card is valid and return index number
                if(cardIndex>=0 && (cardBytes[5]==checksum))
                { // if card number and checksum are valid
                        Serial.println("Card Validated");
                        Serial.print("User: ");
                        Serial.println(names[cardIndex]); // print the relevant name
                        unlock(); // unlock the door
                        Serial.println();
              }
              else
             {
                        Serial.println("Card INVALID");
                        for(i=1;i<11;i++)
                        {
                          x[i-1]=cardNum[i+1];
                          //Serial.print(x[i-1]);
                          //Serial.println(cardNum[i+1]);
                        }
                        //Serial.print(x);
                        x[i+1]='\0';
                        //Serial.print(x);
                        
                        Serial.print("cardNum: ");
                        Serial.println(cardNum); //<---------------------------------------- !
                        Serial.print("x) HEX: ");
                        Serial.println(x);
                        //char z[]="00AC8E03";
                        //y=strtoul(z,NULL,16);
                        y=strtoul(x,NULL,16);
                        Serial.print("y) DEC: ");
                        Serial.println(y);
                        for(int j=0;j<8;j++)
                        {
                          Serial.print(x[j]);
                          Serial.print(" - ");
                        }
                        Serial.println();
                        //Serial.print("Convertito e': ");
                        //Serial.println(y);
                        //tone(speakerPin, 250, 250);
                        delay(250);
                        //tone(speakerPin, 150, 250);
              }
        }
}
int checkCard(char cardNum[10]) {
for (int x=0; x<=users; x++) { // check all valid cards
if(strcmp(cardNum, cards[x])==0) { // compare with last read card number
return (x); // return index of card number
}
}
return (-1); // negative value indicates no match
}
void unlock() {
//tone(speakerPin, 1000, 500);
digitalWrite(lockPin, HIGH);
delay(unlockLength);
digitalWrite(lockPin, LOW);
delay(unlockLength);
digitalWrite(lockPin, HIGH);
delay(unlockLength);
digitalWrite(lockPin, LOW);
}

Leggendo da seriale, il risultato è:

    • Byte: 255 → Integer: 255 [IGNORATO]
    • Byte: 51 → Integer: 3 [IGNORATO]
    • Byte: 67 → Integer: 12
    • Byte: 48 → Integer: 0
    • Byte: 48 → Integer: 0
    • Byte: 67 → Integer: 12
    • Byte: 69 → Integer: 14
    • Byte: 55 → Integer: 7
    • Byte: 53 → Integer: 5
    • Byte: 52 → Integer: 4
    • Byte: 67 → Integer: 12 [CHECKSUM]
    • Byte: 67 → Integer: 12 [CHECKSUM]
      ÿ3C00CE754 <<<------------------------------------------------------------------------ ???
      Card INVALID
      cardNum: <<------- non avviene la stampa del vettore caratteri “cardNum”
      x) HEX: C00CE754
      y) DEC: 3222071124
      C - 0 - 0 - C - E - 7 - 5 - 4 - <<---- Codice HEX relativo alla card

Il problema è quella ÿ (indicata dalla freccia) che si trova in testa al codice. Non si sà da dove venga fuori! è assurdo, o fatto milioni di prove!
Oltretutto, la sua presenza(della Y) crea un successivo errore nella stampa del codice HEX relativo alla card, infatti la ‘C’ che si trova in testa alla sequanza di caratteri, dovrebbe trovarsi in coda!
La ÿ viene fuori da quel byte : 255 presente nel codice soprastante, che ha origine ignota… non so davvero da dove possa provenire quel byte!
Cosa ancor più sconvolgente è che , se faccio leggere al lettore Rfid velocemente lo stesso TAG senza dargli tempo di stampare sulla seriale la prima serie, il risultato è il seguente:

    • Byte: 255 → Integer: 255 [IGNORATO]
    • Byte: 51 → Integer: 3 [IGNORATO]
    • Byte: 67 → Integer: 12
    • Byte: 48 → Integer: 0
    • Byte: 48 → Integer: 0
    • Byte: 67 → Integer: 12
    • Byte: 69 → Integer: 14
    • Byte: 55 → Integer: 7
    • Byte: 53 → Integer: 5
    • Byte: 52 → Integer: 4
    • Byte: 67 → Integer: 12 [CHECKSUM]
    • Byte: 67 → Integer: 12 [CHECKSUM]
      ÿ3C00CE754
      Card INVALID
      cardNum: <<------- non avviene la stampa del vettore caratteri “cardNum” ???
      x) HEX: C00CE754
      y) DEC: 3222071124
      C - 0 - 0 - C - E - 7 - 5 - 4 - ← fine stampa prima sequenza
    • Byte: 51 → Integer: 3 [IGNORATO] <<----NB è scomparso il byte 255, causa della ÿ !!
    • Byte: 67 → Integer: 12 [IGNORATO] <<— ORA RIPORTANO ANCHE I 2 BYTE DA IGNORARE X IL CALCOLO DEL SERIALE
    • Byte: 48 → Integer: 0
    • Byte: 48 → Integer: 0
    • Byte: 67 → Integer: 12
    • Byte: 69 → Integer: 14
    • Byte: 55 → Integer: 7
    • Byte: 53 → Integer: 5
    • Byte: 52 → Integer: 4
    • Byte: 67 → Integer: 12
    • Byte: 67 → Integer: 12 [CHECKSUM]
    • Byte: 66 → Integer: 11 [CHECKSUM]
      3C00CE754C
      Card INVALID
      cardNum: <<------- non avviene la stampa del vettore caratteri “cardNum” ???
      x) HEX: 00CE754C
      y) DEC: 13530444 <<----------È TUTTO ESATTO, PERFINO IL VALORE SERIALE CHE TROVO SCRITTO AL DI FUORI DEL TAG !! (13530444)
      0 - 0 - C - E - 7 - 5 - 4 - C - <<— è proprio l equivalente HEX di 13530444
      TUTTO porta come dovrebbe in questo secondo passaggio!

Non so più davvero a che Santo appellarmi.
Come mai al secondo passaggio tutto va come dovrebbe?!?! come mai è scomparsa la ÿ ??
La stringa cardNum continua a non essere stampata, ma in fin dei conti quello è il male minore…
ho anche provato a fare un flush della seriale, ma niente da fare stesso risultato.
Se do tempo alla seriale di stampare tutti i caratteri, l’algoritmo per ricavare il seriale non funziona, se invece avvicino 2 volte in pochissimo tempo il tag al lettore, senza dar tempo all’ardu di stampare il tutto a video, nella seconda sequenza tutto sembra andar bene e funzionare a dovere (ma nella prima no).

Prova con: Serial.begin(115200); o hai paura che ti multino per eccesso di velocità? :grin: :grin:

Ricorda di modificare anche la velocità nel Serial Monitor dell’IDE.

Niente da fare... con "Serial.begin(115200);" da seriale ho questa stampa: þþÿþþþÿþÿ?$Bà¥W1;ÁP($ 2®¹?¢Ê)?ª4?Ã`)(I²$% %ü

(ovviamente dopo avere modificato anche sul serial monitor la rispettiva velocità)

La variabile i è usata due volte: una è globale e una è nel ciclo for. Il compilatore potrebbe considerarle diverse a causa dei diversi scope; dovresti controllare i valori con dei print.

Niente da fare, purtroppo non dipende da quello... ho provato e mi ritrovo nella stessa situazione di prima..

Prova ad rianalizzarti il codice dall'inizio suddividendolo in funzioni semplici. Da qualche parte l'errore c'è. :roll_eyes:

Ho suddiviso il codice in funzioni più semplici, fatto stampe di debug ovunque, cambiato la modalità di conservazione dei dati seriali (cambiando tipo dato e struttura) ma niente da fare... il grosso dubbio che ho è il fatto che quel bit "strano" scompare solo quando faccio sovrapporre due letture seriali veloci, altrimenti permane in ogni caso... :astonished:

cosa intendi per veloci?non è che si riempie il buffer della seriale? In oltre è normale che la prima lettura in assoluto sia errta se inizia prima del loop di arduino. Infine, quando dici di aver aumentato il baudrate e di aver letto solo roba starna, sicuro di averlo aumentato solo alla comunicazione con il PC e non anche alla comunicazione via seriale (quello è il classico output da baudrate troppo alto, invece se si imposta troppo basso in ricezione di solito non si ha nulla)

La ÿ che leggi è la rappresentazione ASCII di 255, mentre il 3 è il carattere di Start del pacchetto dati.

La stringa che perciò visualizzi non deve contenere i primi due byte.

Ettore Massimo Albani