Peter Hofbauer’s private Homepage
Selbstbauprojekte
eigene Entwicklungen
Die 16bit-Prozessoren von Microchip PIC24/dsPIC..
Bisher habe ich meine Projekte mit den ATMEGA-Prozessoren gemacht. Die sind mir aber für einige geplante Projekte zu langsam. Darum
suche ich jetzt:
Ersatz für die ATMEGA’s
Vorweg: Prozessoren programmiere ich nur in Assembler! Also brauche ich eine Prozessorfamilie mit Entwicklungswerkzeuge die noch
Assembler-freundlich sind. Die Programmiersprache C kann ich zwar, ist mir aber bei meinen Hardware-Entwicklungen zu weit weg.
Eigentlich wollte ich vom ATMEGA zum STM32 wechseln. Weil der ATMEGA mir zu langsam und auch langweilig wurde.
Habe ein STM32-Board besorgt und getestet ob es mit Assembler noch machbar ist. Also eine LED zum Blinken habe ich zwar in Assembler hin
bekommen. Beim genauen studieren der Dokus musste ich einsehen: ohne C ist es sinnlos! Die Dokus für den STM32 sind nur für C ausgelegt.
Dann habe ich die ganze Software für den STM32 vom PC geschmissen und das Board verschenkt.
Nach intensiver Suche bin ich bei den 16-bitter PIC24/dsPIC gelandet. Der Befehlssatz ist sehr Assembler-freundlich und auch deutlich besser
als beim ATMEGA. Und sehr gut dokumentiert. Mit den internen Oszillator benötigen fast alle Befehle nur einen 34ns-Takt. Vor allem der
Befehlssatz macht den Prozessor schnell.
Mal 2 Beispiele:
•
Für die Bedienung einer Sprungtabelle benötigt der ATMEGA 14 Befehle, beim dsPIC nur einen.
•
Für die Addition von BCD-Zahlen hatte der 8051 den Befehl daa. Beim ATMEGA war dazu ein Unterprogramn mit 100 Befehle nötig. Beim
dsPIC ist der Befehl wieder vorhanden.
Aus der Sicht eines Anfängers beschrieben ist für diese 16-Bitter nötig:
•
Als IDE verwende ich die alte MPLAB IDE 8.91 Version. Die neuere MPLABX ist mir zu C-lastig und für Assembler schlecht geeignet.
•
Zum Debuggen / Programmieren verwende ich den PICkit3 oder PICkit3.5. Kosten im www etwa 10 Euro. Funktionieren beide!
•
Ein dsPIC mit DIL-Gehäuse und ein Steckbrett damit man etwas experimentieren kann.
•
Buch in deutsch: “Handbuch PIC24/dsPIC-Mikrocontroller” und für MatheFans “Softwareentwicklund für dsPIC33F-Mikrocontroller”
•
Die komplette Befehlsliste aus z.B. DS70139F (S.136-142) ausdrucken und in Klarsichthüllen stecken, sollte man immer bereit haben.
Einfache Inbetriebnahme der IDE mit einen dsPIC30F2011
Dieser Prozessor ist noch mit 5V zu betreiben und hat ein DIL18-Gehäuse. Man kann ihn also auf ein Steckbrett in Betrieb nehmen. Für diesen
Test reicht die neben stehende Schaltung. Nachdem der Aufbau fertig ist, kann man
mit der IDE starten.
Wie schon erwähnt verwende ich die alte MPLAB V8.91. Zuerst muss ein Projekt eingerichtet werden. Dazu Projekt > Projekt Wizzard...
aufrufen. Mit 4 Schritte wird ein Projekt erstellt:
1.
Prozessor auswählen: dsPIC30F2011
2.
Programmier-Sprache auswählen, unverändert übernehmen
3.
Projektverzeichnis \ Projektdatei: für diesen Test “dsPICTest\dsPICTest1”
4.
Dateien auswählen: unverändert übernehmen
Dieses Projektfenster erscheint, noch ohne Dateien
Dann wie hier gezeigt die Dateien eintragen.
Dazu mit Rechtsklick auf Source Files, die Datei “dsPICTest1.s”
eintragen. Die muss man entweder vom Download holen oder ins
leere Dateifenster eintippen.
Die Dateien “p30F2011.inc” und “p30F2011.gld” sind auf dem PC
unter z.B. “..\Programme(X86)\Microchip\MPLAP ASM30
Suite\Support\PIC30F\inc” und “..\gld” zu finden.
Diese Dateien liefert Mikrochip für jeden Prozessor. Wird bei
der Installation der IDE in die oben angegeben Verzeichnisse
geladen.
“p30F2011.gld” ist eine Linkerdatei. Man braucht sich um den Linker nicht weiter kümmern, mit
dieser Datei geht es von selber.
Dann mal in “Configure>Select Device” nach schauen ob der richtige Device dsPIC30F2011
eingetragen ist.
Dieser Sourcecode enthält nur die mindestens nötigen Zeilen.
In Zeile 5, 8 und 11 wird der Prozessor configuriert.
Im Prinzip das selbe was man beim ATMEGA mit den Fuses
macht.
config ist ein Assembler-Macro, das z.B. den Wert FRC_PLL16
ins Register __FOSC setzt. Hier wird der Interne Takt mit einer
PLL mit 16 multipliziert und dann durch 4 geteilt. Das ergibt eine
Zykluszeit von etwa 34ns.
config ist in *.inc definiert und erklärt.
Die Registeradressen stehen in der Linkerdatei *.gld.
Die Werte stehen in *.inc.
benötigt der Linker
leitet den Codebereich ein
den Stack benötigen wir eigentlich nicht, aber der Debugger
hier wird der Port B als Ausgang gesetzt.
Eine sehr kurze
Programmschleife, damit wird
der Pin alle 100ns gekippt ( 3
Befehlszyklen).
Zur Inbetriebnahme den Debugger PICkit an PC/USB und den Prozessor/X3 anschließen.
Im Output-Fenster ist wenn alles OK ist z.B. diese Meldung sichtbar. Der PICkit wird automatisch erkannt.
Den Modus auf Debug einstellen damit der Prozessor zusätzlich mit Debuggerinfos geladen wird.
Dann übersetzen und in den Prozessor laden. Dann sollte obiges Bild erscheinen und es kann durchs Programm geklickt werden.
Wenn man das Programm startet (mit den blauen Pfeil) ist am Pin 2 des dsPIC mit einen Oszilloskop ein Rechtecksignal zu sehen. Alle 100ns
wird die Spannung gekippt, also mit einer Frequenz von 5MHz.
Die Verbindung Sourcecode > IDE MPLAB > Debugger PICkit > Prozessor dsPIC30F2011 ist damit erfolgreich hergestellt. Der Rest um ein
Programm zu erstellen sollte jetzt ohne größere Probleme machbar sein.
In der Regel besteht ein Programm aus mehreren Sourcedateien. Die kann man einfach zusätzlich im Projektfenster (Rechtsklick auf Source
Files) eintragen, der Linker macht den Rest.
Die 16bit-PICs haben einen sehr praktischen Befehlssatz. Es macht Spaß damit in Assembler zu programmieren. Die Zykluszeit von 34ns ist
heute kein Spitzenwert mehr, aber vor allem der Befehlssatz macht den dsPIC erst so richtig schnell. Im Vergleich zum ATMEGA.
Die IDE MPLAB (ohne X) hat eigentlich alles was man braucht. Die neuere Version hat einen besseren Editor, aber alles andere braucht man
nicht. Leider ist die neue IDE MPLAB-X für C-Programmierer ausgelegt. Wer Lust hat kann ja mal versuchen, damit Assembler Programme zu
machen. Ich habs aufgegeben und MPLAB-X vom PC geschmisssen.
Ich verwende zum editieren für alle Programmiersprachen den selben Editor: PSPad. Den kann man sich für jeden Prozessor und jeder
Programmiersprache einrichten. Nur beim Debuggen verwende ich den Editor in der IDE. Man kann auch parallel beide verwenden, die
vertragen sich. Die Highlighter-Datei für die sdPIC + PSPad habe ich im Download angehängt.
MPLAB V8.91 befindet sich bei Microchip im Archiv.
Unterschiede zum ATMEGA:
Wenn man die Schaltung ohne Debugger in Betrieb nehmen will, muss man von Debug auf Release umschalten und nochmal übersetzen und
in den Prozessor laden. Mit den PICkit, den man danach entfernen darf.
Die Datenrichtung in der Befehlszeile geht beim ATMEGA von rechts nach links, beim dsPIC umgekehrt. Man benötigt einige Zeit um sich daran
zu gewöhnen.
Beim Subbtraktionsbefehl wird das Carry-bit als invertiert ausgefasst.
Downloads
Sourcedatei und Highlighter-Datei (3kB)
MPLAB-X
Assembler-code erkennt der Compiler XC16 automatisch an der Erweiterung “.s”. Man kann MPLAB-X also auch als IDE mit Assembler
verwenden.
für Assembler - Programmierer
Programm Aufbau, Prinzip
für Assembler - Programmierer
Für Assembler Programme gelten nach meiner Ansicht ganz andere Regeln wie für eine Hochsprache. Hier will ich mal beschreiben welche
Regeln sich bei meiner Programmier Art bewährt haben.
Der Aufbau ist wie im Bild zu sehen immer gleich, abgesehen von ganz kleinen Programmen. Nach dem Reset kommt erstmal die
Initialisierung. Dieser Teil wird nur einmal nach einem Reset aktiv.
Darauf folgt die Hauptschleife. Hier werden Programme in einer Endlosschleife hintereinander gesetzt. In dieser Hauptschleife gelten die
folgenden Regeln.
Die Steuerung und der Datentransfer erfolgt ausschließlich über den RAM, keine direkte Variablen
Übergabe.
Der RAM bildet einen Datenbus auf dem alle Programme ohne Beschränkung Zugriff haben. Damit das
funktioniert wird der RAM in einer einzigen Datei (ram.inc) definiert und als global deklariert. Es ist
wichtig, alle Daten, Formate und deren Zweck genau zu beschreiben. Als Kommentar in der “ram.inc”
mache ich das nicht. Zu viel Kommentare machen einen Code sehr schnell unübersichtlich. Ich habe
schon Listings gesehen wo man vor lauter Kommentare den Code nicht mehr findet. Das mache ich in
einen extra Text-Dokument. Damit hat man auch bessere Möglichkeiten und genug Platz. Dieses RAM-
Dokument erstelle ich bevor auch nur eine einzige Zeile Code geschrieben wird. Zusätzlich wird hier der
Datenfluss zwischen den Programmen und die Rechengänge beschrieben. Beim Programmieren, der
Fehlersuche oder bei späteren Erweiterungen ist dieses Dokument das wichtigste Hilfsmittel. Man sollte
das bis zum Schluss aktuell halten.
Die Programme in der Hauptschleife sollten folgende Regeln einhalten:
•
müssen sich separat testen lassen.
•
nur für eine einzige komplette Aufgabe zuständig die in einen kurzen Text beschreibbar ist
•
Ablauf mit Hilfe einer Sprungtabelle in einzelne kurze Schritte, nach dem Motto: “fasse Dich kurz”
•
Warteschleifen sind verboten.
•
es darf keine Rolle spielen, wo es in der Hauptschleife sitzt
•
nur an einer einzigen Stelle in der Hauptschleife darf auf einen CPU-Port zugegriffen werden, mal
abgesehen von begründeten Ausnahmen.
Einige Beispiel über den Aufbau der Programme in der Hauptschleife.
Zeiten:
In vielen Anwendungen sind Wartezeiten nötig. Zum Beispiel reagieren Relais, Displays oder Mechanik viel zu
langsam für den sehr viel schnelleren Mikrokontroller. Warteschleifen sollte man aber auf
keinen Fall einsetzen.
Nur zur Erinnerung: eine Millisekunde sind eine Millionen Nanosekunden!
Dazu verwende ich ein Programm in der Hauptschleife, das ich traditionell “Timer”
nenne. In den ersten Zeilen wird ermittelt, ob inzwischen eine Zeit von z.B. 100us
abgelaufen ist. Das mache ich entweder durch Abfrage eines CPU-Timers im Polling
oder mit Hilfe eines Bits, das per Interrupt getaktet wird.
Ablauf: siehe Diagramm links.
Bei meinen letzten Projekt (Erodiermaschine V2) hatte ich 12 unabhängige Zeiten auf
diese Art realisiert.
Das Diagramm rechts zeigt wie ein Programm diese Zeitzähler abfragt. Unter dem
Sprungziel 1 wird z.B.ein Relais geschaltet und ein Zeitzähler im RAM auf 10ms (also auf
100 wegen der 100us im Timer) gesetzt. Dann folgt ein Return. Unter dem Sprungziel 2 geht es erst dann weiter
wenn dieser Zeitzähler auf 0 steht.
CPU-Port schalten / abfragen:
Die einzelnen Programme in der Hauptschleife greifen nie direkt auf ein Port zu. Immer nur über den RAM. Ein Relais wird geschaltet indem
ein Bit im RAM gesetzt/gelöscht wird. Die Abfrage eines Eingangspegels geht ebenfalls über den RAM. Nur ein einziges Programm in der
Hauptschleife darf das. Dies nenne ich traditionell InOut. Darin werden die richtigen Pins ausgegeben, die Eingänge entprellt und im RAM
ausgegeben. Ebenso die analogen Eingänge. Die werden nach Bedarf umgerechnet usw und im RAM ausgegeben.
Diese Verfahren ist von Vorteil wenn Pins getauscht werden müssen wegen z.B. Layout-Änderungen. Außerdem ist es übersichtlicher,
verhindert Überschneidungen und informiert die übrigen Programme über den aktuellen Zustand an den Pins. Es gibt aber Ausnahmen.
Anzeigen
Um Texte, Ziffern usw auf ein LCD zu bringen, verwende ich zwei Programme in der Hauptschleife. Die nenne ich traditionell “Monitor” und
“LCDout”. Monitor arbeitet unabhängig, die anderen Programme brauchen sich um die Anzeige ihrer Daten und Texte nicht zu kümmern. Mit
Hilfe der einzelnen Schrittzählern der Programme erkennt Monitor was wo angezeigt werden muss. Die Daten stehen immer bereit im RAM.
Dazu ist es wichtig, das der RAM vollständig dokumentiert wurde.
Monitor übergibt einen (meist kurzen) ASCII-Text mit Steuerzeichen in einen Puffer und startet LCDout.
LCDout sendet dann immer nur ein einziges Byte (oder Nible wenn 4-bit Modus) ans LCD. Ein Zeitzähler im Kopf von LCDout verzögert
diese Ausgabe weil die LCDs langsamer arbeiten. Wenn LCDout das Endezeichen erkennt wird sein Schrittzähler auf 0 gesetzt worauf
Monitor den folgenden Puffer aufbereitet.
Dieses Verfahren mag auf den ersten Blick umständlich erscheinen.
Hat aber entscheidende Vorteile. Die Ausgabe ans LCD kann beliebig
langsam erfolgen ohne das die CPU aus gebremst werden muss. Weil
nur Monitor für die komplette Anzeige zuständig ist, wird immer alles
richtig angezeigt was angezeigt werden muss. Überschneidungen wie
z.B. gegenseitiges überschreiben wird vermieden.
Das wichtigste Element: Sprungtabellen
Als Beispiel zeige ich hier den Anfang von “Monitor”. In den ersten
Zeilen wird entschieden, ob dieses Programm aktiviert werden
soll/kann. Dann wird zu einen Label gesprungen auf welches ein
Schrittzeiger zeigt. Hier im Beispiel sind lcdsta ein Schrittzeiger für
LCDout und monsta für Monitor.
Die Unterteilung der Programme über einzelne Schritte macht Echtzeit
möglich. Der Ablauf eines Programms ist einfach zu verfolgen. Jeder
Schritt macht nur eine möglichst kurze Aktion, die durch Überschriften
über jeden Schritt im Listing erklärt wird. Pro Durchlauf wird nur ein
Schritt ausgeführt. Dabei ist es egal ob es immer der gleiche ist, oder
der Reihe nach oder auf irgend einen anderen Schritt gesetzt wird.
Der Boss
Ein Programm in der Hauptschleife muss den Boss machen. Um die Anzeige braucht es sich nicht kümmern, das macht Monitor selber. Es
muss aber den kompletten Ablauf steuern, also entscheiden wer was machen soll usw.
Solch ein Programm wird sehr schnell umfangreich und unübersichtlich. Eine grafische Darstellung mit Flussdiagramm macht es
übersichtlicher. Mir ist es egal ob das gut aussieht oder streng nach Norm ist, Hauptsache es erfüllt seinen Zweck. Mit welcher Software?
Nach umfangreichen Recherchen bin ich bei SmartDraw gelandet. Meine Version V6 gab es sogar in deutsch. Damit kann man einigermaßen
schnell arbeiten ohne überflüssige klickerei.
Die Schritte in meinen Programmen
sind durchnummeriert ab 0. Innerhalb
eines Schrittes setze ich a, b, c...
dran. Diese Nummerierungen sollten
alle auch im Flussdiagramm
auftauchen. Damit eine verfolgbare
Verbindung zum Soucecode bleibt.
Fürs Flussdiagramm sollte man sich
genug Zeit lassen und bis in die
Details ausarbeiten. Danach geht das
Schreiben des Sourcecodes wie von
selbst.
Hier ein kurzes Beispiel
Trotz allem ist meine aufwändige
Dokumentation von einen anderen
Programmierer immer noch schwer
durchschaubar.
Ist mich selber ist diese
Dokumentation wichtig.
(wird später fortgesetzt)