Modulo ID12
L'interfacciamento ad Arduino di un modulo ID12 non presenta particolari difficoltà, dato che l'uscita RS232 è già a livello TTL. Ma senza un semplice accorgimento è necessario disconnetterlo quando si invia un nuovo sketch.
Tale accorgimento è un semplicissimo diodo, collegato opportunamente!
Normalmente, la linea RX di Arduino viene tenuta a livello alto da RN4B (su Arduino UNO). Quindi, collegando l'anodo ad RX ed il catodo al pin 9 del modulo ID12, la linea di programmazione uscente dal'ATMEGA8 funge da pull-up e tutto funziona perfettamente, a patto d non avvicinare un tag mentre si invia lo sketch...
Giusto per completezza, ecco lo schema di connessione ( pin_ID12 -> destinazione):
- 1 -> GND
- 2 -> +5V
- 7 -> GND
- 9 -> catodo --|<|-- anodo -> RX
- 11 -> +5V
Ed ecco un esempio di gestione, codice bruttarello estratto da un programma funzionante ma se non altro senza busy wait (a questo genere di gestione dedicherò un articolo a parte):
// Some useful constants #define STX 0x02 #define ETX 0x03 #define CR 0x0D #define LF 0x0A unsigned long milli=0; // Current 'time' (millisecs from 'on') byte id[5]; // Last read tag byte id_new=0; // Is tag 'new' (new read)? void setup() { Serial.begin(9600); } void loop() { milli=millis(); // Globally available process_reader(); process_tag(); } void process_tag() { static unsigned long upd=0; // First check if there's something to update on display if(upd) { if(milli-upd>5000) { // Timeout after 5s // lcd.setCursor(2,0); lcd.print(" "); // LCD lib is used for this... } } if(id_new) { upd=milli; lcd.setCursor(2,0); lcd.print("B "); for(byte c=0; c<5; ++c) { // lcd.print(bin2asc(id[c]>>4)); // LCD lib is used for this... // lcd.print(bin2asc(id[c])); // LCD lib is used for this... } id_new=0; // Mark tag as handled } } void process_reader() { static char rxbuff[16]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; // String from reader static byte pos=0; char ch; if(id_new) return; // Previous read still unhandled // If there's something new on serial, process it if(!Serial.available()) return; ch=Serial.read(); if(pos==0 && ch != STX) return; // MUST start w/ STX if(pos>15) { pos=0; return; } // Avoid buffer overflow rxbuff[pos++]=ch; // Store char if(ETX==ch) { if(pos==16) { // Complete frame byte cksumr=0, cksumc=0; //Serial.print("ID12 Frame "); for(byte c=0; c<5; ++c) { id[c] =asc2bin(rxbuff[((c<<1)+1)])<<4; id[c]|=asc2bin(rxbuff[(c<<1)+2]); cksumc^=id[c]; } cksumr =asc2bin(rxbuff[11])<<4; cksumr|=asc2bin(rxbuff[12]); if(cksumr!=cksumc) { //Serial.print("ERROR:"); //Serial.print(cksumr, HEX); //Serial.print("!="); //Serial.println(cksumc, HEX); } else { //Serial.print("OK"); id_new=1; } } else { //Serial.println("ID12 Bad frame"); } pos=0; // After ETX pos is always 0 } } // Convert an hex digit to binary byte asc2bin(const char c) { byte rv=0; if(!c) return 0; if ('0'<=c && '9'>=c) rv=c-'0'; else if ('a'<=c && 'f'>=c) rv=c-'a'+10; else if ('A'<=c && 'F'>=c) rv=c-'A'+10; return rv; } // Convert a nibble to hex digit char bin2asc(const byte b) { byte i=b&0x0f; if(0<=i && 9>=i) return i+'0'; return i-10+'A'; }
Probabilmente le funzioni di conversione sono anche già presenti nelle librerie standard, ma sono pigro e non mi andava di cercarle più di pochi minuti...
Ai più attenti non sarà sfuggito che il codice "manipola" ID di 5 byte (40 bit)... Ma i tag non contengono 64 bit?
Beh, si e no.
Si, contengono una memoria da 64 bit, ma no, non sono tutti di identificativo. Nei 64 vengono considerati anche i bit di header e footer, di parità orizzontale e verticale e quelli di CRC! Quindi il codice veramente univoco del transponder è ridotto a soli 40 bit. La sicurezza del sistema non ne risente: è comunque bassissima!
Mangling dei codici: ho notato che sistemi commerciali non "gradiscono" i codici così come vengono letti ed quindi necessario manipolarli per renderli accettabili. Per esempio, i sistemi di controllo accessi che usiamo in ufficio richiedono che i bit di ogni nibble siano invertiti di posizione, così che abcdefgh diventi dcbahgfe (ogni lettera sostituisce un bit). Non dispongo di una casistica tale da poter dire se tale "codifica" sia o meno uno standard o solo una errata interpretazione delle specifiche da parte di un produttore, ma ho già notato vari produttori che utilizzano la stessa notazione.
Possibile evoluzione: possibilità di accendere o spegnere il reader per risparmiare energia e garantire che non vengano letti tag durante la programmazione.