Pages: [1]   Go Down
Author Topic: Türschaltung mit Arduino und RFID  (Read 1188 times)
0 Members and 2 Guests are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 10
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hallo,

ich habe mir vor ein paar Tagen einen Arduino und ein RFID-Readermodul gekauft, um damit eine Tür zu öffnen/schließen.
Mit SoftwareSerial bekomme ich die Verbindung zwischen Arduino und Reader hin, wenn das richtige Tag vor den Reader gehalten wird, dann schreibt der Arduino den Port 13 2 Sekunden lang auf HIGH, dann wieder LOW.
hier mal der code:
Code:
#include <SoftwareSerial.h>

//Kommunikation mit der RFID-Platine
SoftwareSerial rfid = SoftwareSerial(2,6);

//Output zur Türschaltung
byte doorLock = 13;

void setup()
{
  //Pins
  pinMode(doorLock, OUTPUT);
  
  //Serials  
  //Serial.begin(9600);
  //Serial.println("Serial ready");
  
  rfid.begin(9600);
  //Serial.println("RFID ready");
}

//Tags mit Zugangsberechtigung
String tags[] = {"50008F1234D8","5100ABCDEF29","5100FEE1234A"};
int numberOfTags = 3;


//Zu prüfender Tag
String applicant;

void loop()
{
  applicant = getTag();
  //
  
  if (applicant.length() == 12)
  {
    //Serial.println(applicant);
    if (checkTag(applicant) == true)
    {
      digitalWrite(doorLock, HIGH);
      //Serial.println("Access granted");
      delay(2000);      
      digitalWrite(doorLock, LOW);
    }
    else { /*Serial.println("Access denied")*/;}
  }
  
  applicant = "";
}


//Tag-ID auslesen, falls möglich
String getTag()
{
  char c;
  String tag;
  while(rfid.available()>0)
  {
    c=rfid.read();
    tag += c;  
  }
  tag = tag.substring(1,13);
  delay(30);
  return(tag);
  
}

//Hat der Tag Zugangsberechtigung?
boolean checkTag(String applicant)
{
  for(int i = 0; i < numberOfTags; i++)
  {
    if (applicant == tags[i])
      return (true);
  }
  return (false);
}

Das ganze hat folgenden Haken: in der Methode getTag() (ziemlich am Ende) musste ich eine verzögerung von 30ms einbauen, sonst klappt es irgendwie nicht (der reader scheint das tag nicht schnell genug lesen zu können... oder liegts vielleicht an der seriellen Verbindung??). Das führt dazu, dass die Tür (hängt über nen transistor an pin 13) 2 sekunden aufgeht, dann 30ms zu ist usw., was natürlich stört.
Weiß jemand, wie ich diese delay da rauskriegen könnte?

Vielen Dank schon mal für alle Antworten smiley
« Last Edit: November 14, 2012, 06:50:06 pm by albion » Logged

Forum Moderator
BZ (I)
Online Online
Brattain Member
*****
Karma: 236
Posts: 20300
+39 349 2158303
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

benutz kein delay(2000) sondern millis() Siehe http://www.arduino.cc/en/Tutorial/BlinkWithoutDelay

Lies alle 500mS den RFID und setze den Ausgang LOW wenn nach 2 s keine Positive lesung erfolgt.
Grüße Uwe
Logged

Switzerland
Offline Offline
Faraday Member
**
Karma: 96
Posts: 4765
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Dein "delay(30);" hat mit grosser Sicherheit nichts mit dem Problem zu tun. Das grösste Problem bei der Verwendung als Türschloss (Dauerbetrieb) sehe ich in der Verwendung der String-Klasse. Sie fragmentiert den Speicher und zudem hat die  dynamische Speicherverwaltung ein Memory-Leak. Früher oder später wird Dein Sketch also nicht mehr funktionieren. Ersetze alle String-Objekte durch char-Arrays.
Logged

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

dankeschön für die antworten! es klappt jetzt. hab die loop abgeändert:

Code:
unsigned long time = millis();

void loop()
{
  if ( (millis()-time) > 1000)
  {
    applicant = getTag();
    //Serial.println(applicant);
   
    if (checkTag(applicant))
      digitalWrite(doorLock, HIGH);
    else
      digitalWrite(doorLock, LOW);
   
    time = millis();
  }
}

mehr oder weniger so, wie uwe das vorgeschlagen hat.
zu der Stringklasse: inwiefern hat die ein speicherleck? und kann ich den speicher nicht wieder freigeben? hat schon jemand eine dichte Stringklasse implementiert? wäre schön, wenn ich die einfach benutzen könnte, sonst muss ich ja auch die substringmethode umschreiben usw...
Logged

Offline Offline
Jr. Member
**
Karma: 0
Posts: 82
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Der RFID-Tag ist sind 48 Bits. Dein String den du verarbeitest ist die Hexadetimaldarstellung:

50008F1234D8 -> HEX: 0x50 0x00 0x8F 0x12 0x34 0xD8 -> BIN 01010000 00000000 10001111 00010010 00110100 11011000

Also schreib das ganze in ein byte Array:

byte Tag[][]={{0x50, 0x00, 0x8F, 0x12, 0x34, 0xD8}, {0x51, 0x00, 0xAB, 0xCD, 0xEF, 0x29}, {...}}

