Start AVR-KursStartseitenicht verfügbar

3. Ports und Assembler


Die Abbildung links zeigt die Pinbelegung eines ATTiny 2313. Bis aus wenige Ausnahmen sind alle Anschlüsse als Ein-Ausgabe-Leitungen zu verwenden. Über Pin 20 wird in der Regel +5V zugeführt, die Betriebsspannung. Erlaubt sind 2,8V ... 5,5V. Am Pin 10 wird der andere Pol der Spannungsquelle, der Minuspol, angeschlossen. Diesen Spannungspegel bezeichnet man auch als Masse oder Ground-Potential. Manchmal wird auch 0 V dazu gesagt.

Pin 1 wird während des Programmierens und als Resetleitung gebraucht. Ein Low (=0V) setzt den Prozessor zurück oder ermöglicht das Programmieren des Flashprogrammspeichers. Wir der Pin als Portleitung programmiert, dann fallen die eben erwähnten Funktionen flach, der Chip kann also nicht mehr neu programmiert werden - also Vorsicht!

Ähnlich kritisch sind Pin 4 und Pin 5. Hier wird im Regelbetrieb der Schwingquarz angeschlossen. Die Leitungen PA0 und PA1 können nur dann als Ein-Ausgänge programmiert werden, wenn kein Quarz angeschlossen ist. Damit der Prozessor dann noch läuft, muss er mit dem internen Taktgeber verbunden sein. Eingestellt wird das durch sogenannte Fuse-Bits. Achtung falsche Einstellung führt auch hier dazu, dass der Prozessor nicht mehr arbeitet oder schlimmstenfalls nicht mehr programmierbar ist. Mehr dazu im Kapitel "Erste Programmierung".

Pin2 und Pin 3 sind blockiert, wenn die serielle Schnittstelle des Chips benutzt werden soll. Das ist die Leitung, über die man sich mit dem AVR über die RS232-Leitung des PC (sofern vorhanden) unterhalten kann, was meist zum Übermitteln von Befehlen während der Laufzeit oder zum Abfragen von Ergebnissen genutzt wird.

Die anderen Pins dienen dann im Normalfall als Leitungen, über die digitale TTL-Signale an den AVR gelangen oder über die er selbst TTL-Pegel (0V oder 5V) an die Periferie liefert. Freilich haben auch diese anderen Pins meist weitere Doppel- oder gar Dreifachbelegungen, deren Verwendung jedoch stark vom jeweiligen Einsatzzweck abhängt. In jedem Fall müssen die Pins 17 bis 19 auch als Programmierleitungen zur Verfügung stehen, wenn der Chip in der Anwenderschaltung programmiert werden soll. Locker beschaltet, kann man sie dennoch als Portleitungen nutzen.

Der Begriff Port fasst einzelne In-Out-Leitungen zu gemeinsam ansprechbaren Einheiten zusammen. Der ATTiny 2313 enthält die Ports PA, PB und PD. Port A kann nur, wie oben geschildert, in Sonderfällen genutzt werden. Port B besteht aus 8 Leitungen, PB0 bis PB7 und von Port D sind von den eigentlich 7 Leitungen PD0 bis PD6 nur PD2 bis PD6 frei nutzbar, wenn man die RS232-Schnittstelle benötigt. Weitere Leitungen fallen weg, wenn deren Sonderfunktion benötigt wird, dazu später mehr.

Jede Portleitung kann als Eingang oder Ausgang programiert werden. Nach Einschalten der Betriebsspannung sind alle Leitungen als Eingänge programmiert. Zum Verändern der Eigenschaft dient das Datenrichtungsregister (data direction register = DDR), das jeder Port besitzt. Eine 0 im Bit setzt die Leitung als Eingabeleitung, eine 1 setzt die Leitung als Ausgang. Eingabeleitungen werden über das Inputregister (PIN) des Ports eingelesen. Ausgaben erreichen über das Ausgaberegister (PORT) die Ausgabepins. (Achtung PIN = Eingabeport; Pin = Anschluss am AVR) Das Ausgaberegister kann auch gelesen werden, liefert jedoch nicht den Zustand der Eingangsleitungen sondern der zuletzt ausgegebenen Zustand des Ausgaberegisters zurück!

