Auf dieser Seite findest du die Dokumentation zum Praktikum Mikroprozessor-Hardware mit dem Thema: "GPS Daten Logger".
Im Jahr 2004 habe ich zusammen mit einem Kommilitonen an diesem Projekt gearbeitet und eine Mikroprozessor-basierte Schaltung entwickelt, die als Ergänzung für ein Garmin GPS Handgerät eingesetzt werden kann.
3.2 Programmstart und Bedienungsanleitung
4.2.1.1 Serielle Schnittstelle
4.2.1.2 Externer Interrupt (Taster)
4.3.1 Beschreibung der Funktionalität des SRAMs
4.3.2 Registerbausteine zur Adressierung
4.3.3 Logikschaltung zur „Taktung“ der FFs
4.3.4 Beispiel für einen Adressierungsvorgang
4.4 Datenkommunikation (RS-232, MAX232N Baustein)
4.5 Statusanzeige über 7-Segment-Display
5.2 Problemanalyse und Realisation
5.2.1 Grundsätzlicher Programmaufbau und Programmgliederung
5.2.2 „Mainloop“ und Interruptverarbeitung
5.2.3 Datenübertragung über die serielle Schnittstelle
5.2.3 Statusanzeige auf der 7-Segment Anzeige
5.2.4 Speicherverwaltung und Kompression
5.2.5 Datenverarbeitung auf Byte-Ebene
5.2.5.3 Speicherüberlaufprüfung
5.2.5.2 Versenden eines Paketes
5.2.6 Datenverarbeitung auf Paketebene
In diesem Praktikum soll ein Datenlogger für ein GPS Handgerät erstellt werden. Das GPS Handgerät der Firma Garmin hat einen internen Speicher in dem man eine abgelaufene Route (beispielsweise bei einer Wanderung) speichern kann. Allerdings ist dieser interne Speicher für längere Wanderungen nicht ausreichend groß. Deshalb soll ein Gerät entwickelt werden, dass die bereits gespeicherten Daten aus dem GPS Empfänger ausliest und in einem SRAM speichert. Später soll dieser Speicher dann auch wieder ausgelesen und die Daten an einen PC weitergeben werden können. Dafür soll der Mikrokontroller 89C2051 der Firma Atmel eingesetzt werden.
Details
Der AT89C2051 ist mit einer seriellen Schnittstelle ausgestattet. Diese soll für die Kommunikation mit dem GPS Empfänger und auch mit dem PC benutzt werden. Die Kommunikation soll auf 9600 bps,8 Datenbits und 1 Stopbit eingestellt sein. Die Kommunikation mit dem Garmin-GPS-Empfänger findet mit einem speziellen Protokoll statt. Der GPS Empfänger speichert unter anderem sogenannte Way- und Track-Points. Diese sollen beide ausgelesen werden. Das muss man nacheinander machen. Der Ablauf ist aber fast identisch. Wenn die Daten vom PC abgefragt werden, soll sich die Schaltung so verhalten, als ob sie selber ein Garmin GPS-Empfänger ist.
Eine Kompression der Daten ist wünschenswert, um möglichst viele Daten speichern zu können. Ebenfalls wichtig ist, dass die Schaltung auf die Anfrage des PCs korrekt reagiert. Wird eine Anfrage nach den Way-Points gestellt sollen auch nur diese zurück gesendet werden. Analog verhält es sich mit den Track-Points. Es sollte auch möglich sein, mehrere „Sessions“ aus dem GPS Empfänger auszulesen (falls die Wanderung mal wieder etwas länger ausfällt...).
Für die Speicherung steht ein SRAM der Größe 512k x 8 zur Verfügung. Allerdings benötigt man für die Adressierung von 512k bereits 19 Adressleitungen. Das sprengt die zur Verfügung stehende Pinanzahl des Atmels deutlich. Gefragt ist hier eine Lösung, die mit weniger Pins auskommt.
Weiteres Qualitätsmerkmal der Schaltung soll der Stromverbrauch sein. Da die Schaltung die Daten in einem SRAM speichert, muss die Schaltung natürlich permanent versorgt werden, beispielsweise aus einem Batteriepack. Hier soll darauf geachtet werden, dass die Praktikum uProzessor-Hardware-Schaltung so wenig Strom wie möglich verbraucht, wenn Sie eigentlich gerade nichts zu tun hat (Standby Modus).
Abfrage von Track/Way Points aus dem GPS-Empfänger
Die folgenden Paketbezeichnungen werden in dem Dokument: "Garmin GPS Interface Specifikation" erläutert.
Sender | Paketbezeichnung | Packet-ID | Kommentar |
---|---|---|---|
PC | Pid_Product_Rqst | 254 | |
GPS | Pid_Ack_Byte | 6 | |
Pid_Product_Data | 255 | ||
PC | Pid_Ack_Byte | 6 | |
GPS | Pid_Protocol_Array | 253 | |
PC | Pid_Ack_Byte | 6 | |
-- | -- |
Bis hier identisch für Way- und Track-Points |
|
PC | Pid_Command_Data | 10 | Hier: Cmnd_Transfer_Trk für Abfrage der Track-Points, oder Cmnd_Transfer_Wpt für Abfrage der Way-Points |
GPS | Pid_Ack_Byte Pid_Records |
6 27 |
|
PC | Pid_Ack_Byte | 6 | |
GPS | Pid_Trk_Hdr | 99 | !!! Achtung: Nur bei Abfrage von TrackPoints !!! |
PC | Pid_Ack_Byte | 6 | !!! Achtung: Nur bei Abfrage von TrackPoints !!! |
GPS | Pid_Trk_Data oder Pid_Wpt_Data |
34 35 |
Schleife von Data und Ack, bis alle Daten gesendet wurden |
PC | Pid_Ack_Byte | 6 | dito |
GPS | Pid_Xfer_Cmplt | 12 | Endepaket |
PC | Pid_Ack_Byte | 6 |
Hinweis: Die Pid_Ack_Byte bestätigen immer, dass zuletzt empfange Paket. Sollte einmal ein Fehler auftreten, werden sie durch ein Pid_Nak_Byte Paket ersetzt.
Für den Programmablauf des GPS Daten Loggers werden folgende Hard- und Softwarekomponenten vorausgesetzt:
Programmstart:
Nach Aufbau der Schaltung und Anlegen der Betriebsspannung von 5.0V ist die Schaltung betriebsbereit. Die Statusanzeige signalisiert diesen Zustand durch „00“. Das Programm startet im GPS-Modus und ist bereit Daten an den PC zu übertragen (allerdings sind zu Beginn natürlich keine Way- oder Trackpoints gespeichert).
PC-Betrieb:
Durch Betätigen des Modus-Tasters kann die Schaltung in den PC-Betrieb wechseln. Es wird sofort eine Anfrage nach Way- dann nach Track-Points über die serielle Schnittstelle zum GPS-Handgerät gesendet. Dabei wird als erstes ein Handshake mit Protokollprüfung durchgeführt, was auf der Statusanzeige als „11“ zu erkennen ist. Anschließend werden zunächst alle im Handgerät vorhandenen Way-Points in das SRAM der Schaltung übertragen (Statusanzeige: „12“). Danach folgen die Track-Points (Statusanzeige: „13“). Ein erfolgreicher PC-Kommunikationsablauf schaltet die Statusanzeige auf „14“. Die Schaltung befindet sich wieder im Ausgangszustand (GPS-Modus).
GPS-Betrieb:
Ist die Schaltung z.B. nach dem Einschalten im GPS-Modus (Statusanzeige: „00“), kann ein angeschlossener PC die in der Schaltung gespeicherten Daten auslesen. Dazu muss vom PC aus eine Anfrage zur Schaltung losgeschickt werden, woraufhin ein Handshake mit Protokollprüfung durchgeführt wird (Statusanzeige: „01“). Ist der Verbindungsaufbau erfolgreich kann der PC entweder eine Anfrage nach Way- oder nach Track-Points stellen. Die Statusanzeige signalisiert die aktuelle Übertragung von Way-Points („02“) oder Track-Points („03“). Nach erfolgreicher Übermittlung der Daten befindet sich die Schaltung wieder im Ausgangszustand (GPS-Modus) und zeigt über die Statusanzeige den Abschluss an (Statusanzeige: „04“).
Fehlerfälle (Timeout, Speicher voll):
Tritt während einer Übertragung (egal ob im GPS- oder PC-Modus) ein Fehler auf (z.B. durch Kabelfehler), der nicht automatisch korrigiert werden kann, wird im GPS Daten Logger ein Timeout ausgelöst (Statusanzeige: „AA“). Die Schaltung wird dabei automatisch wieder in den Ausgangszustand zurückgesetzt (GPS-Modus). Es kann eine erneute Points-Anfrage vom PC erfolgen oder mittels Tastendruck ein angeschlossenes GPS-Handgerät ausgelesen werden.
Wird während einer Daten-Übertragung zum GPS Daten Logger festgestellt, dass der vorhandene Speicherplatz im SRAM nicht ausreicht, wird ein Fehler ausgelöst und der Status „88“ angezeigt. Die Übertragung wird abgebrochen und die gesamte Session wird nicht gesichert! Die Schaltung befindet sich anschließend wieder im GPS-Modus.
Standby-Modus:
Nach einem abgeschlossenen Übertragungsvorgang (im Ausgangszustand, GPS-Mode) empfiehlt es sich, die Schaltung in den Standby-Modus zu versetzen, indem der Standby-Schalter betätigt wird. In diesem Modus werden alle nicht benötigten Bausteine von der Stromversorgung getrennt. Lediglich der Speicherbaustein bleibt angeschlossen, damit die gespeicherten Daten nicht verloren gehen. Der Stromverbrauch sinkt jedoch auf ein Minimum ab und die Batterie wird nur minimal belastet. Soll eine erneute Übertragung oder ein Auslesevorgang gestartet werden, muss die Schaltung durch zurückstellen des Standby-Schalters wieder reaktiviert werden. Die Statusanzeige leuchtete wieder auf und bestätigt mit „23“ das „Aufwachen“ des GPS Daten Loggers, der sich wieder im Ausgangszustand (GPS-Modus) befindet.
Der GPS Daten Logger gibt (wie im vorigen Kapitel beschrieben) aktuelle Statusinformationen an den Benutzer aus. Folgende Tabelle zeigt eine Übersicht:
Beschreibung: |
Modus (GPS-Gerät / PC): |
Anzeige: |
Eingeschaltet |
GPS |
00 |
GPS Handshake |
GPS |
01 |
GPS Waypoints |
GPS |
02 |
GPS Trackpoints |
GPS |
03 |
GPS Übertragung fertig |
GPS |
04 |
PC Handshake |
PC |
11 |
PC Waypoints |
PC |
12 |
PC Trackpoints |
PC |
13 |
PC Übertragung fertig |
PC → GPS |
14 |
Timeout |
GPS |
AA |
Speicher voll |
GPS |
88 |
Eingeschaltet nach Standby |
GPS |
23 |
Download Schaltplan (PDF-Format)
Die untenstehende Tabelle zeigt alle in der Schaltung verwendeten Elemente:
Halbleiter:
1 x Atmel 89C4051
1 x MAX 232N
1 x HY628400A SRAM
4 x 74LS273
1 x 74HC04
1 x 74LS08
2 x 74LS47
2 x 7-Segment (gem. Anode)
Widerstände:
2 x 100 kΩ
14 x 330 Ω
Kondensatoren:
2 x 33pF
5 x 2,2µF
6 x 100nF
Sonstiges:
1 x Quarz, 22,1184 MHz
1 x Drucktaster
1 x Schalter
1 x Duo-Schalter
1 x RS-232-Verbindungsstecker
Der Atmel-Mikroprozessor unterstützt sowohl timergesteuerte Interrupts, die z.B. für die Nutzung der seriellen Schnittstelle genutzt werden können, als auch externe Interrupts, die durch Flanken oder Pegelwechsel an den entsprechenden Pins ausgelöst werden.
Die im Atmel-Prozessor integrierte serielle Schnittstelle kann in vier verschiedenen Betriebsarten arbeiten, die über die Flags SM0 und SM1 bestimmt werden können. Unsere Schaltung benutzt Betriebsart 1 (SM0=false, SM1=true), bei der die serielle Schnittstelle im Asynchron-Betrieb mit 1 Startbit, 8 Datenbits und 1 Stoppbit arbeitet. Bei dieser asynchronen Datenübertragung wird keine eigene Taktleitung benötigt, Sender und Empfänger arbeiten weitgehend unabhängig voneinander. Um im Betriebsmodus 1 eine exakte Übertragungsrate von 9600 Baud zu erreichen, verwendet die Schaltung den internen 8-Bit Timer (TH0/TH1) des Atmel-Prozessors (interner Takt) mit Auto-Reload (M1=true, M0=false).
Die Baudrate lässt sich nach folgender Formel berechnen:
(SMOD=1, Zählerüberlauf geteilt durch 16)
Durch den eingesetzten Quarz mit f=22,1184 MHz ergeben sich daraus folgende Werte:
TH0 =244, TH1 =100.
Für die Hardwareanschlüsse der seriellen Schnittstelle stellt der Atmel die beiden Pins P3.0 (RXD) für das Empfangen und P3.1 (TXD) für das Senden zur Verfügung.
Die Wandlung von den TTL-kompatiblen Pegeln des Atmels auf Pegel der seriellen Datenübertragung werden extern vom Treiberbaustein (MAX232N) vorgenommen (siehe unteren Abschnitt).
Dieser externe Baustein ist mit den RXD und TXD Pins des Atmels verbunden.
Der Atmel bietet über die Pins P3.2 (INT0) und P3.3 (INT1) zwei nach außen geführte Eingänge für externe Interrupts. Diese Eingänge sind Low-aktiv und können sowohl pegel- als auch flankengesteuert als Interrupt-Quellen arbeiten. Der Pegel wird dabei nach Auslösen in ein internes Latch(IEx) übernommen.
Unsere Schaltung verwendet einen Taster zum Wechsel vom „GPS-Modus“ in den „PC-Modus“ (um Daten zu empfangen). Dieser Taster ist mit dem INT0-Eingangspin des Atmels und der Masseleitung (logisch: Low) verbunden. Bei Tastendruck wird der Eingang auf Low „gezogen“ und ein Interrupt durch die Flanke (IT0=true: Interrupt arbeitet flankengesteuert) des Pegelwechsels ausgelöst.
Für das Speichern der Way- und Trackpoints wird der HY628400A CMOS SRAM Baustein eingesetzt, der 512 Kbyte Speicherplatz zur Verfügung stellt. Der Chip verfügt über 19 Adresseingänge, an denen die gewünschte Speicherplatz-Adresse angelegt werden muss (219 entspricht 512K). Außerdem besitzt er über 8 Pins für ein Datenbyte, das entweder aus dem Speicher gelesen oder hinein geschrieben wird. Daneben gibt es noch drei Steuerbits, die das Verhalten des SRAM-Bausteins kontrollieren (Standby, Aktiv, Lesen, Schreiben). Die wichtigste Funktion für das Ein- und Ausschalten (Standby) des Speichers wird über den Pin /CS gesteuert, der in unserer Schaltung direkt mit dem Atmel-Pin P3.5 verbunden ist, so dass der Speicher über einfaches Setzen eines Pegels an diesem Ausgang sehr schnell aktiviert und deaktiviert werden kann. Darüber hinaus bestimmt ein weiterer Pin am Atmel (P3.7), ob vom Speicher gelesen (P3.7=true) oder in den Speicher geschrieben (P3.7=false) werden soll. Zu diesem Zweck ist der Pin direkt mit dem /WE (schreiben) und invertiert mit /OE (lesen) verschaltet. Ein Schreibevorgang in das SRAM besteht also immer aus folgenden Schritten:
Das SRAM kann insgesamt 2 hoch 19 Bits (=512K) adressieren und abspeichern. Um diesen gesamten Bereich mit dem 8 Bit Ausgang des Atmel-Prozessors abzudecken sind dazu nacheinander drei Takte notwendig, die zunächst jeweils einen Teil der gesamten Adresse (Low, Middle, High) in je ein Register übertragen (Takt 1/2 übertragen je 8 Bit, Takt 3 überträgt 3 Bit). Dazu wird das entsprechende Adressbyte am Port1 des Atmels ausgegeben und die Taktleitung des Zielregisters eingeschaltet, so dass das Byte im Register übernommen und gespeichert wird. Alle drei Registerbausteine sind direkt mit dem Datenausgang des Atmels verbunden und können so das Byte empfangen. Es gibt einen gemeinsamen Adress- und Datenbus. Ist die Adresse vollständig in den drei FlipFlops abgelegt, kann das SRAM die komplette Adresse aus den FlipFlops der Registerbausteine beziehen, da diese auch direkt mit dem SRAM-Chip verbunden sind. Dazu wird der Chip-Select Eingang des SRAM-Bausteins auf Low gesetzt, was zur Folge hat, dass dieser den Standby-Modus verlässt und über die Bytes der drei Register die Adresse bestimmt und den Datenzugriff ermöglicht.
Die einzelnen Registerbausteine mit den FlipFlops werden jeweils einzeln über eine Taktleitung aktiviert bzw. deaktiviert. Da jeweils nur ein Register zur Zeit zum Lesen aktiviert werden muss, gibt es vier Zustände für das Setzen der drei FlipFlops. Diese vier Zustände können mit einer simplen Logikschaltung abgebildet werden:
Zustand: |
Binäre Codierung: P3.3 und P3.4 am Atmel |
Logik für die Taktleitungen der Registerbausteine: |
Zustand 1: |
0 0 |
Alle Register aus (aktuelle Adresse in den drei Registern bleibt unverändert): |
Zustand 2: |
0 1 |
Nur das Register für Low-Anteil an: |
Zustand 3: |
1 0 |
Nur das Register für Mid-Anteil an: |
Zustand 4: |
1 1 |
Nur das Register für High-Anteil an: |
Die benötigten Zustände können mit Hilfe von zwei Invertern und drei Und-Verknüpfungen gebildet werden:
Im folgenden Beispiel soll ein Byte (8 Bit) an die Speicherzelle mit der Adresse 2342 geschrieben werden. Die Adresse 2342 (dezimal) wird intern wie unten beschrieben binär abgebildet:
High Mid Low
00000000 | 00001001 | 00100110 (binary)
Die einzelnen Anteile sind:
0 | 9 | 38 (dezimal)
Da die Schaltung einen gemeinsamen Adress- und Datenbus von 8-Bit Breite verwendet, sind dazu vier Schritte notwendig:
Die Kommunikation mit der seriellen Schnittstelle wird direkt durch den Atmel-Prozessor unterstützt und gesteuert. Da auf physikalischer Ebene jedoch mit unterschiedlichen Spannungspegeln auf TTL- (Atmel/Schaltung) und RS-232-Seite gearbeitet wird, ist eine Umsetzung durch einen Treiberbaustein notwendig. Diese Aufgabe übernimmt der MAX232N-Baustein. Er ist dabei zwischen den RXD/TXD Ports des Atmels und dem Anschluss der seriellen Schnittstelle geschaltet, wie folgende Grafik veranschaulicht:
Damit die Schaltung Informationen an den Benutzer ausgeben kann, ist eine Statusanzeige implementiert. Diese besteht aus zwei 7-Segmentbausteinen die jeweils an einem BCD-7seg Konverter (7447) angeschlossen sind. So kann jede der beiden Anzeigen eine Hexadezimalzahl (0-F) ausgeben. Die Konverter-Bausteine haben jeweils vier Eingabe-Pins, die indirekt aus dem Datenbus des Atmel-Prozessors gespeist werden. Der Datenbus ist jedoch nicht direkt angeschlossen, sondern über ein Register-Baustein mit 8 FlipFlops verschaltet. So kann der Datenbus des Atmels von der Anzeige entkoppelt werden und muss nur zum Aktualisieren der Anzeige die Verbindung herstellen, indem das Register über die Taktleitung aktiviert wird.
Die Konverter codieren jeweils 4 Bits aus dem Register für eine 7-Segment-Anzeige um und geben den neuen Zustand an den Ausgängen aus, so dass der gewünschte Hex-Wert auf dem Display erscheint.
Ein wichtiger Gesichtspunkt beim Entwurf der Schaltung ist die Stromaufnahme. Da die Schaltung nicht über das Netz sondern durch Batterien gespeist werden soll, ist ein geringer Stromverbrauch eine grundlegende Bedingung, um längere „Sessions“ des Anwenders ohne Datenverlust zu ermöglichen. Ein möglicher Ansatz wäre, nach erfolgreicher Datenübertragung den Atmel- und SRAM-Baustein in den unterstützen Standby-Modus zu setzen und die 7-Segment-Anzeige auszuschalten, was den Stromverbrauch bereits deutlich verringern würde. Jeder TTL-Baustein der Logik würde jedoch noch ca. 10 mA Strom aufnehmen und auch der Atmel-Prozessor fordert seinen Anteil.
Unser Entwurf sieht deshalb vor, dass der Benutzer nach erfolgreicher Übertragung über einen zusätzlichen Schalter die Möglichkeit bekommt, nahezu die gesamte Hardware vom Stromkreis zu trennen. Lediglich der wichtige, datenerhaltende SRAM-Speicher und ein zugehöriger Inverter-Baustein werden am Leben erhalten und nicht von der Batterie entkoppelt. Dadurch sinkt die Stromaufnahme der Schaltung auf ein Minimum. Die folgende Tabelle verdeutlicht den Gewinn:
Modus: |
Stromaufnahme: |
Gesamte Schaltung eingeschaltet (inkl. 7-Seg-Anzeige) |
210 mA |
Gesamte Schaltung eingeschaltet (ohne 7-Seg-Anzeige) |
110 mA |
Standby (nur SRAM und Inverter aktiv) |
4,5 µA !!! |
Die Abbildung stellt die Realisierung des Standby-Modus mit Hilfe eines zusätzlichen Duo-Schalters dar.
Durch Umlegen des Standby-Schalters wird der Chip-Select-Eingang des SRAM-Bausteins auf High-Pegel gezogen und der SRAM somit in Standby versetzt, wo er auf keine Daten-Signale mehr reagiert. Gleichzeitig ist die Vcc-Versorgung der restlichen Bausteine getrennt (bis auf den Inverter). Wird der Schalter anschließend zurück in die gezeigte Ausgangslage gestellt, sind alle Elemente wieder mit Spannung versorgt und der Atmel-Prozessor kann erneut „hochfahren“.
Durch einen Checksummen-Test der ersten Bytes im SRAM erkennt der Chip das Erwachen aus dem Standby-Modus, woraufhin er alle internen Variablen aus dem SRAM bezieht und keine Neuinitialisierung durchführt (siehe Kap. 5.2.7).
Die Entwicklung des GPS Loggers wurde mit Hilfe folgender Konfiguration durchgeführt:
Hardware
Software
Der Softwareteil des Projektes „GPS-Datenlogger“ kann nach folgenden Gesichtpunkten gegliedert werden:
Diese Punkte werden in den folgenden Abschnitten ausführlich erläutert.
Wie in der Mikrocontrollerprogrammierung meist üblich, wird auch hier, nach der Initialisierungsphase, der Prozessor in eine Endlosschleife, die Mainloop, versetzt. Somit ist grundsätzlich ein dauerhafter Programmablauf gewährleistet.
Wird ein Interrupt ausgelöst, wird die jeweilige Interrupt-Service-Routine (ISR) abgearbeitet. Die jeweiligen ISR’s selber sind vom Prinzip her ziemlich einfach aufgebaut. In diesen wird quasi nur ein Flag gesetzt, dass der jeweilige Interrupt aufgetreten ist. Diese Flags werden bei jedem Durchlauf der Mainloop abgefragt. Ist ein Flag gesetzt, werden entsprechende Routinen aufgerufen, die dann für die eigentliche Funktionalität des Programms enthalten.
In diesem Programm sind folgende zwei Interrupts freigegeben: Der Interrupt für die serielle Schnittstelle und der externe Interrupt 0. Der externe Interrupt 0 wird nach einem Tastendruck ausgelöst und schaltet den PC-Modus des Gerätes ein. Der Interrupt der seriellen Schnittstelle wird dann ausgelöst, nachdem ein Byte über die diese empfangen oder gesendet worden ist.
Wie oben schon erwähnt, wird nach dem Senden oder Empfangen eines Bytes ein Interrupt ausgelöst. Um zu unterscheiden, ob ein Byte empfangen oder versendet worden ist, werden die Bits „RI“ (Recieve-Interrupt) und „TI“ (Transmit-Interrupt) verwendet: Wurde ein Byte empfangen, wird RI gesetzt, Wurde ein Byte versendet, wird TI gesetzt. Die jeweiligen Bits müssen jedoch manuell wieder zurückgesetzt werden, was am Ende der ISR geschieht.
Soll ein Byte versendet werden, so muss der zu versendende Bytewert der Variablen „sbuf“ zugewiesen werden. Nach der Zuweisung wird automatisch mit der Versendung begonnen. Sollen mehrere Bytes hintereinander gesendet werden, muss gewährleistet sein, dass das Byte komplett versendet worden ist, bevor „sbuf“ ein neuer Wert zugewiesen wird. Dafür wird direkt nach der Zuweisung auf „sbuf“ ein Sendeflag gesetzt. Vor der Zuweisung des nächsten Bytes wird so lange gewartet, bis das Flag wieder zurückgesetzt worden ist, was mit Beendigung der ISR geschieht.
Wurde ein Byte empfangen, steht nach dem Interrupt der empfangene Byte-Wert in der Variablen „sbuf“. Dieser Wert wird anschließend im Programm weiterverwendet. Nach dem Empfang eines Bytes wird immer das Flag gesetzt, das in der Mainloop abgefragt wird, um es im Programm weiterzuverarbeiten.
Um ein Statusbyte auf der 7-Segment Anzeige auszugeben, wird dieses Byte an Port 1 des Prozessors angelegt. Anschließend wird das Statusclock-Bit gesetzt, was bewirkt, dass das Byte in das Register des Statusbytes übernommen wird. Anschließend wird das Bit wieder zurückgesetzt.
Die Daten, die abgespeichert werden müssen, bestehen aus den Waypoints und Trackpoints der GPS-Informationen. Die Speicherplatz des SRAMS wird so vergeben, dass am Anfang des Speichers die Informationen für die Wakeup-Funktion abgelegt werden (siehe dazu auch 5.2.7). Dahinter folgen dann die Bytes der Waypoints.
Die Trackpoints werden ab dem Ende aufsteigend gespeichert. Das Nebenstehende Bild veranschaulicht die Speicherbelegung weitestgehend.
Für jedes einzelne Paket werden nur die PacketID, die Anzahl der Datenbytes und die Datenbytes selber abgespeichert. Daher, dass die Start- und Endebytes eines Paketes nicht mit abgespeichert werden, ist quasi eine kleine Datenkompression zustandegekommen. Unten sei nocheinmal der Aufbau eines Paketes im SRAM-Speicher bildlich dargestellt.
Beim Datenempfang wird, wie oben erwähnt, nach jedem Byte ein Interrupt ausgelöst, was zur Folge hat, dass die Routinen aufgerufen werden, die das Byte verarbeiten können. Beim nächsten Byte werden die Routinen jedoch wieder von neuem aufgerufen. Eine kontinuierliche Datenverarbeitung beim Empfang über mehrere Bytes ist somit nicht möglich. Daher bietet sich hier der Einsatz von Statemachines an. Nach jedem Empfang eines Bytes wird also eine Rountine aufgerufen, die eine Statemachine repräsentiert. Das Zustandsdiagramm ist im folgenden Bild zu sehen. Rechts die Erläuterung der jeweiligen States für den Empfang eines Paketes.
Wurde ein Track- oder Waypoint empfangen und die Checksumme war falsch, so wird der aktuelle Adresszeiger wieder auf das erste Byte nach dem letzten gespeicherten Pakets zurückgesetzt. Anschließend werden, je nach Modus die Routinen zur Verarbeitung und Auswertung der Daten auf Paketebene aufgerufen.
Das Protokoll sieht eine Besonderheit vor: Kommt in den ID-, Größen-, Daten- oder Checksumbytes ein Byte mit dem wert des DLE’s (16) vor, so wird dieses verdoppelt. Dies muss natürlich in der Statemachine berücksichtigt werden. In jedem der relevanten States wird geprüft, ob ein solches Byte empfangen worden ist. Ist dies der Fall, so muss das folgende Byte ja ebenfalls diesen Wert haben. Da dies auch nicht für die Berechnung der Checksumme relevant ist, kann dieses quasi „übersprungen“ werden.
Vor jedem Schreibzugriff auf das SRAM wird außerdem eine Speicherüberlaufsprüfung vorgenommen. Da ja die Waypoints ab dem Speicheranfang und die Trackpoints ab dem Speicherende abgelegt werden, kann der Adresszeiger für die Waypoints nicht größer sein als der für die Trackpoints. Also werden diese beiden Adressen vor dem Schreiben miteinander verglichen.
Ist der Speicher voll, so wird das aktuelle und alle bisherigen gespeicherten Pakete dieser Session verworfen.
Das Versenden eines Pakets ist nicht so sehr komplex wie das Empfangen. Die Pakete, die für die Handshake-Zustände benötigt werden, sind als Konstanten im Programmcode abgelegt. Diese werden einfach byteweise mithilfe einer Schleife versendet.
Soll ein Track- oder Waypoint versendet werden, so müssen die Bytes erst aus dem SRAM ausgelesen werden. Hierbei ist noch zu beachten, dass vor dem Lesezugriff auf das SRAM alle Bits von Port 1 auf „1“ gesetzt werden müssen. Ansonsten verhält sich der Vorgang ähnlich.
Immer wenn ein Paket komplett empfangen worden ist, oder das Paketsende-Flag gesetzt ist, wird eine der beiden Hauptroutinen zur Paketverarbeitung aufgerufen. Auch hier ist das Konzept der Statemachine ideal. Falls im Folgezustand ein Paket versendet werden soll, wird das Paketsende-Flag gesetzt, welches in der Mainloop abgefragt wird. Dies ist nötig, da ja, im Gegensatz zum Paketempfang, kein Interrupt ausgelöst wird, mit dem die Datenverarbeitung fortgesetzt werden kann.
Wenn ein Paket fehlerhaft ist (falsche Checksumme oder falsche PackedID) wird dieses Paket ignoriert
Je nach aktuellem Betriebsmodus ist eine der beiden folgenden Statemachines aktiv.
Für den PC-Modus ist folgende Statemachine implementiert:
Erläuterung der einzelnen States:
Für den PC-Modus ist folgende Statemachine implementiert:
Erläuterung der einzelnen States:
Um den Standbybetrieb zu realisieren sind folgende Dinge notwendig:
Die Adresszeiger auf das erste freie Byte nach den Waypoints (3 Bytes), der Adresszeiger auf das erste freie Byte nach den Trackpoints (3 Bytes), die Anzahl der Waypoints im Speicher (2 Bytes) und die Anzahl der Trackpoints im Speicher (2 Bytes) werden im reservierten Speicherbereich (Header) nach jedem Abgeschlossenen Datentransfer abgespeichert. Anschließend wird aus diesen 10 Bytes eine Checksumme errechnet, die zweimal hinter diesen 10 Bytes abgelegt wird. Der Header des SRAMS ist links dargestellt. Die Ckecksumme wird folgendermaßen berechnet: Alle Bytes werden Addiert (mit Byteüberlauf) und anschließend wird von dieser Summe das Zweierkomplement gebildet.
Bei jedem neuen Prozessorstart wird der Header ausgelesen und die Checksumme der 10 relevanten Datenbytes mit den beiden Checksummenbytes aus dem Speicher verglichen. Stimmen alle drei Bytes überein, werden die Adresszeiger und Paketzähler automatisch gesetzt.
Wenn der Speicher eingeschaltet wird, ist dessen Inhalt undefiniert. Dadurch, dass sie Checksumme zweimal abgespeichert wird ist die Wahrscheinlichkeit, dass trotz eines Kaltstarts alle drei zu vergleichenden Bytes übereinstimmen auf ein Minimum reduziert. Wenn nur ein Byte als Checksumme abgespeichert werden würde, läge die Wahrscheinlichkeit noch bei 1:255, was ein inakzeptabler Wert wäre. Bei zwei Bytes beträgt die Wahrscheinlichkeit jedoch schon bei 1:65535, was einen guten Wert darstellt.
Kommt es während des Datentransfers zu einem Kommunikationsfehler (z.B. Kabel verliert Kontakt), würde das Gerät im aktuellen Zustand bleiben und müsste durch einen kompletten Reset wieder in den ausgangszustand zurückversetzt werden.
Um dies zu vermeiden, ist in der Mainloop ein Zähler implementiert, der bei jedem Schleifendurchlauf, in dem kein Datentransfer stattfindet und die Statemachine des GPS-Modus’ oder des PC-Modus’ nicht in ihrem Ausgangszustand ist, um 1 dekrementiert wird. Bei jedem Datenverkehr wird dieser Zähler wieder auf seinen Anfangszustand zurückgesetzt. Erreicht der Zähler den Wert 0, wird eine Timeoutfehlermeldung als Status ausgegeben, die aktuelle Session verworfen und die Statemachines in ihren ausgangszustand zurückversetzt.
Die wichtigsten Konstanten werden im Folgenden kurz beschrieben.
Name der Konstanten | Kurze Beschreibung |
C_MemStart = 14; | Anzahl Bytes des Headers im SRAM |
C_DLE = 16; C_ETX = 3; |
Konstanten für Anfangs- und Endebytes eines Paketes |
C_Pid_Ack_Byte = 6; C_Pid_Nak_Byte = 21; C_Pid_Protocol_Array = 253; C_Pid_Product_Rqst = 254; C_Pid_Product_Data = 255; C_Pid_Command_Data = 10; C_Pid_Xfer_Cmplt = 12; C_Pid_Records = 27; C_Pid_Trk_Data = 34; C_Pid_Wpt_Data = 35; C_Pid_Trk_Hdr = 99; |
Konstanten für alle Packet IDs der im Programm vorkommenden Pakete |
C_Cmnd_Transfer_Wpt = 7; C_Cmnd_Transfer_Trk = 6; |
Konstanten für die relevanten Kommandodaten eines Records Paketes |
C_Product_Data : array[0..44] of byte = ( 016,255,039,141,000,240,000,101, 084,114,101,120,032,083,117,109, 109,105,116,032,083,111,102,116, 119,097,114,101,032,086,101,114, 115,105,111,110,032,050,046,052, 048,000,097,016,003); |
komplettes "Product_Data" Paket |
C_Protocol_Array : array[0..65] of byte = ( 016,253,060,080,000,000,076,001, 000,065,010,000,065,100,000,068, 108,000,065,201,000,068,202,000, 068,108,000,068,210,000,065,045, 001,068,054,001,068,045,001,065, 244,001,068,245,001,065,088,002, 068,088,002,065,188,002,068,188, 002,065,032,003,068,032,003,219, 016,003 ); |
komplettes "Protocol_Array" Paket |
s_ProductReq = 0; e_ACKproductReq = 1; e_ProductData = 2; e_Protocol = 3; s_Command = 4; e_ACKcommand = 5; e_Records = 6; e_WptData = 7; e_TrkData = 8; e_Cmplt = 9; NachCmplt = 10; |
Konstanten für die einzelnen Stati im PC-Mode Kommunikationsablauf |
e_ProductRequest = 0; s_ProductData = 1; e_ACKproductData = 2; s_Protokollarray = 3; e_ACKprotocolArray = 4; e_CommandData = 5; s_PidRecords = 6; e_ACKrecords = 7; x_setPointerBack = 8; s_Points = 9; e_ACKwptData = 10; e_ACKtrkData = 11; x_repeatComplt = 12; e_ACKCmplt = 13; i_Pointer = 14; |
Konstanten für die einzelnen Stati im GPS-Mode Kommunikationsablauf |
Auflistung und Beschreibung aller eigenen Typen, die im Programm verwendet werden:
Typdeklaration | Beschreibung |
TLinkStates = ( StartDLE, PacketID, PacketSize, EmpfangeDaten, Checksum, EndDLE, ETX ); |
Dieser Typ definiert alle States der unteren Paketebene. Er dient dem korrekten Empfangen und Auswerten der einzelnen Bytes der Pakete. |
TRichtung = ( Hoch, Runter, Nix ); | Variablen dieses Typs geben an, ob von der aktuellen Speicheradresse weiter hochgezählt (Hoch) oder weiter runtergezählt (Runter) wird. Alternativ bleibt die aktuelle Adresse unverändert, wenn „Nix“ angegeben wird. |
Bei der Programmierung des Atmel-Mikroprozessors mit dem Pascal System51 System stehen dem Programmierer 128 Byte Arbeitsspeicher zur Verfügung. Da sowohl Funktionsparameter als auch funktionslokale Variablen diesen Speicherbereich nutzen müssen, wurden viele Variablen global deklariert, um den Speicherplatz durch Mehrfachnutzung besser ausschöpfen zu können, auch wenn dies auf Kosten der Lesbarkeit des Quellcodes geht.
Auflistung und Beschreibung aller globalen Variablen, die im Programm verwendet werden:
Typdeklaration | Beschreibung |
port1 : byte at P1; isLesen : boolean at P3.7; isMemActive : boolean at P3.5; adr3 : boolean at P3.3; adr4 : boolean at P3.4; isStatus : boolean at P3.2; |
- Variable port1 als Bytewert an Port P1 deklarieren - Ausgang zum Setzen des SRAM-Zugriffsmodus: lesen = true, schreiben = false - Ausgang zum aktivieren des SRAMs: standby = false, Aktiv = true - Ausgänge zur Steuerung der Clock-Signale der Adress-Flipflops - Ausgang zur Steuerung des Clock-Signals des Status-Flopflops |
fl_readSerial : boolean; fl_int0 : boolean; fl_senden : boolean; fl_memfull : boolean; fl_wakeup : boolean; TIsendet : boolean; |
- Flag zur Überprüfung, ob ein Interrupt der Seriellen Schnittstelle aufgetreten ist - Flag zur Überprüfung, ob ein Interrupt am Externen Eingang 0 (Taster) aufgetreten ist - Flag zur Überprüfung, ob ein Paket gesendet werden soll - Flag zur Speicherüberlaufsprüfung - Dieses Flag wird gesetzt, wenn der Atmel aus dem Standby Modus "erwacht" - Zeigt an, ob gerade Daten über die Serielle Schnittstelle gesendet werden |
g_DLEflag : boolean; g_PacketID : byte; linkstate : TlinkStates; g_sizeofpacket : byte; checksumcounter : byte; dummy : byte; g_Richtung : TRichtung; g_ChecksumOkay : boolean; g_DataByte0 : byte; g_DataByte1 : byte; g_numBytesEmpfangen : byte; |
- Flag zur Überprüfung, ob ein DLE-Byte in den Bytes eines Paketes empfangen worden ist - speichert die ID des aktuell empfangenen Paketes - speichert den aktuellen Zustand beim Empfangen eines Paketes auf Byte-Ebene - speichert das Längenbyte des gerade empfangenen Pakets - aktualisiert die Checksumme nach jedem empfangenen Datenbyte - Verschiedenes - gibt an, ob und wo im SRAM das aktuell empfangene Paket abgelegt werden soll - speichert, ob die Checksumme des zuletzt empfangenen Pakets richtig war - speichert das erste Datenbyte das aktuell empfangenen Pakets - speichert das zweite Datenbyte das aktuell empfangenen Pakets - speichert die Anzahl der schon empfangenden Datenbytes eines Pakets |
g_TrkPtsPtrHigh : byte; g_TrkPtsPtrMid : byte; g_TrkPtsPtrLow : byte; g_WayPtsPtrHigh : byte; g_WayPtsPtrMid : byte; g_WayPtsPtrLow : byte; g_TmpPtsPtrHigh : byte; g_TmpPtsPtrMid : byte; g_TmpPtsPtrLow : byte; g_TmpStartPtrHigh : byte; g_TmpStartPtrMid : byte; g_TmpStartPtrLow : byte; g_TmpPaketPtrHigh : byte; g_TmpPaketPtrMid : byte; g_TmpPaketPtrLow : byte; |
- zeigt immer auf die Adresse, in der das aktuell zu empfangene Byte geschrieben bzw. aus der das aktuell zu sendende Byte gelesen werden soll - zeigt immer auf das erste freie Byte hinter den Waypoints der letzten Session - zeigt immer auf das erste freie Byte hinter (vor) den Trackpoints der letzten Session - zeigt immer auf das erste Byte nach dem Ende des zuletzt komplett empfangenen Pakets - zeigt immer auf den Anfang eines Pakets (auf Paketebene), um ggf. bei defekten Paketen wieder an die alte Speicheradresse zurückspringen zu können |
g_isPC : boolean; g_PcState : byte; g_GpsState : byte; g_Packetcounter : word; g_PcWillWayPts : boolean; g_numPakete : word; g_numPaketeTrk : word; g_numPaketeWpt : word; |
- bestimmt den aktuellen Arbeitsmodus: "Gerät ist PC" oder "Gerät ist GPS" - speichert den aktuellen Zustand beim Empfangen einer Session auf Paket-Ebene im PC-Modus - speichert den aktuellen Zustand beim Senden aller Daten auf Paket-Ebene im GPS-Modus - gibt an, wie viele Pakete noch empfangen bzw. noch gesendet werden müssen - gibt an, ob die aktuelle Session WayPts (=true) oder TrkPts (=false) behandelt - speichert, wie viele Pakete in akt. Session empfangen werden sollen (Pid_Records) - speichert, wieviele TrkPt-Pakete empfangen wurden und im SRAM liegen (für Pid_Records) - speichert, wieviele WayPt-Pakete empfangen wurden und im SRAM liegen (für Pid_Records) |
g_timer : word; g_timerhelp : byte; |
- dient zur Abfrage von Timeouts - dient zur Abfrage von Timeouts |
Die wichtigsten kritischen Programmabläufe wurden getestet und zusammengestellt:
Testfall |
Erwartetes Ergebnis |
Erzieltes Ergebnis |
Serielles Kabel wird während einer Übertragung durchtrennt. |
Die Schaltung sollte Timeout-Fehler auf der 7-Seg-Anzeige melden und die Übertragung abbrechen. |
Schaltung meldet Timeout-Fehler auf der 7-Seg-Anzeige und bricht Übertragung ab. |
Während einer Übertragung wurde ein Paket durch ein Nak-Paket erneut angefordert. |
Die Schaltung sollte das entsprechende vorige Paket erneut senden. |
Die Schaltung verschickt das vorige Paket erneut. |
Während einer Übertragung wird ein Paket mit ungültiger Packet-ID empfangen. |
Die Schaltung sollte das Paket ignorieren, kein ACK-Paket zurückschicken und auf ein gültiges Paket warten. |
Die Schaltung ignoriert das Paket, sendet kein ACK-Paket zurück, sondern wartet auf ein gültiges Paket. |
Während einer Übertragung wird ein Paket mit ungültiger Checksumme empfangen. |
Die Schaltung sollte den Fehler erkennen und ein Nak-Paket mit Referenz auf das fehlerhafte Paket zurückschicken. |
Die Schaltung sendet ein Nak-Paket mit Referenz auf das fehlerhafte Paket zurück. |
Während einer Übertragung wird ein gültiges Paket eines anderen States empfangen. |
Die Schaltung sollte das Paket ignorieren, kein ACK-Paket zurückschicken und auf ein gültiges Paket warten. |
Die Schaltung ignoriert das Paket, sendet kein ACK-Paket zurück, sondern wartet auf ein gültiges Paket. |
Inmitten einer Übertragung wird der PC/GPS-Modus-Taster gedrückt. |
Der Taster sollte während einer Übertragung deaktiviert sein und keinen Interrupt auslösen. |
Der Taster löst keinen Interrupt aus, sondern bleibt ohne Funktion. |
Bei der Übertragung von Waypoints werden nur drei Way-Points empfangen, obwohl in Pid_Records eine höhere Zahl stand. |
Die Schaltung sollte auf das fehlende Waypoint-Paket warten. Kann keins empfangen werden, muss der Timeout ausgelöst werden. |
Die Schaltung wartet auf das fehlende Waypoint-Paket. Nach ca. 2 Sekunden kommt ein Timeout. |
Im GPS-Modus werden Waypoints angefragt und unsere Schaltung ist noch leer. |
Die Schaltung sollte einen gültigen Durchlauf starten, mit PidRecords=0 und keinen folgenden Waypoints. |
Die Schaltung beantwortet die Anfrage und schickt ein Paket mit PidRecords=0 und keine folgenden Waypoints los. |
Download dieser Dokumentation im PDF-Format
Download des Schaltplans (PDF-Format)
Download Pascal-Quellcode des Programms für den Atmel-Prozessor
Gefällt dir das GPS-Logger Elektronik-Projekt? Schreibe doch einen Kommentar...
Diese Website benutzt Cookies. 🍪 Wenn Sie die Website weiter nutzen, stimmen Sie der Verwendung von Cookies zu. Mehr Infos