tag RFID ed apertura cancello

Dopo il grande successo del primo progetto :slight_smile: sono pronto per il secondo :sunglasses:

Voglio sostituire la serratura elettromeccanica di un cancello (semplice nottolino con chiave che chiude un microswitch) con un lettore RFID controllato da Arduino. Non essendo ancora capace di sviluppare da me sketch avanzati ho cercato in rete ed ho trovato questo sketch. Lo sto studiando e condivido con voi per un parere circa un aspetto in particolare.
Come potete vedere sono state inserite solo tre schede ed i relativi identificativi io ho bisogno di inserire almeno venti tag. Mi suggerite di mantenere il codice sottoriportato semplicemente allungando fino al mio massimo numero oppure mi suggerite una formula diversa?

/* 
Questo programma permette effettuare la lettura di una tessera magnetica e stabilire se quest'ultima
è stata autorizzata.
PINOUT:
  
RC522 MODULE    Uno/Nano    
SDA             D10
SCK             D13
MOSI            D11
MISO            D12
IRQ             N/A
GND             GND
RST             D9
3.3V            3.3V
Autore Giacomo Bellazzi
Versione 1.0
*/
  
#include <SPI.h>
#include <RFID.h>
/* Vengono definiti PIN del RFID reader*/
#define SDA_DIO 10  // 53 per Mega
#define RESET_DIO 9
#define delayRead 1000 // Time of delay 
#define delayLed 2000 
#define ledVerde 3
#define ledRosso 4
/* Viene creata una istanza della RFID libreria */
RFID RC522(SDA_DIO, RESET_DIO); 
  
String codiceAutorizzato1 = "EC40E03478";
String codiceAutorizzato2 = "EC40E03479";
String codiceAutorizzato3 = "EC40E03480";
  
void setup()
{ 
  Serial.begin(9600);
  /* Abilita SPI*/
  SPI.begin(); 
  /* Viene inizilizzato RFID reader */
  RC522.init();
  Serial.println("Setup");
  pinMode(ledVerde,OUTPUT);
  pinMode(ledRosso,OUTPUT);
}
  
void loop()
{
  /* Temporary loop counter */
  byte i;
  // Se viene letta una tessera
  if (RC522.isCard())
  {
    // Viene letto il suo codice 
    RC522.readCardSerial();
    String codiceLetto ="";
    Serial.println("Codice delle tessera letto:");
  
    // Viene caricato il codice della tessera, all'interno di una Stringa
    for(i = 0; i <= 4; i++)
    {
      codiceLetto+= String (RC522.serNum[i],HEX);
      codiceLetto.toUpperCase();
    }
    Serial.println(codiceLetto);
   [color=red] if(verificaCodice(codiceLetto,codiceAutorizzato1)||verificaCodice(codiceLetto,codiceAutorizzato2)
    ||verificaCodice(codiceLetto,codiceAutorizzato3)){[/color]
      Serial.println("Tessera autorizzata");
      accendiLed(ledVerde);
    }else{
      Serial.println("Tessera non autorizzata");
      accendiLed(ledRosso);
    }
  delay(delayRead);  
  }
}
// Questa funzione verifica se il codice Letto è autorizzato
boolean verificaCodice(String codiceLetto, String codiceAutorizzato){
  if(codiceLetto.equals(codiceAutorizzato)){
    return true;
  }else{
    return false;
  }  
}    
// Questa funzione permette di accendere un LED per un determinato periodo
void accendiLed(int ledPin){
  digitalWrite(ledPin,HIGH);
  delay(delayLed);
  digitalWrite(ledPin,LOW);
}
  1. Imparare ad usare le stringhe del 'C' (ovvero array di char) ed evitare l'uso della classe String

  2. Imparare ad utilizzare la PROGMEM per memorizzare i valori costanti fissati nel codice (... NON va bene se pensi di dover modificare dinamicamente i numeri di tessere abilitati, aggiungerne, toglierne, ecc. ecc)

Guglielmo

Caro Guglielmo ti aspettavo al varco con i tuoi criptici aiuti :frowning:

Allora dimmi qualcosa di più chiaro perchè così non ho capito una cippa...

  1. ...quindi l'array di char dovrebbe essere più efficace?

  2. Non interverrò dinamicamente ma solo quando necessario per inserire un nuovo utente e/o toglierne qualcuno.

vince59:
Caro Guglielmo ti aspettavo al varco con i tuoi criptici aiuti :frowning:

vince59:

  1. ...quindi l'array di char dovrebbe essere più efficace?

Mah ... come scrivo sempre, ricorda che ... NON sei su un PC dove c'è un sistema operativo ed un "garbage collector", sei su una piccola MCU con solo 2kBytes di SRAM, dove devi fare tutto tu e dove usare la classe "String", a causa dell'allocazione e riallocazione dinamica della memoria, porta quasi sempre ... a grossi problemi e sicuri mal di testa ! :smiling_imp:

Impara ad usare le stringhe classiche del C ... ovvero semplici array di char terminati dal carattere null (0x00) e le funzioni che trovai nella libreria standard (... che, oltretutto, è automaticamente inclusa dal IDE) AVR libc ed, in particolare, quanto è in <string.h>.

vince59:
2. Non interverrò dinamicamente ma solo quando necessario per inserire un nuovo utente e/o toglierne qualcuno.

Se usi PROGMEM puoi evitare che le varie stringhe costanti con i numeri di tessere (e, se hai dei messaggi o cose simili, anche quelli) occupino quella poca SRAM che c'è, ma rimangano nella flash dove è il programma.

Rovesco della medaglia ...
... ogni volta che devi fare una modifica, devi farla nel sorgente, ricompilare e ricaricare il codice su Arduino.

Maggiori dettagli sull'uso di PROGMEM nel pdf allegato.

Guglielmo

P.S.: Sono stato abbastanza criptico o vuoi che peggioro ? :smiling_imp: :smiling_imp: :smiling_imp:

Progmem.pdf (182 KB)

L'ideale sarebbe avere una "modalità di programmazione", magari abilitata da una tessera "master" il cui ID può essere memorizzato in PROGMEM (o se proprio non ci riesci in RAM, intanto sarà una tessera sola). Qualcosa del genere:

  • Passo tessera master, il sistema la riconosce ed entra in modalità programmazione
  • Passo un'altra tessera:
  • Se la tessera non è tra quelle abilitate, viene abilitata
  • Altrimenti viene disabilitata
  • Ripeto il punto precedente finché non viene ripassata la master oppure scade un timeout

Gli UID delle tessere abilitate possono essere salvati in EEPROM: ce ne starebbero 256. La tessera master ovviamente andrà custodita in cassaforte :D.

Boh, questa è un'idea che mi è venuta sul momento :D.

SukkoPera:
L'ideale sarebbe avere una "modalità di programmazione", magari abilitata da una tessera "master" il cui ID può essere memorizzato in PROGMEM (o se proprio non ci riesci in RAM, intanto sarà una tessera sola). Qualcosa del genere:

  • Passo tessera master, il sistema la riconosce ed entra in modalità programmazione
  • Passo un'altra tessera:
  • Se la tessera non è tra quelle abilitate, viene abilitata
  • Altrimenti viene disabilitata
  • Ripeto il punto precedente finché non viene ripassata la master oppure scade un timeout

Gli UID delle tessere abilitate possono essere salvati in EEPROM: ce ne starebbero 256. La tessera master ovviamente andrà custodita in cassaforte :D.

Boh, questa è un'idea che mi è venuta sul momento :D.

mi piace

vince59:
mi piace

Bene, allora ...
... altro documento in allegato da studiare :stuck_out_tongue_closed_eyes:

Guglielmo

EEPROM.pdf (181 KB)

gpb01:
Bene, allora ...
... altro documento in allegato da studiare :stuck_out_tongue_closed_eyes:

Guglielmo

...

gpb01:
Bene, allora ...
... altro documento in allegato da studiare :stuck_out_tongue_closed_eyes:

Guglielmo

Guglielmo...ti odio :slight_smile:

vince59:
...
Guglielmo...ti odio :slight_smile:

Ahahahahah ... non sei il solo ... :stuck_out_tongue_closed_eyes:

Guglielmo

Guglielmo, sto prendendo confidenza con le array di caratteri e la teoria comincia ad essere meno nebbiosa.
Ti chiedo solo un suggerimento come costruire la parte di codice che conterrà i codici dei tag in maniera ottimale. Mi sembra che dovrò procedere creando un array di caratteri dove mettere tutti i codici di cui ho bisogno (diciamo venti).
Devo poi creare la sequenza con cui il codice letto viene comparato con quelli contenuti nell'array e qui credo di dover creare un ciclo if di verifica con l'operatore OR...giusto?
Il codice, laddove presente nell'array, consentirà il verificarsi delle condizione prevista...ci sono?

Allora, come hai visto una stringa di caratteri DEVE essere sempre terminata da 0x00, quindi, considera il codice più lungo che hai, aggiungi 1 ed hai la lunghezza dei vari elementi della "matrice" di caratteri che salverai ... abbiamo detto in EEPROM vero ?

Quindi ... immaginiamo che il codice più lungo che devi salvare è di 10 caratteri, aggiungi lo 0x00 finale e quindi ti servono per ogni codice 11 caratteri. Immaginiamo che ne vuoi salvare fino a 100 (per un totale di 1100 bytes) ... dovrai riservarti in EEPROM due cose, una variabile di tipo byte per ricordarti quanti ne hai:

byte EEMEM numeroCodici;

... ed uno spazio così definito per salvare i, massimo 100, codici.

char EEMEM codici[100][11];

Ogni singolo codice è identificato dal primo indice (che va da 0 a 99); ogni singolo carattere di ogni singolo codice è identificato dal secondo indice (che va da 0 a 10).

Dato che stiamo facendo una cosa dinamica e NON statica, dovrai, in una parte di programma, fare la routine che va a scrivere i codici abilitati in EEPROM ...

Immaginiamo che, tu digiti da tastiera un codice che salvi in una variabile che chiamiamo codiceDigitato e che sarà:

char codiceDigitato[11];

Non mi metto qui a vedere come fare la funzione per accettare il codice da tastiera e memorizzarli in nella variabile, ma ti mostro come salvarlo nella EEPROM alla posizione N

eeprom_write_block( (const void*) codiceDigitato, &codici[N], 11);

Quando vorrai rileggerlo indietro, ad esempio per rimetterlo in codiceDigitato (o un altro array di char uguale) :

eeprom_read_block( (void*) codiceDigitato, &codici[N], 11);

Ti ho chiarito un po' le idee o ti ho confuso ancora di più ?

Se invece NON vuoi usare la EEPROM per memorizzarli, ma li vuoi mettere fissi nel codice, dimmelo e ti do le indicazioni.

Guglielmo

No non mi hai confuso. Ho letto qualcosa e mi è piuttosto chiaro, però siamo in una condizione differente e forse ho deviato il tuo pensiero. Diversamente da quanto da te esposto, io sto lavorando con un lettore RFID e relativi tag (ognuna con il suo unique ID) del formato tipo EC40E03478) per cui non andrò a digitare codici.

Ciò premesso, io vorrei "registrare" gli ID direttamente nel codice usando l'array piuttosto che la EEPROM e creare un ciclo if che mi paragoni il codice letto con quelli nell'array.

In realtà non so quale sia la soluzione più efficace (EEPROM o codice) ma tieni conto che parliamo di una ventina/trentina di TAG per cui credo sia sufficiente la soluzione meno complessa più veloce.

Al momento mi fermerei qui ma è molto interessante l'idea esposta qualche post più su di creare una modalità "master/admin" per cancellare/inserire i tag ID senza dover intervenire con il pc per sparare nuovamente il codice...questo dopo però!

Ricapitolando la mia ipotesi:

  • creo array ed inserisco TUTTI gli ID;

  • creo ciclo if per comparare il "codice_letto" con TUTTI quelli nell'array.

  • autorizzare/negare apertura cancello su "pin_out".

Mi serve aiuto per costruire nel modo migliore il codice che va a "pescare" (singolarmente/globalmente)" gli ID nell'array per compararli con quello letto.

Grazie

Ciao,
hai provato a vedere qui
http://playground.arduino.cc/Learning/MFRC522
sul forum hanno messo un progetto di apriporta con 522 e eeprom:
http://forum.arduino.cc/index.php?topic=256260
il codice è qui:

Alberto

Grazie BJ...do un occhiata

Ok, quindi a te interessa la versione con i codici "bruciati" nel programma ...

L'array lo definisci allo stesso modo e lo riempi direttamente ...

char codici[30][11] = {"EC40E03478", "EC40E03479", "EC40E03480", .......tutti i tuoi codici (massimo 30) ......... };

Ti serve poi una variabile dove metti il codice letto :

char codiceLetto[11];

Nel codice, ogni volta che leggi un tag, devi solo fare :

for (i = 0; i < 30; i++) {
   if ( strcmp(codici[i], codiceLetto) == 0 ) {
      // HAI trovato il codice, esci dal for. L'indice i ti dice quale è il codice trovato
      break;
   }
}
if (i == 30) {
   // NON HAI trovato il codice e l'indice è arrivato fino a 30 poi sei uscito dal for.
}

Nota che la strcmp() si trova in <string.h> :wink:

Tutto chiaro ?

Guglielmo

P.S.: lascia stare esempi fatti e continua, come stai facendo, ad usare la tua testa ... ci metterai di più, ma alla fine avrai IMPARATO ... :wink:

Perfetto era l'indicazione di cui avevo bisogno di conferma.

Questa è un pò criptica però...

"Nota che la strcmp() si trova in <string.h> ;)"

Il diagramma di flusso e le relative parti di codice le ho a mente e appena ho tempo lo butto giù.

Grazie...vediamo cosa riesco a tirare fuori.

vince59:
Questa è un pò criptica però...
"Nota che la strcmp() si trova in <string.h> ;)"

Come sai, l'IDE di arduino include sempre la AVR libc ... all'interno hai vari gruppi di funzioni, il gruppo <string.h> contiene le funzioni per la manipolazioni delle stringhe come la strcmp().

In testa al programma, assieme alle altre include, sarà quindi sufficiente che metti :

#include <string.h>

per avere a disposizione tutte le funzioni che vedi nel link che ti ho messo.

Guglielmo

Grazie molto chiaro. No, non sapevo della libreria AVR...ora si :slight_smile:

Vedi che quando vuoi sei amabile :wink: :smiley: ;D 8) ??? ::slight_smile: :stuck_out_tongue: :-[ :-X :-\ :-* :cry: :fearful:

vince59:
Vedi che quando vuoi sei amabile ...

Io amabile ? ? ? ...
Guglielmo :smiley: :smiley: :smiley:

...l'array la "infilo" nel loop..anche se mi sembra di poterla mettere anche prima del setup laddove definisco oggetti, variabili ecc