Go Down

Topic: 125khz rfid Reader - char* / char[] (Read 5280 times) previous topic - next topic

lgrube96

Ouh nein, ich dachte ich komm schnell da mit voran, aber so wie es aussieht nicht -_-
Ich nehme jetzt mal nur diesen Ausschnitt:
Quote

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

Ich habe mir mal dein Beispiel angeschaut. Soweit ich das verstanden habe, soll dort ein String und ein char Element mit einander verglichen werden. Lieg ich da richtig ?

Also ich habe das dann mal folgt ausprobiert:
Code: [Select]

#define RICHTIG "05003E22627B"
char msg;

if (strcmp(msg, RICHTIG) == 0) {
  Tue etwas bestimmtes);
}


Msg wurde natürlich vorher festgelegt:
Code: [Select]

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

  }


Ich denke mal ich stelle mich da gerade echt dumm an :/ Habe damit noch nie so richtig gearbeitet und viel im Internet dazu gibt es auch nicht...
Hoffe mal ich bekomme da etwas Unterstützung, was ich aber denke ! :)

Grüße
Lorenz

jurs

#16
Jan 17, 2013, 08:28 pm Last Edit: Jan 17, 2013, 08:41 pm by jurs Reason: 1

Ich denke mal ich stelle mich da gerade echt dumm an :/


Warum nennst Du einen Thread, in dem es um einen völlig einwandfrei funktionierenden RFID-Reader geht, eigentlich "125khz rfid Reader - Problem"? Der Reader funktioniert doch fehlerfrei und er sendet raus, was er raussenden soll?

Warum nicht sowas wie "serielle Schnittstelle auslesen" im Subject, wenn darin das eigentliche Problem besteht?


Hoffe mal ich bekomme da etwas Unterstützung, was ich aber denke ! :)


Fragen zum Auslesen der seriellen Schnittstelle kommen hier im Forum alle paar Tage vor.
Bei manchen kommt sogar das Wort "seriell" im Subject vor, z.B.:
http://arduino.cc/forum/index.php/topic,136027.0.html

Hilft meine Antwort mit dem geposteten Code in diesem Thread (Reply #3) nicht, Dich auf eine Idee zu bringen, wie man nach fest vorgegebenen Begriffen fahnden kann, die über eine serielle Schnittstelle reinkommen? Wenn Du in dem von mir geposteten Code z.B. mal "Serial.available()" durch "Rfid.available()". "Serial.read" durch "Rfid.read" und "test" durch "05003E22627B" bzw. RICHTIG ersetzt?

BTW: Die unbedachte Verwendung von String-Objekten in Arduino-Sketchen ist böse (besseres Mittel: C-Strings/Char-Arrays) und das Reinmixen eines Pointers auf ein String-Objekt anstelle eines Pointers auf einen C-String in eine Funktion, die nur mit C-Strings umgehen kann, führt immer zu irregulärem Programmverhalten.

lgrube96

Vielen Dank erstmal für deine Rückmeldung !
In letzter Zeit habe ich auch schon gemerkt das der Titel kaum passt...mir fällt einfach gerade nichts passendes ein ! Und "serielle Schnittstelle auslesen" ist auch nicht so das ganze ! Weil ich kann ja die Ths lesen usw.. Es ging eigentlich nur um das Problem das der immer je nachdem wie lange man den Tag dranhält, die Led öfters blinken lässt !
Jetzt kommt aber noch das mit "kein Sting" verwenden usw.

Ich werde mir mal deinen Vorschlag da angucken..mal schauen was sich machen lässt !

Grüße
Lorenz

jurs


Es ging eigentlich nur um das Problem das der immer je nachdem wie lange man den Tag dranhält, die Led öfters blinken lässt !


Wenn das ein Problem ist, braucht man sich ja nur in einer long-Variablen die Zeit zu merken, wann es zuletzt geblinkt hat, und dann ignoriert man eben so lange alle weiteren Codes wie kein wiederholtes Blinken auftreten soll.

lgrube96

Wenn du mal auf der 1. Seite lesen würdest !, dann wüsstest du, dass ich das Problem eigentlich schln fasst erledigt habe!!!

Jetzt ist halt nur noch das Problem mit dem String das ich diese weglasse !

michael_x

1. "Dies ist kein String" . Jedenfalls kein String-Objekt.
2. ein char und ein char* sind zwei verschiedene Dinge,
    aber ein char* und ein char array, also dein char buffer[] sind fast das gleiche. Als Funktionsparameter wie in strcmp sind sie auf jeden Fall gleich verwendbar.

pylon


Ich habe mir mal dein Beispiel angeschaut. Soweit ich das verstanden habe, soll dort ein String und ein char Element mit einander verglichen werden. Lieg ich da richtig ?

Also ich habe das dann mal folgt ausprobiert:
Code: [Select]

#define RICHTIG "05003E22627B"
char msg;

if (strcmp(msg, RICHTIG) == 0) {
  Tue etwas bestimmtes);
}



