Projektarbeit
Konzeption eines RFID-Lesegerätes
Michel Steichen
19. Juli 2008
In dieser Projektarbeit wird ein RFID-Lesegerät entworfen, welches RFID-Trans-
ponder lesen und beschreiben kann. Der Aufbau des Gerätes ist einfach nach vollziehbar
und besteht aus leicht beschaffbaren Bauteilen. Das entwickelte Gerät ist so konstru-
iert, dass es zu Demonstrationszwecken auf Workshops oder Messen eingesetzt werden
kann. Es bietet den Zuschauern somit einen kurzen Einblick in die Funktionsweise der
RFID-Technologie.
Inhaltsverzeichnis
1 Einleitung 5
1.1 Definition von RFID . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.2 Der gewählte RFID-Standard . . . . . . . . . . . . . . . . . . . . . . . . 6
1.3 Gliederung der Ausarbeitung . . . . . . . . . . . . . . . . . . . . . . . . . 6
2 Das RFID-Lesegerät 8
2.1 Einführung in die Theorie . . . . . . . . . . . . . . . . . . . . . . . . . . 8
2.2 Hardware des Lesegerätes . . . . . . . . . . . . . . . . . . . . . . . . . . 9
2.3 Technische Anleitung und Tips für den Nachbau . . . . . . . . . . . . . . 14
3 Die Firmware 17
3.1 Der Cross-Compiler und seine Tools . . . . . . . . . . . . . . . . . . . . . 17
3.2 Theoretische Grundlagen . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
3.2.1 Kommunikation von PCD zu PICC . . . . . . . . . . . . . . . . . 18
3.2.2 Kommunikation von PICC zu PCD . . . . . . . . . . . . . . . . . 21
3.2.3 Interaktion PICC/PCD . . . . . . . . . . . . . . . . . . . . . . . 23
3.2.4 Fehlererkennung . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
3.3 Die MIFARE-Karte . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
3.3.1 Der Karten-Speicher . . . . . . . . . . . . . . . . . . . . . . . . . 27
3.3.2 Der Karten-Befehlssatz . . . . . . . . . . . . . . . . . . . . . . . . 28
3.4 Inbetriebnahme des Lesegerätes . . . . . . . . . . . . . . . . . . . . . . . 30
4 Die PC-Software 33
4.1 Das RFID-Paket . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
4.1.1 Kommunikation zwischen Computer und Lesegerät . . . . . . . . 35
4.1.2 Installation des RFID-Paketes . . . . . . . . . . . . . . . . . . . . 36
4.1.3 Anwendung des RFID-Paketes . . . . . . . . . . . . . . . . . . . . 36
4.2 Die JavaFX-Demo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
3
5 Zusammenfassung 40
6 Anhang 41
6.1 Hardware . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
6.1.1 Platinenlayouts zum Belichten . . . . . . . . . . . . . . . . . . . . 41
6.1.2 Bestückungsplan mit Bauteilliste . . . . . . . . . . . . . . . . . . 41
6.2 Firmware . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
6.2.1 rfid.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
6.2.2 rfid.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
6.2.3 mifare.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
6.2.4 mifare.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
6.2.5 lcd.c/lcd.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
6.2.6 Makefile . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
6.3 PC-Software . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
6.3.1 RFIDInterface.java . . . . . . . . . . . . . . . . . . . . . . . . . . 60
6.3.2 RFIDDevice.java . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
4
1 Einleitung
In dieser Projektarbeit wird ein RFID-Lesegerät entwickelt, welches in der Lage ist,
RFID-Transponder zu lesen und zu beschreiben.
Mit dem Selbstbau dieses Gerätes zeigen wir, dass es mit einfachen und leicht erhältlichen
Mitteln möglich ist, ein solchen RFID-Demonstrator zu bauen.
Ein weiteres wichtiges Merkmal, ist die leicht verständliche Bedienung und Funktions-
weise des Gerätes. Somit kann es dazu benutzt werden, die RFID-Technologie auf Messen
oder Workshops zu veranschaulichen.
1.1 Definition von RFID
An dieser Stelle wollen wir dem Leser kurz erklären, was RFID eigentlich bedeutet.
Das Akronym RFID steht für die englischen Begriffe”Radio frequency Identification“,
was frei übersetzt soviel bedeutet wie”Identifikation anhand von elektromagnetischen
Wellen“. Es handelt sich hierbei also um eine kontaktlose Übertragung von Daten zwi-
schen einem Lesegerät und einem RFID-Transponder.
Es gibt eine Reihe von unterschiedlichen RFID-Standards die sich hauptsächlich da-
durch unterscheiden, dass sie verschiedene Frequenzbänder, beziehungsweise Übertra-
gungsprotokolle, benutzen. In Tabelle 1.1 ist ein grober Überblick über die benutzten
Frequenzbereiche mit einigen Beispielen für jeweils mögliche Anwendungsgebiete gege-
ben.
Frequenzbereich Anwendungsgebiet
NF 30-500 kHz Tierchip (ISO 11785/11785) zur Identifikation von HaustierenHF 3–30 MHz Reisepass mit Chip, Smartcards ISO 14443A/B ISO 7816UHF 0,3–1 GHz Paletten- und Container-IdentifikationUHF 2,4–2,5 GHz Mautstationen
Tabelle 1.1: Verschiedene RFID-Technologien
5
1.2 Der gewählte RFID-Standard
Bei der Konzeption eines RFID-Lesegerätes, muss man sich erst einmal für einen (oder
mehrere) der im letzten Abschnitt genannten Standards entscheiden.
In unserem Falle, haben wir uns für die kontaktlose Chipkartentechnik von Mifare
entschieden. Im Folgenden wollen wir diesen Entschluss erklären.
Die Firma Mifare (Phillips) stellt die am meist benutzten RFID-Chips her. Mifare bie-
tet eine ganze Produktpalette von Transpondern an, wie zum Beipiel: Mifare-Classic,
Mifare-Ultralight, Mifare-DESFire um nur ein paar zu nennen. Alle Mifare Chips benut-
zen eine Übertragungsfrequenz von 13,56 MHz und sind ganz nach dem ISO Standard
14443A implementiert.
In dem Frequenzbereich von 13,56 MHz ist es problemlos möglich, mit diskreten Bau-
teilen, eine elektronische Schaltung aufzubauen die, ohne ein hochfrequenztaugliches
Layout, einwandfrei funktioniert. In diesem Frequenzbereich redet man noch nicht von
elektromagnetischen Wellen, der Datenaustausch erfolgt hier über induktive Kopplung
und funktioniert somit laut [3], mit den hier benutzten Energiestärken, auch nur auf eine
begrenzte Distanz von einigen Zentimetern bis höchstens zwei Metern.
Ein weiteres Argument ist die relativ langsame Datenübertragung mit einer Geschwin-
digkeit von 106 kbit/s. Somit ist es problemlos möglich, die empfangenen Daten anhand
eines Standard-Mikrocontrollers (AVR, PIC, . . . ) auszuwerten.
Unter anderem besitzt die Mifare-Ultralight-Karte einen EEPROM-Speicher mit einer
Größe von 64 Byte, der ohne Verschlüsselungsalgorithmen ausgelesen und beschrieben
werden kann.
Schlussendlich ist das benötigte Know-how, um die Kommunikation mit einem Mifare
RFID-Transponder zu realisieren, leicht erhältlich. Die ISO-Norm [3] gibt es im Internet
als Draft-Version herunterzuladen und auf der Mifare-Webseite, bietet die Firma sehr
genaue Informationen über ihre Produkte im Download Bereich an.
1.3 Gliederung der Ausarbeitung
Die folgende Ausarbeitung ist in drei große Kapitel gegliedert.
Kapitel 2 beschreibt die Hardware des RFID-Lesegerätes und vermittelt alle benötigten
Informationen um das Gerät nachzubauen. Die benutzte elekronische Schaltung stammt
aus [1] und wurde vollständig übernommen. Für unsere Zwecke wurde die Schaltung um
6
eine USB-Schnittstelle erweitert. Die gesamte Firmware wurde neu programmiert, sowie
ein geeignetes Platinen-Layout für die neue Schaltung entwickelt.
In Kapitel 3 werden wir auf unsere Firmware des Lesegerätes eingehen. Wir beschäftigen
uns dabei mit der Theorie, wie eine Kommunikation zwischen RFID-Lesegerät und
RFID-Transponder zustande kommt.
Kapitel 4 beschreibt unsere PC-Software die zum Einsatz kommt, um das Lesegerät
an einen Computer anzuschließen und zu steuern.
Zum Abschluss unserer Arbeit zeigen wir dann noch kurz, wie und wo unser Lesegerät
zu Demonstrationszwecken eingesetzt werden kann.
7
2 Das RFID-Lesegerät
Das in unser Projektarbeit entworfene RFID-Lesegerät basiert auf einem Artikel aus der
September Ausgabe 2006 der Zeitschrift Elektor [1]. Die Autoren beschäftigten sich mit
der Frage, ob es machbar sei ein RFID-Lesegerät anhand von einfach erhältlichen und
diskreten Bauteilen zu entwerfen. Das dies möglich ist, wurde in dem genannten Artikel
gezeigt und soll nun noch einmal in dieser Ausarbeitung detailliert nachvollzogen werden.
Das hier vorgestellte Gerät benutzt keine speziellen, für RFID ausgelegte, integrierte
Schaltungen und überzeugt zudem mit der geringen Anzahl an verwendeten Bauteilen.
Aus den teilweise übernommenen Schaltplänen, wurde mit Hilfe von Eagle [2] eine Plati-
ne erstellt. Das Lesegerät wurde außerdem noch mit einer USB-Schnittstelle ausgerüstet,
sowie einer LED-Lichterkette die mittels Software ein- und ausgeschaltet werden kann.
Der genaue Sinn und Nutzen dieser Lichterkette wird in Kapitel 4 erläutert.
Die Funktionen des Lesegerätes lassen sich alle (bis auf die Schreibfunktion) ohne PC,
mit Hilfe eines kleinen Tastenfeldes und einem LCD-Display ausführen. Für erweiter-
te Funktionalitäten lässt sich das Gerät per Software, über die USB-Schnittstelle eines
Rechners ansteuern.
In den folgenden Unterkapiteln wird nun der Hardware-Aufbau und die Funktionsweise
der Schaltung beschrieben. Die Begriffe PCD (Proximity Coupling Device) und PICC
(Proximity Integrated Circuit Card) benutzen wir gleichbedeutend zu RFID-Lesegerät,
beziehungsweise RFID-Transponder.
2.1 Einführung in die Theorie
Um den Aufbau des Lesegerätes zu verstehen, geben wir eine grobe Beschreibung des
Ablaufes einer kontaktlosen Datenübertragung zwischen PCD und PICC. Sämtliche
benötigten Informationen für die Implementierung der Firmware und Software wurden
dabei der Draft-Version der ISO-Norm 14443A [3] und dem Datenblatt [4] für Mifare-
Ultralight-Karten entnommen.
8
Zu Beginn jedes Datenaustausches, baut das Lesegerät ein elektromagnetisches Feld
auf. In unserem Falle schwingt dieses Feld mit einer Frequenz von 13,56 MHz. Befindet
sich jetzt eine PICC in Reichweite dieses Feldes, so wird sie mittels induktiver Kopplung
mit Energie versorgt. Die PICC befindet sich dann in einem Wartezustand und ist bereit
Befehle vom PCD zu empfangen.
Das Senden eines Befehles von PCD nach PICC erfolgt mittels 100% Amplitudenmo-
dulation des Trägers. Das bedeutet, das Energiefeld wird in der Tat vollständig ein- und
ausgeschaltet. Dabei werden die zu übertragenden Bits so codiert, dass das Trägersignal
immer nur für kurze Zeit ausgetastet wird. Somit bleibt die PICC mit Energie versorgt
und kann die gesendete Bitfolge empfangen und verarbeiten.
Die Antwort der PICC erfolgt ebenfalls mittels Amplitudenmodulation. Der RFID-
Chip schaltet dazu, im Takte seiner Modulationsfrequenz, eine auf die Trägerfrequenz
abgestimmte Last ein und aus. Dadurch wird dem Hochfrequenzfeld Energie entzogen
und es bricht bei jedem Modulationsvorgang teilweise ein. Auf Seiten des Lesegerätes
lassen sich diese Belastungen detektieren und entsprechend wieder dekodieren.
Der letzte Abschnitt soll nur einen groben Einblick in die Funktionsweise einer kon-
taktlosen Datenübertragung geben. Eine genauere und detaillierte Erklärung wird es in
Kapitel 3 geben.
2.2 Hardware des Lesegerätes
Es folgt nun ein Überblick über die einzelnen Teile aus denen das Lesegerät besteht. Die
fünf Hauptkomponenten lassen sich deutlich auf dem Platinen-Entwurf in Abbildung 2.1
erkennen.
a) die Sendeschaltung
b) die Empfangsschaltung
c) die digitale Auswertungseinheit mit Ein- und Ausgabeports
d) die USB-Schnittstelle
e) die Sende- und Empfangsantenne
Auf dem Board gibt es außerdem noch drei weitere Schnittstellen:
9
Abbildung 2.1: Platinenentwurf des Lesegerätes
f) zum Anschließen eines LCD-Displays
g) ISP-Schnittstelle zum Brennen der Firmware
h) Anschluss für eine vier Tasten-Tastatur
Auf Seite 11 ist der Schaltplan des Lesegerätes wiedergeben, anhand dessen nun die
Funktionsweise und Aufgabe der einzelnen Komponenten nachvollzogen werden kann.
a) die Sendeschaltung
Die Sendeschaltung besteht aus einem digitalen Quarzoszillator und einer, aus zwei
MOSFETs T1 und T2 bestehenden, Gegentaktstufe, um die vom Oszillator erzeugte
Schwingung zu verstärken. Die digitale Schwingung wird sowohl für die Taktung des Mi-
krocontrollers benutzt, als auch für die Erzeugung des Hochfrequenz-Feldes (HF-Feld).
Die Entscheidung der Elektor-Autoren, den Mikrocontroller mit der Schwingfrequenz
des HF-Feld zu takten, hat bei der späteren Programmierung der Firmware erhebli-
che Vorteile. Das von der Gegentaktstufe verstärkte Signal gelangt nun auf den Serien-
schwingkreis L1, C4. Mit dem Kondensator C4, der als Trimmer ausgelegt ist, lässt sich
die maximale Amplitude des HF-Feldes einstellen. Mit Hilfe eines Einganges von Gatter
IC1.B kann der Mikrocontroller das HF-Feld amplitudenmodulieren. Der Modulations-
grad soll laut Norm 100% betragen, das heißt das HF-Feld wird immer vollständig ein-
10
Abbildung 2.2: Schaltplan des Lesegerätes
11
und ausgeschaltet.
b) die Empfangsschaltung
In der Empfangsschaltung wird das von dem RFID-Chip modulierte HF-Feld demo-
duliert und anschließend digitalisiert. Wie man mit der Thomsonschen Schwingungs-
formel überprüfen kann, liegt die Resonanzfrequenz des L7/C10 Schwingkreises bei
ungefähr f = 12π√L7C10
= 16.283·
√3.3·10−14 = 876 kHz. Somit ist der Empfangskreis auf
die 13.56 MHz/16 = 847,5 kHz Modulationsfrequenz der Mifare-Karte abgestimmt. Am
Ausgang des Komparators steht nun das digitalisierte Signal zu Verfügung, welches vom
Mikrocontroller weiterverarbeitet werden kann
c) die digitale Auswertungseinheit mit Ein- und Ausgabeports
Das Herzstück des Lesegerätes besteht aus einem ATmega16 von Atmel [5]. Dieser Mi-
krocontroller ist mit 16 kB Flash, 1 kB Ram und einer maximalen Taktfrequenz von
20 MHz bestens für die Aufarbeitung der empfangenen Daten geeignet. Der Mikrocon-
troller sendet und empfängt nicht nur die Daten. Er muss sie auch codieren und de-
kodieren. Des Weiteren muss er die Parität und die CRC-Checksumme der empfangen
und gesendeten Daten berechnen. Er bietet dem Nutzer außerdem noch die Möglichkeit,
die auszuführenden Befehle über eine Menüsteuerung mit Hilfe der Mini-Tastatur aus-
zuwählen.
d) die USB-Schnittstelle
Um eine USB-Anbindung an den PC zu realisieren wurde der FT232RL-Chip von der
Firma FTDI [6] verbaut. Der FT232 ist ein bidirektioneller USB/UART-Umsetzer. Er
besitzt zudem einen internen EEPROM, der unterschiedliche Konfigurationen des Con-
trollers ermöglicht (in unserem Projekt gehen wir von der Standardkonfiguration aus,
die der Controller bei der Auslieferung hat). Er lässt sich problemlos an den internen
UART des Mikrocontrollers anschließen. Die Kommunikation zwischen Mikrocontroller
und FT232 erfolgt dabei seriell mit Hilfe von zwei Leitungen (TX, RX). Auf der anderen
Seite kommuniziert der FT232 über USB mit dem PC. Der Hersteller bietet auf seiner
Homepage, für alle gängigen Betriebssysteme (Mac OS X, Linux und Windows), gratis
Treiber zum Herunterladen an. Nach der Installation der Treiber erscheint ein virtuel-
ler serieller Port am Computer. Die Programmierung der PC-Software lässt sich daher
ohne spezielle USB-Kenntnisse bewerkstelligen. Man muss lediglich mit dem virtuellen
seriellen Port arbeiten. Die Umsetzung USB auf UART übernimmt dieser kompakte
12
SMD-Chip (Surface Mounted Device) ganz von alleine.
Eine weitere Funktionalität des FT232, die hier benutzt wurde, ist das Anbringen
von zwei LEDs die die Zustände der RX und TX Leitungen wiedergeben sollen. Per
Standard Einstellung werden diese Signale auf die ersten beiden, der vier I/O Pins des
FT232, ausgegeben. Anhand der Aktivitäten der beiden LEDs kann der Benutzer leicht
erkennen, ob gerade ein Datenaustausch zwischen PC und Lesegerät vonstatten geht.
e)die Sende- und Empfangsantenne
Die Sende- und Empfangsantenne finden ihren Platz auf einer 5 x 6,5 cm großen Platine.
Es handelt sich dabei um zwei verschachtelte Luft-Spulen die mit Hilfe von Leiterbah-
nen realisiert worden sind. Eine der beiden Windungen dient dabei als Sendeantenne
(es ist dabei unerheblich für welche man sich entscheidet), die andere Windung wird
als Schnüffelsonde für den Empfang benutzt. Zum Lesen und Beschreiben eines RFID-
Transponders, wird dieser einfach auf die Antenne aufgelegt.
f)LCD-Anschluss
Der 14-polige Wannenstecker dient zum Anschluss des LCD-Displays. Für den Bau des
Lesegerätes kam dabei ein zweizeiliges, unbeleuchtete Display mit jeweils 24 Zeichen pro
Zeile zum Einsatz. Bei dem LCD handelt es sich um einen HD44780 kompatiblen Typ
mit nur einer positiven Spannungsversorgung, also ohne negative Hilfsspannung. Die
Programmierung erfolgt über vier Datenleitungen und drei Steuerleitungen. Mit dem
Potentiometer neben dem Wannenstecker lässt sich der Kontrast des Displays einstellen.
g)ISP-Schnittstelle
Der kleinere zehn-polige Wannenstecker dient als ISP-Schnittstelle (In System Program-
mer). Mit diesem Anschluss lässt sich die Firmware des AVRs brennen und updaten, ohne
ihn für diesen Zweck ausbauen zu müssen.
h)Tastatur-Anschluss
An diese Anschlüsse werden die vier Taster für die Menüsteuerung, sowie ein Reset-
Taste angeschlossen. Somit kann man bequem mittels einer vorwärts und rückwärts
Taste durch das, mit dem Display, angezeigte Menü navigieren. Die Auswahl eines
Menüeintrags erfolgt mit der Enter-Taste. Mit der Menü-Taste kann man dann wie-
der elegant ins Hauptmenü zurückspringen.
13
Der Nachbau des Lesegerätes ist im Prinzip einfach und unkritisch. Im nächsten Ab-
schnitt soll jedoch noch einmal kurz darauf eingegangen werden.
2.3 Technische Anleitung und Tips für den Nachbau
In diesem Abschnitt beschreiben wir, wie die Anfertigung des Gerätes von statten ging.
Die Grundplatine wurde mit einem selbstgebauten UV-LED-Belichtungsgerät belich-
tet. Als beschichtetes Basismaterial diente dazu eine Platine des Herstellers Bungard.
Mit einem 0.8 mm Bohrer wurden dann die Löcher für die Bauteile gebohrt. Bohrlöcher
für Potentiometer und Wannenstecker wurden mit einem 1 mm Bohrer vergrößert. Das
Löten der Bauelemente erfordert keine besonderen Maßnahmen mit Ausnahme des USB-
Controllers, welcher leider nur in einer SMD-Ausführung im SSOP-Gehäuse verfügbar
ist. Hierbei ist besonders viel Fingerspitzengefühl gefragt. Für das Löten von SMD-
Bauteilen sind Werkzeuge und Materialen wie ein feiner Lötkolben, Flußmitteldispenser
(FL 88 FLUXI), Entlötlitze und SMD-Lötzinn, mit 0,5 mm Durchmesser, unverzicht-
bar. Besonders bewährt hat sich dabei die Methode die feinen SMD-Leiterbahnen zu-
erst mit Lötzinn zu verzinnen. Anschließend wird Flußmitteldispenser auf die Leiter-
bahnkontakte gegeben, das SMD-Teil auf der Platine positioniert und jeweils an zwei
gegenüberliegenden Ecken angelötet. Bis dahin lassen sich noch leichte Positionskorrek-
turen bewerkstelligen. Ist das Bauteil richtig ausgerichtet, fährt man mit der Lötspitze
über sämtliche Beinchen des Bauteiles. Dabei schmilzt das vorher aufgetragene Lötzinn
und verbindet die Anschlusskontakte des Bauteils mit der Platine. An den Stellen wo sich
kleine Zinnbrückchen gebildet haben, wird das überflüssige Lötzinn mit der Entlötlitze
entfernt. Man sollte auf jeden Fall sehr sparsam mit dem Lötzinn umgehen.
Das Löten des SMD-Bauteiles hört sich anspruchsvoll an, lässt sich aber mit der ge-
gebenen Anleitung problemlos durchführen.
Im Anhang befindet sich ein Ausdruck des einseitigen Platinenlayoutes. Es kann als Be-
lichtungsvorlage dienen um das Gerät nachzubauen. Eine Liste der benötigten Bauteile
gibt es ebenfalls im Anhang. Alle verbauten Bauelemente lassen sich problemlos in je-
dem guten Elektronikladen besorgen (zum Beispiel Reichelt [7]). Lediglich der 13,56 MHz
Quarz war schwieriger zu bekommen und muss gegebenenfalls extra bestellt werden.
Da das Lesegerät als autonomes, oder an einen Computer angeschlossenes, Demons-
14
Abbildung 2.3: Das RFID-Lesegerät
trationsgerät dienen soll wurde auch das Gehäuse-Layout dementsprechend angefertigt.
Wie in Abbildung 2.3 zu erkennen ist besteht das”Sandwich-Gehäuse“ aus zwei Ple-
xiglasscheiben, welche mit vier Bolzen zusammengeschraubt sind. Die untere Scheibe
nimmt dabei die ganze Platine mit Tastatur auf. Auf der oberen Scheibe befindet sich
das Display und von unten durchleuchtend ist die Antennen-Platine erkennbar. Durch
diese Konstruktion lässt sich ein wunderbarer Einblick in das elektronische Innenleben
des Gerätes geben, was für Vorführungszwecke besonders sinnvoll ist.
Die 5V-Spannungsversorgung des Gerätes erfolgt über die USB-Schnittstelle. Somit
ist beim Computerbetrieb kein weiteres externes Netzteil von Nöten. Aus Sicherheits-
gründen sollte jedoch immer ein aktiver USB-Hub zwischen Gerät und Computer ge-
schaltet werden. Zu einem wird bei einer Fehlfunktion des Gerätes (Fehler beim Löten)
nicht der USB-Port des Computers zerstört. Und zum zweiten bietet der Hub eine kon-
stante Stromquelle für das Lesegerät.
In Kapitel 4 dieser Ausarbeitung geben wir noch ein Beispiel, wie das Lesegerät zu
Demonstrationszwecken genutzt wird.
Wie man aus diesem Kapitel leicht erkennen kann, hält sich der Hardware-Aufwand
15
sehr in Grenzen. Der Hauptteil der Arbeit bestand darin, die Funktionsweise der be-
nutzten RFID-Technologie zu verstehen, sowie den Mikrocontroller für diesen Zweck am
geeignetsten zu programmieren.
Das nächste Kapitel widmet sich also ganz der Theorie wie RFID funktioniert, sowie
der Beschreibung der implementierten Firmware.
16
3 Die Firmware
Wie schon angedeutet funktioniert ohne die geeignete Firmware gar nichts. Vor der ersten
Inbetriebnahme der Hardware muss also erst einmal eine geeignete Steuersoftware in den
Speicher des Mikrocontrollers geladen werden. Im folgenden Kapitel wird genau erklärt,
wie wir dabei vorgegangen sind. Im Anhang zu dieser Ausarbeitung befindet sich der
vollständige und funktionstüchtige Quelltext der Firmware. Da für die Entwicklung der
Firmware recht umfangreiche Informationen benötigt werden, haben wir uns entschlossen
dieses Wissen nach dem Top-down Prinzip zu vermitteln. Zu Anfang geben wir erst
einmal einen globalen und abstrakten Überblick über die Technologie, um dann nach
und nach detaillierte und grundlegende Kenntnisse zu vermitteln.
3.1 Der Cross-Compiler und seine Tools
In diesem Unterkapitel werden wir den benutzten Compiler, sowie weitere Tools vor-
stellen, die für die Erzeugung der Firmware unerlässlich sind. Besonders praktisch und
finanziell günstig ist die Tatsache, dass alle benutzte Programme und Tools unter der
GNU General Public License (GPL) stehen und somit kostenlos aus dem Internet zu
beziehen sind.
Zum Programmieren des Mikrocontroller bietet sich besonders die Programmierspra-
che C an. Als High-Level-Programmiersprache lassen sich mit ihr sehr schnell, kom-
plexere Algorithmen implementieren. Des Weiteren ist auch die Lücke zwischen der
C-Sprache und der unterliegenden Hardware (in unserem Fall der ATmega16 ) recht
klein und somit Hardware-nahe. Das ist sehr wichtig, da wir uns sehr genau mit der
Hardware beschäftigen und gegebenenfalls mit Assembler optimieren müssen. Ein wei-
terer Vorteil für die in reinem C (ohne AVR-Assembler) programmierten Funktionen ist,
dass sich die Möglichkeit anbietet den Code auf dem Computer auszuführen und auf
eventuelle Fehler zu untersuchen. Dies war beispielsweise bei der Implementierung der
CRC-Berechnungsfunktion sehr hilfreich. Ein Debuggen mit dem Mikrocontroller hätte
die Entwicklungsarbeit nur sinnlos erschwert.
17
Der größte Teil der Firmware wurde wegen der oben genannten Gründen in C pro-
grammiert. Nur die zeitkritischen Funktionen wurden in AVR-Assembler implementiert.
Der C-Code wurde mit dem Xcode-Editor von Mac OS X geschrieben und verwaltet.
Da der gesamte Quelltext nur aus sechs Dateien besteht, wäre es auch durchaus möglich
den Code in dem VIM-Editor zu schreiben und somit dem Konzept der kostenlosen
Software gerecht zu bleiben. Zum Übersetzen des Quelltextes benutzen wir die Version
4.0.2 des avr-gcc-Compilers. Der vom avr-gcc gelieferte binäre Code muss aber noch mit
dem Tool avrobj in einen für den Mikrocontroller verträglichen Objektcode konvertiert
werden. Die somit erzeugte Hex-Datei kann nun mit dem Programm avrdude und einer
geeigneten Brennhardware auf den Mikrocontroller übertragen werden. Das Tool avr-
dude unterstützt eine ganze Palette von Brennhardware. Wir haben uns hier für den
günstigen mySmartUSB-Brenner von myAVR [8] entschieden. Um nicht jedes Mal die
ganzen Kommandos eingeben zu müssen, wurde eine kleine Makefile erstellt, an welcher
man sich im Anhang inspirieren kann. Beispielsweise bei einer Shell-Eingabe wie make
burn wird der Quellcode kompiliert und der internen Speicher des AVRs geflasht.
Nach diesem kurzen Überblick über die benutze Software, kommen wir nun zu den
theoretischen Grundlagen die im weiteren Verlauf benötigt werden.
3.2 Theoretische Grundlagen
Um den genauen Ablauf einer PCD/PICC-Kommunikation auf der Bit-Ebene zu ver-
stehen soll hier eine Sende- und Empfangsfunktion für das RFID-Lesegerät beschrieben
werden.
3.2.1 Kommunikation von PCD zu PICC
Wie schon im zweiten Kapitel kurz angedeutet erfolgt der Datenaustausch mittels Am-
plitudenmodulation des HF-Feldes.
Als erstes soll nun erklärt werden wie die einzelnen Bits eines Bytes übertragen wer-
den. Die Dauer eines Bits ist dabei auf 128/fc Sekunden festgelegt. Die Taktfrequenz
fc (clock frequency) des Mikrocontrollers entspricht dabei genau 13,56 MHz, ist also
identisch mit der Frequenz des benutzten Trägers. Diese Konstante wird im weiteren
Textverlauf immer wieder auftreten, da sich von ihr sämtliche Wartezeiten und andere
Modulationsfrequenzen ableiten lassen. Demnach entspricht die Zeitdauer, im folgen-
den mit ETU (Elementry Time Unit) bezeichnet, eines Bits ungefähr 128/13,56 MHz
18
Abbildung 3.1: Die drei benutzten Sequenzen
= 9,44µs. Die Kodierung der Bits auf seitens des PCB erfolgt nach dem Miller-Code.
Dabei wird ein Bit nur während einer Teilzeit seiner gesamten ETU ausgetastet, in un-
serem Fall beträgt diese Teilzeit immer genau ein Viertel einer ETU. Abbildung 3.1 soll
die drei verschieden Sequenzen verdeutlichen, mit denen die Bits kodiert werden. Bei
der Sequenz X sieht man, dass das Bit nach der ersten Hälfte für eine Zeitspanne von
ETU/4 ausgetastet wird. Bei der Sequenz Y erfolgt keine Austastung und bei Z wird
am Anfang für eine Zeitdauer von ETU/4 ausgetastet. Wie aus dieser Kodierung leicht
ersichtlich ist, sind die Zeiten während denen ausgetastet wird, das Hochfrequenzfeld
also ausgeschaltet wird, nur sehr kurz. Dies ist durchaus erwünscht, da das HF-Feld
nicht nur als Übertragungsmedium benutzt wird, sondern den PICC auch mit Energie
versorgen muss.
Nachdem wir die Kodierungsmuster kennengelernt haben soll nun in der Tabelle 3.1
erklärt werden wann jeweils eine der drei Sequenzen benutzt wird, um jeweils eine logi-
sche 1 oder eine logische 0 zu kodieren.
19
Information Benutztes Muster
Logische 1 X-SequenzLogische 0 Y-Sequenz mit den folgenden beiden Ausnahmen:
1. Falls zwei oder mehrere hintereinander kommende lo-gische
”0“en zu übertragen sind, wird ab der zweiten
logischen”0“ die Z-Sequenz benutzt.
2. Wenn das erste Bit nach einem Übertragungsanfangeine logische
”0“ ist, so wird die Z-Sequenz für diese Bit
benutzt und für alle direkt darauf folgenden logischen
”0“en.
Start einer Übertragung Z-SequenzEnde einer Übertragung Logische
”0“ mit darauffolgender Y-Sequenz (0Y)
Keine Datenübertragung Mindestens zwei Y-Sequenzen
Tabelle 3.1: Benutzungsregeln
Die Daten Bits Die kodierte Sequenz
Z Z (Startsequenz)0 Z0 Z1 X1 X0 Y0 Z1 X0 Y0 Z (Endsequenz)Y Y (Endsequenz)
Tabelle 3.2: Benutzungsregeln
Um die Anwendung dieser Kodierungsregeln besser zu verstehen, erklären wir sie
anhand eines kleinen Beispiels. Wählen wir willkürlich die hexadezimale Zahl 0x32.
Ihre binäre Darstellung als Byte (8 Bit, falls nötig die höherwertigen Bits mit 0en
auffüllen) entspricht 00110010. Aus der Tabelle 3.1 können wir entnehmen, dass ein
zu übertragendes Byte immer mit einer Startsequenz Z eingeleitet wird und mit einer
”0Y“ Sequenz aufhört. Unser Byte sieht also dann wie folgt aus: Z001100100Y. Da das
erste Bit eine logische Null ist wird es mit der 2. Ausnahmeregel für logische”0“ co-
diert. Die vollständige Kodierung sieht dann wie folgt aus ZZZXXYZXYZY und lässt
sich anhand der Tabelle 3.2 gut nachvollziehen. Aus Vollständigkeitsgründen sollte noch
erwähnt werden, dass bei einer Übertragung die Reihenfolge der Bits erst umgedreht
20
Abbildung 3.2: Manchester-Kodierung
wird. Das bedeutet das erste übertragende Bit ist also immer das niedrigstwertige Bit
(LSB), das letzte Bit das MSB. Außerdem ist bei einigen PICC-Befehlen die Länge des
Befehls nicht 8 Bit sondern nur 7 Bit.
3.2.2 Kommunikation von PICC zu PCD
Die Datenübertragung von der PICC zum PCD erfolgt ebenfalls mittels Amplituden-
modulation. Dazu schaltet die PICC periodisch eine interne, auf die Trägerfrequenz fc
abgestimmte Last, ein und aus und kann somit dem Hochfrequenzfeld Energie entziehen.
Der PCD kann nun, anhand dieser Amplitudeneinbrüche des Trägersignals, eine Ant-
wort der PICC erkennen. Die Zeitlänge eines übertragenen Bits entspricht auch hier der
im letzten Abschnitt definierten Zeitdauer ETU. Der eigentliche Unterschied taucht in
der abweichenden Bit-Kodierung auf. Und zwar werden die Bits nach der Manchester-
Methode übertragen. Somit wird eine logische 1 in der ersten Hälfte seiner ETU-Dauer
moduliert und eine logische 0 während der zweiten Hälfte (wie in Abbildung 3.2 verdeut-
licht). Wichtig hierbei zu verstehen ist die Tatsache, dass die PICC beim modulieren das
Hochfrequenzfeld nicht während der ganzen ETU/2 Zeit belastet, vielmehr wird mit einer
Unterträgerfrequenz fc/16 ( 847,5 kHz ) die Last periodisch ein- und ausgeschaltet. Man
muss bedenken, dass jeder Amplitudeneinbruch des HF-Feldes eine kurze Energiever-
sorgungsabschaltung für die PICC bedeutet. Durch einen internen Speicherkondensator
kann die PICC diesen Energieentzug kurzzeitig überbrücken. Durch die benutzte Kodie-
rung wird garantiert, dass diese Ausfälle so gering wie möglich bleiben. In Bild 3.3 soll
veranschaulicht werden, wie eine solche Amplitudenmodulation der PICC aussieht.
Die Sinusschwingung des HF-Feldes ist hier als durchgehender schwarzer Balken dar-
gestellt. Dies ist damit zu begründen, dass die ETU-Zeitlängen 128 mal länger sind
als eine Periodendauer der Trägerfrequenz. Dementsprechend wäre die Sinusform des
Trägers in dem gewählten Maßstab nicht mehr deutlich zu erkennen. Die Stellen an de-
21
Abbildung 3.3: Oszillogramm
Sequenz Beschreibung
D-Sequenz Der Träger wird während der ersten Hälftevon ETU moduliert
E-Sequenz Der Träger wird während der zweiten Hälftevon ETU moduliert
F-Sequenz Träger wird während der ganzen Dauer vonETU nicht moduliert
Logische”1“ D-Sequenz
Logische”0“ E-Sequenz
Start einer Übertragung D-SequenzEnde einer Übertragung F-SequenzKeine Datenübertragung Träger bleibt unmoduliert
Tabelle 3.3: Manchester-Verfahren
nen das HF-Feld zum Teil einbricht, sind die Zeiten während denen moduliert wird. Die
schwarzen Striche, die in diesen Lücken eingezeichnet sind, sollen die Amplitudenspit-
zen der 847,5 kHz Modulationsfrequenz der PICC schematisieren. Es wurden bewusst
vier solcher Striche eingezeichnet, da eine Periodendauer der Modulationsfrequenz des
PICC 16/fc lange dauert und somit passen genau vier solcher Sinusschwingungen in
einen Zeitspalt der Länge ETU/2 ( 16/fc * 4 = 64/fc = ETU/2).
In Tabelle 3.3 sind die Kodierungsregeln für das benutzte Manchester-Verfahren aufge-
listet. Diese Regeln wurden in Bild 3.3 angewendet und die somit dekodierte Information,
welche in dem gezeichneten Oszillogramm enthalten ist, in binärer Darstellung unten-
drunter geschrieben. Die eigentlichen Nutzdaten bestehen in diesem Beispiel lediglich aus
der Bitfolge 101. Die erste 1 aus der dekodierten Bitfolge 11010 dient zur Ankündigung
eines Übertragungsanfangs und die 0 am Schluss, mit anschließender F-Sequenz (Aus-
bleiben der Modulation) soll das Ende der Übertragung kennzeichnen.
22
Mit den ausführlichen Hinweisen und Erklärungen aus den letzten beiden Unterkapi-
teln, soll nun die Interaktion zwischen PICC und PCD erläutert werden.
3.2.3 Interaktion PICC/PCD
In dem folgenden Abschnitt erklären wir ausführlich wie eine Kommunikation zwischen
einem PCD und einer PICC von statten geht. Die Sende- und Empfangsfunktion, die in
der Firmware des Lesegerätes enthalten ist, wurde dementsprechend implementiert. Eine
wesentliche und praktische Gegebenheit, der wir uns zu Nutze machen, ist dass die PICC,
laut der zugrunde liegenden ISO-Norm, mindestens nach einer festdefinierten Zeitspan-
ne auf eine Anfrage des PCD antwortet. Diese Mindestzeit zwischen zwei aufeinander
folgenden Übertragungsrahmen beträgt laut Spezifikation 948/fc, also 69,91µs. Deswei-
teren lässt sich aus dem Mifare-Datenblatt[4] entnehmen, dass die maximale Länge einer
PICC-Antwort auf 163 Bits beschränkt bleibt. Wie man auf die Berechnung dieser Zahl
kommt wird im Verlauf dieses Kapitels erläutert. Unsere Sende- und Empfangsmethode
implementieren wir also dementsprechend um einen potenziellen Empfang von einer 163
langen Bit-Sequenz zu gewährleisteten.
Aus diesen beiden Informationen, frühstmögliche Antwort der PICC und maximale
Rahmenlänge, steht einer erfolgreichen Programmierung einer funktionsfähigen Sende-
und Empfangsmethode nichts mehr im Wege.
Die Funktion wurde komplett in Assembler implementiert, da es sich hierbei um zeit-
kritische Programmabläufe handelt. Würde man hierfür C benutzen, könnten je nach
gewählten Optimierungsoptionen und Compilerversionen, erhebliche Unterschiede in der
binären Objektdatei entstehen und die korrekte Funktionalität der Firmware wäre nicht
mehr gewährleistet.
Die Kommunikation zwischen PCD und PICC wird immer vom PCD gestartet. Be-
findet sich eine PICC in Reichweite, antwortet sie nach einer gewissen Wartezeit und
steht dann für weitere Anfragen des PCD zu Verfügung. Aus diesem Grunde wurde das
Senden und Empfangen von Informationen auch in einer Methode implementiert.
Die meisten Befehle unseres µC werden in einem Taktzyklus ausgeführt, so auch der
NOP-Befehl (NO Operation). Wie schon erwähnt arbeitet der Mikrocontroller ebenfalls
mit der Taktfrequenz von fc. Da sämtliche Warte-, Bit- und Modulationszeiten immer
ganze vielfache der Periodendauer von fc sind, lassen sich diese Wartezeiten somit sehr
exakt nachbilden.
23
Die zu versendeten Daten stehen in einem 82 Byte großem Puffer zum Abruf bereit.
Die Überlegung besteht darin das Senden von Daten so leicht wie möglich zu machen
und das auf Kosten von Ram-Speicher, der aber mit einem Kilobyte völlig ausreicht.
Sämtliche Daten im Puffer sind schon nach dem Muster des zu erzeugenden Sendesi-
gnals abgespeichert. Wie schon am Anfang dieses Kapitel erklärt, werden die Datenbits
mit dem Miller-Code übertragen. Dazu wird ein Datenbit in vier gleiche Teilzeiten ein-
geteilt, und jedem dieser Teilzeiten wird ein Bit aus dem Puffer geopfert. Beispielsweise
werden für ein zu übertragendes Datenbit das mit der X-Sequenz kodiert wird, die vier
Bits 1101 in den Puffer geschrieben. Der Puffer wird nun sequenziell durchlaufen und
der Wert des aktuell gelesenen Bits (eins oder null) bestimmt, ob das HF-Feld ein- oder
ausgeschaltet wird. Zwischen zwei solcher Bits muss natürlich ETU/4 = 2,35µs lange
gewartet werden. In anderen Worten wir führen eine Folge von ETU/4 = 128/4 = 32
NOP-Befehlen aus und lassen somit die erwünschte Zeit von 2,35µs verstreichen. Oder
eleganter formuliert wir führen eine kleine nichts tuende Schleife aus die nach 32 Taktzy-
klen abbricht. Aus technischen Gründen müssen wir auch noch die Zeit beachten, die der
µC braucht um den gewünschten Wert an einem I/O-Port einzustellen. Beim ATmega16
dauert das ungefähr ein Taktzyklus lang. Nach dem erfolgreichen Senden eines Befehles
von Seiten des PCD warten wir, wie weiter oben schon gesagt, mindestens 69,91µs auf
eine Antwort. Nach dieser vorgeschriebenen Wartezeit ist der µC bereit eine Antwort
seitens der PICC zu erhalten. Dazu lassen wir noch einmal zusätzliche 32 Zyklen ver-
streichen, um dann jeweils zweimal während jeder ETU-Zeiteinheit das empfange Signal
abzutasten und das Resultat in den Datenpuffer zu speichern. Diese zusätzliche Wartezeit
von einem Viertel einer ETU-Zeit, garantiert uns, dass wir das Empfangssignal immer in
der Mitte der ersten und der zweiten Bithälfte abtasten. Diese Methode ermöglicht eine
korrekte Interpretation des Empfangssignals. Würden wir am Anfang oder am Schluss
einer Bithälfte abtasten, könnten Lesefehler entstehen, da mögliche high-low oder low-
high Zustandsübergänge einen nicht definierten Zustand bilden können. Die empfangen
Daten werden dann der Reihe nach in dem Puffer abgespeichert, wobei bei der Datenaus-
tauschrichtung PICC zu PCD ein übertragenes Datenbit (wegen Manchester-Codierung)
nur noch zwei Bits aus dem Puffer benötigt.
Aus den während des Baus des Lesegerätes gesammelten Erfahrungen haben wir festge-
stellt, dass es bei einer Datenübertragung durchaus zu längeren Verzögerungen als den
69,91µs zwischen Senden und Empfangen kommen kann. Die einzige Kommunikation in
denen die PICC die Antwortzeiten sehr exakt einhält ist bei einer Kollisionsauflösung,
24
also dem Kommunizieren mit mehreren PICC in dem HF-Feld eines PCD. Sequenziel-
les Auslesen von mehreren PICC wurde in dieser Ausarbeitung jedoch nicht behandelt.
Ein Grund dafür ist die Tatsache, dass die Leistung des HF-Feld unseres Lesegerätes
nur sehr schwach ausgelegt wurde und somit ist es fast unmöglich, dass zwei PICC in
dem selben HF-Feld mit Energie versorgt werden können. Aus Vollständigkeitsgründen
soll hier trotzdem noch erwähnt werden, dass der in der Norm beschriebene Kollisions-
auflösungsalgorithmus genaues synchrones Timing aller beteiligten PICC erfordert. Des-
wegen konnten wir auch nur beim Senden dieser Befehle eine ganz präzise Antwortzeit
der PICC feststellen. Als weitere interessante Feststellung scheint noch erwähnenswert
zu sein, dass die verspätete Antwort der PICC, immer ein Vielfaches der Länge einer
ETU entspricht. Das hat den Vorteil, dass es unmöglich ist beim Abtasten aus dem Bit-
Raster herauszufallen. Es bleibt also gewährleistet, dass wir das Signal immer genau im
ersten Viertel und im letzten Viertel abtasten. Ein vor der Antwort des PICC angefan-
genes Abtasten ist nicht weiter schlimm, da man dann lediglich 0 Werte empfängt und
die beim Auswerten der Daten im Puffer einfach ignorieren kann. Bei einer Puffergröße
von 82 Bytes ( 82 * 8 = 656 Bit ) und einer maximalen Rahmengröße von 163 Bit, blei-
ben also 656 – 2 * 163 = 330 Bits im Puffer übrig. In Zeit ausgedrückt bedeutet dies, die
Karte kann sich um insgesamt 330 * ETU = 3,11 ms verspäten, was aber nicht vorkommt.
Zum Abschluss dieses Kapitels und um die Theorie ein bisschen anschaulicher zu ma-
chen zeigen wir, anhand von Bild 3.4, ein Oszillogramm das beim Senden eines REQA-
Befehles aufgenommen wurde. Das Band was man im oberen Kanal erkennen kann ist
der Hochfrequenz-Träger. An den sieben Stellen wo der Träger ausgetastet ist, wurde er
moduliert. Der zweite Kanal zeigt den digitalen Datenstrom den die Empfangsschaltung
zeitgleich auswertet. Da es sich hierbei um die gerade gesendete Sequenz handelt, sind
diese Empfangsdaten natürlich nicht relevant.
Im nächsten Unterkapitel werden wir näher auf die benutzten Fehlererkennungsalgo-
rithmen eingehen.
3.2.4 Fehlererkennung
Um Übertragungsfehler rechtzeitig zu erkennen und die Integrität der Daten zu gewährleisten,
werden sämtliche übertragende Bytes einer Paritäts- und CRC-Kontrolle unterzogen. Ei-
ne 16 Bit lange CRC-Summe wird dabei für alle Befehle mit Parameter berechnet. Diese
zwei Prüfsummen Bytes werden an die zu übertragende Byte-Kette angehängt. Anschlie-
25
Abbildung 3.4: Senden eines REQA Kommandos
ßend wird an jedes Byte dieser Kette ein neuntes Bit angehängt, welches als Paritätsbit
zur ungeraden Paritätskontrolle dient. Im Anhang der ISO-Norm [3] befindet sich ein
optimierter in C geschriebener Algorithmus der die CRC-Kontrolle durchführt. Obwohl
es zahlreiche Möglichkeiten gibt einen CRC-Algorithmus zu implementieren, empfehlen
wir die Benutzung dieses vorgegebenen Code-Fragments. Der Code ist speziell auf das in
dem Dokument ITU-T V.41 [9] vorgeschlagenen CRC-Verfahren zugeschnitten. Die ITU
(International Telecommunication Union) schlägt vor das CRC-Polynom x16+x12+x5+1
zu benutzen und als Startwert soll das CRC-Register den Wert 0x6363 enthalten. Sogar
eine Umsetzung mittels Lookup-Tabelle wird sich kaum lohnen, da diese im Verhältnis zu
der dadurch erfolgenden geringen Geschwindigkeitssteigerung weit mehr Speicherplatz
in Anspruch nimmt. Es muss noch drauf geachtet werden, dass die beiden CRC-Bytes in
der richtigen Reihenfolge an die Nutzdaten angehängt werden. Das heißt, das LSB-Byte
zuerst, und anschließend das MSB.
Der nächste Abschnitt befasst sich mit dem Aufbau der MIFARE-Ultralight-Karte.
26
Byte Inhalt 0x00 0x01 0x02 0x03 Seite
Seriennummer SN0 SN1 SN2 BCC0 0x00Seriennummer SN3 SN4 SN5 SN6 0x01Internal/Lock BCC1 Internal Lock0 Lock1 0x02
OTP OTP0 OTP1 OTP2 OTP3 0x03Data R/W Data 00 Data 01 Data 02 Data 03 0x04Data R/W Data 04 Data 05 Data 06 Data 07 0x05Data R/W Data 08 Data 09 Data 10 Data 11 0x06Data R/W Data 12 Data 13 Data 14 Data 15 0x07Data R/W Data 16 Data 17 Data 18 Data 19 0x08Data R/W Data 20 Data 21 Data 22 Data 23 0x09Data R/W Data 24 Data 25 Data 26 Data 27 0x0AData R/W Data 28 Data 29 Data 30 Data 31 0x0BData R/W Data 32 Data 33 Data 34 Data 35 0x0CData R/W Data 36 Data 37 Data 38 Data 39 0x0DData R/W Data 40 Data 41 Data 42 Data 43 0x0EData R/W Data 44 Data 45 Data 46 Data 47 0x0F
Tabelle 3.4: Mifare-Ultralight EEPROM-Speicher
3.3 Die MIFARE-Karte
In den folgenden beiden Abschnitten gehen wir näher auf die Speicherstruktur der
Mifare-Karte ein und erläutern den von der Firmware unterstützten Befehlssatz.
3.3.1 Der Karten-Speicher
Der EEPROM-Speicher (Electrical Erasable Programmable Read Only Memory) der
Mifare-Ultralight-Karte besteht aus 512 Bit, also 64 Bytes. Der Speicher ist in 16 Seiten
mit jeweils 4 Bytes aufgeteilt. Im Prinzip stehen dem Benutzer aber nur 48 Bytes für
Nutzdaten zur Verfügung. Wie in Tabelle 3.4 zu erkennen, beinhalten die ersten 9 Bytes
die Seriennummer der Karte. Diese Speicherzellen können aus Sicherheitsgründen, um
die weltweite Eindeutigkeit dieser Seriennummer zu gewährleisten, nicht mehr geändert
werden. Ebenso unveränderbar ist das zweite Byte der Seite 0x02. Es ist für interne
Zwecke reserviert und somit auch nicht beschreibbar.
Die beiden letzten Bytes der Seite 0x02 dienen dazu die Seiten 0x03 bis 0x0E read-only
zu machen. Dieser Vorgang ist, genauso wie das Schreiben der OTP0 - OTP3 Bytes (One
Time Programmable) nicht mehr umkehrbar. Um ein versehentliches Schreiben dieser
Speicherzellen zu vermeiden und die Karte somit unbrauchbar zu machen, wird das
27
Schreiben dieser Seiten nicht von unserer Firmware unterstützt. Diese Funktionalität
lässt sich aber jederzeit leicht nachrüsten. Jedoch sollte man sich vorher die genauen
Erklärungen dazu im Datenblatt [4] durchlesen.
Abschließend wollen wir noch angeben wie die Korrektheit der Seriennummer überprüft
werden kann. Wenn die folgenden beiden Gleichungen erfüllt sind handelt es sich um eine
gültige Seriennummer: BCC0 = 0x88⊕ SN0⊕ SN1⊕ SN2BCC1 = SN3⊕ SN4⊕ SN5⊕ SN6Der Operator ⊕ steht für die binäre XOR-Verknüpfung.
3.3.2 Der Karten-Befehlssatz
Die in diesem Abschnitt vorgestellte Kommandoliste besteht aus den wichtigsten und
meist genutzten Befehlen. Die Mifare-Ultralight Karte-unterstützt noch ein paar weiterer
Befehle, die aber im Rahmen dieser Projektarbeit nicht benutzt wurden. Die Erweiterung
des Befehlssatzes ist jedoch problemlos durchführbar und nur mit geringem Aufwand
verbunden. Bild 3.5 zeigt den Teil des Zustandsdiagramms der Mifare-Karte, den wir
mit den implementierten Befehlen ablaufen können. Die gestrichelten Teile sind nicht
umgesetzt, wurden aber wegen Erklärungsgründen eingezeichnet. Für das vollständigen
Diagramm verweisen wir den Leser auf das Datenblatt [4].
Wird die Karte mit Energie versorgt, geht sie über in den Ruhezustand und ist dann
bereit bestimmte Befehle zu empfangen.
1. Der REQA-Befehl.
Mit Hilfe des REQA-Befehles (von REQuest Typ A), bringt man die Mifare-Karte
in den Bereitschaftszustand. Falls dieser Vorgang erfolgreich war, antwortet die
Karte mit einem ATQA (Answer To reQuest Typ A). Somit eignet sich dieses
Kommando auch um das Vorhandensein einer PICC zu kontrollieren. Des Weiteren
muss dieser Befehl nach jedem WRITE-Befehl gesendet werden. Dies steht nicht
ganz explizit im Datenblatt und hat dazu geführt, dass die Implementierung des
WRITE-Kommandos am Anfang nicht funktioniert hat. Der REQA-Befehl besteht
nur aus aus sieben Bit, wobei das letzte Bit zur Paritätskontrolle dient. Es werden
zudem keine Parameter benötigt.
2. Der WUPA-Befehl.
28
Abbildung 3.5: Zustandsdiagramm Mifare-Ultralight-Karte
Mit dem WUPA-Befehl (Wake UP vom Typ A) erreicht man ebenfalls den Ready-
Zustand. Des Weitern lässt sich die Karte aus dem Haltezustand mittels WUPA
aufwecken. Wie bei REQA besteht der Befehl nur aus sieben Bit und wird ohne
Parameter ausgeführt.
3. Der READ-Befehl.
Der READ-Befehl eignet sich dazu den Speicherinhalt der Karte auszulesen. Als
Parameter benötigt er die Anfangsadresse des zu lesenden Bereiches. Jedes Byte
der Anfrage wird um ein Paritätsbit erweitert und mit einer CRC-Prüfsumme am
Ende abgeschlossen. Die Mifare-Karte antwortet indem sie 16 Bytes an Daten, von
der ihr übermittelten Anfangsadresse an, zurück sendet. Um den READ-Befehl
auszuführen, muss sich die Karte im Bereitschafts- oder im Aktivzustand befinden.
4. Der WRITE-Befehl.
Um den Datenspeicher der Karte mit Daten zu beschreiben, gibt es den WRITE-
Befehl. Es können immer nur seitenweise Daten geschrieben werden. Die vier By-
tes einer Seite werden dem Befehl als Parameter übergeben. Zur Fehlererkennung
kommen auch hier Paritäts- und CRC-Kontrolle zum Einsatz. Wie schon erwähnt,
sollte man nach einem erfolgreichen WRITE-Befehl nicht vergessen einen REQA-
Befehl hinterher zu schicken, da ansonsten die Daten nicht übernommen werden.
29
Kommando Hexcode Parameter Data Fehlercodes Antwort
REQA 0x26 (7 Bit) - - Paritätsbit ATQA = 0x0044WUPA 0x52 (7 Bit) - - Paritätsbit ATQA = 0x0044READ 0x30 (8 Bit) Adresse: 0x00-0x0F - Paritätsbit,CRC 16 Byte DatenWRITE 0xA2 (8 Bit) Adresse: 0x00-0x0F 4 Byte Paritätsbit,CRC -
Tabelle 3.5: Mifare-Ultralight-Befehle
Der WRITE-Befehl lässt sich nur in dem Aktivzustand ausführen.
Es soll noch erwähnt werden, dass nicht gültige oder nicht erwartete Befehle, von
der Karte als Fehler interpretiert werden und sie sich somit selbst in den Ruhezustand
zurücksetzt.
Tabelle 3.5 fasst noch mal sämtliche Befehle mit ihren relevanten Informationen zu-
sammen.
Somit sind wir fast am Ende von Kapitel 3 angelangt. Abschließend wird nun noch
erklärt was bei der ersten Inbetriebnahme des Lesegerätes berücksichtigt werden muss.
3.4 Inbetriebnahme des Lesegerätes
Kapitel 2 diente dazu dem Leser die Hardware des Lesegerätes näher zu bringen und
dessen Nachbau zu ermöglichen. In Kapitel 3 wurden dann die Grundlagen der Mifare-
Technologie beschrieben. Nach dem Lesen dieser beiden Kapitel sollte es also für einen
technisch versierte Leser möglich sein ein funktionstüchtiges Gerät nachzubauen.
Bevor das Gerät jedoch einwandfrei funktioniert, muss es noch kalibriert werden. Wir
benötigen dafür ein Oszilloskopen (mit mindestens 15 MHz Bandbreite), eine Mifare-
Ultralight-Karte und eine selbstgebaute Schnüffelsonde. Die Einstellmöglichkeiten be-
grenzen sich auf die drei Potentiometer P1, P2 und P3 und den Trimmer T1. Die Namen
beziehen sich auf die Bauteile in Abbildung 3.6.
Als erstes werden wir die Amplitude des HF-Feldes mit Hilfe von T1 auf ein Maximum
einstellen. Dazu bauen wir uns erst eine Schnüffelsonde indem wir fünf Windungen, ein
Millimeter dicken Drahtes, auf einen 5 x 6,5 Zentimeter Rahmen wickeln. Die Windun-
gen müssen schön nebeneinander gewickelt werden, um Verzerrungen des zu messenden
Signals zu vermeiden. Die Spule wird nun an den Eingang des Oszilloskopen gehängt
und das Lesegerät eingeschaltet. Das Display zeigt jetzt den ersten Menüeintrag an. Mit
30
Abbildung 3.6: PCD Platine
P3 lässt sich der Kontrast des LCDs einstellen. Beim Auflegen der Sonde auf die Anten-
ne sollte jetzt eine 13,56 MHz Sinusschwingung sichtbar werden. T1 wird nun so lange
verändert bis wir eine maximale Amplitude der Schwingung erreicht haben. Bei opti-
maler induktiver Kopplung der beiden Spulen erreicht der Scheitelwert der Sinusschwin-
gung fast 5 V. Damit ist der erste Kalibrierungsschritt abgeschlossen. Der Vollständigkeit
halber wollen wir noch darauf hinweisen, dass mit dieser primitiven Einstellungsmetho-
de nicht unbedingt die optimale Amplitude eingestellt werden kann. Da unsere Sonde
lediglich aus einer Spule besteht und keinerlei Maßnahmen für eine korrekte Impedanz-
Anpassung durchgeführt wurden, wird bei der Messung das HF-Feld dementsprechend
belastet. Dieses einfache Verfahren ist jedoch für unsere Zwecke bestens geeignet und die
korrekten Einstellungen waren jederzeit reproduzierbar. Für professionellere Einstellun-
gen und präzise Messmethoden, verweisen wir auf die Methoden wie sie in [10] erläutert
werden.
Für den weiteren Verlauf der Kalibrierung, benötigen wir die RFID-Karte. Sie wird
auf das Antennen-Feld des Lesegerätes aufgelegt. Dann stellen wir das Lesegerät auf
den ersten Menüeintrag ein und halten die Enter-Taste gedrückt. Mit dem Oszillosko-
pen messen wir das Signal, welches an dem Emitter von Transistor Q1 anliegt. P2 wird
31
jetzt so lange verdreht bis zu dem Punkt an dem der Transistor das Rechtecksignal nicht
mehr wegen Übersteuerung verzerrt. Wenn wir Glück haben, dann gibt das Lesegerät
jetzt die Meldung heraus, dass eine Karte erkannt wurde. Falls dies nicht der Fall ist,
lassen wir die Eingabe-Taste weiterhin gedrückt und drehen solange an P1, bis die Kar-
te erkannt wird. P1 ist übrigens zuständig um die Schwellspannung des Komparators
einzustellen.
Nach der Kalibrierung müsste das Gerät einwandfrei funktionieren und der Leser kann
sich nun, durch Ausprobieren, mit dessen Funktionen vertraut machen.
Mit dem Abschluss dieses Kapitels besitzen wir ein autonomes funktionstüchtige
RFID-Lesegerät. Wir können jetzt Seriennummern und Speicher von Mifare-Ultralight-
Karten auslesen. Jedoch fehlt uns noch die Möglichkeit sinnvolle Daten in den Speicher
der Karte zu schreiben. Dies ist nur mit Hilfe eines Computers machbar.
Im nächsten Kapitel befassen wir uns deswegen mit der Entwicklung einer geeigneter
PC Software für unser Lesegerät.
32
4 Die PC-Software
Die Herausforderung der PC Software bestand darin, ein kleines Softwarepaket zu ent-
wickeln, mit welchem man das Lesegerät über die USB-Schnittstelle steuern kann. Wie
schon in Kapitel 2 erwähnt, wird als USB-Controller Chip der FT232 von FTDI [6] be-
nutzt. Auf der Homepage des Herstellers finden wir geeignete Treiber für alle gängigen
Betriebssysteme (Linux, OS X, Windows,...). Wie auch schon angedeutet, sind we-
gen diesen Treibern, keine besonderen Kenntnisse über die Programmierung von USB-
Schnittstellen erforderlich. Der Treiber erzeugt einen virtuellen seriellen Port der pro-
blemlos, wie eine ganz konventionelle serielle Hardware-Schnittstelle, angesprochen und
programmiert werden kann.
Seitens der Softwareprogrammierung würde sich die C-Sprache natürlich bestens an-
bieten. Da es sich hier jedoch um eine ganz spezifische Hardware nahe Programmierung
handelt, könnten wir nicht garantieren, dass unserer C-Code auf jedem Betriebssys-
tem kompilierbar ist. Es müssten also mehrere Versionen gewisser Programmstellen für
die jeweiligen Betriebssysteme entworfen werden. Wegen dieses zusätzlichen Aufwandes,
haben wir uns dazu entschlossen die ganze Software in Java zu implementieren. Un-
ser Entschluss Java zu benutzen, basierte dabei auf der Hoffnung, dass man mit dieser
Programmiersprache, Betriebssystem übergreifende funktionstüchtige Programme ent-
wickeln kann. Vorgreifend können wir schon einmal verraten, dass unsere Forderungen
und Hoffnungen bestens erfüllt wurden.
Eine plattformübergreifende Programmierung war in unserem Fall besonders wichtig,
weil sämtliche Arbeiten, inklusive das Verfassen dieser Ausarbeitung, mit Hilfe eines
Intel iMac unter dem Betriebsystem OS X Tiger getätigt wurden. Um zu garantieren,
dass unsere Software auch auf den weiter verbreiteten Betriebssystemen wie Linux und
Windows lauffähig ist, haben wir uns schlussendlich für Java entschieden.
Die Umsetzung der Software gliedert sich in zwei wesentlichen Hauptteile. Die Imple-
mentierung einer Software-Bibliothek, mit Hilfe welcher die gesamte Funktionalität des
Lesegerätes benutzt werden kann, sowie die Programmierung einer graphischen Demo,
33
Abbildung 4.1: UML-Diagramm vom Paket-RFID
die aus ein paar Slides besteht und dem Zuschauer aktiv erklären soll wie das Lesegerät,
beziehungsweise allgemeiner die RFID-Technologie funktioniert.
Im folgenden soll nun die Vorgehensweise bei der Implementierung der Java-Bibliothek
erläutert werden.
4.1 Das RFID-Paket
Um eine plattformübergreifende Nutzung von seriellen und parallelen Hardware-Schnittstellen
zu gewährleisten, hat Sun Microsystems die Java Communications Library [11] entwi-
ckelt. Leider war zum Zeitpunkt unserer Projektarbeit keine lauffähige Version dieser
Bibliothek für OS X verfügbar.
Eine intensive Suche nach einer Alternative brachte schließlich Erfolg, als wir auf ei-
ne frei verfügbare Nachimplementierung dieser Bibliothek aufmerksam wurden. Hierbei
handelt es sich um die RXTX lib [12]. Die API (Aplication Programming Interface) die-
ses Klons hält sich strikt an die Vorgaben des Originals. Der einzig wichtige Unterschied
ist, dass sie für eine breite Auswahl von Betriebssystemen verfügbar ist, unter anderem
OS X. Die Bibliothek wird unter der GNU Lesser General Public License, kurz LGPL,
herausgegeben und kann somit ohne rechtliche Bedenken in unserem Softwarepaket ein-
gesetzt werden.
Unsere RFID-Bibliothek besteht aus den zwei Java Klassen RFIDInterface und RFID-
Device. Das UML-Diagramm in Bild 4.1 verdeutlicht die Beziehung zwischen beiden
34
Klassen und gibt einen Überblick über die verfügbaren Methoden. RFIDInterface ist
eine abstrakte Klasse die nur zum Teil implementiert ist und selbst nicht instanziiert
werden kann. RFIDDevice hingegen spezialisiert RFIDInterface und stellt dem Benutzer
eine vollständige Klasse mit diversen nutzvollen Methoden zu Verfügung, mittels denen
das RFID-Lesegerät über USB gesteuert werden kann. Sämtliche Funktionen die von der
Firmware unterstützt werden, sind in Form von Methoden in der RFIDDevice Klasse
implementiert worden. Das Ausführen einer beliebigen Methode läuft dabei immer gleich
ab und soll nun willkürlich anhand der Methode Request() erläutert werden.
4.1.1 Kommunikation zwischen Computer und Lesegerät
Die Request() Methode, wie der Name es schon sagt, ist die Umsetzung des REQA-
Befehles. Beim Ausführen dieser Klassenmethode wird im Hintergrund eine serielle Kom-
munikation mit dem Lesegerät aufgebaut. Das Lesegerät muss sich dafür im USB Ver-
bindungsmodus befinden (Menüeintrag 5). Mit Hilfe eines Zufallsgenerators wird eine
32 Bit lange Sequenznummer erzeugt. Diese intern verwaltete Nummer identifiziert die
aktuelle Verbindung und wird im Falle einer fehlerhaften Datenübertragung benutzt,
um die Verbindung gezielt und kontrolliert zu beenden.
Hinter den Kulissen und für den Benutzer unsichtbar, wird parallel zu jeder Daten-
verbindung ein Thread gestartet. Dieser Thread überprüft periodisch, ob die aktuelle
Verbindung reibungslos abläuft. Im Falle eines Fehlers, wie zum Beispiel ein Heraus-
ziehen des USB-Kabels, hängt sich die unterliegende RXTX lib auf. Der Thread würde
dann die Verbindung, in einem solchen Szenario, nach Ablauf eines festgelegten Timeouts
schliessen. Mit dieser Vorgehensweise ist es fast unmöglich die Computersoftware, durch
von außen wirkende Einflüsse seitens des Lesegerätes, zum Abstürzen zu bringen.
Um dem Lesegerät nun mitzuteilen, dass ein REQA-Befehl ausgeführt werden soll,
wird eine, für den REQA-Befehl festgelegte, Identifikationsnummer mit der Länge eines
Bytes übertragen. Benötigt der Befehl noch Parameter (was bei REQA nicht der Fall
ist), werden diese anschließend byteweise übertragen. Nachdem das Lesegerät alle Daten
empfangen hat, führt es den Befehl aus und liefert das Ergebnis zurück. Für den REQA-
Befehl gibt es als Rückgabewert nur die beiden Möglichkeiten, ob der Befehl erfolgreich
war oder nicht. Ein positives Feedback bedeutet es liegt ein RFID-Transponder auf dem
Lesegerät, eine negative Antwort heißt, dass kein Transponder in Reichweite ist. Somit
haben wir also eine Möglichkeit herauszufinden, ob eine Karte aufliegt oder nicht. Die
Methode isPICC() geht übrigens nach dem Prinzip vor und liefert dementsprechend den
35
Wert true oder false.
Falls in Zukunft weitere Funktionen in die Firmware integriert werden, so lässt sich das
RFID-Paket schnell und leicht erweitern. Der intuitive und leicht verständliche Java-
Programmcode befindet sich zur freien Nutzung im Anhang.
Im nächsten Abschnitt werden sämtliche Schritte erklärt die für eine erfolgreiche In-
stallation des RFID-Paketes nötig sind.
4.1.2 Installation des RFID-Paketes
Die folgende Anleitung erläutert die Vorgehensweise, die bei einer erfolgreichen Instal-
lation des RFID-Paketes beachtet werden muss. Der Installationsvorgang gliedert sich
dabei in drei Schritte:
1. Installation der Treiber.
Auf der Webseite des Herstellers FTDI [6] kann man sich den benötigten Treiber
für den FT232RL-Chip herunter laden. Nach der Installation des Treibers erscheint
ein virtueller serieller Port.
2. Installation der RXTX lib.
Die RXTX lib kann man sich unter [12] aus dem Internet herunter laden. Es
stehen aktuell drei Versionen für die Betriebssysteme Linux, OS X und Windows
zu Verfügung. Man hat nun die Wahl die Bibliothek selber zu kompilieren oder
gleich die binären Dateien zu installieren. An diesem Punkt verweisen wir den
Leser auf die hervorragende Wiki-Dokumentation der Entwickler.
3. Installation des RFID-Paketes.
Wenn man die ersten beiden Punkte erfolgreich abgeschlossen hat, kann man den
Quelltext des RFID-Paketes, aus dem Anhang, kompilieren. Dem Leser steht nun
eine funktionsfähige RFID-Bibliothek zur Verfügung, die er nach Lust und Laune
benutzen und optimieren kann.
Im nächsten Abschnitt soll anhand eines kleinen Code-Fragmentes demonstriert werden,
wie das RFID-Paket angewendet werden kann.
4.1.3 Anwendung des RFID-Paketes
Listing 4.1 zeigt ein praktisches Anwendungsbeispiel für unsere RFID-Bibliothek. In Zei-
le 1 wird das RFID-Paket eingebunden. Wie aus Zeile 8 und 36 ersichtlich wird, müssen
36
die gesamten Aufrufe der RFID-Methoden von einem try/catch-Block umschlossen sein.
Was für Exceptions geworfen werden, lässt sich in der RXTX-Dokumentation [12] nach-
lesen. In Zeile 5 deklarieren wir eine Variable vom Typ RFIDDevice, die in Zeile 19
initialisiert wird. Das Java-Programm muss mit einem gültigen seriellen Port als Pa-
rameter aufgerufen werden. Wird kein Parameter übergeben, gibt das Programm mit
Zeile 15 eine Liste von möglichen seriellen Schnittstellen heraus. Der Benutzer muss nun
wissen oder ausprobieren an welcher dieser Schnittstellen sein Lesegerät angeschlossen
ist. Unter Windows ist der Standardname für eine serielle Schnittstelle immer COM X,
wobei X für eine Ziffer oder Zahl steht. Unter Unix und Linux Systemen könnte der
Name der Schnittstelle wie /dev/tty.USBtoSerialXX aussehen. Die Namensgebung un-
ter diesen Betriebssystemen ist meistens selbsterklärend und somit intuitiv verständlich.
Um mögliche Frustrationen bei der Parameter Eingaben zu umgehen sollte man unter
allen Betriebssystemen auf die Groß- und Kleinschreibung acht geben.
Nehmen wir nun an es wurde ein gültiger Parameter übergeben und die serielle Schnitt-
stelle wurde erfolgreich geöffnet. Dann kann man beispielsweise, wie in Zeile 20 gezeigt,
dem Gerät mitteilen einen REQA-Befehl zu verschicken oder, wie in Zeile 21 bis 30, die
eindeutige Seriennummer eines aufliegenden RFID-Transponders erlangen. Die genaue
Syntax aller Methoden ist übrigens, mit Hilfe von Javadoc-Anweisungen, im Programm-
code ausführlich erklärt. Nach dem Benutzen des Lesegerätes sollte man nicht vergessen
die Hardware-Ressource wieder frei zu geben (siehe dazu Zeile 24 oder Zeile 31 ).
Listing 4.1: Anwendungbeispiel des RFID-Paketes
1 import RFID . ∗ ;2 import java . u t i l . ArrayList ;
3
4 class RFIDtest {5 RFIDDevice dev i c e ;
6 public stat ic void main ( St r ing args [ ] )
7 {8 try
9 {10 ArrayList data = new ArrayList() ;
11 i f ( args . l ength < 1)
12 {
37
13 System . out . p r i n t l n ( ” S e r i e l l e n Port auswählen ” ) ;
14 RFIDInterface . L i s tPor t s ( ) ;
15 System . e x i t ( 1 ) ;
16 }17 else
18 {19 dev i c e = new RFIDDevice ( args [ 0 ] ) ;
20 System . out . p r i n t l n ( ”>>Reply from PCD: ” + dev i ce . Request ( ) ) ;
21 i f ( Device . GetUID( data ) . equa l s ( ”UID ERROR” ) )
22 {23 System . out . p r i n t l n ( ”>>> Cannot read PICC” ) ;
24 dev i ce . CloseDevice ( ) ;
25 System . e x i t ( 1 ) ;
26 }27 else
28 {29 System . out . p r i n t l n ( ”>>PICC UID : ” +
30 RFIDDevice . Ar rayL i s t2St r ing ( data ) ) ;
31 dev i ce . CloseDevice ( ) ;
32 System . e x i t ( 0 ) ;
33 }34 }35 }36 catch ( Exception e )
37 {38 System . out . p r i n t l n ( e ) ;
39 i f ( dev i c e instanceof RFIDDevice )
40 dev i ce . CloseDevice ( ) ;
41 System . e x i t ( 1 ) ;
42 }43 }44 }
38
4.2 Die JavaFX-Demo
Zum Abschluss dieses Kapitels und der gesamten Ausarbeitung haben wir eine kleine
graphische Demo entwickelt, die, mit Hilfe des Lesegerätes, einen praktischen Einblick
in die Funktionsweise der RFID-Technologie geben soll. Diese Demo wurde extra für
Vorführungen, auf Messen oder Workshops, konzipiert.
Die graphisch interaktive Präsentation läuft voll automatisch ab und fängt nach je-
dem Durchlauf wieder von vorne an. Die Demo ist in drei Slides aufgeteilt. Die erste
Folie vermittelt dem Zuschauer einen kurzen theoretischen Überblick über die RFID-
Technologie. Ausgestattet mit diesem theoretischen Grundwissen werden dann auf der
zweiten Folie die verschiedenen Komponenten des RFID-Lesegerätes anschaulich erklärt.
Die letzte Folie beinhaltet den interaktiven Teil der Vorführung. Der Zuschauer hat nun
die Möglichkeit eine rote oder eine blaue RFID-Karte auf das Gerät aufzulegen. Die
Stelle an der die Karte aufgelegt werden soll, wird dem Zuschauer mit Hilfe einer LED-
Hintergrundbeleuchtung angezeigt. Anhand der Seriennummer ist es dem Gerät dann
möglich dem Publikum mitzuteilen, welche der beiden Karten ausgewählt wurde.
Die Demo wurde in der Skriptsprache JavaFX programmiert. In ihr lassen sich auf
schnelle und einfache Weise multimediale und animierte Präsentationen realisieren. Ein
weiterer Vorteil ist, dass sich problemlos existierende Java-Klassen, wie zum Beispiel die
aus unserem RFID-Paket, aufrufen und eingliedern lassen.
Da es nicht möglich ist die Demo in den Anhang zu stellen, kann ein Version per
E-mail unter m [email protected] angefordert werden.
39
5 Zusammenfassung
Das Hauptziel diese Projektarbeit war es, ein funktionsfähiges Lesegerät für RFID-
Transponder zu entwickeln.
Um dieses Ziel zu erreichen, mussten wir uns erst für einen der vielen RFID-Standards
entscheiden. Anschließend haben wir uns detaillierte Informationen über die ausgewählte
Technologie zusammengesucht. Als weitere Inspirationsquellen kamen uns andere frei
verfügbare RFID-Projekte zu Gute.
Um unser Projekt erfolgreich umzusetzen, benötigten wir sowohl elektronische und
programmiertechnische Grundkenntnisse. Unser Lesegerät basiert zum größten Teil auf
der in [1] veröffentlichten Schaltung. Das Gerät wird jedoch von einer, von Grund auf
neu programmierten und umfangreicheren Firmware, gesteuert. Des Weiteren besitzt
unser RFID-Demonstrator ein USB-Schnittstelle.
Zusätzlich dazu haben wir ein Softwarepaket entwickelt, mit welchem man das Lese-
gerät, mit Hilfe eines Computers, über den USB-Anschluss steuern kann.
Am Schluss der Projektarbeit hatten wir schliesslich sämtliche Ziele erreicht und be-
sitzen nun ein RFID-Lesegerät, welches alle gestellten Anforderungen erfüllt.
Der Bau des Lesegerätes war sehr interessant und lehrreich, und hat dem Autor zahlrei-
che Erfolgserlebnisse beschert.
40
6 Anhang
6.1 Hardware
6.1.1 Platinenlayouts zum Belichten
Die Abbildungen 6.1 und 6.2 können als Vorlage zum Belichten benutzt werden. Die
Breite der Platinen ist 10,1 cm beziehungweise 6,5 cm.
6.1.2 Bestückungsplan mit Bauteilliste
Liste der Bauteile mit Bestückungsplan in Abbildung 6.3
C1 33 pF
C2 33 pF
C3 4,7 nF
C4 330 pF
C5 220 pF
C6 220 pF
C7 100 nF
C8 220 pF
C9 100 nF
C10 330 pF
C11 60 pF
C12 100 nF
C13 100 nF
C14 100 nF
C15 10 nF
C18 100 nF
C19 4,7µF
D1 BAT42
D2 BAT42
IC1 FT232RL
IC2 MEGA16-P
IC3 LM393N
IC4 74HC00N
L5 2.2µH
L6 100µH
L7 100µH
L8 0.1µH
LED1 grün
LED2 grün
Q1 BC560
Q2 BS250
Q3 BS170
Q4 13,56 MHz
R1 2,2 MΩ
R2 2,2 kΩ
R3 2,2 kΩ
R4 4,7 kΩ
R5 4,7 kΩ
R6 4,7 kΩ
R7 1 kΩ
R8 220 Ω
R9 100 Ω
R10 10 kΩ
R11 1 kΩ
R12 2,2 kΩ
R13 1 kΩ
R14 2,2 kΩ
R15 330 Ω
R16 25 kΩ
R17 4,7 kΩ
R18 4,7 kΩ
R19 270 Ω
R20 270 Ω
SV1 ISP
SV2 LCD
USB connector
41
Abbildung 6.1: Platine des Lesegeräts
Abbildung 6.2: Platine der Antenne
42
Abbildung 6.3: Bestückungsplan
6.2 Firmware
Die Firmware besteht aus den sechs Quelltextdateien rfid.c, rfid.h, mifare.c, mifare.h,
lcd.c und lcd.h.
6.2.1 rfid.h
1 #include
2 #include
3 #include ” l cd . h”
4
5 #define XX 0xDD
6 #define XY 0xDF
7 #define XZ 0xD7
8
9 #define YX 0xFD
10 #define YY 0xFF
11 #define YZ 0xF7
12
13 #define ZX 0x7D
14 #define ZY 0x7F
15 #define ZZ 0x77
16
17 #define X 0xD0
18 #define Y 0xF0
19 #define Z 0x70
20
21 #define CRC16INITVAL 0x6363
22 #define SENDRECEIVEBUFFERSIZE 82
23 #define DATABUFFERSIZE 21
24
25 volat i le u in t 8 t da t a bu f f e r [DATABUFFERSIZE ] ;
26 volat i le u in t 8 t s e nd and r e c e i v e bu f f e r [SENDRECEIVEBUFFERSIZE ] ;
27
28 //number o f PCD b i t s
29 volat i le u in t 8 t PCD bit count LSB ;
30 volat i le u in t 8 t PCD bit count MSB ;
43
31
32 //number o f PICC b i t s
33 volat i le u in t 8 t PICC bit count LSB ;
34 volat i le u in t 8 t PICC bit count MSB ;
35
36 enum eReturnCode { REQA REPLY OK,REQA REPLY ERROR,37 WUPA REPLY OK,WUPA REPLY ERROR,
38 READ REPLY OK,READ REPLY ERROR,
39 WRITE OK,WRITE ERROR,BAD PAGE,
40 CRC OK, CRC ERROR,
41 UID OK, UID ERROR,
42 EXIT USB OK, LED ON, LED OFF } ;43
44 typedef enum eReturnCode eReturnCode ;
45
46 void EncodePCDRequest ( u i n t 8 t ) ;
47 u in t16 t CRC16 ( u i n t 8 t ∗ , u i n t 8 t ) ;48 u i n t 8 t DecodePICCReply ( ) ;
49 void DisplayDataBuffer ( u i n t 8 t ) ;
50 i n l i n e void WaitCycles ( u in t 16 t ) ;
51 eReturnCode READ ( u in t 8 t ) ;
52 eReturnCode WRITE ( u in t 8 t , u i n t 8 t ∗ ) ;53 eReturnCode WUPA ( ) ;
54 eReturnCode REQA ( ) ;
55 u i n t 8 t Nibble2Hex ( u i n t 8 t ) ;
56 u i n t 8 t GetByteFromDataBuffer ( u i n t 8 t ) ;
57 void InitUSART ( ) ;
58 u i n t 8 t RX( ) ;
59 void TX( u in t 8 t ) ;
6.2.2 rfid.c
1 #include ” r f i d . h”
2
3 stat ic i n l i n e void EnableRFField ( ) ;
4 stat ic i n l i n e void DisableRFField ( ) ;
5 stat ic void REQA( ) ;
6 stat ic void SendAndReceive ( ) ;
7 stat ic void EraseBuf f e r s ( ) ;
8
9 u i n t 8 t GetByteFromDataBuffer ( u i n t 8 t byte )
10 {11 i f ( byte < DATABUFFERSIZE )
12 return da ta bu f f e r [ byte ] ;
13 return 0 ;
14 }15
16 u i n t 8 t Nibble2Hex ( u i n t 8 t n ibb l e )
17 {18 i f ( n ibb l e > 15 )
19 return 0 ;
20 i f ( n ibb l e < 10)
21 return ( n ibb l e +48);
22 else
23 return ( n ibb l e +55);
24 }25
26 stat ic void EraseBuf f e r s ( )
27 {28 u i n t 8 t loop ;
29 for ( loop =0; loop < DATABUFFERSIZE; loop++)
30 {31 da t a bu f f e r [ loop ] = 0x00 ;
32 s end and r e c e i v e bu f f e r [ loop ] = 0x00 ;
33 }34
35 for ( ; loop < SENDRECEIVEBUFFERSIZE; loop++)
36 {37 s end and r e c e i v e bu f f e r [ loop ] = 0x00 ;
38 }39 }
44
40
41 void EncodePCDRequest ( u i n t 8 t l ength )
42 {43 u i n t 8 t l a s t b i t ;
44 u i n t 8 t n ex t b i t ;
45 u i n t 8 t n ibb l e count e r ;
46 u i n t 8 t cur r en t byte ;
47 u i n t 8 t p a r i t y b i t ;
48 u i n t 8 t counter ;
49 u i n t 8 t b i t ;
50 u i n t 8 t byte ;
51 u i n t 8 t sequence ;
52 u i n t 8 t byte count ;
53 byte count=length ;
54
55 // compute CRC and add to d a t a b u f f e r
56 // crc i s on l y needed f o r read and wr i t e commands
57 u in t16 t CRC checksum = CRC16 ( ( u i n t 8 t ∗) da ta bu f f e r , byte count ) ;58 da t a bu f f e r [ byte count ] = ( u i n t 8 t ) ( CRC checksum & 0x00FF ) ;
59 da t a bu f f e r [ byte count +1] = ( u i n t 8 t ) ( CRC checksum >> 8 ) ;
60 byte count += 2 ;
61 // add s t a r t sequence and p a r i t y b i t
62 // r e v e r s e s b i t s
63 // one b i t i s r e p r e s en t e d in f ou r t ime un i t s
64 //X = 0xD Y = 0xF and Z = 0x7
65
66 counter = 0 ;
67 s end and r e c e i v e bu f f e r [ counter ] = Z ; // add s t a r t b i t
68 l a s t b i t = 0 ;
69 n ibb l e count e r = 1 ;
70
71 for ( byte=0; byte < byte count ; byte++)
72 {73 cur r en t byte = da ta bu f f e r [ byte ] ;
74 p a r i t y b i t = 1 ;
75 for ( b i t =0; b i t < 8 ; b i t++)
76 {77 nex t b i t = cur r ent byte & 0x01 ; //LSB
78 cur r en t byte = cur r en t byte >> 1 ;
79 p a r i t y b i t = pa r i t y b i t ˆ n ex t b i t ;
80
81 i f ( n ex t b i t == 1)
82 sequence = X;
83 else i f ( l a s t b i t == 0)
84 sequence = Z ;
85 else
86 sequence = Y;
87 s end and r e c e i v e bu f f e r [ counter ] = s end and r e c e i v e bu f f e r [ counter ] | ( sequence >>(4∗n ibb l e count e r ) ) ;88
89 i f ( n ibb l e count e r == 1)
90 {91 n ibb l e count e r = 0 ;
92 counter++;
93 }94 else
95 n ibb l e count e r = 1 ;
96 l a s t b i t = nex t b i t ;
97 }98
99 i f ( p a r i t y b i t == 1)
100 sequence = X;
101 else i f ( l a s t b i t == 0)
102 sequence =Z ;
103 else
104 sequence = Y;
105 s end and r e c e i v e bu f f e r [ counter ] = s end and r e c e i v e bu f f e r [ counter ] | ( sequence >>(4∗n ibb l e count e r ) ) ;106 i f ( n ibb l e count e r == 1)
107 {108 n ibb l e count e r = 0 ;
109 counter++;
110 }111 else
45
112 n ibb l e count e r = 1 ;
113 l a s t b i t = pa r i t y b i t ;
114 }115 // end sequence
116 i f ( l a s t b i t == 1)
117 s end and r e c e i v e bu f f e r [ counter ] = s end and r e c e i v e bu f f e r [ counter ] | (Y>>(4∗n ibb l e count e r ) ) ;118 else
119 s end and r e c e i v e bu f f e r [ counter ] = s end and r e c e i v e bu f f e r [ counter ] | (Z>>(4∗n ibb l e count e r ) ) ;120
121 i f ( n ibb l e count e r == 1)
122 {123 n ibb l e count e r = 0 ;
124 counter++;
125 }126 else
127 n ibb l e count e r = 1 ;
128 s end and r e c e i v e bu f f e r [ counter ] = s end and r e c e i v e bu f f e r [ counter ] | (Y>>(4∗n ibb l e count e r ) ) ;129 }130
131 eReturnCode REQA()
132 {133 EnableRFField ( ) ;
134 REQA( ) ;
135 SendAndReceive ( ) ;
136 DecodePICCReply ( ) ;
137 DisableRFField ( ) ;
138
139 i f ( ( da t a bu f f e r [ 0 ] == 0x44 ) && da ta bu f f e r [ 1 ] == 0x00 )
140 return REQA REPLY OK;
141 else
142 return REQA REPLY ERROR;
143 }144
145 stat ic void REQA() // Reques t t ype A
146 {147 //REQA code : 0 x26 (7 b i t s )
148 // add s t a r t− and end b i t ; no p a r i t y b i t i s added149 // Modi f i ed M i l l e r encod ing : ZZ XX YZ XY ZY
150 EraseBuf f e r s ( ) ;
151 s end and r e c e i v e bu f f e r [0 ]=ZZ ;
152 s end and r e c e i v e bu f f e r [1 ]=XX;
153 s end and r e c e i v e bu f f e r [2 ]=YZ;
154 s end and r e c e i v e bu f f e r [3 ]=XY;
155 s end and r e c e i v e bu f f e r [4 ]=ZY;
156 PCD bit count LSB = 0x28 ; // 40d
157 PCD bit count MSB = 0x00 ;
158 // re sponse 0 x0044
159 //2 b y t e s w i th p a r i t y + 1 s t a r t b i t
160 //38 eru = 0x26
161 // sa v i n g 0 x0190 eru
162 PICC bit count LSB = 0x90 ;
163 PICC bit count MSB = 0x01 ;
164 }165
166 eReturnCode WUPA () //Wake up t ype A
167 {168 //WUPA code : 0 x52 (7 b i t s )
169 // add s t a r t− and end b i t ; no p a r i t y b i t i s added170 // Modi f i ed M i l l e r encod ing : ZZ XY ZX YX YY
171 EraseBuf f e r s ( ) ;
172 s end and r e c e i v e bu f f e r [0 ]=ZZ ;
173 s end and r e c e i v e bu f f e r [1 ]=XY;
174 s end and r e c e i v e bu f f e r [2 ]=ZX;
175 s end and r e c e i v e bu f f e r [3 ]=YX;
176 s end and r e c e i v e bu f f e r [4 ]=YY;
177 PCD bit count LSB = 0x28 ; // 40d
178 PCD bit count MSB = 0x00 ;
179 // re sponse 0 x0044
180 //2 b y t e s w i th p a r i t y + 1 s t a r t b i t
181 //38 eru = 0x13
182 PICC bit count LSB = 0x90 ; //
183 PICC bit count MSB = 0x01 ;
46
184 EnableRFField ( ) ;
185 SendAndReceive ( ) ;
186 DisableRFField ( ) ;
187 DecodePICCReply ( ) ;
188
189 i f ( ( da t a bu f f e r [ 0 ] == 0x44 ) && da ta bu f f e r [ 1 ] == 0x00 )
190 return WUPA REPLY OK;
191 else
192 return WUPA REPLY ERROR;
193 }194
195 eReturnCode READ ( u in t 8 t page )
196 {197 u in t16 t CRC checksum ;
198
199 i f ( page > 0x0F)
200 return BAD PAGE;
201 EnableRFField ( ) ;
202 REQA( ) ;
203 SendAndReceive ( ) ;
204 DecodePICCReply ( ) ;
205 i f ( ( da t a bu f f e r [ 0 ] != 0x44 ) | | da ta bu f f e r [ 1 ] != 0x00 )206 return REQA REPLY ERROR; // e x i t f u n c t i o n
207 //READ code : 0 x30
208 //Parameter : 0x00−0x0F209 //CRC check
210 EraseBuf f e r s ( ) ; // very impor tan t
211 da t a bu f f e r [ 0 ] = 0x30 ;
212 da t a bu f f e r [ 1 ] = page ;
213 EncodePCDRequest ( 2 ) ; // dont change , 2 i s l e n g t h o f command
214 //2 cmd by t e s , 2 crc by t e s , 1 s t a r t b i t , 2 end b i t s , p a r i t y b i t s f o r each b y t e => 39 b i t s
215 //−> 39 ∗ 4 −> 19 ,5 b y t e s216 PCD bit count LSB = 0x9C ; // 156d
217 PCD bit count MSB = 0x00 ;
218 PICC bit count LSB = 0x90 ; //
219 PICC bit count MSB = 0x01 ;
220 SendAndReceive ( ) ;
221 DecodePICCReply ( ) ;
222 DisableRFField ( ) ;
223 //make CRC check
224 CRC checksum = CRC16 ( ( u i n t 8 t ∗) da ta bu f f e r , 1 8 ) ;225 i f (CRC checksum != 0x0000 )
226 return CRC ERROR; // e x i t f u n c t i o n
227 return READ REPLY OK;
228 }229
230 i n l i n e void WaitCycles ( u in t 16 t count )
231 {232 asm volat i le ( ”cp %A0 , z e r o r e g \n\ t ”233 ”cpc %B0 , z e r o r e g \n\ t ”234 ”breq 2 f \n\ t ”235 ” 1 : \n\ t ”236 ” sbiw %0,1 \n\ t ”237 ”brne 1b \n\ t ”238 ” 2 : ”
239 : ”=w” ( count )
240 : ”0” ( count )
241 ) ;
242 }243
244 eReturnCode WRITE ( u in t 8 t page , u i n t 8 t ∗ data )245 {246 u in t16 t CRC checksum ;
247
248 i f ( ( page < 0x04 ) | | ( page > 0x0F) )249 return BAD PAGE;
250
251 EnableRFField ( ) ;
252 REQA( ) ;
253 SendAndReceive ( ) ;
254 DecodePICCReply ( ) ;
255 i f ( ( da t a bu f f e r [ 0 ] != 0x44 ) | | da ta bu f f e r [ 1 ] != 0x00 )
47
256 return REQA REPLY ERROR; // e x i t f u n c t i o n
257
258 EraseBuf f e r s ( ) ; // very impor tan t
259
260 // read (0)
261 da t a bu f f e r [ 0 ] = 0x30 ;
262 da t a bu f f e r [ 1 ] = 0x00 ;
263 EncodePCDRequest ( 2 ) ;
264 PCD bit count LSB = 0x9C ; // 156d
265 PCD bit count MSB = 0x00 ;
266 PICC bit count LSB = 0x90 ; //
267 PICC bit count MSB = 0x01 ;
268 SendAndReceive ( ) ;
269 DecodePICCReply ( ) ;
270 CRC checksum = CRC16 ( ( u i n t 8 t ∗) da ta bu f f e r , 1 8 ) ;271 i f (CRC checksum != 0x0000 )
272 return CRC ERROR; // e x i t f u n c t i o n
273
274 EraseBuf f e r s ( ) ; // very impor tan t
275 // w r i t e
276 da t a bu f f e r [ 0 ] = 0xA2 ;
277 da t a bu f f e r [ 1 ] = page ;
278 da t a bu f f e r [ 2 ] = ∗data ;279 da t a bu f f e r [ 3 ] = ∗( data +1);280 da t a bu f f e r [ 4 ] = ∗( data +2);281 da t a bu f f e r [ 5 ] = ∗( data +3);282
283 EncodePCDRequest ( 6 ) ;
284 PCD bit count LSB = 0x2C ; // 300d
285 PCD bit count MSB = 0x01 ;
286 PICC bit count LSB = 0x90 ; //
287 PICC bit count MSB = 0x01 ;
288
289 SendAndReceive ( ) ;
290 // have to send REQA to comp le t e w r i t e command
291 REQA( ) ;
292 SendAndReceive ( ) ;
293 DecodePICCReply ( ) ;
294 DisableRFField ( ) ;
295 return WRITE OK;
296 }297
298 u in t16 t CRC16 ( u i n t 8 t ∗ data , u i n t 8 t l ength )299 {300 u i n t 8 t byte ;
301 u in t16 t CRC16 ;
302 CRC16 = CRC16INITVAL;
303
304 do{305 byte = ∗data++;306 byte = ( byte ˆ( u i n t 8 t ) ( (CRC16) & 0x00FF ) ) ;
307 byte = ( byte ˆ( byte 8)ˆ(( u in t 16 t ) byte
328 // /////////////////////////
329 // l a s t b y t e o f s e n d a n d r e c e i v e b u f f e r must be c l e a r e d
330 // ensure s t h a t a l o r i t hm s t o p s
331 // search f o r f i r s t b i t s e t in s e n d a n d r e c e i v e b u f f e r b i t s tream
332 asm volat i le (
333
334 ”push r20 \n\ t ”335 ”push r21 \n\ t ”// b i t p o s i t i o n coun te r f o r r2336 ”push r22 \n\ t ”// cu r r en t b y t e from d a t a b u f f e r337 ”push r23 \n\ t ”// b i t p o s i t i o n coun te r f o r r4338 ”push r24 \n\ t ”// cu r r en t b y t e from e u b u f f e r339 ”push r25 \n\ t ”340 ”push r26 \n\ t ”341 ”push r27 \n\ t ”342 ”push r28 \n\ t ”//LSB o f Y343 ”push r29 \n\ t ”//MSB o f Y344 ”push r30 \n\ t ”//LSB o f Z345 ”push r31 \n\ t ”//MSB o f Z346
347 // /////////////////
348 // s t a r t o f i n i t //
349 // /////////////////
350
351 ” l d i r28 , l o8 ( da t a bu f f e r )\n\ t ”// l oad &d a t a b u f f e r in Y352 ” l d i r29 , h i8 ( da t a bu f f e r )\n\ t ”353 ” l d i r30 , l o8 ( s e nd and r e c e i v e bu f f e r )\n\ t ”// l oad &e u b u f f e r in Z354 ” l d i r31 , h i8 ( s e nd and r e c e i v e bu f f e r )\n\ t ”355 ” l d i r21 , 8 \n\ t ”356 ” l d i r23 , 8 \n\ t ”357 ” ld r24 , Z+ \n\ t ”358 ” l d i r25 , 0xFF \n\ t ”// t imeou t359 //” l d i r26 , 0 \n\ t ”360 ” l d i r27 , 0x80 \n\ t ”//= 1 f o r odd p a r i t y361 ” l d i r20 , 0 \n\ t ”362
363 // ///////////////
364 // end o f i n i t //
365 // ///////////////
366
367 // ////////////
368 /// s e a r c h i n g f i r s t s e t b i t in e u b u f f e r
369 // i f no b i t i s s e t w i t h i n t h e r25 b i t s o f e u b u f f e r−> q u i t w i t h e r r o r370 // ///////////
371
372 ” 10 : \n\ t ”373 ” r c a l l g e t b i t \n\ t ”374 ”dec r25 \n\ t ”375 ”breq 20 f \n\ t ”// e r r o r376 ” brcc 10b \n\ t ”377 // found 1
378 ” r c a l l g e t b i t \n\ t ”// found 1 in b i t s tream ! ; nex t b i t has to be a 0 f o r c o r r e c t s t a r t sequence379 ” brcs 20 f \n\ t ”// i f C i s t s e t => e r r o r380 // decod ing data
381 ” 15 : \n\ t ”382 ” r c a l l g e t b i t \n\ t ”383 ” brcc 11 f \n\ t ”384 ” r c a l l g e t b i t \n\ t ”// e x p e c t i n g 0385 ” brcs 20 f \n\ t ”// e r r o r i f 11 sequence386 ” sec \n\ t ”387 ” r c a l l pu t b i t \n\ t ”// decoded wi th s u c c e s s 10 −> 1388 ”rjmp 15b \n\ t ”389 ” 11 : \n\ t ”390 ” r c a l l g e t b i t \n\ t ”// e x c p e c t i n g 1391 ” brcc 12 f \n\ t ”// i f 00 sequence −> end o f stream392 ” c l c \n\ t ”393 ” r c a l l pu t b i t \n\ t ”// decoded wi th s u c c e s s 01 −> 0394 ”rjmp 15b \n\ t ”395 // put b i t from Carry in 2 r2
396 // i f b y t e i s f u
Top Related