Ports - Wenn der AVR steuert
Materialbedarf
Anz. | Bezeichnung | Datenblatt |
1 | Batterie/Spannungsquelle 9V | |
1 | Spannungsregler 7805 | |
1 | ATMega8 AVR-Prozessor | |
2 | Widerstand 220 Ohm | |
1 | Widerstand 10 kOhm | |
1 | Elektrolytkondensator 100 µF/16V | |
1 | Kondensator 100nF | |
2 | Mikrotaster | |
2 | Standard-Leuchtdiode 3mm oder 5mm | 3mm, 5mm |
Eine LED wird aktiv
Beim ATMega8 gibt es diverse Ein-/Ausgänge. Diese sind jeweils zu 8 Bit zu einem Port zusammen gefasst. Der ATMega8 besitzt 3 dieser Ports. Die Ports hat man nach dem Alphabet benannt. Unser AVR besitzt Ports mit den Namen Port B, Port C und Port D. Beim Port C hat man die 8. Leitung nicht heraus geführt.
Jeden Anschluss kann man entweder als Einzel-Eingang oder Ausgang definieren oder man kann auch den gesamten Port als ganzes verwenden. Da jeder Pin noch eine Zweitfunktion besitzt, ist die Definition als Einzelpin sehr sinnvoll.
Um
die Funktion eines Portpins zu verdeutlichen, schliessen wir hier an den
Pin 0 von Port D eine Leichtdiode an. Wir gehen einmal davon aus, dass der Programmspeicher des AVR gelöscht ist. Wenn wir nun die Betriebsspannung anlegen, passiert erst einmal gar nichts. Nun nehmen wir Bascom zu Hilfe und schreiben ein kleines Programm. |
$regfile "m8def.dat" $crystal = 1000000 Config Portd = Output Portd.0 = 1 Stop |
Wird jetzt dieses Programm compiliert und mit Hilfe des SPI-Kabels übertragen, leuchtet die LED auf und bleibt auch an. Was ist nun passiert?
Schauen wir uns das Programm einmal genauer an. Die ersten beiden Zeilen sind Konfigurationseinstellungen für Bascom. Interessant wird die 3. Zeile:
Config Portd = Output |
Hier teilen wir dem Controller mit, dass wir den gesamten Port D als Ausgang verwenden möchten. Im AVR wird dabei ein Register, also ein bestimmter Speicher, gesetzt, der der Steuerelektronik von den Ports sagt, dass hier der Port auf Ausgang schalten soll. Dieses Register nennt man Datenrichtungsregister oder kurz DDR (Data Direction Register).
Mit der darauf folgenden Anweisung schalten wir einfach den Ausgang auf 1. Da wir hier nur einen bestimmten Pin ansteuern möchten, muss dieser mit angegeben werden. Daher findet man in der Anweisung den Zusatz '.0' an der Bezeichnung PortD. Somit wird der Ausgang 0 des Port D auf 1 gesetzt, also eingeschaltet.
Der letzte Befehl sorgt nur dafür, dass der Controller in eine Endlosschleife gefangen wird und somit das Programm im Grunde gestoppt wird.
Das einfache Aufleuchten einer Leuchtdiode ist natürlich nicht gerade eine Spitzenleistung eines Controllers. Dies hätte man natürlich auch ganz ohne Controller bewerkstelligen können. Ein Controller entfaltet aber seine Stärke unter anderem darin, dass man einfach nur das entsprechende Programm ändern muss und schon erfüllt der AVR eine ganz andere Aufgabe. Schreiben wir also unser Programm mal ein wenig um:
$regfile "m8def.dat" $crystal = 1000000 Config Portd = Output Do Portd.0 = 1 Waitms 500 Portd.0 = 0 Waitms 500 Loop |
Als erstes fällt hier auf, dass hier die Befehle 'Do' und 'Loop' verwendet wurden. Alles was zwischen diesen beiden Anweisungen steht, wird immer wieder ausgeführt. Im Prinzip also unendlich. Daher kann auch die 'Stop'-Anweisung entfallen, da der AVR aus dieser Schleife nie heraus kommt.
Nach dem aktivieren des Pins 0 vom Port D, haben wir hier jetzt einen Wartebefehl eingefügt. 'Waitms' lässt den Controller die angegebene Zahl an Millisekunden warten. In unserem Beispiel 500 = 0,5s.
Als nächstes schalten wir den Ausgang wieder aus und lassen den ATMega wieder warten. Dann wird das ganze wiederholt oder, wie in diesem Programm, die Leuchtdiode blinkt.
Bisher
haben wir ja nur Pin 0 des Port D verwendet. Wer aber sagt uns denn,
dass hier wirklich nur Pin 0 angesteuert wird und nicht auch die
anderen? Um dies einmal zu überprüfen, schliessen wir eine 2. Leuchtdiode an Pin 1 des Port D an. Wird jetzt die Schaltung wieder in Betrieb genommen, beginnt die D1 wieder zu blinken. Die zusätzliche LED jedoch, bleibt aus. |
Um jetzt die LED D2 zum blinken zu bringen, brauchen wir das Programm nur etwas abändern und schon blinkt die zweite Diode anstelle von D1.
$regfile "m8def.dat" $crystal = 1000000 Config Portd = Output Do Portd.1 = 1 Waitms 500 Portd.1 = 0 Waitms 500 Loop |
Nach dem Übertragen blinkt jetzt D2.
Da wir jetzt 2 Leuchtdioden zur Verfügung haben, sollen beide LEDs wechselseitig blinken. Dazu müssen wir nur eine Leuchtdiode einschalten während die jeweils andere ausgeschaltet wird. Ergänzen wir einfach mal unser Programm:
$regfile "m8def.dat" $crystal = 1000000 Config Portd = Output Do Portd.0 = 1 : Portd.1 = 0 Waitms 500 Portd.0 = 0 : Portd.1 = 1 Waitms 500 Loop |
Der AVR wertet Eingaben aus
Nahezu
jeder Mikrokontroller muss irgendwelche Eingaben auswerten und
dementsprechend reagieren. Um dies mal näher zu verdeutlichen, erweitern
wir unseren AVR mal mit einem Taster der an Pin 0 von Port B
angeschlossen wird. Taster, Schalter etc. sollten bei den AVR-Controllern immer gegen Null schalten. Dies hat einen bestimmten Grund. Schreiben wir hierzu wieder ein kleines Programm und übertragen es: |
$regfile "m8def.dat" $crystal = 1000000 Config Portd = Output Config Portb = Input Portb.0 = 1 Do Portd.0 = Pinb.0 Loop |
Bei der Inbetriebnahme leuchtet die LED sofort auf. Wenn man nun den Taster S1 betätigt, geht die Leuchtdiode aus und leuchtet weiter, wenn man den Taster wieder los lässt. Der AVR reagiert also auf die Tastenbetätigung. Aber er reagiert ja eigentlich 'Falsch' herum. Warum ist das so? Dafür schauen wir uns den Eingangsport mal genauer an.
Eine besondere Eigenschaft der AVR-Controller ist, dass die Ports bei Verwendung als Eingang einen Pull-Up-Widerstand besitzen, welchen man bei Bedarf zuschalten kann. Dieses haben wir in unserem Programm gemacht. |
Nachdem wir den Port B mit der Anweisung
Config Portb = Input |
Folgt darauf eine Zuweisung des Pins 0 von Port B mit einer 1:
Portb.0 = 1 |
Durch diese Zuweisung sagt man den Controller, dass er den Pull-Up-Widerstand an Pin 0 des Ports B aktivieren soll. Würde man eine 0 zuweisen, wird der interne Widerstand deaktiviert.
Ist der Widerstand aktiviert, wird von dem Port immer eine '1' erkannt, wenn der Anschluss offen ist, oder wie hier, der Taster gerade nicht betätigt wird. Drückt man nun den Taster, wird der Eingang auf '0' gezogen und dies wird dann auch eingelesen.
In einer Dauerschleife lesen wir hier den Port ständig ein und weisen ihn gleich dem Ausgang zu wo unsere Leuchtdiode angeschlossen ist.
Es ist bestimmt aufgefallen, dass man hier nicht einfach geschrieben 'PortD.0=PortB.0'. Hier ist die nächste Eigenschaft des ATMega8. Der Controller benutzt für die Funktion als Ausgang und für die Funktion als Eingang zwei verschiedene Register. Daher sieht dann unsere Direktzuweisung so aus:
Portd.0 = Pinb.0 |
Nun wollen wir dem AVR aber noch einmal eine richtige kleine Steuerung aufbürden. Dazu ergänzen wir die vorhandene Schaltung noch mit einem weiteren Taster und schließen diesen an den Pin 1 des Port B an.
Mit dieser Schaltung soll jetzt die Leuchtdiode D1 mit S1 eingeschaltet werden. Der zusätzliche Taster soll die LED wieder abschalten. Hierfür müssen wir beide Taster abfragen, und falls einer von diesen betätigt wird, entsprechend den Ausgang 0 an Port D an bzw. abschalten. Dies erreichen wir durch dieses kleine Programm: |
$regfile "m8def.dat" $crystal = 1000000 Config Portd = Output Config Portb = Input Portb = 255 Do If Pinb.0 = 0 Then Portd.0 = 1 If Pinb.1 = 0 Then Portd.0 = 0 Loop |
Mit der 'If''-Anweisung prüfen wir ob der entsprechende Taster betätigt wird. Trifft dies zu schalten wir den Ausgang entsprechend. Bei diesem Programm sehen wir auch gleich, das man einen ganzen Port einen Wert zuweisen kann.
Portb = 255 |
Hier wird gleich bei allen definierten Eingängen, also Bit 0 bis Bit 7 des Ports B, der interne Widerstand aktiviert.
Ein- und Ausgaben auf einen Port
Oft hat man Steuerungen, wo man nur ganz wenig Ausgänge oder Eingänge benötigt. Wie z.B. unsere letzte Schaltung. Da ist es nicht sehr effektiv, immer gleich einen ganzen Port zu belegen, wenn man nur einen Eingang oder Ausgang hat. Bei den AVR-Controllern ist es auch möglich nur einzelne Pins zu definieren. Legen wir hierzu den Taster ein wenig um.
Hier
sieht man nun, dass der Taster an Pin 1 von Port D angeschlossen ist.
Die Leuchtdiode belassen wir an Pin 0. Jetzt müssen wir dem ATMega8 nur noch sagen, dass wir nicht mehr den ganzen Port D als Ausgang verwenden wollen, sondern nur noch Pin 0. |
$regfile "m8def.dat" $crystal = 1000000 Config Portd.0 = Output Config Portd.1 = Input Portd.1 = 1 Do Portd.0 = Pind.1 Loop |
Man kann an der 'Config'-Anweisung erkennen, dass es sich hier nur um eine bitweise Definition handelt. Bei Pin 1 aktivieren wir mit der nächsten Anweisung auch hier den internen Pull-Up-Widerstand.