Der Arduino ist nicht gemacht dafür Texte zu verarbeiten. Die Konversionen kosten nur Speicher und Rechenzeit. Und speicher ist beim Arduino nicht grade üppig vorhanden.
Logged

Switzerland
Offline Offline
Faraday Member
**
Karma: 96
Posts: 4765
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
zu der Stringklasse: inwiefern hat die ein speicherleck? und kann ich den speicher nicht wieder freigeben? hat schon jemand eine dichte Stringklasse implementiert?

Das Speicherleck ist in der AVR-Implementation von free(), also der C-Funktion, die Speicher wieder freigibt.

Die String-Klasse hat aber auch ein grundsätzliches Problem. Sie alloziert für fast jede Operation neu Speicher und gibt den alten wieder frei. Auf einem heutigen PC-System ist das kein Problem, die haben dafür MMUs (Memory Management Units), welche den physikalisch vorhandenen Speicher abstrahieren und auch nicht-zusammenhängende Bereiche als zusammenhängend darstellen können. Zudem ist es auf einem PC egal, wenn mal 2kB Speicher nicht mehr verwendet werden können, weil der Bereich zu klein ist für die nächste Allokation.
Ein Arduino hat nur 2kB Speicher (SRAM) und keine MMU. Wenn also 15 Byte Speicher alloziert wird, dann ein Zeichen hingefügt wird, so wird neu Speicher für 16 Byte alloziert, dann die 15 Byte freigegeben. Beim nächsten Hinzfügen braucht die Klasse 17 Byte. Die vorher freigegebenen 15 Byte können nicht verwendet werden, da 17 aufeinanderfolgende Bytes gebraucht werden, also werden sie hinter den 16 Bytes alloziert und darauf hin die 16 Bytes freigegeben. Wenn Du dieses Muster weiterdenkst, siehst Du, dass der Speicher irgendwann eine Wüste mit verschiedenen Allokationen und dazwischen kleinen Lücken ist, die aber häufig nicht mehr gebraucht werden können, weil sie zu klein für die jetzige Allokation sind. Zudem muss der Heap (also der Speicherbereich, welcher die lokalen Variablen hält) immer zusammenhängend sein, weshalb Du bei nur 2kB Speicher sehr schnell an die Grenzen kommst. Wenn diese erreicht ist, kann die CPU nur noch eine Exception werfen, was meist in einem Reset endet. Da dies unkontrolliert passiert, ist ein solcher Zustand für ein embedded System unhaltbar, diese müssen meist 24/7/365 laufen.
Logged

Germany
Online Online
Faraday Member
**
Karma: 49
Posts: 2759
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Sehr gute Erklärung!

Bis auf:
Quote
kann die CPU nur noch eine Exception werfen, was meist in einem Reset endet
Wenn's wenigstens das wäre. Der new Operator liefert einfach eine 0 zurück, was die meisten Programme aber nicht abfragen, ( was soll man auch machen in einem Controller ) Also wird irgendwas überschrieben, das Programm läuft weiter und hängt irgendwo ( z.B. wegen überschriebener Rücksprungadressen) oft ohne Reset.
Logged

Switzerland
Offline Offline
Faraday Member
**
Karma: 96
Posts: 4765
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Wenn's wenigstens das wäre. Der new Operator liefert einfach eine 0 zurück, was die meisten Programme aber nicht abfragen, ( was soll man auch machen in einem Controller ) Also wird irgendwas überschrieben, das Programm läuft weiter und hängt irgendwo ( z.B. wegen überschriebener Rücksprungadressen) oft ohne Reset.

Das mit der Exception passiert eigentlich eher, wenn der Heap keinen Platz mehr hat. Bei new bzw. malloc() sollte der Rückgabewert eigentlich immer geprüft werden, aber das steht auf einem anderen Blatt...

Du hast aber Recht, dass häufig der Prozessor einfach in's Nirwana springt und hängen bleibt, auf jeden Fall ist das Verhalten meist nicht vorhersagbar (nicht-deterministisch).
Logged

Offline Offline
Edison Member
*
Karma: 21
Posts: 1407
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Für solch unvorhersehbares Verhalten gibt es einen Watchdog-Timer, mit dem man aber auch vorsichtig sein sollte. Die Zeit sollte immer größer sein, als der der Bootloader wartet ob eine neuer Sketch übertragen wird.
Im Grund ist der Watchdog-Timer eine Art Countdown der von einer gesetzten Zeit rückwärts zählt. Kommt er bei 0 an, wird ein Reset ausgelöst und der Prozessoer damit wieder in einen definierten Zustand gesetzt. Um den Reset zu verhindern, muss innerhalb der gesetzten Zeit der Timer zurückgesetzt werden. Damit "weiss" der Watchdog dann, das das Programm noch "lebt".
Logged

AREA COLOGNE
Offline Offline
Edison Member
*
Karma: 15
Posts: 1069
I am 1 of 10 who understands binary
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Der watchdog ist ein hund den du regelmässig aus deinem Programmheraus beissen musst, machst du das nicht dann beißt er zurück, aber so das dir "schwarz" vor augen wird. Nutzt man eine Wtchdog sollte man sowieso wenn es geht auf den Bootloader verzichten und über ISP Programmieren.

Gruß#
Der Dani
Logged

So ist das Leben:
Manchmal bis du das Denkmal, manchmal die Taube!

Pages: [1]   Go Up
Jump to: