23 | 02 | 2012
Lerneinheit 1: Ansprechen von LEDs auf dem PicKit1
Sonntag, den 07. März 2010 um 15:10 Uhr

1 Einleitung

Mit dem Mikrokontroller können direkt auf dem Board 8 Leuchtdioden (LED's) angesprochen werden. Außerdem kann ein Taster ausgewertet werden und ein AnalogDigitalWandler-Eingang (ADC). Der Spannungswert am Wandlereingang kann durch einen Regelwiderstand manuell verändert werden. Es werden alle Mikrocontroller-Pins über eine Buchsenleiste nach außen geführt.

1.1 Strukturplan

Das nebenstehende Bild soll nur die Belegung der Pins veranschaulichen. Es soll also nur zur Orientierung dienen. Die Pins GP1, GP2, GP4 und GP5 sind mit den Dioden D1-D8 geeignet verbunden. Es können 4 weitere Dioden auf der Platine eingelötet werden. Pin GP3 ist mit einem Taster verknüpft. Pin AN0 ist der Eingang für eine Spannung die durch einen Spannungsteilereingestellt wird. Es ist hier also möglich, digitale Ein- und Ausgabe und Nutzung des Analogdigitalwandlers auszutesten ohne weiter Lötarbeiten. In den Unterlagen zum Entwicklungsboard sind eingehende Informationen enthalten.  

1.2  Genaueres zum Anschluss der Dioden auf dem PICkit™1 Entwicklerboard

Bei der digitalen Ein- und Ausgabe kann ein Pin drei Zustände annehmen. Es ist möglich der Zustand 0 , 1 und Z. Im Zustand Z ist der Pin hochohmig. Logisch 0 würde hier beispielsweise 0V, logisch 1 würde 5Volt entsprechen. Im Zustand Z ist der Eingang hochohmig, d.h. es fließt also in diesem Fall kein nennenswerter Strom („keine Verbindung“)

Eine LED leuchtet, wenn eine geeignete Spannung (bspw. 1,73V) anliegt, hierbei muss auf die Polung geachtet werden. Bei richtiger Polung fließt ein Strom und die LED leuchtet, bei falscher Polung fließt kein Strom. Die LED leuchtet in diesem Falle nicht. Die Widerstände sind so gewählt, dass an den LED's eine geeignete Spannung anliegt. GP1, GP2, GP4 und GP5 repräsentieren jeweils Bit 1, 2, 4 und 5 im Register GPIO was auch noch einmal in der unten gezeigten Registertabelle deutlich wird.

Soll beispielsweise die LED D0 leuchten, dann müssen am Ausgang GP4 5V (logisch 1) anstehen und der Pin GP5 muss auf logisch 0 gesetzt werden, alle anderen relevanten Pins müssen hochohmig sein.

Für die PIC™ Programmierung ist der jeweilige Schaltplan (siehe Abbildung rechts) der zu programmierenden Steuerung unabdingbar und sollte zumindest bei Anfängern immer griffbereit liegen.

 

2 Programmierung des PIC™

2.1 Programm 0 (Das Grundprogramm)

Das Grundprogramm besteht nur aus wenigen Zeilen und dient als Grundpfeiler der eigentlichen Anwendung. In ihm wird das CONFIG-Register initialisiert. Die Einstellungen sollen hier nicht weiter problematisiert werden. Nähere Angaben lassen sich dem Datenblatt vom PIC™ entnehmen. Beispielsweise wird der interne Oszillator ausgewählt usw.

Mit einem Semikolon wird ein Kommentar eingeleitet. Die Assembleranweisung #include bindet ein weiteres Assemblerprogramm ein. In dieser Datei p12f675.inc werden eine Reihe von Definitionen gegeben, so dass wir Register unter ihrem Namen einfügen können.

Quelltext:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
;**************************************************************************
;Autor buh 12.03.08
;Programm 1 Leds manipulieren
;Entwicklungsboard Pickit1
;**************************************************************************
 
#include <p12f675.inc>
;Dieses File wird eingebunden, es enthält Bezeichner für Statusregister u.ä.
;Bspw. ist TRISIO ein Register mit dem das Ein- oder Ausgabeverhalten der PIO
;definiert wird.
 
; Hier folgen grundlegende Einstellung, bsp Watchdog aus u.ä.
__CONFIG _CP_OFF&_WDT_OFF&_BODEN_ON&_PWRTE_ON&_INTRC_OSC_NOCLKOUT&_MCLRE_OFF&_CPD_OFF
 
;**************************************************************************
;Definitionen
;**************************************************************************
 
;RA4 und RA5 sind allein als Ausgabe gesetzt.
;R6 und R7 egal, da diese Pins nicht existieren.
;Muss im TRISIO-Register abgespeichert werden.
#define led_pins B'11001111'
 
;RA0 bis RA3 ist egal, da Eingänge. RA4 ist auf
;1 gesetzt, also 5V und RA5 auf 0V also leuchtet D0,
;falls dieser Wert in GPIO eingetragen wird
#define led_D0_an B'00010000'
 
;Jetzt leuchtet D1, falls dieses Wort in GPIO eingegetragen wird.
;Wird hier im Programm aber nicht benutzt.
#define led_D1_an B'00100000'
 
 
;**************************************************************************
;ab hier beginnt das Programm. 1. Eintrag in Speicherstelle 0000h
;**************************************************************************
ORG 0x000
 
;Bank0 wird ausgewählt, RP0 im Register STATUS wird auf 0 gesetzt.
bcf STATUS,RP0
 
;Jetzt leuchtet D0. Die Adresse von GPIO liegt in Bank 0 Speicherplatz: 05h
movlw led_D0_an
movwf GPIO
 
;Bank1 auswählen, RP0 in Register STATUS wird gesetzt
bsf STATUS,RP0
 
;TRISIO ist das Register mit dem Ein- bzw. Ausgaberichtung der Pins eingestellt wird.
;Liegt in Bank1 Speicheradresse: 85h
movlw led_pins
movwf TRISIO
 
 
 
end ;Hier ist das Assemblerfile zu ende.
 

 

2.2 Ansprechen der Leuchtdioden auf dem PICkit™1

2.2.1 Einleitung

Das Programm wird schrittweise entwickelt. Es wird auf die Informationen und Abbildung aus 1.2 (LED-Netz) und Artikel "PIC™ 12F675- > 2. Die Speicherverteilung" zurückgegriffen. Außerdem werden die genutzten Assembleranweisungen näher erläutert.

Um LED D0 auf dem Board ansprechen zu können, müssen die Pins GP1, GP2, GP4 und GP5 geeignet konfiguriert werden. GP4 und GP5 werden als digitale Ausgangspins konfiguriert, GP1 und GP2 müssen hochohmig sein, d.h. diese Pins werden als Eingabepins konfiguriert.

Programmtechnisch heißt dies, dass entsprechende Konfigurationsspeicher verändert werden. AN0 ist (s. Strukturbild) auf dem PICkit™1 der analoge Eingang, also ist hier GP0 nicht verfügbar, GP3 ist für den Taster vorgesehen, Dieses PIN ist fest als Eingabepin voreingestellt.

Speicherbereiche werden häufig auch als Register bezeichnet. In der folgenden Darstellung wird i. d. R. die Bezeichnung Register verwendet.

2.2.2 Konfiguration der Pins

2.2.2.1  Vorüberlegungen

Das Ein- bzw. Ausgabewort wird mit Hilfe von Register GPIO bestimmt.
Der Komparator mit Hilfe von Register CMCON.  

Es werden in Register GPIO alle Bits 0 gesetzt. Das Register GPIO besteht für den 12f675  aus 6 veränderbaren Bits.
Die Bits haben die Bezeichnungen GPIO0- GPIO5 und beziehen sich auf die 6  Pins mit den Bezeichnungen GP0 bis GP5. Wir setzen zu Beginn alle Registerbits auf 0.

Es wird der Komparator ausgeschaltet.
Um die Komparator-Funktion auszuschalten, müssen die drei niederwertigen Bits des Registers jeweils auf 1 gesetzt werden. Diese Bits werden sinnigerweise CM0, CM1 und CM2 genannt. Mit diesen Bits wird der Komparator-Modus eingestellt.

Als nächstes wird das Register ANSEL verändert. Die vier niederwertigen Bits ANS0, ANS1, ANS2 und ANS3 bestimmen, ob ein Pin für eine analoge Eingabe ausgewählt wird oder als digitale   Ein- bzw. Ausgabe dienen soll.
Diese 4 Pins sind die  möglichen Eingabekanäle für den Analogdigitalwandler. Da nur an Eingang AN0 beim PICkit™1 ein Regelwiderstand anliegt, wird ANS0 auf 1 gesetzt und alle anderen Bits auf 0. Wenn es nur darum geht, eine LED auf dem PICkit™1 zum Leuchten zu bringen, können auch alle Bits des Registers ANSEL auf 0 gesetzt werden.

Im Register TRISIO wird nun eingestellt, welche Pins Aus- und welche Pins Eingabepins sein sollen. In unserem Programm 1 soll LED 0 zum Leuchten gebracht werden.

Für unser Programm ist es an dieser Stelle unwichtig, ob ein Eingang als digitaler bzw. analoger Eingang benutzt wird, da in beiden Fällen der Eingang hochohmig wird, also nur ein „kleiner“ Strom fließt. Also werden wir das ANSEL-Register nicht konfigurieren. Auch eine Veränderung des Komparator-Registers ist nicht notwendig, da maximal nur ein Eingang als analoger Eingang geschaltet ist. Bei anderen Konstellationen kann dies natürlich anders sein. Das folgende Programm führt bereits zu dem gewünschten Ergebnis „Leuchten der Leuchtdiode D0“.

2.2.2.2 Betroffene Register

Im Baustein PIC™12F675 sind nur zwei Bänke realisiert. Es können maximal 256 Speicherplätze angesprochen werden. Die 256 Speicherplätze haben die absoluten Adressen von 00h bis FFh (00dezimal bis 255 dezimal). Da eine Bank maximal 128 Speicherplätze umfasst, muss vor einem Zugriff auf einen Speicher die geeignete Bank eingestellt werden. Dies geschieht im Statusregister. Setze ich RP0=1 wird Bank 1 angsprochen. Gilt RP0=0 so wird Bank 0 ausgewählt. Die relative Adresse 05 weist auf das GPIO-Register falls Bank 0 ausgewählt wurde. Wurde Bank1 ausgewählt weist diese Adresse auf das TRISIO-Register.

 

2.2.2.3 Welche Assembleranweisungen benötigen wir für das erste Programm?

Alle Anweisungen, welche in dem ersten Programm (ansprechen einer LED) benötigt werden, sind in der nachfolgenden Tabelle nocheinmal veranschaulicht.

Das Simikolon ';' leitet einen Kommentar ein, d.h. alles was nach ihm in der selben Zeile steht wird von dem Compiler nicht mit interpretiert.

Anmerkung: Es ist sehr hilfreich wenn alle Programme schon bei der Entwicklung vernünftig kommentiert werden bzw. der Sinn der einzelnen Anweisungen kurz erläutert wird. Bei nicht gut kommentierten Programmen, gerade in Sprachen mit einer niedrigeren Abstraktionsstufe (wie Assembler), wird es zu einem späteren Zeitpunkt sehr schwer nachzuvollziehen was man sich ursprünglich dabei gedacht hat!

Syntax: Bedeutung:

Zahlendarstellung  die  der Assembler versteht

B'11111111' Das folgende Byte (binär) wird übergeben
D '20' Das Byte mit dem Wert 20 (dezimal) wird übergeben
H'FFFF' Das Byte mit dem Hexadezimalwert FFFF wird übergeben
0x05 Speicherplatz 05 Hexadezimal
Verschiedene nützliche Anweisungen
ORG xxxxh ab hier wird das Programm im Programmspeicher abgespeichert
_CONFIG Wichtige Voreinstellungen für den Mikrocontroller werden hiermit vorgenommen. Genaueres lässt sich im Datenblatt des Mikrocontrollers nachlesen .
#include<...>

Füge Dateiinhalt (Dateiname in den spitzen Klammern) beim Kompilieren ein.

Beipiel:

#include <p12f675> ;Hier wird die Datei eingefügt, die den Kontrollregister Klarnamen zuordnet. Diese Namen können nun im Quelltext verwendet werden. Beispielweise TRISIO entspricht der Hexadezimal H'0085'. D.h. binär 10000101. Das höchste Bit wird von den Speicherbefehlen nicht genutzt, so dass für einen Speicherbefehl hier die Zahl 05h erkannt wird. Also binär 101.

#define<Name><Wert>

Mit #define können sogenannte Macros definiert werden. Anstelle bestimmter Werte können wur nun einfach mit Namen arbeiten. Alle in <Wert> angegebenen Zeichenfolgen werden praktisch durch die in <Name> angegebenen Namen ersetzt.

Beispiel:

#define led _pins B'11001111'   ; Immer wenn nun led_pins im Programmcode verwendet wird, ist dies gleichbedeutend mit der Zahl B'11001111'

Kopieren von Speicherinhalten und Manipulation von Bits
movlw <Wert> Kopiere die Zahl 1 (von Litera), hier Wert, nach dem Arbeitsregister w.
movwf <Speicheradr.> Kopiere Inhalt von Arbeitsregister nach Speicheradresse
bcf f,b Das b.te Bit des Speichers f wird auf 0 gesetzt (0<=b<=7; 0<=f<=127)
bsf f,b das b.te Bit des Speichers f wird auf 1 gesetzt.

 

2.2.3 Quellcode (Programm1_1: Ansprechen einer LED auf dem PICkit™1)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
;**************************************************************************
;Autor buh 12.03.08
;Programm 1 Leds manipulieren
;Entwicklungsboard Pickit1
;**************************************************************************
 
#include <p12f675.inc>
;Dieses File wird eingebunden, es enthält Bezeichner für Statusregister u.ä.
;Bspw. ist TRISIO ein Register mit dem das Ein- oder Ausgabeverhalten der PIO
;definiert wird.
 
; Hier folgen grundlegende Einstellung, bsp Watchdog aus u.ä.
__CONFIG _CP_OFF&_WDT_OFF&_BODEN_ON&_PWRTE_ON&_INTRC_OSC_NOCLKOUT&_MCLRE_OFF&_CPD_OFF
 
;**************************************************************************
;Definitionen
;**************************************************************************
 
;RA4 und RA5 sind allein als Ausgabe gesetzt.
;R6 und R7 egal, da diese Pins nicht existieren.
;Muss im TRISIO-Register abgespeichert werden.
#define led_pins B'11001111'
 
;RA0 bis RA3 ist egal, da Eingänge. RA4 ist auf
;1 gesetzt, also 5V und RA5 auf 0V also leuchtet D0,
;falls dieser Wert in GPIO eingetragen wird
#define led_D0_an B'00010000'
 
;Jetzt leuchtet D1, falls dieses Wort in GPIO eingegetragen wird.
;Wird hier im Programm aber nicht benutzt.
#define led_D1_an B'00100000'
 
 
;**************************************************************************
;ab hier beginnt das Programm. 1. Eintrag in Speicherstelle 0000h
;**************************************************************************
ORG 0x000
 
;Bank0 wird ausgewählt, RP0 im Register STATUS wird auf 0 gesetzt.
bcf STATUS,RP0
 
;Jetzt leuchtet D0. Die Adresse von GPIO liegt in Bank 0 Speicherplatz: 05h
movlw led_D0_an
movwf GPIO
 
;Bank1 auswählen, RP0 in Register STATUS wird gesetzt
bsf STATUS,RP0
 
;TRISIO ist das Register mit dem Ein- bzw. Ausgaberichtung der Pins eingestellt wird.
;Liegt in Bank1 Speicheradresse: 85h
movlw led_pins
movwf TRISIO
 
 
;Hier ist das Assemblerfile zu ende.
end
 

 


2.2.4 Übungsaufgabe

  • Voraussetzungen: Anschlussplan LEDS (s.o) und  Befehlsliste (s.o). Die Befehle des Assemblers sind vollständig im Datenblatt enthalten.
  • Aufgabe: Versuche, die LEDs von D2 bis D7 einzeln mit kleinen Programmen anzusprechen.

2.2.5 Weitere Allgemeine Anmerkungen

Jeder Prozessor verfügt über einen Programmschrittzähler. Die Programmschritte werden nacheinander abgearbeitet, d.h., dass der Programmschrittzähler abhängig vom Taktgeber jeweils um 1 erhöht wird, es sei denn, dass wir gezielt den Programmschrittzähler verändern. Hierfür gibt es ebenfalls Assembleranweisungen. Im Programm 1 wird dieser Zähler nicht von uns beeinflusst. Der Zähler zählt als bis zum 1024 Speicherplatz und fängt anschließend wieder bei 0 an. Die Assemblerbefehle werden also immer wieder bei jedem Durchlauf erneut durchgeführt. Wer sich dies verdeulichen will, sollte mal das Simulationstool MPLAB SIM ausprobieren (s. unter Menüeintrag „Debugger“ in MPLAB). Wollen wir vermeiden, dass immer wieder erneut die Befehle durchgeführt werden, können wir eine Leerschleife (s.u.) einfügen. Es sind hierzu folgende Schritte nötig:

  • Wir müssen eine Ansprungsmarke (Label) setzten. Durch diese wird es ermöglicht zu bestimmten Passagen im Code zurück zu springen um bspw. bestimmte Programmanweisungen zu wiederholen.
  • Wir müssen die  goto-Anweisung verwenden. Durch diese Anweisungen wird zu dem vorher definierten Label gesprungen.

Das für uns sichtbare Ergebnis ist immer noch dasselbe. Sehen  wir  mit dem Debugger die Programmabarbeitung an, so stellen wir fest, dass der Programmzeiger  von goto  zur Marke ab_hier springt. NOP steht für No Operation. Es handelt sich hier um eine Leeranweisung. Diese muss im Beispiel hier nicht unbedingt stehen. Allerdings würden wir dann im Simulationsprogramm nicht sehen, dass der Programmzeiger immer hin- und herspringt.

Beispiel:

ab_hier   NOP  ; Hier wird ein Label mit dem Namen ab_hier gesetzt

goto ab_hier   ; Springe zum Punkt ab_hier. Aus dieser „Schleife“ kommt der Controller nicht mehr raus.

 

Wurde das Simulationstool gestartet, so erweitert sich die Symbolleiste um eine Gruppe von Symbolen wie in der rechten Abbildung zu sehen ist

Wird „Reset“ gedrückt, so geht das Simulationspro­gramm zum Anfang des As­semblerprogrammes. Dies wird durch den  grünen Pfeil deutlich, er zeigt dann auf den Befehl bcf ....

Wird „Animate“ gedrückt, so sehen wir, wie das Programm schrittweise ausgeführt wird (Simulation).

Schließlich pendelt der Zeiger immer zwischen dem Befehl NOP und dem Befehl goto...