Portleitungen kann man einzeln über die Speicheraddresse des Ports und die Nummer des Bits ansprechen. Dazu muss man wissen wo die Portregister in der Speicherlandschaft angesiedelt sind.

Entnehmen kann diese Info dem Datenblatt (PDF-Datei) in der Sektion "Register Summary". Die folgende Tabelle zeigt die grundsätzlich nutzbaren Leitungen und ihre Portadressen. Achtung: die Ports gehören wir die anderen Steuerregister des Prozessors zu den Spezialregistern (special function registers = sfr) und liegen daher in einem eigenen Speicherbereich, der von 0x00 bis 0x3F durchnumeriert ist. Die in der Tabelle aufgeführten Nummern sind nur in Verbindung mit In-Out-Befehlen nutzbar. Sie können also nicht zu arithmetischen Zwecken verwendet werden.

Adresse hex
Name
Bit 7
Bit 6
Bit 5
Bit 4
Bit 3
Bit 2
Bit 1
Bit 0
0x1B
PORTA
0x1A
DDRA
0x19
PINA
0x18
PORTB
0x17
DDRB
0x16
PINB
0x12
PORTD
0x11
DDRD
0x10
PIND

Beispiel:
setzt die Portleitung 0 von Port B als Ausgang und gibt dort einen kurzen Einzelimpuls aus
Achtung: die Zuweisung erfolgt stets von rechts nach links.

ldi       0x11, 0b00000001; Lade Register R17 mit dem Binärwert 1
out      0x17, 0x11             ; Gib den Inhalt von R17 nach DDRB aus ( setzt die Portleitung 0 als Ausgang)
ldi       0x11, 0x00             ; Lade R17 mit lauter Nullen in allen Bits
out      0x18, 0x11             ; Setze die Portleitung PB0 auf 0
ldi       0x11, 0x01             ; Lade R17 mit einer 1 in Bit 0
out      0x18, 0x11             ; Setze die Portleitung PB0 auf 1

Mit reinen Zahlen ist das sehr verwirrend und unübersichtlich. Der Assembler hilft hier, indem man für häufig wiederkehrende Adressen symbolische Namen vergeben kann. Und selbst diese Aufgabe ist von den Entwicklern der Software bereits erledigt worden. Zu jedem einzelnen Prozessortyp gibt es ein sogenanntes "Definitionsfile" in dem solche Vereinbarungen bereits getroffen sind. Der folgende Ausschnitt aus der Definitiondatei "tn2313def.inc" aus dem Programmverzeichnis des Assemblers macht dies für die Ports des ATTiny 2313 deutlich. Achtung: die Zuweisung erfolgt stets von rechts nach links.

.equ DDRA = 0x1A
.equ PINA = 0x19
.equ PORTB = 0x18
.equ DDRB = 0x17
.equ PINB = 0x16
.equ PORTD = 0x12
.equ DDRD = 0x11
.equ PIND = 0x10

Der Pseudo-Befehl ".equ" leitet so eine Definition eines Namens für eine Adresse ein. Es folgt der Name und nach einem "="-Zeichen die Adresse, dezimal oder hexadezimal ist egal. Ähnliche Definitionen gibt es auch für die einzelnen Portbits.

.equ PINB1 = 1

Dieser Pseudobefehl belegt die Variable PINB1 mit dem Wert 1. Um zu wissen welche Pseudonyme es insgesamt gibt, sollte man die Definitionsdatei kennen oder wenigstens zum Nachschalgen bereit halten.

Nicht nur die Ports sind mit Pseudonymen ansprechbar, auch die normalen Arbeitsregister, mit denen gerechnet wird, haben Namen und zwar:

Speicherstelle
Name
0x1F
R31
...
...
0x00
R0

Das obige Beispiel wird dadurch um ein wesentliches leichter lesbar.
Achtung: die Zuweisung erfolgt stets von rechts nach links.

ldi       R17, 0b00000001  ; Lade Register R17 mit dem Binärwert 1
out      DDRB, R17             ; Gib den Inhalt von R17 nach DDRB aus ( setzt die Portleitung 0 als Ausgang)
ldi       R17, 0x00                ; Lade R17 mit lauter Nullen in allen Bits
out      PORTB, R17           ; Setze die Portleitung PB0 auf 0
ldi       R17, 0x01                ; Lade R17 mit einer 1 in Bit 0      0x01 = 0b00000001
out      PORTB, R17           ; Setze die Portleitung PB0 auf 1

Das folgende Beispiel liest über das Portbit 3 von Port D die anliegende Information ein.
Achtung: die Zuweisung erfolgt stets von rechts nach links.

in       R16, DDRD             ; Lies den INhalt des Datenrichtungsregisters von Port D ein
andi  R16, 0b11110111  ; lösche das Bit 3 (= setze es auf Null)
out    DDRD, R16             ; Schreibe den Inhalt von R16 zurück nach DDRD, Leitung 3 ist jetzt sicher ein Eingang
in       R16, PIND               ; lies den Eingang von Port D
andi   R16, 0b00001000 ; isoliere das Bit 3

Das Byte in R16 hat jetzt den Wert 8, falls Bit 3 gesetzt ist oder 0, falls Bit 3 = 0 war. Auf diese Werte kann in weiteren Programm getestet werden.

Zu den beiden andi-Befehlen ist zu sagen, dass ihnen die bitweise Und-Funktion zugrunde liegt. Ein Bit wird im Ergebnis zu 1, wenn in beiden Operanden das korrespondierende gesetzt war. War eines der Ausgangsbits oder beide auf 0, so ist das Ergebnis 0 (siehe dazu die folgende Tabelle). Neben dem andi-Befehl, der als zweiten Operanden eine Konstante hat, gibt es noch den and-Befehl, der auf zwei Register wirkt. Zielregister ist stets dasjenige, welches links vom Komma steht.

 
Bit 7
Bit 6
Bit 5
Bit 4
Bit 3
Bit 2
Bit 1
Bit 0
Byte 1
1
1
1
0
1
0
0
1
Byte 2
0
1
1
1
1
1
1
0
and / andi
Ergebnis
0
1
1
0
1
0
0
0

Die obigen Methoden sind gut, wenn auf mehrere Portleitungen gleichzeitig zugegriffen werden soll. Sind nur einzelne Portleitungen von PORT und DDR zu setzen kann man diese Bitweise erledigen:

cbi    DDRD, 3  ; löscht das Bit 3 in DDRD

sbi    PORTB, 0; setzt das Bit 0 in PORTB

Achtung diese Befehle sind nur für die unteren SFR von 0x00 bis 0x1F anwendbar! Ähnliche Befehle gibt es auch für die normalen Register aber dort müssen die Bits anders codiert werden:

cbr    R16, (1<<5)  ; löscht Bit 5 in Register 16

sbr    R17, (1<<3)  ; setzt Bit 3 in Register 17

Diese Funktionen sind nur für die oberen Register von R16 bis R31 anwendbar! Das hängt damit zusammen, dass intern ein andi mit der angegebenen binären Konstanten (1<<3) = 0b00001000 durchgeführt wird und diese Operation nur für die oberen Register definiert ist.

Ob ein Bit in einem IO-Register gesetzt ist oder nicht lässt sicjh durch die Sprungbefehle sbic (skip if bit in IO clear) und sbis (skip if bit in IO set) testen. Skip heißt überspringen. Der dem sbis- Befehl folgende Befehl wird also übersprungen, falls das Bit im IO-Register gesetzt ist.

sbis     PIND, PIND3   ; Überspringe den nächsten Befehl, falls Bit 3 in PIND gesetzt ist
rjmp     ist_auf_0         ; An der Programmmarke beginnt die Behandlung des Falls, dass Bit 3 nicht gesetzt ist
ist_auf_1:
ldi        R16, 0x5A       ; Behandlungsroutine für Bit 3 = 1

....

rjmp     weiter
ist_auf_0:
ldi        R16, 0x24       ; Behandlungsroutine für Bit 3 = 0

....

weiter:

; weiterer gemeinsamer Programmablauf

 

 


 

Start AVR-KursAn den Seitenbeginnnicht verfügbar