Forum: Mikrocontroller und Digitale Elektronik Arduino RFID RC522 Meldung senden wenn KEINE Karte vorhanden ist


von Alain Z. (alzen)


Lesenswert?

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

von Helmut H. (helmuth)


Lesenswert?

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   {
    }
}

: Bearbeitet durch User
von Alain Z. (alzen)


Lesenswert?

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
MFRC522 mfrc522(SS_PIN, RST_PIN);
6
7
int taster = 0;         // Set Tastervariable
8
long saveCode=0;        // Gespeicherter Code, wenn diese Karte gelesen wird, geht OK LED an
9
long aktCode = 0;       // Aktueller Code
10
long altCode = 0;       // vorheriger Code
11
12
void setup()
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
void loop()
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
  long code = 0;        // Variable für Code
43
  for (byte i = 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
74
{ 
75
digitalWrite (2, HIGH); // OK LED an
76
delay (1000);           // für 1 Sekunden
77
digitalWrite (2, LOW);  // OK LED aus
78
} 
79
else 
80
{ 
81
digitalWrite (3, HIGH); // NOK LED an
82
delay(1000);
83
digitalWrite(3, LOW);
84
}
85
}

von Helmut H. (helmuth)


Lesenswert?

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.

: Bearbeitet durch User
von Helmut H. (helmuth)


Angehängte Dateien:

Lesenswert?

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.

von Alain Z. (alzen)


Lesenswert?

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?

von Helmut H. (helmuth)


Angehängte Dateien:

Lesenswert?

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.

: Bearbeitet durch User
von Alain Z. (alzen)


Lesenswert?

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

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.