AVR-Tutorial

Aus der Mikrocontroller.net Artikelsammlung, mit Beiträgen verschiedener Autoren (siehe Versionsgeschichte)
Wechseln zu: Navigation, Suche

Ausser diesem Tutorial gibt es noch das AVR-GCC-Tutorial sowie die Artikel in der Kategorie:avr-gcc Tutorial.

Aufbau des Tutorials

Falls ihr irgendwelche Fragen habt, stellt diese bitte im Forum!

Was ist ein Mikrocontroller?

Ein Mikrocontroller ist einem Prozessor ähnlich. Der Unterschied zu PC-Prozessoren besteht darin, dass bei einem Mikrocontroller Speicher, Digital- und Analog-Ein- und -Ausgänge etc. meist auf einem einzigen Chip integriert sind, so dass eine Mikrocontroller-Anwendung oft mit wenigen Bauteilen auskommt.

Mikrocontroller werden als erstes an der Bit-Zahl des internen Datenbusses unterschieden: 4bit, 8bit, 16bit und 32bit. Diese Bit-Zahl kann man als die Länge der Daten interpretieren, die der Controller in einem Befehl verarbeiten kann. Die größte in 8 Bit (= 1 Byte) darstellbare Zahl ist die 255, somit kann ein 8-Bit-Mikrocontroller z. B. in einem Additionsbefehl immer nur Zahlen kleiner-gleich 255 verarbeiten. Zur Bearbeitung von größeren Zahlen werden dann jeweils mehrere Befehle hintereinander benötigt, was natürlich länger dauert. Ein Mikrocontroller braucht zum Betrieb, wie jeder andere Prozessor auch, einen Takt. Die maximale Taktfrequenz mit der ein Controller betrieben werden kann, reicht von 1 MHz bei alten Controllern bis hin zu über 100 MHz bei teuren 32-Bittern. Diese Taktfrequenz sagt jedoch noch nichts über die tatsächliche Geschwindigkeit eines Prozessors aus. So wird z. B. bei den meisten 8051-Controllern die Frequenz intern durch 12 geteilt, ein mit 24 MHz getakteter 8051 arbeitet also eigentlich nur mit 2 MHz. Benötigt dieser dann für einen Befehl durchschnittlich 2 Taktzyklen, so bleiben "nur" noch 1 Mio. Befehle pro Sekunde übrig - ein AVR, der ungeteilt mit 8MHz arbeitet und für die meisten Befehle nur einen Zyklus braucht, schafft dagegen fast 8 Mio. Befehle pro Sekunde.

Wozu ist ein Mikrocontroller gut?

Hier ein paar Beispiele, für welche Aufgaben Mikrocontroller verwendet werden (können):

  • Ladegeräte
  • Motorsteuerungen
  • Roboter
  • Messwerterfassung (z. B. Drehzahlmessung im Auto)
  • Temperaturregler
  • MP3-Player
  • Schaltuhren
  • Alarmanlagen
  • LED-Matrizen (Blinkmuster etc.)
  • Zur Steuerung und Regulierung von Flüssigkeiten
  • ...

Welchen Mikrocontroller soll ich verwenden?

Typische Anforderungen an einen Mikrocontroller für Hobbyanwender (einige davon konkurrieren miteinander):

  • Gute Beschaffbarkeit und geringer Preis
  • Handliche Bauform: Ein Controller mit 20 Pins ist leichter zu handhaben als einer mit 128
  • Flash-ROM: Der Controller sollte mindestens 1000 mal neu programmiert werden können
  • In-System-Programmierbarkeit (ISP): Man benötigt kein teures Programmiergerät und muss den Controller zur Programmierung nicht aus der Schaltung entfernen
  • Kostenlose Software verfügbar: Assembler bekommt man praktisch immer kostenlos

Weitere Entscheidungskriterien sind im Artikel Entscheidung Mikrocontroller zusammengefasst.

