Ob es warm oder kalt ist, das ist Gefühlssache. Um Temperaturen jedoch konkret zu erfassen, braucht es ein vernünftiges Messinstrument: Das Thermometer. In diesem Artikel erkläre ich den Aufbau und die Funktion eines einfachen elektrischen Thermometers mit einem PT100 Temperatursensor.
Wer nicht so viel lesen und lieber gleich loslegen will, der findet im Abschnitt Technischen Daten einen Link zu den Projektunterlagen. Die Projektunterlagen enthalten Schaltplan, Boardlayout, Breadboardplan und so weiter.
Viel Spaß beim kreativ werden
Hans
Wie arbeitet der Temperatursensor PT100?
Der PT100 ist ein Platinwiderstand, der bei 0°C einen Widerstand von exakt 100Ω besitzt. Sein
Widerstand nimmt mit steigender Temperatur zu. Das Verhältnis zwischen
Widerstand und Temperatur ist dabei nahezu linear. Daher wird die Kennlinie des PT100 gern mit der folgenden Formel vereinfacht.
RT = R0 • ( 1 + α • T )
RT… Widerstand des PT100 in Abhängigkeit der Temperatur
R0… Widerstand des PT100 bei 0°C (R0 = 100Ω -> konstant)
Wie man deutlich in der Formel erkennen kann, ist T, die Temperatur, die einzige Komponente, die sich verändern kann. Dadurch erhält man eine lineare Kennlinie zwischen Temperatur und Widerstand des PT100. Die nachfolgende Grafik zeigt die reale Kennlinie des PT100 gestrichelt und die angenäherte Kennlinie aus der Formel als Vollstrich.
Man kann gut erkennen, dass die Kennlinie im Bereich von -100°C - 200°C fast linear ist, aber spätestens bei 600°C zeigt sich eine deutliche Krümmung. Da wir uns mit unserer Entwicklung in einem Bereich bewegen, in dem die Kennlinie sehr linear verläuft, vernachlässigen wir die Krümmung und arbeiten mit dem idealisierten linearen Modell.
Aufbau des Thermometers
Das Blockschaltbild in Abbildung 4 zeigt schematisch, wie die Temperatur auf der Platine ermittelt und aufbereitet wird. Die Skizze beginnt beim PT100. Mit seiner als linear angenommenen Kennlinie kann er die aktuelle Temperatur detektieren und in eine Widerstandsänderung übertragen. Da durch den PT100 ein Konstantstrom von 1mA fließt, wird seine Widerstandsänderung in eine Spannungsänderung umgesetzt. Allerdings liefert der PT100 mit 100Ω bei 0°C auch einen erheblichen Spannungsoffset, dieser muss später entfernt werden.
An den Klemmen des PT100 sitzt ein Instrumentenverstärker. Dieser stabilisiert die gemessene Spannung und verstärkt sie um den Faktor 10.
Zuletzt wird durch einen Differenzverstärker der bereits erwähnte Spannungsoffset entfernt und das Nutzsignal um den Faktor 8.3 verstärkt. Dadurch ergibt sich eine Kennlinie, die bei einer Temperaturänderung von 150 K einen Spannungsbereich von 0…5V durchläuft.
Schaltplan
Der Schaltplan lässt sich mit dem vorherigen Kapitel Aufbau des Thermometers sehr schnell und einfach verstehen. Im oberen Bereich des Schaltplans befinden sich die drei einzelnen Stufen Konstantstromquelle mit PT100, Instrumentenverstärker und Differenzverstärker. Im unteren Bereich werden zwei Festspannungen eingestellt, welche in der Schaltung als Referenzspannungen benötigt werden.
Symmetrische Spannungsversorgung
Im Schaltplan unten links befindet sich eine Schaltung, welche aus der unsymmetrischen 5V Betriebsspannung eine symmetrische ±2.5V Betriebsspannung erzeugt. Dazu wird mit einem einfachen Spannungsteiler ein künstlicher symmetrischer Nullpunkt bei halber Betriebsspannung definiert. Der dem Spannungsteiler nachgeschaltete OPV ist als Impedanzwandler geschaltet. Seine Aufgabe ist es, den neuen Nullpunkt stabil zuhalten. Die symmetrische Spannungsversorgung ist nötig, um den Instrumentenverstärker zu betreiben und um auf einige OPV Grundschaltungen zurückgreifen zu können. Da symmetrische Spannung und unsymmetrische Spannung direkt übereinander liegen, ist es wichtig die Bezeichnungen beider Netze nicht miteinander zu verwechseln. Die nachfolgende Tabelle zeigt, wie die erzeugte symmetrische Spannung die unsymmetrische Spannung überlagert.
Unsymmetrische Spannung
Symmetrisch Spannung
5V
+2.5V
2.5V
0V
0V
-2.5V
Offsetkorrekturspannung
Die Offsetkorrekturspannung wird auf die gleiche Weise erzeugt, wie der Nullpunkt für die symmetrische Spannungsversorgung. Sie wird benötigt, um den Offset, der durch den Grundwiderstand des PT100 entsteht, zu eliminieren. Mit Potentiometer R12 kann die Offsetkorrekturspannung und damit der Mittelpunkt des Messbereichs eingestellt werden. Wird UREF auf 3.3V eingestellt ergibt sich ein Messbereich von -50°C bis 100°C.
Anschluss des PT100
Der PT100 wird in 4-Leitertechnik angeschlossen, was dafür sorgt, dass man sehr lange Kabel (>10m) verwenden kann, ohne dass das Messergebnis zusätzlich verfälscht wird.
Konstantstromquelle
Um den PT100 zu betreiben wird er von einem Konstantstrom von 1 mA durchflossen. Um diesen Konstantstrom zu erzeugen, wird eine OPV als Konstantstromquelle geschaltet. Die Parallelschaltung der Widerstände R1 und R11 erzeugt einen Gesamtwiderstand von 2.5kΩ. Da sich der OPV an seinem positiven Eingang auf die symmetrische Masse bezieht, fallen an dem Gesamtwiderstand R1||R11 2.5V ab. So wird ein Konstantstrom von 1mA erzeugt. Dieser Strom fließt kontinuierlich durch den PT100.
Instrumentenverstärker
Der Konstantstrom erzeugt am PT100 eine temperaturabhängige Spannung. Diese Spannung wird vom Instrumentenverstärker abgegriffen, stabilisiert und um den Faktor 10 verstärkt. Da der Eingangswiderstand des Instrumentenverstärkers extrem hoch ist, belastet er das Sensorsignal des PT100 nicht. Im Moment liegt noch der volle Offset durch den PT100 (100Ω bei 0°C) auf dem Sensorsignal. Dieser muss in der nächsten Stufe entfernt werden, um das Signal anschließend auf volle Betriebsspannung anheben zu können.
Offsetkorrektur
In der letzten Stufe wird der Offset des PT100 korrigiert. Dazu wird ein OPV als Differenzverstärker geschaltet. In dieser Schaltung wird die Offsetkorrekturspannung UREF vom aufbereiteten Sensorsignal abgezogen. Anschließend wird das Ergebnis mit dem Faktor 8.3 auf Betriebsspannung verstärkt.
Breadbord
Hier sieht man die Schaltung auf einem Steckbrett aufgebaut. Es ist zwar einiges an Kabeln zu verlegen, aber der Aufwand hält sich noch in einem erträglichen Rahmen. Auch die Übersicht über die Schaltung bleibt halbwegs erhalten.
Boardlayout
Wer es etwas schicker und professioneller mag, dem kann ich hier ein schönes kleines SMD Layout anbieten. Ich selbst habe die Platine so im Einsatz und bin sehr zufrieden damit.
Im Zuge einer Studienarbeit habe ich mit meinem Freund Christian ein 4-Gewinnt entwickelt. Es läuft auf Raspberry Pi mit einem selbst gebauten Hardwaremodul auf Lochrasterplatine.
Der Raspberry Pi wird mit Raspbian betrieben und der Quellcode ist in Python geschrieben. Auf dem Hardwaremodul sind eine 7x6 LED-Matrix und 3 Taster zum steuern des Spiels aufgebaut. In den folgenden Kapiteln erkläre ich das Projekt etwas genauer.
Falls ihr jedoch einfach nur schnell loslegen wollt: Schaltplan, Quellcode und die offizielle Doku findet ihr in den Projektdaten bei den folgenden Hostern:
Die LED-Matrix besteht aus 7x6 Duo-LEDs mit gemeinsamer Kathode. Sie haben die Farben Rot und Grün. Die Matrix wird durch zwei 8-Bit High-Side-Treiber an den 14 Anoden und einem 8-Bit Low-Side-Treiber an den 6 Kathoden mit Strom versorgt. Die Ansteuerung der Matrix übernehmen drei in Serie geschaltete 8-Bit Schieberegister.
Die folgende Abbildung zeigt den Aufbau und die Ansteuerung der LED-Matrix. Dabei beginnt der Datenvektor stets an der oberen rechten Seite der Matrix und zieht sich durch die Spalten von rechts nach links und anschließend durch die Zeilen von oben nach unten bis zum unteren linken Ende der Matrix.
Um für eine richtige Anzeige zu sorgen, muss der Datenvektor korrekt zusammengesetzt sein. Die Vektorpositionen 0, 1, 16, 17 sind nicht beschaltet. Welche Werte hier eingetragen werden ist grundsätzlich irrelevant. Bei den Positionen 2–15 handelt es sich um die Matrix-Spalten. Dabei sprechen die geraden Zahlen die grüne Anode der jeweiligen LED an, während die ungeraden Zahlen die rote Anode der jeweiligen LED ansprechen. Die Positionen 18–23 entsprechen den Zeilen, hier werden die Kathoden der jeweiligen LEDs angesprochen.
Um eine LED in der Matrix anzusteuern, wird sowohl in den Spalten, als auch in den Zeilen mit High-Pegel adressiert. Das bedeutet, wenn man beispielsweise die LED in der 5. Spalte und der 3. Reihe mit grün ansprechen möchte, müssen an den Datenpositionen 6 und 20 High-Pegel anliegen. Alle anderen Datenpositionen müssten Low-Pegel halten. In diesem Fall würde nur die ausgewählte LED grün leuchten und der Rest der Matrix wäre dunkel. (Datenvektor: ← 00010000 00000000 01000000 ←)
Die Schieberegister beziehen ihre Daten hauptsächlich von der Datenleitung SER und den zwei Taktleitungen SCK und RCK. Des Weiteren existieren die VektorlöschenLeitung SCL und die Freigabeleitung G. Diese 5 Datenleitungen sind mit dem Raspberry Pi verbunden und für die Steuerung der LED-Matrix verantwortlich. Weitere Informationen zu den verschiedenen Steuerleitungen sind in Tabelle 1 zusammengefasst.
1.3 Taster
Die Taster sind unterhalb der LED-Matrix angeordnet. Mit ihnen wird das Spiel gesteuert. Dabei gibt es zwei Taster, um den Coin nach rechts(Right) und links(Left) zu bewegen und einen Taster um den Coin fallen zu lassen(Enter). Der Enter-Taster hat eine Zusatzfunktion. Hält man ihn für längere Zeit gedrückt, so wird ein Reset ausgeführt und das Spiel neu gestartet.
Jeder Taster ist durch eine kleine Schaltung Hardware-Entprellt und führt eine eigene Datenleitung zum Raspberry Pi. Allerdings ist in der Software noch ein Algorithmus zum Entprellen der Taster vorhanden. Dies ist vorangegangen Entwicklungsphasen geschuldet und völlig unkritisch. In einer späteren Entwicklungsstufe sollte dieser Programmabschnitt angepasst und optimiert werden.
1.4 GPIO-Schnittstelle
An der GPIO-Schnittstelle werden alle Ein- und Ausgänge sowie die Betriebsspannung der Platine in einem Sockel zusammengefasst. An dieser Stelle muss der Raspberry Pi angeschlossen werden. Tabelle 1 gibt eine detaillierte Übersicht über alle Pins und zeigt, wie das Board mit dem Raspberry Pi zu verbinden ist.
1.5 Schaltplan
1.6 Board
2 Software
Die Software zur Ansteuerung des 4-Gewinnt-Spiels wurde für Raspberry Pi auf dem Betriebssystem Raspian geschrieben. Die dazu verwendete Programmiersprache ist Python. Da Python eine Interpretersprache ist, besteht keine Notwendigkeit, den Quellcode zu kompilieren, er wird direkt im Betriebssystem interpretiert.
Die gesamte entwickelte Software des 4-Gewinnt Spiels befindet sich in der Python-Datei VierGewinnt v1.4.py. Nachfolgend werden die einzelnen Komponenten dieser Software und der Ablauf des Hauptprogramms näher beschrieben.
2.1 Softwaremodule
Die Software ist in 3 Abschnitte aufgeteilt. Dabei handelt es sich um die Definition der Variablen, die Definition der Funktionen und den Ablauf des Hauptprogramms. Nachfolgend werden die Definition der Variablen und die Definition der Funktionen näher betrachtet und erläutert.
2.1.1 Definition der Variablen
Die Software beginnt mit der Definition der GPIO-Pins. Dazu wird für jeden Pin eine globale Variable definiert. Die Pin-Variablen enthalten dabei eine Zahl entsprechend des zugewiesenen Pins. Beim Aufrufen von Funktionen mit diesen Variablen wird die enthaltene Zahl verwendet, um auf den entsprechenden GPIO-Pin zu verlinken. Eine genaue Übersicht zu den GPIO-Pin-Variablen liefert Tabelle 2.
Im zweiten Programmschritt werden einige Programm-Variablen definiert. Sie werden vielfältig in den einzelnen Funktionen und im Hauptprogramm verwendet. Tabelle 3 zeigt die Programm-Variablen übersichtlich dargestellt und erklärt.
2.1.2 Definiton der Funktionen
Um ein Programm schlank und übersichtlich zu programmieren, wurden wiederkehrende Programmbestandteile in Funktionen integriert. Nachfolgend werden alle im Programm definierten Funktionen aufgelistet und beschrieben. In Abbildung 6 werden unter den Funktionen bestehende Abhängigkeiten veranschaulicht.
Button(button nr) Eingabevariable:
button nr . . . kann eine der 3 Button-Variablen enthalten (2/3/4)Beschreibung:
Gibt an, ob ein Taster gedrückt wurde. Welcher Taster geprüft werden soll, wird
durch die Eingabevariable ausgewählt. Rückgabewert:
0. . . Taster ist nicht gedrückt, 1. . . Taster ist gedrückt
global button state. . . gibt an, ob Taster gedrückt wurde
global button old . . . speichert, welcher Taster gedrückt wurde. Erst wenn dieser los-
gelassen wird, kann er erneut betätigt werden.
Output Enable() Eingabevariable:
— Beschreibung:
Aktiviert die Tri-State-Ausgänge der Schieberegister und erlaubt das Durchschalten
der Speicherregister auf die Ausgänge. Damit können die Daten der Speicherregister
auf der LED-Matrix angezeigt werden. Siehe hierzu auch Anhang D Datenblatt
Schieberegister 74HC595 (Auszug). Rückgabewert:
—
Output Disable() Eingabevariable:
— Beschreibung: Schaltet die Tri-State-Ausgänge der Schieberegister hochohmig. Dadurch können die Speicherregister keinen Wert auf die Ausgänge schreiben.
D Datenblatt Schieberegister 74HC595 (Auszug) Rückgabewert:
—
Clear Shift Register() Eingabevariable:
— Beschreibung:
Löscht den gesamten in den Schieberegistern gespeicherten Datenvektor. Der neue
Vektor enthält ausschließlich Nullen. Rückgabewert:
—
Set Shift Register(data) Eingabevariablen:
data. . . zu schreibender LED-Matrix Datenvektor Beschreibung:
Schiebt einen Datenvektor beliebiger Länge in die Schieberegister. Rückgabewert:
—
Set Storage Register() Eingabevariable:
— Beschreibung:
Übergibt den aktuellen Datenvektor der Schieberegister an die Speicherregister.
Dort wird der aktuelle Datenvektor auf die LED-Matrix ausgegeben. Rückgabewert:
—
Sample(sample nr) Eingabevariable:
sample nr . . . wählbarer Standarddatensatz (0. . . 7) Beschreibung:
Gibt einen Standarddatensatz für die LED-Matrix entsprechend der eingegebenen
Datensatznummer zurück. (Startbildschirm, ’HI’, ’DU’, ’P1’, ’P2’, Unentschieden-
Bildschirm, ’Player 2 Win’, ’4 Gewinnt’) Rückgabewert:
Datenvektor für LED-Matrix (84 Bit / mehr bei Lauftext - Sample 6 + 7) Send Data(data) Eingabevariable:
data. . . Datenvektor für LED-Matrix Beschreibung:
Schreibt einen Datenvektor auf die LED-Matrix. Der Vektor enthält ein vollständiges
Bild. Rückgabewert:
— Position Check(level) Eingabevariable:
level . . . zum Prüfen des Bitzustands (0. . . Low, 1. . . High)
global pos. . . aktuelle Position im Matrix-Datenvektor
global player nr . . . zeigt an, welcher Spieler an der Reihe ist (Matrixnavigation) Beschreibung:
Prüft, ob die LED an der aktuellen Position des Matrix-Datenvektors ein- oder
ausgeschaltet ist. Es wird immer nur rot oder grün eingeschaltet, niemals beide LED-
Farben gemeinsam. Ist eine Farbe eingeschaltet, so gilt die LED als eingeschaltet. Rückgabewert:
0. . . Bit6 = level, 1. . . Bit=level
Win Check(r)Eingabevariablen:
r . . . Reihe der aktuellen Matrix-Position
global pos. . . aktuelle Position im Matrix-Datenvektor
global data. . . Matrix-Datenvektor Beschreibung:
Überprüft ausgehend von der übergebenen Position, ob das Spiel gewonnen wurde.
Es wird in alle Richtungen geprüft. (4 Coins in Reihe/Spalte/Diagonal) Rückgabewert:
0. . . Spiel nicht gewonnen, 1. . . Spiel gewonnen
global win row . . . Vektor mit 4 Daten, gibt die Position des Gewinns an
Win Screen() Eingabevariable:
— Beschreibung:
Zeigt den Gewinn eines Spielers an. Die Anzeige dauert 4s. Rückgabewert:
—
Draw Screen() Eingabevariable:
— Beschreibung:
Zeigt an, dass das Spiel unentschieden ausgegangen ist. Die Anzeige dauert 4s. Rückgabewert:
—
2.2 Programmablauf
An dieser Stelle wird der Ablauf des Hauptprogramms beschrieben. Um die Übersichtlichkeit zu wahren, wird der Programmablauf in kleinen Absätzen nachvollzogen.
Definiton der Variablen
Das Programm beginnt mit der Definition der Variablen. Dabei wird zwischen GPIO-Variablen und Programm-Variablen unterschieden. Die GPIO-Variablen werden verwendet, um den verschiedenen Signalleitungen je einen GPIO zuzuordnen. Tabelle 2 zeigt eine detaillierte Zuordnung der einzelnen GPIO-Pins. Die Programm-Variablen werden im Hauptprogramm und den Funktionen verwendet. Eine detaillierte Zuordnung zeigt Tabelle 3.
Definiton der Funktionen
Nach den Variablen werden die Funktionen definiert. Dazu ist jede für das Programm geschriebene Funktion mit ihrem jeweiligen Quellcode nacheinander angeordnet. Um dem Interpreter deutlich zu machen, dass es sich um eine Definition handelt, bekommt jede Funktion das Präfix def.
Interrupt Event: Reset()
Die Funktion Reset() wird in einem parallelen Prozess geladen. Sie prüft, ob der Spieler einen Abbruchwunsch äußert. Auf diese Weise kann das Spiel jederzeit neu gestartet werden.
Begrüßung der Spieler
Zur Begrüßung der Spieler wird ein Lauftext "4 Gewinnt" auf der LED-Matrix ausgegeben.
Hauptschleife und Initialisierung
An dieser Stelle beginnt die Hauptschleife des Programms. Während der Initialisierung werden die Grundeinstellungen zum Starten des Spiels getroffen. Dabei wird das Reset-Flag gelöscht, die Grundposition der Matrix eingestellt, Spieler 1 als aktiv gewählt, der Tri-State-Ausgang der Schieberegister aktiviert und der aktuelle Datenvektor in den Schieberegistern gelöscht und an die Ausgänge übernommen.
Spielschleife
Die Spielschleife wiederholt sich so lang, bis das Reset-Flag gesetzt wird. Dies kann durch den parallelen Prozess Reset() oder durch das Ende des Spiels geschehen. Das Spiel wird beendet, wenn ein Spieler gewonnen hat oder keine Züge mehr möglich sind, weil die Matrix zu 100% gefüllt ist.
In der Spielschleife laufen immer die folgenden Schritte nacheinander ab: Sende Daten an LED-Matrix, prüfe Left-Taster, prüfe Enter-Taster, prüfe Right-Taster. Je nachdem, ob und, wenn ja, welcher Taster betätigt wurde, arbeitet die Spielschleife eine andere Aktion ab.
Left-Taster
Der Coin wird auf der LED-Matrix um eine Position weiter nach links verschoben. Sollte der Rand der LED-Matrix erreicht worden sein, so verharrt der Coin auf seiner aktuellen Position am linken Rand der Matrix.
Enter-Taster
Der Coin wird in der aktuellen Spalte fallen gelassen. Er gleitet bis zur untersten noch von keinem Coin besetzten Stelle und verharrt an dieser. Anschließend wird überprüft, ob durch den Wurf ein Gewinn erzielt wurde. Ist das der Fall, wird eine Gewinnmeldung ausgegeben und das Spiel beendet. Falls kein Gewinn festgestellt wurde, wird nun überprüft, ob noch gültige Züge vorgenommen werden können. Sollte die LED-Matrix bereits vollständig ausgefüllt sein, ist dies nicht mehr möglich und ein Unentschiedenbildschirm wird ausgegeben und das Spiel beendet. Falls noch weitere gültige Spielzüge möglich sind, wird der Spieler gewechselt und regulär in die Spielschleife zurück gesprungen.
Right-Taster
Der Coin wird auf der LED-Matrix um eine Position weiter nach rechts verschoben. Sollte der Rand der LED-Matrix erreicht worden sein, so verharrt der Coin auf seiner aktuellen Position am rechten Rand der Matrix.
3. Diskussion
3.1 Bekannte Probleme und Fehler
Flackerndes Display
Die LED-Matrix kann gelegentlich etwas flackern. Das liegt daran, dass die LED-Matrix vom Hauptprogramm beschrieben wird. Da je nach gewählter Aktion ein kürzeres oder längeres Hauptprogramm ausgeführt wird, ist kein gleichmäßiges Beschreiben der LED-Matrix möglich. Dieser Effekt ist jedoch sehr gering und fällt kaum ins Gewicht.
3.2 Ausblick
Parallele Prozesse und Interrupts
In der aktuellen Entwicklung könnten viele Funktionen des Hauptprogramms in Interrupts oder parallele Prozesse ausgelagert werden. So könnte beispielsweise das Beschreiben des Displays wesentlich gleichmäßiger ablaufen, wenn es in einen parallelen Prozessausgelagert wird. Auch das Abfragen der Taster könnte durch die Verwendung von Interrupts effizienter gestaltet werden.
Computergegner
Eine schöne Erweiterung des Projekts wäre ein optionaler Computergegner. So könnte man das Spiel auch allein spielen. Des weiteren wäre auch das Implementieren eines Demonstrationsmodus interessant. Dabei können zwei Computergegner in immer neuen Variationen gegeneinander spielen.
Integration weiterer Spiele
Für spätere Entwicklungen ist es vorstellbar, weitere Spiele auf der bereits vorhandenen Hardware zu programmieren. Gut geeignete Spiele wären beispielsweise Varianten von Tetris, Pong oder Snake.
Nachfolgend wird erläutert, wie eine freie Programmierumgebung für STM32 unter Ubuntu eingerichtet werden kann. In diesem Beispiel baut die Entwicklungsumgebung auf Eclipse mit diversen Erweiterungen auf.
In diesem Tutorial beziehen ich mich auf das Olimex STM32-P152 Evaluation-Board, welches einen STM32L152VBT6 Mikrocontroller enthält. An einigen Stellen gibt es allerdings auch Verweise für die Familien F0, F1, F2, F3 und F4.
1. Verwendete Komponenten
Evaluation Board: Olimex STM32-P152
JTAG-Debugger: Olimex ARM-USB-TINY-H
2. Verwendete Programme
Ubuntu 14.10
Eclipse Kepler 4.3 (Service Release 2)
OpenOCD 0.9.0
ARM GCC Toolchain 5.0
ARM GCC Plugin 2.8.1 (Eclipse Plugin)
Zylin 4.16 (Eclipse Plugin)
3. Vorgehensweise
installiere „OpenOCD“
installiere „GCC ARM Embedded Toolchain”
installiere Eclipse für C/C++ (Kepler)
Eclipse add-ons hinzufügen
ein neues Projekt in Eclipse beginnen
Einrichten von OpenOCD in Eclipse
Einrichten des Debuggers in Eclipse
4. Installiere OpenOCD
OpenOCD steht für Open On-Chip Debugger. Dieses Tool stellt die Verbindung zwischen Board, Debugger und PC her.
Die GCC ARM Toolchain wird benötigt, um den C-Quellcode in maschinenlesbaren Code zu übersetzen. Sie übernimmt in Eclipse das Builden und einen Teil des Debuggens.
Eclipse wird von uns als Entwicklungsumgebung für C/C++ verwendet. Eine Entwicklungsumgebung ist ein Programm, in dem der Quellcode geschrieben, gebuildet und debuggt wird. Es ist damit die Hauptoberfläche mit der sich ein Programmierer beschäftigt.
Automatische Installation
Terminal: ~$ sudo apt-get install eclipse
Falls keine aktuelle Version von Eclipse installiert werden sollte, (Eclipse 4.3 Kepler oder höher) muss Eclipse manuell installiert werden.
lade Eclipse Kepler oder eine höhere Version für Linux herunter (achte dabei auf 32 Bit / 64 Bit)
installiere ROOT-Befehl für graphische Anwendungen: ~$ sudo apt-get install gksu
starte Nautilus mit ROOT-Rechten: ~$ gksudo nautilus
navigiere zum Verzeichnis /opt/
Extrahieren des Eclipse-Archivs hier in einen Ordner (eine eindeutige Namenswahl ist immer gut, z.B. eclipse_kepler)
Nach dem Entpacken muss der Datenpfad, in dem Eclipse abgelegt wurde, für den Benutzer freigegeben werden.
Im folgenden Terminal-Befehl muss $USER durch den Benutzernamen des Kontos ersetzt werden, welcher für die Verwendung von Eclipse freigegeben werden soll (z.B. jochen). Der Ordner „eclipse_kepler“ muss durch den gerade erstellten Ordnernamen ersetzt werden. ~$ sudo chown -R $USER:$USER /opt/eclipse_kepler
Um Eclipse für die geplante Aufgabe tauglich zu machen, ist es notwendig einige Plugins zu installieren. Plugins können meistens auf mehreren Wegen installiert werden. In diesem Dokument wurde versucht, die jeweils einfachste und schnellste Variante zu wählen.
7.1. CDT
Zu Beginn erweitert man Eclipse um die Plugins „CDT“ (C/C++ Development Tools) und „G++“ (GNU-C/C++ Compiler). Dabei handelt es sich um die C/C++Software Development-Funktion und einen C/C++ Compiler von GNU. Diese Plugins machen ein Programmieren in C/C++ möglich.
Das „GNU ARM Eclipse Plugin“ erweitert Eclipse um einige Bibliotheken und bietet für die STM32-Familien F0xx, F10x, F2xx, F3xx und F4xx vorgefertigte Template-Projekte an. Des Weiteren werden für diese Familien auch die Standard Peripherie Bibliotheken geladen. Die von mir Verwendete Familie L1 gibt es leider nicht in den fertigen Templates, für sie werden auch keine Standard Peripherie Bibliotheken geladen. Diese Templates und Bibliotheken müssen selbst geschrieben (bzw. als fertiges Template von dieser Seite eingebunden) werden.
Installation aus dem Internet
starte Eclipse ⇒ Menüleiste > Help > Install New Software ...
Das Zylin-Plugin ist ein GDB-Server. Es ist dafür verantwortlich, dass das Debuggen auf dem Entwicklungsboard vonstattengehen kann. Dazu verwendet es teile der GCC ARM Toolchain und OpenOCD.
Installation
starte Eclipse ⇒ Menüleiste > Help > Install New Software ...
work with: klicke „Add...“
Name: (leer lassen)
Location: http://opensource.zylin.com/zylincdt
setze einen Haken bei „Zylin Embedded CDT“
klicke 2x Next, bestätige die Lizenzvereinbarung und beende die Installation mit einem Klick auf Finish
Nachdem wir nun viele Programme und Programmbestandteile installiert haben, bekommen wir erstmals das eigentliche C-Projekt zu Gesicht. Für das Erstellen eines neuen Projekts gibt es je nach Mikrocontroller-Familie verschiedene Möglichkeiten. Hier wird eine Möglichkeit für die Familie L1 und eine zweite Möglichkeit für die Familien F0, F1,F2, F3 und F4 vorgestellt.
Nun wird das Projekt noch umbenannt und der Postprocessor des Builders an den neuen Namen angepasst:
Menüleiste >File >Rename...
wähle den Namen für den Projekt und Klicke OK
jetzt muss der Postprocessor an den neuen Namen angepasst werden
Menüleiste >Project >Properties
Navigiere zu: C/C++ Build >Settings
wähle den Tab „Build Steps“
ändere im Abschnitt „Post-build steps“ die Zeile „Command:“, der alte Projektname muss durch den neu gewählten ersetzt werden, Klicke Apply und anschließend OK
öffne Eclipse ⇒ Menüleiste > File > New > C Project und klick Next
benenne dein Projekt und benutze „Cross ARM GCC“ als Toolchain, klick Next
Project name: (Der Name deines Projektes)
Project type: (je nach Chip)
STM32F0xx C/C++ Project
STM32F1xx C/C++ Project
STM32F2xx C/C++ Project
STM32F3xx C/C++ Project
STM32F4xx C/C++ Project
Toolchain: Cross ARM GCC
Nun werden die Target processor settings eingestellt, diese Daten müssen mit den Daten des Boards und des Mikrocontrollers abgeglichen werden. Eclipse trifft zwar meist die richtigen Einstellungen automatisch, darauf sollte man sich jedoch nicht verlassen.
Processor core: (Datenblatt Chip)
Flash size (kB): (Datenblatt Chip)
RAM size (kB): (Datenblatt Chip)
clock(Hz): (Datenblatt Board)
content: Blinky (blink a led)
use system calls: Freestanding (no POSIX system calls)
trace output: Semihosting DEBUG channel
enable Boxes: ✔Check some warnings, ✔Use newlib nano
Als nächstes wird die Ordnerstruktur festgelegt
include folder: inc
source folder: src
system folder: system
CMSIS library folder: cmsis
C library folder: newlib
linker script folder: ldscripts
vendor CMSIS name: DEVICE
bei Set Configurations wird ✔Debug und ✔Relase ausgewählt, klick Next
wähle die vorher installierte GNU ARM Toolchain, klick Finish
toolchain name: GNU Tools for ARM Embedded Processors (arm-none-eabi-gcc)
toolchain path: (Der Pfad zu den Ausführbaren Dateien der Toolchain, er sollte in folgendem Verzeichnis zu finden sein: /usr/bin/arm-none-eabi-gcc)
9. Einrichten von OpenOCD in Eclipse
OpenOCD steht für „Open On Chip Debugger“ und ist für die Verbindung zwischen Mikrocontroller, JTAG-Debugger und PC verantwortlich. Um dieser Aufgabe nachzugehen muss das Programm auf die vom Nutzer verwendeten Hardware eingestellt werden.
lade die Config-Datei des Boards vom Hersteller runter (stm32l.cfg)
Achte darauf, dass die Dateien in Location und Arguments auch wirklich da sind, die Pfade müssen ggf. an die vorgenommene Installation angepasst werden!
Einstellung für den Common-Tab:
save as: Local file
Display in Favorites menu: ✔External Tools
Die Restlichen Einstellungen können in Standardposition bleiben
Einstellung der anderen Tabs ist nicht nötig, klick Apply und danach Close
Im Favoriten-Menü (Button-Leiste) gibt es einen Button für die External Tools, in seiner Auswahl ist jetzt das von uns definierte OpenOCD-Makro „connect-ARM-USB-TINY-H“ enthalten.
Mit einem Klick darauf kann nun die Verbindung zum Board per OpenOCD hergestellt werden. Die Console sollte folgende Meldung ausgeben:
Open On-Chip Debugger 0.8.0 (2014-05-10-23:20) Licensed under GNU GPL v2 For bug reports, read http://openocd.sourceforge.net/doc/doxygen/bugs.html /usr/bin/openocd: invalid option -- ’0’ /usr/bin/openocd: invalid option -- ’0’ Info : only one transport option; autoselect ’jtag’ adapter speed: 100 kHz adapter_nsrst_delay: 100 jtag_ntrst_delay: 100 cortex_m reset_config sysresetreq Info : clock speed 100 kHz Info : JTAG tap: stm32l.cpu tap/device found: 0x4ba00477 (mfg: 0x23b, part: 0xba00, ver: 0x4) Info : JTAG tap: stm32l.bs tap/device found: 0x06416041 (mfg: 0x020, part: 0x6416, ver: 0x0) Info : stm32l.cpu: hardware has 6 breakpoints, 4 watchpoints
Während einer Eclipsesitzung brauch die Verbindung per OpenOCD nur ein Mal hergestellt werden, sie bleibt erhalten, bis man sie manuell trennt
10. Einrichten des Debuggers in Eclipse
öffne Eclipse und navigiere dich zu: Menüleiste > Run > Debug Configurations...
Rechtsklick auf Zylin Embedded debug(Nativ) > New
gehe auf den neu entstandenen Punkt und gib ihm einen aussagekräftigen Namen z.B. (Projekt)-Debug-Zylin
Einstellungen im Main-Tab
Project (optional): (Projektname, z.B. HelloWorld)
C/C++Application: Debug/(Projektbinary, z.B. HelloWorld.elf)
Der Pfad in Zeile 5 muss angepasst werden und zum Projekt-Binary (z.B. HelloWorld.bin) führen
’Run’ commands: (leer)
Einstellungen im Common-Tab
✘Local file
Display in favorites menu: ✔Debug
Einstellung der anderen Tabs ist nicht nötig, klick Apply und danach Close
Im Favoriten-Menü (Button-Leiste) gibt es einen Button für Debug, er kann nun jeder Zeit verwendet werden um das Projekt zu debuggen.
vor dem Debuggen (!) ist es wichtig ein OpenOCD-Verbindung herzustellen
11. Sie haben Ihr Ziel erreicht!
Wenn alle vorangegangenen Schritte richtig ausgeführt worden sind, sollte es jetzt möglich sein, das Projekt fehlerfrei zu builden und zu debuggen. Dabei ist der Ablauf immer wie folgt:
Code schreiben (.c und .h Dateien)
builden (Menü-Button „Hammer“)
mit OpenOCD die Verbindung zum Board herstellen (Menü-Button „Koffer“)
mit Zylin debuggen (Menü-Button „Käfer“)
In der von ST bereitgestellten STM32L1xx_StdPeriph_Lib gibt es viele nützliche Programmierbeispiele, die einem das Arbeiten wesentlich leichter machen. Ein Streifzug durch die unter dem nachfolgenden Link geführte Bibliothek ist daher sehr zu empfehlen.
Heute stelle ich ein Projekt zur Realisierung eines Weckers mit MSP430 vor. Dieses Projekt wurde von meinem Freund Christian und mir während des 4. Semesters im Fach Mikrorechnerarchitekturen" bearbeitet. Dazu wird ein Evaluation Board, welches zum Buch "Mikrocontrollertechnik" von M.Sturm, angeboten wird verwendet.
Für eine Waldparty brauchten wir noch ein bisschen Licht. Daher habe ich eine Lichtorgel mit 6 Kanälen entwickelt. Besonders beachtenswert ist, dass an jedem Kanal bis zu 5A Leistung entnommen werden kann. Das sind 1100 Watt oder 11 super helle Glühbirnen an einem Kanal!
Es gibt zwar noch einiges zu verbessern, aber für einen ersten Prototypen haben wir hier ein echt fettes Teil.
Die Solid-State-Relais vertragen laut Hersteller keine induktiven und kapazitiven Lasten.
Das bedeutet, es ist sinnvoll nur Glühbirnen dran zu hängen. Ich hab zwar auch schon LEDs (Netzteil) und Halogenleuchten daran betrieben, aber wegen den hohen Spannungsspitzen beim ausschalten einer induktiven Last, sollte man sowas nicht übertreiben, sonst ist so ein Solid-State-Relais schnell hinüber... ;-)
Die Lichtorgel läuft im Moment noch autark und vollig ohne Kopplung an die Musik. Leider wird man verrückt wenn sechs Lichter unabhängig von der Musik blinken. Daher soll sich das ändern.
Lösung
Sinnvoll wäre das einbauen eines Basstrigger oder Geschwindigkeitseinstellung mit Poti
Problem:
Die angeschlossenen Lichter steuern beim Einschalten immer voll durch. Der Scheinwerfer geht also nicht langsam an, sondern knallt einem sofort ins Gesicht. Dafür wäre eine geschmeidigere Lösung angebracht.
Lösung:
Wahrscheinlich muss man für diesen Wunsch das Konzept mit den Solid-State-Relais grundsätzlich überdenken...
Problem:
Die Steuerung ist sehr mühselig und wenig komfortabel, mehr Bedienelemente und ein besseres Programmfeedback wären sehr wünschenswert.
Lösung:
Der Programmcode muss überarbeitet werden. Dabei sollten Interrupts eingebunden und Kontroll sowie Bedienelemente erweitert werden.