kramann.info
© Guido Kramann

Login: Passwort:










1.3 Assemblerbeispiel

- Wie Maschinenprogramme bei Mikrocontrollern aussehen.

Was ist Assembler?

  • Um bei der direkten Programmierung von Maschinenbefehlen, nicht mit diesen Zahlencodierungen hantieren zu müssen, gibt es die Assembler-Programmiersprache, bei der den verschiedenen Befehlen Namen gegeben wurden.
  • Neben den Speicherstellen von Programm- und Datenspeicher, kommen den so genannten Registern der CPU eine besondere Bedeutung zu:
  • Für diese Register gibt es viele Maschinenbefehle zu deren Manipulation und zum Laden und Verschieben von deren Inhalten in oder von dem Arbeitsspeicher.
  • Diejenigen Register, für das es die meisten Manipulationsbefehle gibt und auf die diese auch mit den wenigsten Taktzyklen abgearbeitet werden können, können in Assembler beim ATmega32 über die Namen r0, r1,..,r16 angesprochen werden.
  • Ein Beispiel für einen Assembler-Befehl:
  • LDI
  • Der Assembler-Befehl LDI bedeutet: Lade in eines der Register r16..31 direkt eine bestimmte Zahl zwischen 0 und 255.
  • Folgerichtig muß der CPU neben der Tatsache, dass dieser Befehl abgearbeitet werden soll, noch mitgeteilt werden, in welches der Register die Zahl geladen werden soll und um welche Zahl es sich handelt.
  • Bei großzügigem Umgang mit dem Programmspeicher, hätte man den gesamten Befehl auf drei Byte verteilen können:
  • 1. Byte im Programmspeicher: Der Code für LDI
  • 2. Byte im Programmspeicher: Die Nummer des Registers, in das die Zahl geladen werden soll.
  • 3. Byte im Programmspeicher: Die Zahl, die geladen werden soll.
  • Tatsächlich benötigt der Befehl nur zwei Bytes.
  • Schauen wir uns dazu einen entsprechenden Auszug aus dem "AVR instruction set" an. In diesem Datenblatt sind alle Assemblerbefehle der AVR-Familie genau beschrieben.
  • In Assembler liest sich die entsprechende Befehlszeile z.B. so:
  • LDI r16,42
  • Damit wird direkt die Zahl 42 in das Register r16 geladen.
Assembler Befehle

Bild 1.3-1: Ein kurzer Auszug aus dem "AVR instruction set" (s. Material avr_instruction_set.pdf) - Teil des Überblicks mit dem Befehl LDI.

  • Obiges Bild zeigt einen Teil des Überblicks der bei den AVR-Prozessoren verfügbaren Assembler-Befehlen, hier ein Teil der Ladebefehle.
  • Das folgende Bild zeigt die genaue Beschreibung des LDI-Befehls:
Assembler Befehl LDI

Bild 1.3-2: Ein kurzer Auszug aus dem "AVR instruction set" (s. Material avr_instruction_set.pdf) - Der Befehl LDI.

  • Aus dem 16-Bit-Opcode entnehmen wir:
  • Das erste Nibble (= Tetrade = 4Bit) des Worts (= 16 Bit, da der Programmbus 16 Bit breit ist) enthält den Code für LDI: 1110
  • Das zweite Nibble enthält die eine Hälfte der notwendigen Bits zur Darstellung der zu ladenden Zahl.
  • Zwischen dem ersten Nibble und dem zweiten der Zahl, schiebt sich dann das Nibble, mit dem das Zielregisters codiert wird.

Datenblätter

  • Alle als Literatur angegebenen Bücher enthalten immer nur einen kleinen, Anwendungs-bezogenen Teil der Beschreibung der Mikrocontroller.
  • Sie dienen ausnahmslos dazu, den Einstieg in die Mikrocontroller-Programmierung zu finden.
  • Hat man diesen einmal gefunden, wird man stets auch auf die sehr ausführlichen Datenblätter (i.d.R. bei Mikrocontrollern hunderte an Seiten) zugreifen müssen, um Programme nach eigenen Vorstellungen schreiben zu können.

Geschwindigkeit

  • Da bei den Assembler-Befehlen bekannt ist, wieviele Taktzyklen deren Abarbeitung benötigt, also wieviele Schwingungen des Taktgenerators/Quarzes, kann man für ein Assemblerprogramm sehr leicht ausrechnen, wie lange der Mikrocontroller für dessen Abarbeitung benötigt.
  • Der beschriebene Befehl LDI benötigt, wie aus dem Datenblatt ersichtlich, nur einen Taktzyklus zur Abarbeitung.
  • Das wird verständlich, wenn man sich bewußt macht, dass nur der Programmbus benutzt wird und die 16 Bit des Befehls in einem Schritt geladen und abgearbeitet werden können.
Architektur des ATmega32

Bild 1.3-3: Überblick über die Architektur des ATmega32

Das erste Assemblerprogramm

  • Um ein erstes kleines Assemblerprogramm angeben zu können, werden zwei weitere Assembler-Befehle eingeführt:
  • RJMP - Ein Sprungbefehl, der es erlaubt eine Endlosschleife zu erzeugen
  • OUT - Ein Schiebebefehl, der es erlaubt, die in ein Register geladene Zahl nach einem Ausgangsport zu schieben.
  • Ports, kann man sagen, sind Register mit Außenwirkung: Den 8 Bits eines Ports entsprechen in der Regel 8 bestimmte Pins außen am Mikrocontroller.
  • Ein Port-Bit auf 1 gesetzt, führt bei entsprechender Konfiguration des Ports zu einer Spannung von 5V am korrespondierenden Pin, das gleiche Bit auf Null gesetzt zu einer Spannung von 0 Volt am gleichen Pin.
  • Das folgende Programm schiebt ständig das Byte 010000002 = 6410 in das Port-Register PORTC.
  • Da auf dem in der Laborübung verwendeten Testboard die 8 Bit von Port C mit Hilfe eines zweiten Mikrocontrollers dezimal dargestellt werden, ist nach Programmstart die Zahl 64 auf der 7-Segment-Anzeige zu sehen.
  • Um sichtbar anzuzeigen, dass das Programm läuft, könnte man auch an Pin 28 des Mikrocontrollers eine LED anschließen (s. weiter unten).
  • Hier also das Assembler-Programm innerhalb der Entwicklungs-Umgebung AVR-Studio:
Assembler-Programm

Bild 1.3-4: Assembler-Programm innerhalb der Entwicklungs-Umgebung AVR-Studio

  • Mit ; (Semikolon) werden Zeilenkommentare abgetrennt.
  • Dem rjmp Befehl wird einfach eine frei wählbare Marken-Bezeichnung hinzugefügt, die sich weiter oben im Programm-Code wieder findet und den Zielpunkt des Sprungs bezeichnet.
  • Im echten Maschinen-Code wird bei rjmp die Anzahl an Bytes angegeben, die das Programm von dieser Stelle aus vor- oder zurückspringen soll.
  • Die Arbeit, das auszurechnen, nimmt einem der Assembler-Compiler ab.
  • Gerne wird das Register r16 mit "akku" bezeichnet, da die in alten Prozessoren das Arbeitsregister so bezeichnet war. Dies wird mit .DEF bewerkstelligt.
  • Damit der Compiler weiß, für welchen Mikrocontroller das Programm compiliert werden soll, findet sich am Anfang eine Einfügung der passenden Library.
  • Der folgende Stromlaufplan zeigt nun noch die Minimalbeschaltung des ATmega32, die notwendig ist, um das Programm ausprobieren zu können.
  • Neben der Stromversorgung, könnte noch ein Quarz angeschlossen sein, da es aber auch einen internen RC-Taktgenerator gibt, ist dies nicht unbedingt erforderlich.
  • Außerdem werden wir den ATmega32 über den so genannten SPI-Bus programmieren. Dieser besteht aus einer Masse-Leitung (GND=Ground), und vier Datenleitungen.
  • Diese könnten auch noch zu einer Buchse herausgeführt werden, dann wäre die Schaltung "autark"
  • (Wir werden noch sehen, dass der SPI-Bus nicht nur zum Programmieren (Flashen des Programmspeichers), sondern auch zum Datenaustausch zwischen mehreren Mikrocontrollern verwendet werden kann.)
Stromlaufplan zum Test des Programms

Bild 1.3-5: Stromlaufplan zum Test des Programms

  • Schwerpunktmäßig wird die Programmierung in dieser Veranstaltung in C erfolgen.
  • Im Rahmen einiger spezieller Anwendungen, werden wir aber auch Assembler verwenden und unseren Befehlsumfang noch ein wenig erweitern.