In meinem Code ist buffer ein character array, was natürlich eine String-Konstante (à la "34533454") auch ist. Somit werden Äpfel mit Äpfeln verglichen und alles ist in Ordnung. Du definierst aber msg als einen Character (nicht Array), somit ist es nicht mehr das Gleiche.
Arrays werden in C einfach als Pointer auf das jeweilige Objekt aufgefasst, wie das michael_x bereits erklärte. Daraus resultiert dann, dass in C ein Textstring ein Character-Array (char[]) und somit ein Character-Pointer (char *) ist. Ich hoffe, das klärt Deine Verwirrung etwas.

lgrube96

Soweit ich das jetzt verstehe, muss ich jeden String einfach zu ein char* Objekt verändern ?!
Also so:
Code: [Select]

char* msg;
char* lastread;


Ich dachte das ist irgendwie viel komplizierter ?!
Wahrscheinlich habe ich da mal was falsch verstanden...


michael_x


Soweit ich das jetzt verstehe, muss ich jeden String einfach zu ein char* Objekt verändern ?!
Also so:
Code: [Select]

char* msg;
char* lastread;


Ich dachte das ist irgendwie viel komplizierter ?!
Wahrscheinlich habe ich da mal was falsch verstanden...


viel komplizierter ist es nicht, aber ein bisschen fehlt doch noch:
Der Datentyp von msg und lastread ist schonmal gut, nur zeigen sie so nirgends hin.

Code: [Select]
char msg[81] ; // legt einen Speicherbereich für max 80 Zeichen + EndeKennung fest.
lastread = msg; // lastread zeigt jetzt auf den gleichen Speicher
lastread++; // zeigt jetzt auf den 2. Buchstaben von msg

lgrube96

Ganz ehrlich...irgendwie komme ich da mit nicht zu recht -_-

Ich weiß noch nicht ganz, wie ich das alles genau lösen soll.
Weil wenn ich Anfangs erstmal folgendes definiere:
Code: [Select]
char msg[81];
char lastRead[81];


und ich möchte dann den gelesenen Tag in msg hineinschreiben.
Code: [Select]
for (x = 0; x < 12; x++)
  {
    delay(10); 
    inChar = Rfid.read();
    msg[x] += inChar;

  }
Serial.println(msg);


Ich hoffe mal, dass das bis hier hin alles so einigermaßen richtig ausschaut ! Zum mindest wird der Tag richtig, beim ersten dranhalten,  erkannt, wenn ich dann aber nochmal lesen lasse, dann kommen da ganz komisches Gewirr von Zeichen usw. Ich müsste wahrscheinlich char irgendwie "leeren" aber da weiß ich zur Zeit noch nicht, wie ich das anstellen soll.
Nur wenn ich nun ein Vergleich tätigen möchte, hapert es leider noch:
Code: [Select]
if(strcmp("05003E22627B", msg)== 0)
  {
Serial.println("Zurtitt erlaubt");
}


Das funktioniert auch nicht !
Und auch das gleichsetzen von lastRead und dem gelesenen Tag klappt nicht so wie ich es von michael entnommen habe:
Code: [Select]

lastRead = msg;


Kann mir auch nicht vorstellen, dass das so einfach bei char array ist !

Grüße
Lorenz

michael_x

Quote
Kann mir auch nicht vorstellen, dass das so einfach bei char array ist !


Was ich vergessen habe:
1. ein char array hat ein Endekennzeichen: eine (binär) 0 nach dem letzten Zeichen.
print, strcmp, usw. arbeiten immer bis zu dieser 0.
Code: [Select]
char msg[13]; // 0 .. 12
if (Rfid.available())
{
  for (byte x = 0; x < 12; x++)
  {
    delay(10); 
    char inChar = Rfid.read();
    msg[x] += inChar; 
  }
  msg[x]=0;  // EndeKennung in msg[12] !!!
  Serial.println(msg);
}


2. ein char array und ein char* unterscheiden sich insoweit, als ein char* eine eigene Variable ist, die auf ein char array verweist.

