Loading...
Pages: [1] 2 3 4   Go Down
Author Topic: 125khz rfid Reader - char* / char[]  (Read 1696 times)
0 Members and 1 Guest are viewing this topic.
Germany
Offline Offline
Sr. Member
****
Karma: 2
Posts: 269
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hallo,

ich würde gerne ein Tür mit einem Rfid chip "öffnen" ! Zuvor probiere ich es erstmal mit einer LED, die grün leuchtet wenn die richtige RFID Karte drangehalten wurde und rot wenn eine falsche Rfid Karte erkannt wurde.
Dazu habe ich mir erstmal dieses RFID modul besorgt http://www.seeedstudio.com/depot/-p-171.html.
Anschließend habe ich erstmal so ein paar Tutorials gemacht:
http://www.instructables.com/id/Arduino-and-RFID-from-seeedstudio/ (das hat mir an sich gut gefallen, nur funktioniert der Sketch bei mir nicht so wie er sollte. Es wurde nicht der "fertige" RFID Tag in eine Zeile in den Seriellen Monitor geschrieben, sondern jede Zeile kam eine neue Zahl dazu ?!)
http://proto-pic.co.uk/125khz-rfid-module-uart/
Da ist ja weiter unten, unter dem Punkt Documents ein Bespiel für den Arduino mit einer Anwendung für VB. Ich habe mich natürlich nur auf den "Arduino Teil" konzentriert.
Erstmal der Sketch von der Website:
Code:
// Interfacing the 125Khz RFID module - UART(PPRFR101A1M-X)
// Created 20 May 2011 www.proto-pic.co.uk

#include <SoftwareSerial.h>

String msg;
char inChar;
int x;
SoftwareSerial Rfid(2, 3);    // RX as pin 2

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

void loop()

{
  
while (inChar = Rfid.read() != 2)    // Wait for start byte from Rfid reader when tag is swiped
{
}

msg = "";
for (x = 0; x < 12; x++)
{
    delay(10);  
    inChar = Rfid.read();
    msg += inChar;
}

Serial.print(msg);    // Sends the ID plus the checksum byte (12 bytes)
}

Da dieser Sketch erstmal nur die Tags lesen konnte, und auch vernünftig dem Seriellen Monitor die Tags übergeben konnte, habe ich diesen Sketch mal etwas abgeändert !

Code:
#include <SoftwareSerial.h>

#define RICHTIG "05003E22627B"
String msg;
char inChar;
int x;
SoftwareSerial Rfid(2, 3);    // RX as pin 2
int rot = 5;
int gruen = 6;
int rgbblinkhigh[] = {250, 250, 2000};
int rgbblinklow[] = {250, 250, 100};
boolean var = true;

void setup()
{
 pinMode(rot, OUTPUT);
 pinMode(gruen, OUTPUT);
 Serial.begin(9600);
 Rfid.begin(9600);
}

void loop()

{
  digitalWrite(rot, HIGH);
  digitalWrite(gruen, HIGH);
  
if(var == true) //dieses soll bewirken das der Rfid reader nur einmal liest, wenn er einen Tag erkennt ! also nicht mehrmals in den Seriellen monitor schreiben. (Das ist das Problem)
{
  var = false;
while (inChar = Rfid.read() != 2)    // Wait for start byte from Rfid reader when tag is swiped
{
}

msg = "";

for (x = 0; x < 12; x++)
{
    delay(10);
    inChar = Rfid.read();
    msg += inChar;
    
}
}

Serial.println(msg);
// Sends the ID plus the checksum byte (12 bytes)

if(msg.indexOf(RICHTIG)>=0)
{
  Serial.println("Zutritt erlaubt");
  for(int i = 0; i < 3; i++)
       {
       digitalWrite(gruen, LOW);
       delay( rgbblinkhigh [i]);
       digitalWrite(gruen, HIGH);
       delay( rgbblinklow [i]);
       }      
 
}

else
{
  Serial.println("Zutritt verboten");
  for(int i = 0; i < 3; i++)
       {
       digitalWrite(rot, LOW);
       delay( rgbblinkhigh [i]);
       digitalWrite(rot, HIGH);
       delay( rgbblinklow [i]);
       }              
      
  }
  var = true; //wieder auf true, damit wieder ein Tag gelesen werden kann
 
}

Ich hoffe jeder versteht was da so in dem Sketch "vor sich geht" ! Sonst fragt !
Bisher liest das RFID module die Tags ja ununterbrochen (d.h. der Tag wird immer weiter an den Monitor gesendet), natürlich nur wenn er einen erkennen kann, sprich wenn jemand einen vor die Antenne hält. Ich würde es gerne schaffen, dass, wenn der RFID reader ein Chip erkennt, diesen nur einmal liest, und danach eine "blink" - Folge der LED nur einmal startet. Zur Zeit ist es noch so, dass wenn ich den Chip mal etwas zu lang gegen die Antenne gehalten habe, dann wurde die blink Folge zweimal oder dreimal, je nach dem wie lange man den Chip vor die Antenne hält , abgespielt. Dazu wurde natürlich auch der Tag mehrmals in den Seriellen Monitor geschrieben.
Ich würde es nun gerne hinbekommen, dass das RFID module sozusagen nur einmal liest...sodass nur einmal die LED blinkfolge abläuft und auch nur einmal der Tag in den Seriellen Monitor geschrieben wird....ich finde das gerade echt schwer, dass hier alles so zu beschreiben !
Dazu habe ich mir erstmal gedacht, einfach eine If bedingung aufzustellen, wie man in dem Sketch sieht (var). Also solange var = true ist, soll das Module lesen und wenn false halt nicht. Direkt nach der Bedingung wird var auf false gesetzt, sodass dieser Abschnitt erstmal nicht nochmal durchlaufen kann (habe ich mir so vorgestellt), und wenn die LED fertig mit ihrer Blinkfolge sind, dann wird var wieder auf true gesetzt, wodurch der Abschnitt, also der rfid reader, wieder lesen kann. Da man den Chip wieder wegnimmt, sobald die LED anfängt so blinken, müsste es ja eigentlich passen. Aber irgendwie bekomme ich das nicht so hin, wie ich das gerne haben möchte ! :/

Also ich hoffe mich kann da jemand etwas helfen....entweder ist es mega einfach und ich bin einfach zu doof das mal wieder zu finden smiley-grin oder es ist aus irgendeinem Grund nicht so einfach wie ich mir gedacht habe...
Falls ihr das nicht so versteht, was ich jetzt so genau meine, dann fragt nochmal ! Wird wahrscheinlich so sein, habe mir leider nicht so viel Mühe gegeben, ist aber auch nicht immer einfach hier so alles im Detaill zu beschreiben !

Hoffe auf hilfreiche Antworten/Fragen ! smiley

Grüße Lorenz
« Last Edit: January 21, 2013, 07:00:19 am by lgrube96 » Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 9
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Das ist eigentlich recht einfach. Du nimmst einfach die ID der aktuellen Karte und speichert sie. Jedes mal, wenn du nun eine neue Karte empfängst, vergleichst du die gespeicherte ID mit der, die du gerade gelesen hast. Wenn die beiden gleich sind, machst du nichts. Und wenn sie sich unterscheiden führst du deine Blinksequenz durch.
Logged

Bavaria
Offline Offline
Newbie
*
Karma: 0
Posts: 14
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Das ist eigentlich recht einfach. Du nimmst einfach die ID der aktuellen Karte und speichert sie. Jedes mal, wenn du nun eine neue Karte empfängst, vergleichst du die gespeicherte ID mit der, die du gerade gelesen hast. Wenn die beiden gleich sind, machst du nichts. Und wenn sie sich unterscheiden führst du deine Blinksequenz durch.

Für den Türöffner solltest du aber noch eine zeitliche Komponente einbauen, sonst kannst du die Tür mit dem selben Tag nicht mehr öffnen, bevor sie mit einem anderen Tag geöffnet wurde.
Oder du machst es gleich nur mit einer gespeicherten Zeit. Beim Lesen des Tags speicherst du die Zeit in eine Variable:
Code:
lastread = millis();
beim Auslösen des Öffners (oder LED) prüfst du, ob das letzte Lesen mehr als 5(?) Sekunden her ist:
Code:
if(abs(millis()-lastread) > 5000){
//Aufmachen oder Blinken
}
Logged

Germany
Offline Offline
Sr. Member
****
Karma: 2
Posts: 269
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Vielen Dank erstmal für die Antworten !

Quote
Für den Türöffner solltest du aber noch eine zeitliche Komponente einbauen, sonst kannst du die Tür mit dem selben Tag nicht mehr öffnen, bevor sie mit einem anderen Tag geöffnet wurde.

Das stimmt allerdings ! Wäre echt unpraktisch wenn man vorher immer erst einen anderen Tag benutzen muss, damit das wieder funktioniert.

Mit millis() kenn ich mich jetzt eigentlich gar nicht so wirklich mal aus ! Habe mal unter References gesucht und habe da auch was gefunden.
Aber da ist das Beispiel auf etwas anderes bezogen smiley-grin Ich weiß auch gar nicht ob das auch wirklich funktioniert ! http://arduino.cc/en/Reference/millis

Ich habe dann mal gedacht so zu machen:
Code:
while (inChar = Rfid.read() != 2)    // Wait for start byte from Rfid reader when tag is swiped
{
}
lastread = millis();
Und weiter unten, jetzt nur bei der grünen Led:
Code:
if(msg.indexOf(RICHTIG)>=0)
{
  if(abs(millis()-lastread > 120)
{ //hier wusste ich nicht genau welche Zahl am besten passt, mit 120 funktioniert es noch gerade so.
  Serial.println("Zutritt erlaubt");
  for(int i = 0; i < 3; i++)
       {
       digitalWrite(gruen, LOW);
       delay( rgbblinkhigh [i]);
       digitalWrite(gruen, HIGH);
       delay( rgbblinklow [i]);
       }     
}
}

Ich muss schon irgendwie noch relativ viel lernen so mit millis(); :/
Wäre nett wenn mich da jemand unterstützen könnte !

Grüße
Lorenz
Logged

Bavaria
Offline Offline
Newbie
*
Karma: 0
Posts: 14
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hallo Lorenz,

millis() gibt die Anzahl der Millisekunden (tausendstel!) zurück, die vergangen sind, seit der Arduino gestartet wurde. Mit
Code:
if(abs(millis()-lastread) > 5000)
sagst du dem Arduino "führ das folgende aus, wenn der Unterschied zwischen dem akuellen millis()-Wert und dem beim letzten Lesen mindestens 5000 ist", sprich wenn es länger als 5 Sekunden her ist. Bei dir sind es 0,12 Sekunden... bissl kurz vielleicht.
abs() steht für "Absolutwert" (macht z.B. -2000 zu 2000). Das hat zwei Gründe: Erstens must du nicht aufpassen, welche Zahl zu von welcher abziehst und zweitens  fängt millis() nach ca. 50 Tagen wieder bei Null an.

ulli.
Logged

Switzerland
Offline Offline
Faraday Member
**
Karma: 69
Posts: 3256
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Wenn lastread als unsigned long (oder uint32_t) definiert ist, kannst Du Dir das abs() sparen, denn ein unsigned integer kann nicht negativ werden. Aber es ist durchaus relevant, welche Zahl Du von welcher abziehst, da hilft dann das abs() nicht weiter.
Logged

Bavaria
Offline Offline
Newbie
*
Karma: 0
Posts: 14
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Sorry, Pylon... aber das sehe ich anders.

Nehmen wir mal last=80000, now=90000, schwellenwert 5000 (-> die Bedingung sollte TRUE sein)

now-last=10000 > 5000 true
abs(now-last)=10000 > 5000 true
last-now=-10000 < 5000 false
abs(last-now)=10000 > 5000 true

nehmen wir vereinfachend an, dass der Arduino nach 99999 wieder bei 0 anfängt und nehmen last=95000, now=2000, schwellenwert 5000 (-> die Bedingung sollte TRUE sein)

now-last=-93000 < 5000 false
abs(now-last)=93000 > 5000 true
last-now=93000 > 5000 true
abs(last-now)=93000 > 5000 true

Bei "rund um die 99999" in diesem Beispiel ist es nicht egal, welche Zahl ich von welcher abziehe; aber das sollte in der Realität (alle ~50 Tage) auch untergehen.

Oder sehe ich da was falsch?

ulli.
Logged

Switzerland
Offline Offline
Faraday Member
**
Karma: 69
Posts: 3256
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Oder sehe ich da was falsch?

Ja. Bei einem unsigned integer gibt es KEINE negativen Zahlen. Ein unsigned long kann Zahlen von 0 bis 4294967295 darstellen. Wenn ich bei 4294967295 eins dazu zähle, kriege ich 0. Wenn ich von 0 eins abzähle, kriege ich 4294967295.

In Deinem Beispiel:

now-last = 10000
last-now = 4294957296

Die abs()-Funktion hat keine Funktion auf diesen Zahlen.
Logged

Bavaria
Offline Offline
Newbie
*
Karma: 0
Posts: 14
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Wenn ich von 0 eins abzähle, kriege ich 4294967295.

Danke, dieses Verhalten kannte ich noch nicht.
Again what learned  smiley
Logged

Germany
Offline Offline
Sr. Member
****
Karma: 2
Posts: 269
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hallo,
erstmal vielen Dank für die Antworten, auch wenn die jetzt nicht direkt etwas mit der Frage zu tun hatten.

@jubi40 : Also ich verstehe jetzt was millis() genau machen, nur weiß ich noch nicht gut drum bescheit wie ich die einem Sketch anwenden kann.
Ich wüsste absolut nicht wie ich das mit dem RFID Sketch in den Griff bekommen soll, du hast mir zwar schon da so ein Schnipsel mal geschrieben, aber so ganz funktioniert das auch nicht -_-

Logged

Switzerland
Offline Offline
Faraday Member
**
Karma: 69
Posts: 3256
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Der Aufruf von millis() liefert Dir die Zeit seit dem Starten des Arduinos in Millisekunden(!).

Der Post von jubi40 wollte Dir zeigen, dass Du die Zeit, wann Tag gelesen wurde, abspeichern kannst. Das macht nur dann Sinn, wenn Du auch den Inhalt des Tags speicherst, denn wenn unterschiedliche Tags gelesen werden, interessiert Dich der zeitliche Abstand wahrscheinlich nicht.

Also sieht das etwa so aus:

Lese Tag - überprüfe Tag auf Gültigkeit - wenn gültig, führe Aktion aus und speichere Zeitpunkt in "lastmillis" und Tag in "lasttag" ab.
Lese Tag - wenn Tag == lasttag und (millis()-lastmillis < 5000) -> speichere nur Zeitpunkt in lastmillis, andernfalls führe die Aktion trotzdem aus, denn die letzte Schlüsselverwendung liegt mehr als 5 Sekunden zurück.
Die 5 Sekunden sind willkürlich gewählt, Du kannst sie auch anpassen. Wichtig ist, dass Du den Wert von lastmillis erst änderst, wenn Du ihn mit millis() verglichen hast, sonst ist die Funktion unnütz.
Logged

Germany
Offline Offline
Sr. Member
****
Karma: 2
Posts: 269
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Ouh...Vielen Dank !
Hatte zur Zeit das kleine Problem erst mal auf Eis gelegt, aber ich habe dann mal gerade versucht das mit deiner super Anleitung zu basteln. Der Sketch ist jetzt nicht wirklich komprimiert geschrieben, einfach mal so dahin "geworfen" , von daher verzeiht mir so paar undurchsichtigkeiten, falls es welche geben sollte.
An sich funktioniert er eigentlich, solange ich immer nur den "RICHTIGEN" Tag an die Antenne halte, dann klappt alles so wie es geplant war, also dass das "blinken" nur einmal ausgeführt wird. An sich schon mal gut ! Aber wenn ich dann einen anderen Tag dranhalte, dann funktioniert das nicht so ?! Entweder übersehe ich da gerade was relativ einfaches, oder ich habe mich bei der ganzen Vorgehensweise geirrt ?!
Hier erstmal der Code:
Code:
#include <SoftwareSerial.h>

String RICHTIG  = "05003E22627B";
String msg;
String lastRead; //Speichert zuletzt erkannten RFID Tag
char inChar;
int x;
SoftwareSerial Rfid(2, 3); // RX als pin 2
int rot = 11;
int gruen = 12;
int rgbblinkhigh[] = {250, 250, 2000};
int rgbblinklow[] = {250, 250, 100};
boolean var = false;
long lastMillis; // speichert millis();


void setup()
{
 pinMode(rot, OUTPUT);
 pinMode(gruen, OUTPUT);
 Serial.begin(9600);
 Rfid.begin(9600);
}

void loop()

{
  unsigned long currentMillis = millis();
 
  digitalWrite(rot, HIGH);
  digitalWrite(gruen, HIGH);
 
while (inChar = Rfid.read() != 2)   
{
}
msg = "";

for (x = 0; x < 12; x++)
{
    delay(10); 
    inChar = Rfid.read();
    msg += inChar;
   
}

if(msg == RICHTIG)
{
if(msg == lastRead)
{
  if(millis() - lastMillis > 5000) {lastMillis = currentMillis; lastRead = 0;} //Lastread "Resetten"   
}
else
{
  Serial.println(msg);
  Serial.println("Zutritt erlaubt");
  for(int i = 0; i < 3; i++)
       {
       digitalWrite(gruen, LOW);
       delay( rgbblinkhigh [i]);
       digitalWrite(gruen, HIGH);
       delay( rgbblinklow [i]);             
       }
  lastMillis = currentMillis;
  lastRead = msg;
}
}

else
{
  if(msg == lastRead)
  {
  if(millis() - lastMillis > 5000) {lastMillis = currentMillis; lastRead = 0;} //Lastread "Resetten"   
  }
else
{
  Serial.println(msg);
  Serial.println("Zutritt verboten");
  for(int i = 0; i < 3; i++)
       {
       digitalWrite(rot, LOW);
       delay( rgbblinkhigh [i]);
       digitalWrite(rot, HIGH);
       delay( rgbblinklow [i]);
       }
  lastMillis = currentMillis;
  lastRead = msg;     
}
}
}
Ich hoffe jeder blickt durch und mir könnte jemand helfen, falls ich bald noch nicht auf den Fehler komme !

Grüße
Lorenz
Logged

Switzerland
Offline Offline
Faraday Member
**
Karma: 69
Posts: 3256
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Aber wenn ich dann einen anderen Tag dranhalte, dann funktioniert das nicht so ?!

Wie funktioniert's denn in diesem Fall? Was passiert? Ich hätte erwartet, dass die rote LED das Blinkmuster zeigt und "Zutritt verboten" auf die serielle Schnittstelle geschrieben wird.

Dein Sketch ist etwas übermässig komplex geschrieben, scheint aber grundsätzlich in Ordnung. Der grosse Fehler ist die Verwendung der String-Klasse. Die solltest Du nicht verwenden, da der Speicher im Nu fragmentiert ist und schnell kein dynamischer Speicher mehr zur Verfügung steht. Zusätzlich ist in den aktuellen IDEs (bzw. den dort enthaltenen C-Bibliotheken) ein Fehler in der free()-Funktion, womit ein Sketch, der viele Stringmanipulationen mit der String-Klasse macht, früher oder später in einem unkontrollierten Zustand endet.
Logged

Germany
Offline Offline
Sr. Member
****
Karma: 2
Posts: 269
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Ups, hab ich ganz vergessen. Also wenn ich den falschen Tag dranhalte dann blinkt das wieder öfters !

Quote
Dein Sketch ist etwas übermässig komplex geschrieben, scheint aber grundsätzlich in Ordnung.

Joa das stimmt schon ! Ich bin nicht so einer der immer so alles gleich super kompriemirt schreibt smiley-grin

Quote
Der grosse Fehler ist die Verwendung der String-Klasse. Die solltest Du nicht verwenden, da der Speicher im Nu fragmentiert ist und schnell kein dynamischer Speicher mehr zur Verfügung steht. Zusätzlich ist in den aktuellen IDEs (bzw. den dort enthaltenen C-Bibliotheken) ein Fehler in der free()-Funktion, womit ein Sketch, der viele Stringmanipulationen mit der String-Klasse macht, früher oder später in einem unkontrollierten Zustand endet.

Ist String wirklich so katastrophal ? verbraucht wohl leider viel Speicher -_- Was könnte ich gegen die Verstreuung machen ? Arrays bilden ? Oder wie meinst du das ? Das vielleicht  : http://arduino.cc/en/Reference/String Ich weiß gerade absolut nichts...
Und unter free() verstehe ich absolut nichts....
Scheint mir ja doch nicht so ganz einfach !

Grüße Lorenz
« Last Edit: January 16, 2013, 10:38:50 am by lgrube96 » Logged

Switzerland
Offline Offline
Faraday Member
**
Karma: 69
Posts: 3256
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Ist String wirklich so katastrophal ?

Ja, leider schon. Auch wenn das Teil schön angenehm zu benutzen ist (vor allem für Anfänger), ist auf dem Arduino leider wirklich dringendst davon abzuraten, mal von ein paar Übungssketches abgesehen.

Verwende char-Arrays, Vergleiche machst Du dann mit strcmp(), Anhängen mit direktem Zugriff auf den entsprechenden Index plus danach noch ein Null-Byte schreiben, etc.

Code:
// nur Beispielcode, nicht zum unveränderten Gebrauch gedacht
#define BUFFER_SIZE

char buffer[BUFFER_SIZE];
byte i = 0;
char c;
buffer[0] = 0;
while (i < BUFFER_SIZE - 1 && (c = Serial.read()) > 48) {
  buffer[i++] = c;
  buffer[i] = 0;
}

if (strcmp("2234553", buffer) == 0) {
  Serial.println("Got the right one!");
}
Logged

Pages: [1] 2 3 4   Go Up
Print
 
Jump to: