Buongiorno a tutti, sto realizzando un piccolo controllo accessi con RDM6300 ed un arduino nano. Tutto funziona correttamente ma ho deciso di avere la possibilità di aggiungere una card premendo un pulsante e memorizzare il codice nella EEprom di arduino.
Per fare questo ho scritto il codice:
void memorizza(){
Serial.println("Memorizzazione");
for (int i = 0;i<100;i++);{
uno_e=EEPROM.read(i);
due_e=EEPROM.read(i+1);
tre_e=EEPROM.read(i+2);
if ((uno_e==uno) && (due_e==due) && (tre_e==tre)){
Serial.println("Codice già memorizzato");
//break;
}
else{
Serial.print("Da memorizzare ");
for (int i=0;i<10;i++){
int uno_e=EEPROM.read(i);
int due_e=EEPROM.read(i+1);
int tre_e=EEPROM.read(i+2);
if ((uno_e==0x00) && (due_e==0x00) && (tre_e==0x00)){
EEPROM.update(i, uno);
EEPROM.update(i+1, due);
EEPROM.update(i+2, tre);
delay(20);
Serial.println("Codice nuovo memorizzato");
break;
}
}
}
}
delay(1000);
detachInterrupt(0);
}
Il problema è che mi memorizza tutto fino a riempire la EEprom senza fermarsi a tre celle.
Mi sta facendo diventare matto anche perchè non sono troppo esperto. Grazie a chi mi darà un suggerimento. Ovviamente le variabili uno, due e tre sono state create dopo la lettura del codice della scheda e sono in formato 0xFF.
Nella parte dove memorizzi scrivi tre celle alla volta ma dentro un ciclo che va da zero a nove solo se le tre celle contigue sono uguali a zero quindi diciamo che scrivi i primi tre caratteri, poi salti i successivi due perché non saranno zero, poi dalla posizione quattro scrivi di nuovo i tre caratteri nelle variabili uno, due e tre e così via finché i non vale 10.
Più o meno la stessa cosa la vai con il ciclo esterno dove però ripeti finché i non è cento.
Se devi scrivere solo tre caratteri perché usi i cicli?
Penso che quello esterno possa servire a cercare di capire se hai già in memoria il codice ma così facendo se le prime posizioni appartengono ad un altra card vai a sovrascrivere.
Ti suggerisco di cambiare approccio utilizzando la prima posizione della EEPROM per sapere quante card hai già memorizzato e in base a quello cercare il codice della card attuale nelle posizioni 1,2,3 se non lo trovi nelle 4,5,6 e così via finché non hai cercato tra tutte le card già memorizzate. Se hai trovato non memorizzi, se non hai trovato allora incrementi il numero delle card memorizzate e usi questo indice (N) per determinare la posizione in cui memorizzare i tre caratteri della card (Es.1+(3*N), 2+(3*N), 3+(3*N))
L'indice N partirà da zero quando nessuna card è stata memorizzata
In effetti ho pensato dopo per il ciclo lo avevo scelto per avere il riferimento della prima cella di memoria libera e da li scrivere le tre celle.
Proverò a fare un if ed un incremento di 1 fino alle tre celle vuote e poi scriverle. Potrebbe andare? Domani provo e ti so dire. Grazie per la risposta.
La lettura del codice della tessera mi ritorna una stringa da 6Byte tipo AAAAAA ((rdm6300.get_new_tag_id())). Lo so che i numeri sono di più ma mi basta perchè è molto improbabile trovare due carte che abbiano la stessa parte del codice uguale
Hai tolto i cicli ma la logica non è cambiata di una virgola praticamente.
Non puoi limitarti a leggere i primi tre caratteri e decidere se la tessera è già memorizzata, a meno che tu non preveda una sola tessera e allora il discorso cambia.
Se prevedi due o più tessere allora la logica dovrebbe essere questa:
Leggo dalla EEPROM il numero di tessere memorizzate in precedenza (0 se non hai mai memorizzato nulla)
Cerchi nelle posizioni di memoria della EEPROM se la tua tessera è già presente cercando tre celle alla volta fino a raggiungere il massimo numero di card memorizzate, quindi se hai già memorizzato 3 tessere dovrai cercare se il tuo codice è uguale alle celle 1,2,3 se non è uguale verifichi 4,5,6 se non è uguale allora verifichi 7,8,9. Se non è stato trovano in nessuna delle posizioni allora dovrai memorizzarla.
Se non è stata memorizzata memorizzare la nuova tessera aggiornando anche il numero di card memorizzate nella prima cella di memoria della EEPROM
Ti suggerisco di spezzare in due funzioni la cosa, ovvero fai una funzione che serve per controllare se la tessera è già presente o meno, questa funzione potrebbe restituire vero/falso o un numerico che rappresenta l'indice in EEPROM in cui la tessera è stata memorizzata
In base al valore ritornato dalla funzione (vero o falso, zero se non trovata o maggiore di zero se trovata) allora farai una seconda funzione che si occupa di memorizzare la nuova card all'occorrenza. Questa funzione oltre a memorizzare la nuova card aggiornerà anche il numero di card in memoria nella prima cella della EEPROM.
Ovvio che questo algoritmo non è il massimo in quanto se tu volessi rimuovere una card dovresti fare un po' di salti mortali ma per iniziare a gestire la cosa non è troppo sbaglaito come approccio
Per il tuo punto 2, verifica scheda memorizzata, lo faccio nel loop per aprire l'elettroserratura. Per la memorizzazione pensavo di usare un interrupt che trova le tre celle vuote e memorizza il codice di quella nuova.
nel loop leggo la scheda con i comando
(rdm6300.get_new_tag_id())
dopo di che assegno il valore letto ad una variabile long
divido in tre e memorizzo quello che ho in tre variabili (uno due e tre) che hanno una lunghezza di 1 byte. La parte della verifica funziona perchè se inserisco i tre byte all'interno della memoria (programmandola direttamente con un altro sketch) funziona regolarmente.
Il discorso è che mi verifica e memorizza i dati della tessera ma col for mi va a scrivere la serie di tre byte fino all'esaurimento delle celle e non si ferma dopo una memorizzazione delle prime tre celle.
Così come hai postato il codice se la tessera che controlli non è quella delle prime tre posizioni la ritieni non memorizzata e vai a scriverla in EEPROM.
Il fatto che poi hai anche un secondo errore che ti porta a scrivere su tutte le celle non esclude il primo errore.
Prima di decidere di salvare la nuova tessera devi verificare non solo i primi 3 caratteri ma tutte le card già memorizzate, è proprio sbagliata la logica del tuo programma.
Se già hai la parte che verifica se una card è presente, spostala in una funzione e usala per entrambi gli scopi poi resta la parte di memorizzazione che ho già spiegato prima come metterei in piedi
In realtà no perché la parte di memorizzazione dipende dalla lettura della posizione "libera" che hai individuato con la lettura che è errata.
Come già suggerito scrivi una funzione che determina se hai già memorizzato o meno usando un contatore di card memorizzate, fatta quella allora in base se hai trovato o no sarà facile, utilizzando il contatore di cui sopra, memorizzarne una nuova.
Inoltre dai un occhiata ai metodi get e put della libreria EEPROM perché con quelli puoi memorizzare tutta la stringa di tre caratteri in un colpo solo con tutte le dovute verifiche già preimpostate.
Allora ho riscritto tutto il codice solo che adesso mi sorge un problema è possibile rendere globale il valore della variabile in modo che lo stesso valore, generato dal loop() possa essere visibile in un altro blocco p.e. mioblocco()?
Scusa la domanda banale
Grazie per la risposta, la variabile è la long codice. Comunque ho riscritto tutto il codice eliminando le chiamate e facendo tutto alla pressione del tasto con digitalRead. Il tutto funziona alla grande. Grazie per le idee.
Questo è il codice, un pochino macchinoso ma funzionante
#include <Arduino.h>
#include <rdm6300.h>
#include <EEPROM.h>
#define RDM6300_RX_PIN 4 // read the SoftwareSerial doc above! may need to change this pin to 10...
int PULS = 2;
int i;
int a;
byte PinOutput = 8 ;
byte PinLed=13;
long codice_e;
long codice;
bool StatoLed;
int mem;
long tp=0;
long ritardo=400;
Rdm6300 rdm6300;
void setup()
{
Serial.begin(9600);
pinMode(PinOutput, OUTPUT);
digitalWrite(PinOutput, HIGH);
digitalWrite(PinLed, LOW);
digitalWrite(PinOutput, LOW);
pinMode(PULS, INPUT);
pinMode(PinLed, OUTPUT);
pinMode(PinOutput, OUTPUT);
rdm6300.begin(RDM6300_RX_PIN);
Serial.println("\nPlace RFID tag near the rdm6300...");
}
void loop()
{
int a= EEPROM.read(1); /Cancella la EEprom
if (a==0xFF){
for (int i=0;i<999;i++){
EEPROM.update(i, 0);
}
Serial.println("Memoria cancellata");
}
for(i=0;i<100;i++){ //Verifica il primo blocco di memoria libero
int c=i*4;
EEPROM.get(c, codice_e);
if (codice_e == 0){
mem=c;
break;
}
}
if (rdm6300.get_new_tag_id()){ //Legge il tag
codice= rdm6300.get_tag_id();
Serial.println(codice, HEX);
//Verifica abilitazione
for (i=0; i<400; i=i+4){
EEPROM.get(i, codice_e);
if (codice_e == codice) {
//Due tipi di escita nonostabile o bistabile
//Da selezionare decommentano la parte interessata
// Bistabile
Serial.println("Codice valido");
StatoLed = digitalRead(PinOutput );
StatoLed = !StatoLed;
digitalWrite(PinOutput, StatoLed );
digitalWrite(PinLed, StatoLed);
//Monostabile
/*digitalWrite (PinOutput, uscita);
//delay(500);
//uscita=!uscita;
//digitalWrite(PinOutput, 0);
//delay(2000);
*/
break;
}
}
}
bool Puls= (digitalRead(PULS)); //Verifica pressione pulsante
if (!Puls){
if ((millis()-tp)>ritardo){
tp=millis();
for (i=0; i<400; i=i+4){ //Verifica codice già memorizzato
EEPROM.get(i, codice_e);
if (codice_e == codice) {
Serial.print("Codice già memorizzatoin posizione: ");
Serial.println(i/4+1);
break;
}
}
}
if (i>mem){ //memorizzazione codice
EEPROM.put(mem, codice);
EEPROM.update(mem+3, 0x00);
}
}
}
Sto già vedendo di fare qualche modifica al programma per provvedere alla cancellazione o all'abilitazione dell'uscita variabile con funzione analogRead.