Code: [Select]
char* mp = msg; // mp kann jetzt genau wie msg verwendet werden, z.B. in print oder strcmp
// auch das ist alles möglich:
*mp == mp[0]; // vergleicht den ersten Buchstaben mit sich selbst
mp[0] = 'x';  // ändert den  ersten Buchstaben in msg
*(mp+1) = 'y'; // ändert den nächsten Buchstaben in msg

Man kann natürlich mp selbst auch ändern  (z.B.  mp++; ) und mit *mp jeweils einzelne Buchstaben ansprechen.
Das macht mit einem char array keinen Sinn!

Wenn du dich daran ein wenig gewöhnst, ist es wirklich einfach.

lgrube96

#26
Jan 25, 2013, 01:19 pm Last Edit: Jan 25, 2013, 03:03 pm by lgrube96 Reason: 1
So...endlich habe ich mal wieder etwas Zeit gefunden mich mit Arduino weiter zu beschäftigen !
Nun habe ich es mittlerweile nach langwierigem basteln mit dem Code endlich hinbekommen, Vielen Dank bis hierhin schonmal !:
Code: [Select]
#include <SoftwareSerial.h>

char msg[13];
char inChar;
int x;
SoftwareSerial Rfid(2, 3); // RX als pin 2

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

void loop()
{
 while (inChar = Rfid.read() != 2)    
 {
 }  

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


Anfangs hatte ich immer folgendes:
Code: [Select]
msg[x] += inChar;
Und das hat alles meine ganzen Leseergebnisse richtig verfälscht, da kam einfach nur "Dünnschiss" raus :D.

Im laufe des Tages werde ich mich dann auch mal dransetzen, dass mit der Led einzubinden, ist ja an sich eigentlich gar nicht so eine große Sache, aber ich lasse mir gerne etwas Zeit.

Noch eine Frage am Rande:
Wahrscheinlich ist es dann auch Sinnvoll, wenn man mit der SD card arbeitet, wenn man schöne char elemente benutzt ?!
Und was genau passiert bei char elementen im Speicher, warum verbrauchen die letztendlich weniger Speicher als String ?!

Grüße
Lorenz

EDIT: Wie mache ich das eingentlich, dass, in meinem Fall lastRead, die gleichen Werte wie msg annimmt ?
Mit einem einfachen Gleich ist es wohl nicht getan. Ist dort eine Schleife anzuwenden ?
EDIT: Also so:
Code: [Select]
for(int i = 0; i <= 12; i++)
  {
   lastRead[i] = msg[i];
  }

michael_x

Quote
Wie mache ich das eingentlich, dass, in meinem Fall lastRead, die gleichen Werte wie msg annimmt ?
Mit einem einfachen Gleich ist es wohl nicht getan. Ist dort eine Schleife anzuwenden ?


Wenn msg und lastRead zwei unterschiedliche Texte sein können, ( d.h. wenn lastRead erhalten bleiben muss, während msg wieder geändert wird )
dann brauchst du zwei char arrays die du umkopierst, entweder wie in deinem Vorschlag, oder mit strcpy().
Wenn aber lastRead nur eine andere Sicht auf den gleichen Text ist, kannst du  char* lastRead = msg; schreiben.

Dein "Dünnschiss" sieht übrigens besser aus, wenn du msg[x++] = inchar; schreibst. Kleiner Unterschied in der Schreibweise, anderer Effekt.

jurs


Und was genau passiert bei char elementen im Speicher, warum verbrauchen die letztendlich weniger Speicher als String ?!


char-Arrays mit C-Strings sind Standard im Zusammenspiel mit der C-Standardlibrary. Die C-Standardlibraries enthalten seit Jahrzehnten bewährten und millionenfach getesteten, (so gut wie) fehlerfreien Code ohne Speicherlecks.

String-Objekte sind vergleichsweise neu. Und String-Objekte auf einer Mikrocontroller-Plattform mit den diversen Arduino-Magic-Tricks vor dem Kompilieren zu implementieren, damit haben die Arduino-Macher Neuland betreten und sich dabei gehörig vergallopiert.

Einerseits bekommen String-Objekte ihre Länge dynamisch zur Laufzeit zugewiesen, dadurch wird der Heap bei laufendem Programm fragmentiert, wenn Zuweisungen ständig unterschiedlich langer Strings erfolgen. Irgendwann ist dann kein freier Speicherbereich zur Zuweisung eines langen Strings mehr frei ==> Crash. Alleine schon deswegen eignen sich String-Objekte eigentlich nur auf Systemen mit weitgehend unbegrenztem Hauptspeicher, insbesondere für Computer mit der Möglichkeit von Auslagerungsspeicher auf Festplatte.

Aber bei der Arduino-Software ist alles noch schlimmer.
Denn offensichtlich ist die String-Library auf der Arduino-Software mit ihren ganzen Magic-Arduino-Tricks vor dem Kompilieren fehlerhaft  implementiert, sonst könnte es nicht sein, dass bei nur so wenigen Iterationen der Speicher crasht und das Ende der while-Schleife nicht erreicht wird:

Crash-Code mit String-Objekten, Demonstration für Arduino UNO:
Code: [Select]

void setup() {
  Serial.begin(9600); 
  String str, strMalDrei, strMalZehn;
  int n = 0;
  // Auf einem Arduino "UNO" crasht die while-Schleife
  // ohne das Schleifenende zu erreichen
  while(n <= 100) {
    str= String(n);
    strMalDrei=String(n*3);
    strMalZehn=String(n*10);
    str = str + ", " + strMalDrei + ", " + strMalZehn;
    Serial.println(str);
    delay(250);
    n++;
  }
  Serial.println("Done"); 
}

void loop() {
  // put your main code here, to run repeatedly:
}

==> Crash mit String-Objekten auf Arduino UNO mit Arduino 1.0.1 vor dem Schleifenende.

lgrube96

Vielen Dank an euch beide ! Habe das jetzt endlich mal einigermaßen verstanden, was so ein char Array alles gutes bewirkt !

Ich habe mich dann auch mal an den "fertigen" Code gesetzt und folgendes ist rausgekommen:
Code: [Select]
#include <SoftwareSerial.h>

char msg[12];
char lastRead[12];
char inChar;
int x;
SoftwareSerial Rfid(2, 3); // RX als pin 2

int rot = 11;
int gruen = 10;

long lastMillis;

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

}

