RFID über UART einlesen.

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
LotharK
User
Beiträge: 51
Registriert: Sonntag 22. März 2015, 10:02

Hallo,

ich habe mir einen RFID-Leser gekauft.
Diesen habe ich am Raspberry Pi2 angeschlossen. +5V, GND und RXD über 2x 5,6KOhm

Mit diesem Code lese ich die Daten der Chips aus.

Code: Alles auswählen

import serial
import time

def read_rfid():
   ser=serial.Serial("/dev/ttyAMA0", 9600)
    
   if(not(ser.isOpen())):
      ser.open()
      #print "Open"
   daten=ser.read(14)
   ser.close()
   daten=daten.replace("\x02", "" )
   daten=daten.replace("\x03", "" )
   return daten
   
while True:
   print "Reader bereit"
   id=read_rfid()
   print id
 
Der Code funktioniert einige Zeit einwandfrei. Die Karten-Daten werden einwandfrei gelesen.

Nach einigen Einlesungen, die Anzahl ist sporadisch, stürzt das Programm mit folgenden Fehlern ab.

Traceback (most recent call last):
File "UART.py", line 18, in >module>
id=read_rfid()
File "UART.py" line 10, in read_rfid
Daten=ser.read(14)
File "/usr/lib/python2.7/dist-packages/Serial/serialposix.py", line 449, in read
buf = os.read(self.fd, size-len(read))
OSError: [Errno 11] Resource temporarly unavailable


Nun weiß ich nicht, ob es an meinem Code liegt, ob es ein Fehler in serialpos1x.py des Systems ist, oder ob mein Reader spinnt.

Hat jemand Erfahrungen mit dem Fehler? Ist mein Reader Schrott? Nach einem Neustart des Programms funktioniert es wieder einige Zeit. Für einen tipp wäre ich dankbar.

MfG
Sirius3
User
Beiträge: 18335
Registriert: Sonntag 21. Oktober 2012, 17:20

Der Fehler kommt ja vom Betriebssystem, also muß Dein Programm solche Fehler abfangen können und entsprechend darauf reagieren.
LotharK
User
Beiträge: 51
Registriert: Sonntag 22. März 2015, 10:02

Hi,

danke für die Antwort. Das der Fehler vom BS kommt, ist schlecht. Von der Hardware wäre mir lieber. Ich bekomme erst wieder Daten, wenn ich den Reader Spannungsfrei mache und neu verbinde.
Ich habe einige Artikel gelesen, dort beschrieb keiner so ein Phänomen. Kann ich das, mit einem Update beheben, oder einem anderen Katenleser? Störsignale vom Reader kann ich (fast) ausschließen.

Natürlich muss ich den Fehler programmtechnisch ebenfalls abfangen, nur hätte ich die eigentliche Fehlerquelle gern beseitigt.

Gruß Lothar
BlackJack

@LotharK: Der Low-Level-Fehlercode hier ist 'EAGAIN':

Code: Alles auswählen

In [13]: errno.errorcode[11]
Out[13]: 'EAGAIN'
Den bekommt man bei einem `read()`-Systemaufruf wenn man von einer Verbindung die nicht-blockierend geöffnet wurde lesen will, aber keine Daten zur Verfügung stehen. Das ist in sofern komisch als das die `PosixSerial.read()`-Methode vorher mit `select.select()` prüft ob Daten vorhanden sind, und dann dürfte dieser Fehlercode gar nicht kommen. Ausser vielleicht wenn noch ein anderes Programm Daten von diesem Port liest und einem genau zwischen `select.select()` und `os.read()` die Rückgabedaten ”klaut”. Hast Du vielleicht parallel noch irgend etwas anderes laufen? Ein Terminalprogramm oder die Arduino-IDE zum Beispiel?

Die Zeilen 7 und 8 sind übrigens überflüssig weil `Serial`-Objekte auf jeden Fall offen sind wenn man sie mit Portangabe erstellt hat. Beim ``if`` sind auch ein paar Klammern zu viel.

Das `close()` wird im Falle einer Ausnahme bei `read()` nicht aufgerufen. Das sollte man entweder in ein ``finally`` stecken oder noch besser ``with`` zusammen mit dem `Serial`-Objekt verwenden. Die Klasse unterstützt das.

Edit:

Code: Alles auswählen

#!/usr/bin/env python
# coding: utf8
from __future__ import absolute_import, division, print_function
from serial import Serial


def read_rfid():
    with Serial('/dev/ttyAMA0', 9600) as serial:
        return serial.read(14).replace('\x02', '').replace('\x03', '')


def main():
    while True:
        print('Reader bereit')
        print(read_rfid())


if __name__ == '__main__':
    main()
LotharK
User
Beiträge: 51
Registriert: Sonntag 22. März 2015, 10:02

Hallo,
danke für die Antwort.
Nein, bei mir läuft nichts anderes. Habe auch den Pi mehrmals neu gestartet.

Ich habe mich als root angemeldet (ich weiß, wenn alles läuft, ändere ich das. Jetzt aber zur Fehlerelemenierung nicht)
Programmstart mit: python uart.py

Nach 2, maximal vier Einlesungen, (immer der gleiche Transponder) , stürzt auch Dein Code ab.
Hm, gerade die Zeile 7 und 8 habe ich aus einem Buch. RaspBerry Pi - Der praktische Einstieg.

Ist schlecht, wenn man sich Bücher kauft um zu lernen und dann doch wieder alles falsch ist. In den Foren kommt dann meist die Bemerkung: Mach Dich erst mal schlau. Gute Bücher gibt es genug. :(

Schade, so richtig weiß ich jetzt nicht mehr, was ich tun soll.

Leider kann ich dein with und return nicht geistig auflösen. Das ist für mich noch zu komplex. Das kommt erst mit der Zeit.

MfG LotharK
LotharK
User
Beiträge: 51
Registriert: Sonntag 22. März 2015, 10:02

Hallo,

ich habe den Fehler gefunden. Danke allen, die mir geholfen haben.

die Zeile
T0:23 respam:/sbin/getty -L ttyAMA0 115200 vt100
in der Datei /etc/inittab muss auskommentiert werden.
Seitem läuft das Programm.
Achtung nach Abschalten dieser Zeile kann die UART nicht andersweitig genutzt werden.

MfG Lothar
BlackJack

@LotharK: Das wollte ich auch gerade anmerken, das das System da noch selbst auf Anmeldungen warten könnte. :-) Wobei: Gerade *durch* das auskommentieren dieser Zeile kann man die serielle Schnittstelle des Chipsatzes für etwas anderes benutzen.

Den Ausdruck beim ``return`` solltest Du verstehen, denn der macht ja nichts anderes als in Deinem Quelltext, nur das halt nicht jedes Zwischenergebnis an einen Namen gebunden wird.

Und das ``with`` ist eigentlich nicht wirklich schwer zu verstehen. Es wird ein `Serial`-Exemplar erstellt und an den Namen `serial` gebunden und wenn der Kontrollfluss den ``with``-Block verlässt, egal aus welchen Gründen dann wird das dem `Serial`-Objekt mitgeteilt und das schliesst die Verbindung. Ohne ``with`` müsste man das hier schreiben:

Code: Alles auswählen

def read_rfid():
    serial = Serial('/dev/ttyAMA0', 9600)
    try:
        return serial.read(14).replace('\x02', '').replace('\x03', '')
    finally:
        serial.close()
Und die eine oder die andere Variante muss man nehmen, sonst hat man das Problem das die Verbindung nicht deterministisch sauber geschlossen wird wenn eine Ausnahme beim Lesen der Daten auftritt. Das würde ich als Programmfehler ansehen.
LotharK
User
Beiträge: 51
Registriert: Sonntag 22. März 2015, 10:02

Danke für die Antwort. NOCH sieht die Routine für mich viel übersichtlicher aus.
Natürlich könnte ich sie so noch nicht selbst entwickeln.
Ich werde das mal so machen. Da finde ich mich dann in späterer Zeit noch rein. Da ich nicht mehr vor habe, ein Python-Profi zu werden.

Auf alle Fälle Hut ab, vor dem kleinen Raspi.

Danke bis zum nächsten Stolperstein.

MfG LotharK
Antworten