Hallo Leute,
Ich habe aktuell ein Projekt mit dem RC522 Rfid Reader und suche dafür
noch eine Lösung, wie ich den Arduino programmieren, dass er eine
Meldung sendet wenn KEINE Chipkarte auf dem Lesegerät liegt.
Mein aktueller Code basiert ursprünglich auf den Programmieranleitungen,
allerdings habe ich ihn um eine Speicher- und Vergleichsfunktion
erweitert. Mittels Taster kann ich eine Karte einspeichern und je
nachdem welche Karte danach gelesen wird leuchtet entweder eine grüne
oder rote LED. Bei Interesse kann ich den Code auch posten.
Das Problem ist, dass ich einen Code brauch der eine Meldung sendet oder
eine LED anschaltet so bald KEINE Karte auf dem RC522 liegt. Ich habe
schon viel rumprobiert und stundenlang gegoogelt aber noch keine Lösung
gefunden.
Es scheint, dass der Code ohne Karte in folgendem Bereich einfach hängen
bleibt und ewig wartet bis eine Karte gelesen wird und es im Loop weiter
geht.
1
...
2
if(!mfrc522.PICC_IsNewCardPresent())
3
{
4
return;
5
}
6
if(!mfrc522.PICC_ReadCardSerial())
7
{
8
return;
9
}
10
...
Gibt es eine Möglichkeit den Code so zu schreiben, dass beispielsweise
nach 5 Sekunden erfolglosem Suchen der Suchbefehl abgebrochen wird und
das Programm weiterläuft bis zum nächsten Loop?
Vielen Dank für eure Hilfe.
Alain
Das mit dem Return haut nicht hin. Gelesen werden darf nur wenn eine
neue Karte verfügbar ist.
void newcard(){
if ( ! mfrc522.PICC_ReadCardSerial())
Serial.print("ReadCard returned 0");
}
...
}
void loop() {
if (mfrc522.PICC_IsNewCardPresent()) {
newcard();
}
if (Serial.available() > 0) {
...
}
if 5 Sekunden vorbei {
}
}
Hallo Helmut,
vielen Dank für deine Antwort. Leider verstehe ich noch nicht so richtig
wo genau ich deinen Code in meinen einfügen muss.
Ich habe versucht die void newcard(){...} zwischen mein void setup()
{...} und mein void loop() {...} einzusetzen und den void loop
entsprechend umgeändert. Ergebnis war dass im serieller Monitor stets
"ReadCard returned 0" geschrieben wurde, egal ob Karte vorhanden oder
nicht. Wahrscheinlich habe ich als Anfänger etwas durcheinander
gebracht.
Hier ist mein orginaler lauffähiger Code, vielleicht kanns du ja mal
einen kurzen Blick draufwerfen wo ich deine Erweiterungen einbauen muss.
Vielen Dank.
1
#include<SPI.h>
2
#include<MFRC522.h>
3
#define SS_PIN 10
4
#define RST_PIN 9
5
MFRC522mfrc522(SS_PIN,RST_PIN);
6
7
inttaster=0;// Set Tastervariable
8
longsaveCode=0;// Gespeicherter Code, wenn diese Karte gelesen wird, geht OK LED an
9
longaktCode=0;// Aktueller Code
10
longaltCode=0;// vorheriger Code
11
12
voidsetup()
13
{
14
Serial.begin(9600);
15
SPI.begin();
16
mfrc522.PCD_Init();
17
pinMode(2,OUTPUT);// grüne OK LED
18
pinMode(3,OUTPUT);// rote NOK LED
19
pinMode(4,OUTPUT);// blaue Set LED
20
pinMode(5,INPUT_PULLUP);// SetTaster
21
}
22
voidloop()
23
{
24
if(saveCode==0)// Wenn kein Code gespeichert ist, soll das angezeigt werden
25
{
26
digitalWrite(4,HIGH);// Set LED an
27
taster=1;// Tastervariable setzen, erster gelesener Code wird damit automatisch gespeichert
28
}
29
if(digitalRead(5)==LOW)// SetTaster betätigt um neuen Code zu speichern, alter wird überschrieben
30
{
31
taster=1;// Tastervariable setzen
32
digitalWrite(4,HIGH);// SetLED anschalten
33
}
34
if(!mfrc522.PICC_IsNewCardPresent())
35
{
36
return;
37
}
38
if(!mfrc522.PICC_ReadCardSerial())
39
{
40
return;
41
}
42
longcode=0;// Variable für Code
43
for(bytei=0;i<mfrc522.uid.size;i++)
44
{
45
code=((code+mfrc522.uid.uidByte[i])*10);
46
aktCode=code;
47
}
48
if(taster==1)// Wenn Tastervariable gesetzt wurde, soll der gelesene Code gespeichert werden
49
{
50
saveCode=aktCode;// gelesenen Code speichern
51
digitalWrite(4,LOW);// SetLED ausschalten
52
taster=0;// Tastervariable zurücksetzen
53
}
54
if(altCode==aktCode)// Statusupdate Unterdrückung wenn kein Kartenwechsel
55
{
56
}
57
else
58
{
59
Serial.print("Der alte Code lautete:");
60
61
Serial.println(altCode);
62
63
altCode=aktCode;// alten Code durch neuen ersetzen
64
65
Serial.print("Die neue Kartennummer lautet:");
66
67
Serial.println(aktCode);
68
69
Serial.print("Der gespeicherte Code lautet:");
70
71
Serial.println(saveCode);
72
}
73
if(aktCode==saveCode)// Wenn der Code dem gespeicherten Code entspricht
Hi
schön kommentiert, aber tu dir und dritten einen Gefallen und verwende
sprechende Namen statt der Portnummern
1
digitalWrite (2, HIGH); // OK LED an
2
digitalWrite (LedOK, HIGH);
dann könnte man auf den Kommentar verzichten, das hilft auch ungemein,
wenn man die LED plötzlich nicht an Port 2 sondern an 13 haben will.
NB: ist konstruiert, aber wem sollte man hier glauben, dem Kommentar
oder dem Code?
1
digitalWrite (3, HIGH); // OK LED an
Teile das Programm auf, es gibt Sachen die man nur einmal macht wenn
eine neue Karte erkannt wird, das wollte ich mit dem newcard andeuten.
Also: wenn eine Karte erkannt wird (beachte, dass hier kein
Ausrufezeichen steht) dann ruft es die Routine auf.
1
if (mfrc522.PICC_IsNewCardPresent()) {
2
newcard();
3
}
In der newcard() steht alles ab
1
2
if ( ! mfrc522.PICC_ReadCardSerial()) {
3
Serial.println ("Card lesen hat nicht funktioniert")
4
return; // <----hier ist das return richtig
5
}
6
usw ...
Dadurch wird das Programm übersichtlicher weil der Ablauf besser
erkennbar ist.
Hi Alain
habe mal meinen RFID Lese/Schreib Sketch rausgekramt und dabei Dein
Problem erst jetzt verstanden.
"eine Meldung sendet oder eine LED anschaltet so bald KEINE Karte auf
dem RC522 liegt"
Mein aktueller Stand: Keine Ahnung wie das gehen soll, weil eben newcard
nur einmal getriggert wird.
Mein Ansatz wäre: Jede Sekunde lesen, wenn das fehlschlägt ist keine
Karte mehr da.
Ich versuchs mal heute abend.
PS: der Sketch verwendet LCD über I2C und einen Beeper an SOUND_PIN,
müsste aber auch ohne gehen.
Hallo Helmut,
vielen Dank für deine ausführliche Informationen.
Das Ziel von dem Projekt ist gewissermaßen eine Positionsüberwachung von
einem Behälter und so lange sich der richtige Chip vor dem Lesegerät
befindet, bedeutet das, dass sich der richtige Behälter an der richtigen
Stelle befindet. So bald der Behälter entfernt wird verliert das
Lesegerät den Kontakt und das soll dann angezeigt werden. Mittels
zusätzlichem Taster oder Reedkontakt könnte man das wahrscheinlich auch
lösen, nur sehe ich nicht wirklich ein weshalb ein zusätzliches Bauteil
unbedingt notwendig ist.
Der Code müsste dafür so sein, dass der Kartensuchbefehl zeitlich
limiert ist. Findet der RC522 etwas in der Zeit läuft es weiter wie
bisher, wenn nicht gibt er die Meldung weiter und der Loop startet
wieder von vorne. Alternativ, gibt es eine Möglichkeit im Code die
Durchlaufzeit von einem Loop zu messen und bei überschreiten von einem
Wert diesen Loop abzubrechen und wieder neu zustarten?
Laut MFRC522.cpp:
PICC_IsNewCardPresent() calls PICC_RequestA. Only "new" cards in state
IDLE are invited. Sleeping cards in state HALT are ignored.
PICC_RequestA() Invites PICCs in state IDLE to go to READY
PICC_WakeupA() Invites PICCs in state IDLE and HALT to go to
READY
PICC_HaltA() Instructs a PICC in state ACTIVE(*) to go to
state HALT.
PCD_StopCrypto1() Remember to call this function after
communicating with an authenticated PICC - otherwise no new
communications can start.
* Man kann eine neue PICC nur lesen wenn man das StopCrypto aufgerufen
hat.
* wenn man StopCrypto aufruft wird sofort von IsNewCardPresent eine
eventuell noch vorhandene PICC erkannt
Ist also ganz einfach, jede Sekunde (oder so, siehe nexttime+1000) wird
ein disconnect(PICC_HaltA und PCD_StopCrypto1) ausgeführt und vermutet,
dass kein PICC mehr da ist.
Wenn nach zwei Sekunden nicht das newcard getriggert wurde, dann wird
die Vermutung zur Gewissheit.
Damit sich das nur bei Bedarf so verhält kann man es auch abschalten:
int state=2;
/* to
0 Disabled ->n by serial '0' to '3'
1 PICC present ->2 by disconnect
2 unknown ->1 by newcardPresent ->3 by 2nd read
3 no PICC present ->1 by newcardPresent
*/
Jetzt muss nur noch der State abgefragt werden, beim Testprogramm gibt
es das auf LCD aus.
Nachtrag:
Müsste also für dich passen, würde mal mit dem nexttime experimentieren
wie weit man damit runtergehen kann. Bei mir hat es mit 100 ms auch
funktioniert, dabei einen bug entdeckt: state case 2 sollte kein
disconn() machen.
Bei >2cm Abstand wird sicher ein No card erkannt.
Hallo,
vielen Dank für die Hilfe.
Inzwischen ist mir noch eine Idee gekommen wie das ganze noch viel
einfacher gelöst werden kann, ohne dass der RFID Leser zurück gesetzt
werden muss.
Ich nutze nur die millis() Funktion und mache mir den Umstand zu nutze,
dass der Chipsuchprozess erst beendet wird wenn eine Karte gelesen
wurde.
Findet er eine Karte, d.h. code>0 wird dieser Zeitpunkt mit
letzteZeitEinChip = millis() festgehalten.
Am Loop Anfang vergleiche ich einfach die aktuelle Zeit mit diesem
gespeicherten Zeitpunkt, wird ein bestimmtes Intervall überschritten
bedeutet das, dass sich kein Chip vor dem Lesegerät befindet.
MfG