void loop()

  unsigned long currentMillis = millis();

  while (inChar = Rfid.read() != 2)   
  {
  } 

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

  if(strcmp("05003E22627B", msg)== 0)
  {
   
    if(strcmp(msg, lastRead)== 0 )
    {
      if(millis() - lastMillis > 5000) {
        lastMillis = currentMillis;
        lastRead[1] = 0;
      } //Lastread "Resetten"   
    }

    else
    {

      Serial.println("Zutritt genehmigt");
      Serial.println( msg);   
      digitalWrite(gruen, LOW);
      delay(400);
      digitalWrite(gruen, HIGH);
      delay(400);             
      lastMillis = currentMillis;
      char* lastRead = msg;
    }
  }
  else
  {   
    if(strcmp(msg, lastRead)== 0 )
    {
      if(millis() - lastMillis > 5000) {
        lastMillis = currentMillis;
        lastRead[1] = 0;
      } //Lastread "Resetten"   
    }
    else
    {
      Serial.println("Zutritt verweigert");
      Serial.println( msg);
      digitalWrite(rot, LOW);
      delay(400);
      digitalWrite(rot, HIGH);
      delay(400);
      lastMillis = currentMillis;
      char* lastRead = msg;   
    }
   
  }
}


Also es ist leider immer noch das Problem von 'damals' vorhanden :/ Solange ich nur den RICHTIGEN Tag verwende funktioniert das mit dem einmal-ausführen echt super ! Aber wenn ich dann zum FALSCHEN Tag greife dann macht der das so lange ich den Tag an die Antenne halte ?! Ich weiß einfach nicht woran das liegen kann !!! Für mich ist das sowas unerklärlich ?! Das echt so ein nerviger Fehler ! Hoffentlich kann mich jemand darüber aufklären !

Und dann hätte ich da noch eine Frage bezüglich Arduino Mega2560:
Da ich später eh zu einem Mega greifen werde, weil ich etwas größere Sachen mit Arduino vorhabe, habe ich mal Fix ausprobiert, ob das mit dem RFID auch beim Mega auf Anhieb klappt. Natürlich musste ich noch den RX pin ändern, da ja die SoftwareSerial.lib nicht alle Pins beim Mega unterstützt. Da habe ich erstmal so pin 50 benutzt.
An sich funktioniert es EIGENTLICH, aber wirklich zuverlässig liest der Mega nicht mehr ! Manchmal tut er es und manchmal nicht, weiß jetzt nicht wie man das noch besser beschreiben könnte...
Hoffe ich habe das irgendwas kleine Übersehen ! Oder ist das unmöglich mit dem Mega ?

Grüße
Lorenz

Go Up