Viele dieser Anforderungen werden von den 8-bit-AVR-Controllern von Atmel erfüllt. Deshalb werde ich einen AVR, genauer gesagt den ATmega8, in diesem Tutorial einsetzen.

Und damit kein Missverständnis aufkommt: So etwas wie den "besten" Controller gibt es nicht. Es hängt immer von der Aufgabenstellung ab, welcher Controller gut dafür geeignet ist. Natürlich haben sich einige Controller als Standardtypen in der Praxis durchgesetzt, mit denen man in vielen Fällen ein gutes Auslangen hat und die mit ihrer Leistungsfähigkeit einen weiten Bereich abdecken können. Der ATmega8 ist z. B. so einer. Aber daneben gibt es noch viele andere.

In welcher Sprache soll programmiert werden?

Je nach Anforderungsfall bieten sich verschiedene Sprachen an:

Vorbemerkung

Warum ist dieses Tutorial für Assembler geschrieben, wo es doch einen kostenlosen C-Compiler (WinAVR, AVR-GCC) und einen billigen Basic-Compiler gibt?

Assembler ist für den Einstieg "von der Pike auf" am besten geeignet. Nur wenn man Assembler anwendet, lernt man den Aufbau eines Mikrocontrollers richtig kennen und kann ihn dadurch besser nutzen; außerdem stößt man bei jedem Compiler irgendwann mal auf Probleme, die sich nur oder besser durch das Verwenden von Assemblercode lösen lassen und sei es nur, dass man das vom Compiler generierte Assemblerlisting studiert, um zu entscheiden, ob und wie man eine bestimmte Sequenz im C-Code umschreiben soll, um dem Compiler das Optimieren zu ermöglichen/erleichtern.

Allerdings muss auch erwähnt werden, dass das Programmieren in Assembler besonders fehleranfällig ist und dass es damit besonders lange dauert, bis das Programm erste Ergebnisse liefert. Genau aus diesem Grund wurden "höhere" Programmiersprachen erfunden, weil man damit nicht immer wieder "das Rad neu erfinden" muss. Das gilt besonders, wenn vorbereitete Programmblöcke zur Verfügung stehen, die man miteinander kombinieren kann. Auch der Geschwindigkeitsvorteil ist selten und nur bei kritischen Anwendungen von Bedeutung. Heutige Compiler generieren zudem oft schnelleren oder kleineren Code als handgeschriebene Assemblerroutinen. Wer regelmäßig programmieren und auch längere Programme schreiben möchte, dem sei deshalb geraten, nach diesem Assembler-Tutorial C zu lernen, zum Beispiel mit dem AVR-GCC-Tutorial.

Wer C schon kann, für den bietet es sich an, das Tutorial parallel in C und Assembler abzuarbeiten. Die meisten hier vorgestellten Assemblerprogramme lassen sich relativ einfach in C umsetzen. Dabei sollte großes Augenmerk darauf gelegt werden, dass die dem Programm zugrunde liegende Idee verstanden wurde. Nur so ist ein vernünftiges Umsetzen von Assembler nach C (oder umgekehrt) möglich. Völlig verkehrt wäre es, nach sich entsprechenden 'Befehlen' zu suchen und zu glauben, damit hätte man dann ein Programm von Assembler nach C übersetzt.

Assembler

Die Vorteile von Assembler wurden bereits genannt:

- direkter Einstieg in die Hardware - keine Abhänhigkeit von Compilern und deren Fehlern, bzw Misinterpretation - optimaler Code erzeugbar - sehr schnell in der Ausführung - Feintuning der Geschwindigkeitsreserven - kurzer Weg zu hardwarenahen Funktionen - sehr langer Weg zu komplexeren Funktionen

Basic

Basic bietet den einfachsten Einstieg, wenn man bereits eine höhere Programmiersprache beherrscht und wenig Kenntnisse über die Hardware hat und sich zudem auf komplexere Steuerungen ohne optimale Ausschöpfung der HW-Resourcen beschränkt.

- direkter Einstieg in komplizierte Abläufe - einfacher Einstieg in die Programmiersprache - Abhängigkeit von Compilern und deren Fehlern - Code ist schnell erzeugbar - sehr langsam in der Ausführung - kurzer Weg zu komplexeren Funktionen - keine hardwarenahen Funktionen verfügbar

C

C bietet den optimalen Kompromiss, da man durch Funktionen und Prozeduren sehr leicht hochsprachliche Strukturen und Datentypen nutzen kann und dennoch sehr effektiven Code produzieren (lassen) kann. Allerdings ist C strukturell am schwierigsten zu verstehen.

- schwieriger Einstieg in die Programmiersprache - Abhängigkeit von Compilern und deren Fehlern, allerdings verifizierbar - Code ist automatisch erzeugbar, manuell aber kompliziert - sehr schnell in der Ausführung - akzeptabler Weg zu komplexeren Funktionen - hardwarenahe Funktionen verfügbar - mit Assembler kombinierbar

Mit Betriebssystem oder ohne ?

Betriebssysteme erfreuen sich auch auf embedded UCs inzwischen immer grösserer Beliebtheit. Multitasking- und Echtzeitanwendungen lassen sich so manchmal viel einfacher implementieren, da standardisierte Schnittstellen und Zugriffsmethoden verwendet werden und die zur Verfühung stehenden Libs und SW-Pakete genutzt werden können. Es ist jedoch stets abzuwägen, ob der Mehraufwand der Einführung eines Multitasking-OS und der damit in Verbindung stehende Programmieraufwand mit dem potenziellen Ersparnis an Denk- und Planungszeit, die zur "händischen" Realisation der benötigten Funktionen benötigt würde, im Verhältnis steht. Oftmals wird in der Industrie nach wie vor aus Kostengründen auf ein OS verzichtet, weil es einen nicht zu vertretenden overhead birgt und die Ausnutzung der Rechenpower - gerade kleiner UCs - stark herabsetzt, was widerum die Echtzeitfähigkeit verschlechtert.

Mit OS

  • Einführung des Multitasking-OS kostet Zeit und Geld
  • Prinzipiell Echtzeitfunktion einfacher möglich, da ein Multitasking die parallele Reaktion des Systems auf äussere Einflüsse erleichtert
  • Multitaskingfunktion ist vorimplementiert - muss nur genutzt werden
  • Implementierung des Multtaskings kostet weniger Zeit
  • die Multitasking-relevanten Teile des Codes sind OS-spezifisch und nicht übertragbar
  • der gesamte Code ist weniger gut auf andere Controller portierbar
  • μC ist pauschal mit viel nicht nutzbarem overhead belastet
  • Es muss tendenziell ein teuerer μC eingesetzt werden

Ohne OS

  • Keine Kosten für die Einführung eines Multitasking-OS
  • Multitaskingfunktion muss selbst komplett implementiert werden
  • Implementierung des Multtaskings kostet mehr Zeit
  • die Multitasking-relevanten Teile des Codes sind voll übertragbar
  • der gesamte Code ist besser auf andere Controller portierbar
  • μC ist mit viel weniger overhead belastet, da nur benötigte Funktionen eingebaut werden
  • Echtzeitfunktion ebenfalls möglich, - muss einerseits genauer betrachtet werden, - ist andererseits effektiver und besitzt höhere Reserve
  • Es kann tendenziell ein preiswerterer μC eingesetzt werden

Weitere Informationen

Weiterführende Informationen u. A. zu den berüchtigten Fuse-Bits, zu Programmier-Hard- und Software, dem AVR Softwarepool und einer Checkliste mit Hinweisen zur Lösung üblicher Probleme finden sich im Hauptartikel AVR.

vor zum ersten Kapitel