ISBN 978-3-89576-322-9
Elektor-Verlag GmbH 52072 Aachen www.elektor.de
Das Buch wendet sich an alle, die bisher mit dem Arduino programmiert haben und nun nach technischen Möglichkeiten und Wegen suchen, ihre Elektronik- und Programmierkenntnisse zu erweitern. Dazu eignet sich die AVR-Programmierung im besonderen Maße.
AVR-PROGRAMMIERUNG FÜR QUEREINSTEIGER
AVR-Programmierung für Quereinsteiger besteht aus zwei Teilen. Im ersten Teil wird in einfachen Worten erklärt, wie eine MCU (= Micro Controller Unit) im Detail arbeitet. Dem folgt eine Einführung in die Programmiersprache C. Anschließend taucht der Leser im zweiten Teil des Buches in die Welt der Register und ihre Bits ein. Dort findet man auch ein umfangreiches Glossar aller Register- und Bit-Namen. Das Buch dient somit auch als Nachschlagewerk, wenn man sich durch das Datenblatt oder andere Texte arbeiten muss.
●
Auf ein abgeschlossenes Studium der Elektrotechnik (Schwerpunkt: Mess-, Regel- und Datentechnik) folgten etliche Jahre in der Industrie. Vor 20 Jahren brach er mit seinem Motorrad zu einer Weltumrundung auf (das war das Beste, was er sich in seinem Leben angetan hat).
Atmel AVR ist eine 8-Bit-Mikrocontroller-Familie des Herstellers Atmel. Diese Controller sind wegen ihres einfachen Aufbaus, ihrer leichten Programmierbarkeit, den kostenlosen Entwicklungswerkzeugen und der Verfügbarkeit in DIP-Gehäuseformen auch bei Elektronikern und Makern äußerst beliebt. Darüber hinaus sind diese Controller bereits ab zwei Euro erhältlich. Im Arduino UNO-Board wird der ATmega328 verwendet.
AVR-PROGRAMMIERUNG
JÜRGEN D. HENNING
Jürgen D. Henning
FÜR QUEREINSTEIGER
SHARE
AVR-PROGRAMMIERUNG
DESIGN
FÜR QUEREINSTEIGER
Jürgen D. Henning LEARN
DESIGN
SHARE
LEARN
LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● S RN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE SIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● RN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE
AVR-Programmierung für Quereinsteiger.indd All Pages
25-10-16 13:41
AVR-Programmierung für Quereinsteiger Für ATmega8 und ATmega328
● Jürgen D. Henning
an Elektor Publication LEARN
AVR Programmierung DE 160929.indd 3
DESIGN
SHARE
25-10-16 11:45
●
© 2016: Elektor Verlag GmbH, Aachen.
●
Alle Rechte vorbehalten.
1. Auflage 2016
Die in diesem Buch veröffentlichten Beiträge, insbesondere alle Aufsätze und Artikel sowie alle Entwürfe, Pläne, Zeichnungen und Illustrationen sind urheberrechtlich geschützt. Ihre auch auszugsweise Vervielfältigung und Verbreitung ist grundsätzlich nur mit vorheriger schriftlicher Zustimmung des Herausgebers gestattet. Die Informationen im vorliegenden Buch werden ohne Rücksicht auf einen eventuellen Patentschutz veröffentlicht. Die in diesem Buch erwähnten Soft- und Hardwarebezeichnungen können auch dann eingetragene Warenzeichen sein, wenn darauf nicht besonders hingewiesen wird. Sie gehören dem jeweiligen Warenzeicheninhaber und unterliegen gesetzlichen Bestimmungen. Bei der Zusammenstellung von Texten und Abbildungen wurde mit größter Sorgfalt vorgegangen. Trotzdem können Fehler nicht vollständig ausgeschlossen werden. Verlag, Herausgeber und Autor können für fehlerhafte Angaben und deren Folgen weder eine juristische Verantwortung noch irgendeine Haftung übernehmen. Für die Mitteilung eventueller Fehler sind Verlag und Autor dankbar. Umschlaggestaltung: Elektor, Aachen Satz und Aufmachung: D-Vision, Julian van den Berg | Oss (NL) Druck: WILCO, Amersfoort (NL) Printed in the Netherlands
●
ISBN 978-3-89576-322-9
Elektor-Verlag GmbH, Aachen www.elektor.de
Elektor ist Teil der Unternehmensgruppe Elektor International Media (EIM), der weltweit wichtigsten Quelle für technische Informationen und Elektronik-Produkte für Ingenieure und Elektronik-Entwickler und für Firmen, die diese Fachleute beschäftigen. Das internationale Team von Elektor entwickelt Tag für Tag hochwertige Inhalte für Entwickler und DIYElektroniker, die über verschiedene Medien (Magazine, Videos, digitale Medien sowie Social Media) in zahlreichen Sprachen verbreitet werden. www.elektor.com
LEARN
AVR Programmierung DE 160929.indd 4
DESIGN
SHARE
25-10-16 11:45
Inhalt Einleitung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 Die Pins alphabetisch . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 Kapitel 1 • Programmierung des ATmega8 und des ATmega328 . . . . . . . . . . . . . . 15 1.1 Was Sie auf den nächsten Seiten erwartet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19 1.2 Was ist eine Micro Controller Unit (MCU)? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20 1.3 Woraus besteht eine einfache CPU? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21 1.3.1 Das Status-Register . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25 1.4 Was braucht man um die CPU (nicht MCU) herum? . . . . . . . . . . . . . . . . . . . . . . . 26 1.4.1 Speicher . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 1.4.2 Wie sieht die CPU den Speicher . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30 1.5 Wie bekommt man ein Programm in die MCU? . . . . . . . . . . . . . . . . . . . . . . . . . . 31 1.5.1 Bootloader . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33 1.5.2 SPI (Serial Programming Interface) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34 1.5.3 Parallele und HV-Programmierung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35 1.6 Das erste Programm zum Laufen bringen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35 1.6.1 Das erste Assembler-Programm . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38 1.6.2 Das Gleiche noch einmal in C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41 1.6.3 Eine kleine Vereinfachung der Arbeit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42 1.6.4 Arbeiten mit einem Mini-Entwicklungsboard . . . . . . . . . . . . . . . . . . . . . . . . . . 43 Kapitel 2 • Die Register . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46 Kapitel 3 • Der Stack . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47 Kapitel 4 • Programmieren in C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50 4.1 Editor, Compiler, Linker, Loader, Debugger und IDE . . . . . . . . . . . . . . . . . . . . . . 53 4.2 Das Semikolon in C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54 4.3 Die Programmiersprache C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55 4.3.1 Die mitgelieferten Datentypen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55 4.3.2 Defines, Makros und Include-Dateien . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57 4.3.3 Kommentare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59 4.3.4 Blöcke . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60 4.3.5 Unterprogramme . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61 4.3.6 Arrays, Strings und Matrizen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
●5
AVR Programmierung DE 160929.indd 5
25-10-16 11:45
AVR-Programmierung für Quereinsteiger 4.3.7 Pointer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66 4.3.8 Zusammengesetzte Typen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70 4.3.9 Anweisungen in C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72 4.3.10 Schleifen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77 4.3.11 Goto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79 4.3.12 return . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80 4.3.13 continue . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80 4.3.14 break . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80 4.4 Bit-Manipulationen in C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80 4.5 Einführung in die AVR-libc . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87 4.6 Das 'Betriebssystem' des kleinen Mannes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99 Kapitel 5 • Interrupts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103 5.1 Nebeneffekte und Nested Interrupting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104 5.2 Interrupt-Vektor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105 5.3 Interrupts in C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109 5.4 Externe Interrupts INT0 und INT1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112 5.4.1 ATmega8 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113 5.4.2 ATmega328 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114 5.5 PCINT (Pin Change INTerrupt) nur beim ATmega328 . . . . . . . . . . . . . . . . . . . . . 115 5.5.1 Die Register für PCINT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116 Kapitel 6 • Schlafmodi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117 6.1 Schlafmodi des ATmega . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117 6.1.1 Sleep-Mode im ATmega8 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118 6.1.2 Sleep-Mode im ATmega328 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118 Kapitel 7 • Paralleler Input/Output . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120 7.1 ATmega, Register für die Nutzung der Parallelports . . . . . . . . . . . . . . . . . . . . . . 122 7.1.1 Parallelports im ATmega8 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123 7.1.2 Parallelports im ATmega328 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123 Kapitel 8 • Timer und Counter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124 8.1 Waveform-Generation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126 8.1.1 Rechteckgenerator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126
●6
AVR Programmierung DE 160929.indd 6
25-10-16 11:45
Inhalt 8.1.2 PWM und schneller PWM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127 8.1.3 Phasenkorrekte PWM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128 8.1.4 Input Capture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129 8.1.5 Vergleichsregister . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130 8.1.6 Race-Conditions bei Änderung der Werte im Vergleichsregister . . . . . . . . . . . . 131 8.1.7 Forced Output Compare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132 8.2 Timer/Counter Interrupts im ATmega . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132 8.2.1 ATmega8, Timer/Counter-Interrupts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132 8.2.2 ATmega328, Timer/Counter-Interrupts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132 8.3 Timer/Counter 0 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133 8.3.1 ATmega8: Timer/Counter 0 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133 8.3.2 ATmega328: Timer/Counter 0 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134 8.4 Timer/Counter 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137 8.4.1 ATmega8: Die Register des Timers/Counters 2 . . . . . . . . . . . . . . . . . . . . . . . 137 8.4.2 ATmega328: Die Register des Timers/Counters 2 . . . . . . . . . . . . . . . . . . . . . . 140 8.5 Timer/Counter 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144 8.5.1 ATmega: Die Register des Timers/Counters 1 . . . . . . . . . . . . . . . . . . . . . . . . 144 8.5.2 ATmega8: Die Register des Timers/Counters 1 . . . . . . . . . . . . . . . . . . . . . . . 147 8.5.3 ATmega328: Die Register des Timers/Counters 1 . . . . . . . . . . . . . . . . . . . . . . 148 Kapitel 9 • Serielle Datenübertragungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 150 9.1 SPI (Serial Peripheral Interface) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151 9.1.1 ATmega: Die Register für SPI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 152 9.2 TWI (Two Wire Interface) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154 9.2.1 Takt- und Daten-Leitung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157 9.2.2 Arbitration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 158 9.2.3 Sleep Mode des TWI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 159 9.2.4 Allgemeine Erklärung der TWI-Funktion . . . . . . . . . . . . . . . . . . . . . . . . . . . . 159 9.2.5 TWI-Interrupt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 159 9.2.6 ATmega: Die Register für TWI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163 9.2.7 ATmega328: Ein Register mehr für TWI . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165 9.3 USART Universal Syn- & Asynchronous Receiver Transmitter . . . . . . . . . . . . . . . 166
●7
AVR Programmierung DE 160929.indd 7
25-10-16 11:45
AVR-Programmierung für Quereinsteiger 9.3.1 USART-Interrupts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171 9.3.2 MPCM (Multi Processor Communication Modus) . . . . . . . . . . . . . . . . . . . . . . . 171 9.3.3 ATmega8: Die Register des USART . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 173 9.3.4 ATmega328: Die Register des USART . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 177 9.4 ATmega328: SPI über den USART . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 178 9.4.1 Register für SPI über den USART . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 179 Kapitel 10 • Analog-Digital-Konverter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 182 10.1 Noise Canceller . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 184 10.2 ATmega328: Der Temperatursensor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 184 10.3 ATmega: Die Register des ADC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 185 10.4 Atmega328: ADC-Register, die nur der ATmega328 hat . . . . . . . . . . . . . . . . . . 187 Kapitel 11 • Analog Comparator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 189 11.1 ATmega: Die Register für den 'Analog Comparator' . . . . . . . . . . . . . . . . . . . . . 190 11.2 ATmega8: Die Register für den 'Analog Comparator' . . . . . . . . . . . . . . . . . . . . 191 11.3 ATmega328: Die Register für den 'Analog Comparator' . . . . . . . . . . . . . . . . . . 192 Kapitel 12 • Das gibt es nur im ATmega328 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194 12.1 Clock Prescaler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194 12.2 General Purpose I/O-Register . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194 12.3 PRR (Power Reduction Register) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 195 12.4 debugWIRE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 195 Kapitel 13 • Lock-Bits und Fuses . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197 13.1 ATmega: Lock-Bits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197 13.2 Fuses . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 198 13.2.1 ATmega8: Fuses Low Byte . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 198 13.2.2 ATmega328: Fuses Low Byte . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 199 13.2.3 ATmega: Fuses High Byte . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 200 13.2.4 ATmega8: Fuses High Byte . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 201 13.2.5 ATmega328: Fuses High Byte . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 201 13.2.6 ATmega328: Extended Fuse Bits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 201 Kapitel 14 • Programmierung des EEPROM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 202 14.1 ATmega: Die Register, um das EEPROM zu programmieren . . . . . . . . . . . . . . . 202
●8
AVR Programmierung DE 160929.indd 8
25-10-16 11:45
Inhalt 14.1.1 ATmega8: Das EEPROM Controller Register . . . . . . . . . . . . . . . . . . . . . . . . . 203 14.1.2 ATmega328: Das EEPROM-Controller-Register . . . . . . . . . . . . . . . . . . . . . . . 204 14.2 EEPROM unter C programmieren . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205 Kapitel 15 • Watchdog-Timer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 207 15.1 Watchdog Timer im ATmega8 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 208 15.2 Watchdog Timer im ATmega328 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 209 Kapitel 16 • Taktversorgung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 211 Kapitel 17 • Reset . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 213 Kapitel 18 • Simulatoren und (In Circuit) Debugging . . . . . . . . . . . . . . . . . . . . . . 214 18.1 Ein kleines Hardware-Problem . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 217 18.2 Hterm.exe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 221 18.3 Der Simulator des Atmel Studios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 224 18.4 Zusammenfassung: . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 227 Kapitel 19 • Hoffentlich hilfreiche Links . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 229 Kapitel 20 • Glossar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 232 Kapitel 21 • Register alphabetisch . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 268 Kapitel 22 • Alle Register-Bits alphabetisch . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 271 Kapitel 23 • Fuses und Lock-Bits alphabetisch . . . . . . . . . . . . . . . . . . . . . . . . . . . 279 Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 280
●9
AVR Programmierung DE 160929.indd 9
25-10-16 11:45
Kapitel 1 • Programmierung des ATmega8 und des ATmega328
Kapitel 1 • Programmierung des ATmega8 und des ATmega328 Das allgemeine Vorgehen in diesem Buch ist folgendes: Zunächst gibt es allgemeine Erklärungen zu einer Funktionsgruppe und dann geht es an die Registerinhalte. Hierbei werden zunächst die Register und ihre Bits beschrieben, die beim ATmega8 und beim ATmega328 identisch sind. Dann folgen, falls vorhanden, die jeweiligen Eigentümlichkeiten. Wenn im Text 'ATmega' steht, sind sowohl der ATmega8 als auch der ATmega328 gemeint, ansonsten wird der Prozessor ausdrücklich genannt. Nach der Lektüre dieses Buches sollten Sie eigentlich beide MCUs sicher beherrschen können. Da trotz großer Sorgfalt Fehler nicht ausgeschlossen werden können, gilt, dass das Datenblatt letztlich (fast) immer Recht hat. In den meisten Büchern und Tutorials (es gibt so einige, insbesondere im englischen Sprachraum) geht es nach einer minimalistischen Einführung fast immer mit einfachen Programmierbeispielen weiter, oftmals auch in Assembler. In diesem Buch wird mit der Programmiersprache C gearbeitet, allerdings werden nur wenige und kurze Programmsequenzen gebracht. Der Grund hierfür ist, dass man im Internet von Beispielprogrammen erschlagen wird und ich nicht wissen kann, was Sie gerne realisieren möchten, folglich würden die meisten Programmbeispiele völlig an Ihren Interessen vorbeigehen. Der Schwerpunkt liegt also auf einer verständlichen Beschreibung der möglichen Funktionen der MCU (Micro Controller Unit). wenn man weiß, was möglich ist und was man will, findet man auch die benötigten Anweisungen. Auch wenn Sie schon Erfahrung in der Programmierung mit C haben, sollten Sie in das Kapitel 4 zumindest hineinschauen, insbesondere ins Kapitel 'Bit-Manipulationen'. Der Grund ist, dass sich bei der Programmierung von MCUs ein Stil durchgesetzt hat, der die Programme ein wenig lesbarer macht, denn es wird direkt mit den Namen der Register und den Namen der einzelnen Bits gearbeitet und nicht explizit mit Bit-Positionen. Man kann sich sehr darüber streiten, ob die jeweilige Namensgebung durch Atmel gelungen war, aber jetzt müssen wir damit leben. Wenn Sie direkt mit Bit-Positionen arbeiten wollen, werden Sie also mit dem Datenblatt arbeiten müssen. Es ist vielleicht nicht nett von mir, aber ich übe einen leichten Zwang aus, damit Sie die Notation benutzen, die weltweit (fast) alle Programmierer von AVR-Mikrocontrollern benutzen (nach ein paar Anlaufschwierigkeiten ist es einfacher und übersichtlicher, als man zunächst meint). Wenn es an die Fehlersuche geht (früher oder später geht es beim Programmieren immer um die Fehlersuche, oftmals deutlich mehr als die Hälfte der Zeit), hat man durch die Beschreibung in normaler Sprache so viel Hintergrundwissen, dass man eine Strategie für die Fehlersuche entwickeln kann. Man sucht also nicht plan- und hoffnungslos. Ohne das Hintergrundwissen muss man hoffen, nette Leute in einem Forum zu finden, die ihre Freizeit opfern, weil man selbst weniger nachdenken will. Wenn man dies zu dreist macht, bekommt man zu Recht ein RTFM (siehe Glossar) gepostet. Dieses Buch setzt nur geringe Vorkenntnisse voraus, allerdings kann nicht immer bei Adam und Eva angefangen werden (dafür gibt es andere Bücher), sondern oftmals bei Kain und Abel. Da ich Elektrotechniker bin und nicht Religionswissenschaftler, geht es auch an den beiden immer recht zügig vorbei. Wenn Sie bei diesen Vorbeiflügen arge Verständnispro-
● 15
AVR Programmierung DE 160929.indd 15
25-10-16 11:45
AVR-Programmierung für Quereinsteiger
Kapitel 2 • Die Register Beim ATmega8 liegen alle Register, ohne Lücken zu lassen, zwischen der Absolutadresse 0x20 und 0x5F. Beim ATmega328 liegen sie, mit vielen Lücken, im Bereich zwischen 0x20 und 0xFF. Wenn Sie, etwa bei der Lektüre eines Fachartikels, auf den Namen eines Bits oder eines Registers stoßen, das Sie nicht kennen, müssten Sie normalerweise das Datenblatt, beispielsweise mit Adobe, öffnen und eine Volltextsuche starten. Oder Sie müssen darauf hoffen, bei der Internetsuche schnell auf einen Beitrag zu stoßen, der Ihnen weiterhilft Hinten im Buch befinden sich zwei alphabetisch sortierte Listen. In der einen Liste sind alle Bit-Namen gelistet und es wird angegeben, in welchem Register sich das Bit befindet. Es gibt Bit- und Register-Namen, die nur im ATmega8 zu finden sind, es gibt solche, die sich auch im ATmega328 finden und solche, die sich nur im ATmega328 finden. Von den Bits gibt es also mindestens einen Querverweis auf ein zugehöriges Register und im Register gibt es einen Querverweis auf das Kapitel (oder auch die Kapitel), in dem seine Funktionalitäten erklärt werden. Auf die Auflistung der Register entsprechend ihrer Adresse (so, wie sie im Datenblatt zu finden ist) wurde verzichtet, da sich hierdurch kaum ein Erkenntnisgewinn oder gar eine Arbeitshilfe ergibt. Die Inhalte der einzelnen Register werden in den Kapiteln über die Funktionsgruppen beschrieben.
● 46
AVR Programmierung DE 160929.indd 46
25-10-16 11:45
Kapitel 3 • Der Stack
Kapitel 3 • Der Stack Der Stack (engl. für Stapel) ist ein sogenannter Last-In-First-Out Speicher. Der Stack wird benutzt, um Daten temporär zu speichern – es gibt keine verbreitete Rechnerarchitektur, die völlig ohne Stack auskommt. Die einfachste Nutzung des Stacks besteht darin, dort bei einem Unterprogrammaufruf die Rückkehradresse zu speichern. Hierbei arbeiten der Stack-Pointer (ein Zeiger, der auf das aktuelle Ende des Stacks verweist) und der Instruction-Pointer (Program Counter) zusammen. Der Programmfluss läuft auf einen Unterprogrammaufruf auf, der die Zieladresse (also den Ort des Unterprogramms) enthält. Jetzt wird die Adresse, die auf den Unterprogrammaufruf folgt, auf den Stack gelegt, der Stack-Pointer entsprechend der Anzahl der Bytes der Adresse verändert und die Adresse des Unterprogramms wird in den Instruction-Pointer übernommen. Der nächste Befehl, der ausgeführt wird, ist also der erste Befehl aus dem Unterprogramm. Das Unterprogramm wird mit dem Assembler-Befehl RET beendet, die Rückkehradresse wird vom Stack geholt und in den Instruction-Pointer übertragen. Man muss im Unterprogramm also aufpassen, dass man den Stack nicht durcheinanderbringt. Wenn man in C programmiert, muss man sich keine Gedanken über die Umsetzung machen, denn das geht automatisch. Im einfachsten Fall werden alle benötigten Parameter über die CPU-Register an das Unterprogramm übergeben und das Unterprogramm liefert, falls das erforderlich ist, alle Ergebnisse gleichfalls in den Registern zurück. Das Problem hierbei ist, dass man alle Register, die unerwünschterweise vom Unterprogramm verändert werden könnten, zwischenzeitlich irgendwo retten muss, um sie später wieder zu restaurieren. Hierzu bietet sich natürlich wieder der Stack an. Traditionellerweise wird der Stack im oberen Bereich des Speichers angelegt, er wird also von oben nach unten vergrößert. Im unteren Bereich des Speichers befindet sich der sogenannte Heap (engl. für Haufen), der nach oben wächst (etwa, weil man vom Betriebssystem Speicher anfordert). Da es in einem laufenden System mit einer MCU praktisch keine Möglichkeit gibt, Überschneidungen von Stack und Heap zu verhindern, sollte man Stack und Heap nur mit Bedacht nutzen, also keine rekursiven Programme schreiben, es sei denn, man weiß genau, was man da macht, wie tief die Rekursion gehen wird und wie viel Speicher pro Rekursion auf dem Stack benötigt wird. Es gibt den Push-Befehl, um den Inhalt eines Registers auf den Stack zu bringen, hierbei wird der Inhalt des Registers dort abgelegt, wo der Stack-Pointer hinzeigt, und anschließend wird der Stack-Pointer dekrementiert (um eine Position verringert). Mit dem Pop-Befehl kann man ein Datum wieder vom Stack herunterholen, der Stack-Pointer wird inkrementiert (um eine Position erhöht) und das Datum wird eingelesen. Eine Überprüfung, ob Quelle oder Ziel sinnvoll sind/sein könnten, erfolgt nicht. Die Nutzung des Stacks ist eine übliche Methode, um etwa zwei Registerinhalte schnell zu
● 47
AVR Programmierung DE 160929.indd 47
25-10-16 11:45
AVR-Programmierung für Quereinsteiger
Kapitel 4 • Programmieren in C C ist eine uralte Programmiersprache. Sie wurde Ende der 60er- bis Anfang der 70er-Jahre überwiegend von Dennis Ritchie an den Bell Laboratorien entwickelt. Wie man leicht vermuten kann, gab es auch die Vorläufer 'A' und 'B'. Zur damaligen Zeit wurden Betriebssysteme in Assembler entwickelt, was sehr zeitaufwendig und fehleranfällig war, denn jede Rechnerfamilie hatte ihre eigene Assembler-Version! Der Arbeitsschwerpunkt von Dennis Ritchie war es, eine Hochsprache zu entwickeln, mit deren Hilfe man ein komplettes Betriebssystem programmieren konnte. Das Ergebnis war schließlich C, das 1973 veröffentlicht wurde. Das Betriebssystem, das darauf aufbauend entwickelt wurde, nennt sich nach über 40 Jahren immer noch UNIX, und es ist alles andere als tot, was man von vielen Mitbewerbern nicht sagen kann. Die mittlerweile wahrscheinlich bekanntere Variante nennt sich Linux, und auch Linux wurde in C entwickelt. C ist also schon ein wenig angestaubt und an den Universitäten lernt man, wenn überhaupt noch, natürlich C++ oder C#, denn die angehenden Informatiker und Techniker sollen ja lernen, objektorientiert zu denken. Das hat in gewisser Weise auch seine Berechtigung, allerdings sperrt man sich hierdurch von allem aus, was in C so richtig Spaß macht. Auf der anderen Seite gibt es Assembler-Puristen, die sogar C als zu einschränkend empfinden. Wir sehen uns das auf den folgenden Seiten etwas genauer an. Da ein Betriebssystem in der Lage sein muss, praktisch alle Ressourcen eines Computers anzusprechen, hätte C also alles können müssen, was man mit der jeweiligen Assembler-Sprache realisieren konnte. Dieser Anspruch war allerdings deutlich zu hoch, so dass ein pragmatischer Kompromiss herauskam: Man schreibt den Großteil des Betriebssystems in C und die Teile, in denen der Sprachumfang von C nicht hinreichend ist, werden in Assembler geschrieben. Jetzt kommt ein kleiner Trick hinzu: Diejenigen, die die Compiler, Linker und Loader schrieben (was das ist, wird gleich erklärt) sorgten dafür, dass sich C und Assembler problemlos verkuppeln lassen. Man kann also aus einem C-Programm heraus ein Assembler-Unterprogramm aufrufen und auch umgekehrt. Es geht sogar noch eine Stufe weiter, denn man kann C und Assembler mischen (das nennt sich Inline-Assembler und wird später behandelt). Über C wurden schon komplette Lehrbücher mit etlichen hundert Seiten geschrieben. Eine vollständige Beschreibung von C würde den Rahmen dieses Buches völlig sprengen, denn es hat einen anderen Schwerpunkt. Was ich Ihnen liefere ist alles das, was Sie unbedingt wissen müssen, um eigene Programme schreiben zu können. Einige 'dirty tricks', die aber in C absolut legal und normal sind, werden Sie im Laufe der Zeit selber finden. Mein Tipp dazu: Nur benutzen, wenn es unbedingt erforderlich ist! Viele Leute behaupten nicht ganz zu Unrecht, dass es sich bei C um einen Hochsprachen-Assembler handelt, C wurde schließlich entwickelt, um aus wirtschaftlichen Gründen die Nutzung von Assembler zurückzudrängen. C bietet also die Möglichkeit, mit wesentlich weniger Aufwand (verglichen mit Assembler) zum Ziel zu kommen, und wenn man seine (Unter-)Programme sorgfältig plant, ist die Wahrscheinlichkeit hoch, dass man bestimmte Funktionen später auch in anderen Projekten einsetzen kann (die berühmten Libraries).
● 50
AVR Programmierung DE 160929.indd 50
25-10-16 11:45
Kapitel 5 • Interrupts
Kapitel 5 • Interrupts Prozessoren sind von ihrem ursprünglichen Konzept her darauf ausgelegt, das aktuelle Programm Schritt für Schritt auszuführen. Eine Überwachung externer Vorgänge kann als Teil dieses Ablaufs erfolgen. Das Problem ist nur, dass man nicht beides gleichzeitig kann, nämlich überwachen und etwas anderes Sinnvolles tun. Die einzige Möglichkeit, beides mehr oder weniger gleichzeitig zu tun, besteht darin, die sinnvolle Arbeit in viele kleine Teilarbeiten zu zerlegen und die Überwachung dazwischen einzufügen. Muss die Frequenz der Überwachung geändert werden, steht zwangsweise ein komplettes Redesign des Programms an. Dieser Schwachpunkt wurde schon in der Frühzeit der Computerei entdeckt und durch die Einführung von Interrupts behoben. Ein Interrupt ist ein Ereignis der Hardware. Um einen Interrupt auszulösen, muss etwas in der Hardware seinen Wert ändern. Per Definition kommt ein Interrupt in Bezug auf das aktuell laufende Programm immer überraschend und unvorhersagbar. Die sogenannten Software-Interrupts sind in diesem Sinne keine Interrupts, denn sie werden immer an der gleichen Stelle im Programm ausgelöst und dienen eigentlich nur einem Kontextwechsel, und auf MCUs gibt es keine Software-Interrupts, obwohl man von einem Programm aus auch einige Interrupts gezielt auslösen kann. Was man mit einem Interrupt erreichen will, ist, dass das aktuell laufende Programm angehalten wird, eine zum Interrupt passende Routine ausgeführt wird und anschließend das angehaltene Programm weiterläuft, als wäre zwischenzeitlich nichts geschehen. Wenn man in die Bearbeitung eines Interrupts hineingeht, muss als Erstes gespeichert werden, wo im aktuellen Programm man gerade war. Diesen Schritt macht die MCU automatisch, indem sie diese Adresse auf dem Stack ablegt. Und die MCU macht noch etwas automatisch, sie setzt nämlich das I-Bit (global Interrupt enable) zurück. Dies hat den Effekt, dass die jetzt laufende Interrupt-Behandlung nicht von anderen Interrupts unterbrochen werden kann. Warum das wichtig ist, wird gleich erklärt. Zudem weiß die MCU, welcher Interrupt ausgelöst wurde und wo die dazugehörige Routine steht (darauf gehen wir gleich noch genauer ein), und springt auf den ersten Befehl dieser Routine. Das Erste, was in dieser Routine geschehen muss, ist das Speichern des Status-Registers auf dem Stack, denn die Befehle der Interrupt-Routine werden diese Flags mit an Sicherheit grenzender Wahrscheinlichkeit beeinflussen, was dann bei Rückkehr in die unterbrochene Routine zu Problemen führen kann. Damit der Interrupt das zuvor laufende Programm logisch überhaupt nicht beeinflussen kann, muss nach Behandlung des Interrupts der Zustand der Flags restauriert werden, der direkt vor dem Interrupt vorlag. Wenn man in C programmiert, muss man sich hierüber keine Gedanken machen, denn der Compiler erledigt das automatisch. Wenn man umfangreiche Interrupt-Routinen in Assembler schreibt, kann man sehr schnell den Überblick verlieren, welche Register benutzt werden. Folglich müssten im nächsten Schritt sämtliche 32 Register auf dem Stack gesichert werden. Sind die Interrupt-Routinen eher übersichtlich, geht man durch den Code und macht eine Liste, welche Register benutzt
● 103
AVR Programmierung DE 160929.indd 103
25-10-16 11:45
Kapitel 6 • Schlafmodi
Kapitel 6 • Schlafmodi Ein ATmega hat bei einer Taktversorgung mit 4 MHz und einer Versorgungsspannung von 3 Volt einen Verbrauch von 10,8 Milliwatt, wenn der Baustein aktiv ist. Im Idle Mode geht der Verbrauch auf 3 Milliwatt herunter. Im Power-Down-Modus muss man schon ein sehr gutes Messgerät haben, um den Verbrauch noch messen zu können (0,015 Milliwatt). Die Schlafmodi dienen also dem Energiesparen, wenn aktuell überhaupt keine Arbeit zu erledigen ist, was insbesondere bei Batteriebetrieb wichtig ist. Wenn der Analog-Digital-Wandler aktiviert ist, wird eine Messung gestartet, sobald einer der Schlafmodi aktiviert wird. Der Sinn ist, eine Messung mit möglichst geringen elektromagnetischen Störungen durchführen zu können. Nach Ende der Messung wird ein Interrupt ausgelöst und die MCU ist wieder aktiv. Egal, welcher Schlafmodus ausgewählt wird, ein Interrupt weckt die CPU auf jeden Fall (es wird also die zugehörige Interrupt-Routine ausgelöst, und wenn sie beendet ist, wird das 'normale' Programm, also meistens die Endlosschleife in main(), an der Stelle fortgesetzt, die direkt hinter dem Sleep-Befehl steht). 6.1 Schlafmodi des ATmega
In Assembler wird die MCU mithilfe des Befehls "sleep" in den Schlafmodus gebracht und in C durch "_SLEEP( )". Voraussetzung dafür, dass der Baustein überhaupt schlafen kann, ist, dass das Bit SE (Sleep Enable) aktiviert wurde (siehe gleich). Idle Mode In diesem Modus wird der Takt von der CPU abgenommen (die macht also überhaupt nichts mehr), während der Rest des Chips noch aktiv ist, also insbesondere die Interrupt-Quellen. Power Down Mode Bis auf die Interrupt-Quellen ist der ganze Chip abgeschaltet. Power Save Mode Bis auf Timer-2 ist alles abgeschaltet. Falls dieser Timer mit einem externen Takt versorgt wird, kann er einen Overflow oder einen Compare-Interrupt auslösen. Auch die externen Interrupts INT0 und INT1 könnten die MCU wecken. Hat dieser Timer keinen externen Takt und können weder INT0 noch INT1 einen Interrupt auslösen, ist die MCU tot (nur über einen Reset wieder aktivierbar). ADC Noise Reduction Die CPU und die IO-Module sind abgeschaltet, nur die Timer und der ADC arbeiten noch. Dieser Modus soll verhindern, dass durch die Aktivitäten der MCU das Messergebnis per elektromagnetischer Wechselwirkung verfälscht wird. Standby Mode Die ganze MCU ist stillgelegt, jedoch wird der Systemtakt noch weiterhin erzeugt. Da jeder Oszillator eine bestimmte Einschwingzeit benötigt, bis er stabil arbeitet,
● 117
AVR Programmierung DE 160929.indd 117
25-10-16 11:45
AVR-Programmierung für Quereinsteiger
Kapitel 7 • Paralleler Input/Output
1
28 PC5
PD0
2
27 PC4
PD1
3
26 PC3
PD2
4
25 PC2
PD3
5
24 PC1
PD4
6
23 PC0
7 8 PB6
9
ATmega
PC6
22 21 20
PB7 10
19 PB5
PD5 11
18 PB4
PD6 12
17 PB3
PD7 13
16 PB2
PB0 14
15 PB1
Abbildung 11: Die Pin-Belegung des ATmega Im Bild sieht man einen ATmega im DIP-Gehäuse und welche Pins für IO-Ports verwendet werden können (die möglichen anderen Verwendungsarten der Pins sind nicht dargestellt, um Verwirrungen zu vermeiden). Wir haben also drei IO-Ports. Port B und D haben acht IO-Pins und Port C hat nur sieben. Port B
Port C
Port D
Pin-Nummer
Pin-Nummer
Pin-Nummer
Bit 0
14
23
2
Bit 1
15
24
3
Bit 2
16
25
4
Bit 3
17
26
5
Bit 4
18
27
6
Bit 5
19
28
11
Bit 6
9
1
12
Bit 7
10
13
● 120
AVR Programmierung DE 160929.indd 120
25-10-16 11:45
AVR-Programmierung für Quereinsteiger
Kapitel 8 • Timer und Counter 28
2
27
3
26
4
25
5 OC2B
24
6
23
7 8 TOSC1
9
ATmega
T0
1
22 21 20
TOSC2 10
19
T1 11 OC0B 12 OC0A
18 OC2A 17 OC2
13
16 OC1B
ICP1 14 CLKO
15 OC1A
Abbildung 12: Die Pin-Belegung Der ATmega hat drei unabhängige Timer/Counter (Zeitmesser/Zähler). Wenn das verwendete Taktsignal in gleichmäßigen Zeiträumen kommt, spricht man allgemein von einem Timer (denn man kann eine Zeitdauer messen/abwarten) und andernfalls von einem Counter, wenn die tatsächliche Zeit nicht entscheidend ist, sondern die Anzahl von Ereignissen. Rein technisch betrachtet sind sie letztlich identisch, es ist nur die Frage, ob das Taktsignal für das jeweilige Vorhaben geeignet ist. ATmega8
ATmega328
Funktion
-
CLKO
CLocK Output
IPC1
IPC1
InPut Capture von Timer 1
-
OC0A
Output Compare A von Timer 0
-
OC0B
Output Compare B von Timer 0
OC1A
OC1A
Output Compare A von Timer 1
OC1B
OC1B
Output Compare B von Timer 1
OC2
OC2A
Output Compare (A) von Timer 2
-
OC2B
Output Compare B von Timer 2
● 124
AVR Programmierung DE 160929.indd 124
25-10-16 11:45
AVR-Programmierung für Quereinsteiger
Kapitel 9 • Serielle Datenübertragungen Der ATmega8 verfügt über drei serielle Kommunikationskanäle. Bei keinem der drei Kanäle gibt es Vorgaben darüber, welche Informationen in welcher Reihenfolge übertragen werden. Dies ist abhängig vom jeweils implementierten Protokoll (siehe Glossar). 1. Zunächst gibt es das SPI (Serial Peripheral Interface), das mit 3 Leitungen arbeitet (eigentlich 5, denn der Slave muss per Hardware selektiert werden und Masse brauchen wir auch noch). Bei diesem Verfahren hat man eine Hierarchie, denn ein Master sucht sich seinen Kommunikationspartner (Slave) aus und wählt ihn mithilfe einer Selektionsleitung aus. Nur der selektierte Slave reagiert, alle anderen machen ganz einfach mit ihrer Arbeit weiter (oder tun nichts). Grundidee ist, dass beide Kommunikationspartner ein Schieberegister haben und der Ausgang des einen Registers mit dem Eingang des anderen verbunden ist (das sind die nächsten beiden Leitungen). Zusätzlich gibt es die Taktleitung (Nummer 4). Nach 8 Takten haben die beiden Register ihre Inhalte ausgetauscht. Es findet also eine vollduplexe Kommunikation statt, aber ob das ausgenutzt wird, ist eine andere Frage. Für leichte Verwirrung sorgt bisweilen, dass es auch ein Serial Programming Interface (SPI) gibt, wozu meistens auch noch das SPI benutzt wird. 2. Dann gibt es das TWI (Two Wire Interface), das ab 1980 von Philips als I²C entwickelt wurde. Dies ist ein Kommunikationsbus (wie bei dem Namen zu vermuten ist, mit zwei Leitungen), in dem eine größere Anzahl Kommunikationspartner interagieren kann. Hierbei ist ein Baustein der Master, der selektiert, mit welchem Sklaven er sich unterhalten will. Hierbei sagt der Master entweder "Slave, hör mir zu!" oder "Slave, sag' mir!" Was der jeweilige Inhalt dieser Nachrichten ist, muss der Programmierer festlegen. Im Prinzip kann jeder Slave auch Master werden. Wer in einem bestimmten Moment welche Rolle einnimmt, wird durch ein Schiedsverfahren bestimmt (Arbitration, darauf gehen wir später genauer ein). 3. Der ATmega hat auch einen USART (Universal Synchronous/Asynchronous Receiver/ Transmitter). Hier werden die Daten ohne eine Taktleitung verschickt, weshalb diese Übertragungsart auch als asynchron bezeichnet wird. Die einzelnen Datenpakete enthalten zwischen 5 und 9 Datenbits. Ein Datenpaket wird durch ein Start-Bit eingeleitet und durch ein Stop-Bit beendet (Bedeutung geht aus den Signalpegeln hervor, wird gleich erklärt). Vor dem Stop-Bit kann noch ein Parity-Bit eingeschoben werden, das es mit etwas Sicherheit erlaubt, Fehler in der Übertragung festzustellen (eine deutlich höhere Sicherheit kann durch eine Prüfsumme über einen Datenblock erreicht werden, dieses Verfahren wird nicht vom USART der MCU unterstützt). USARTs waren weit verbreitet, als die digitale Übertragung noch über normale Telefonleitungen lief (Uralttechnik halt, aber noch nicht sinnlos). Zusätzlich beherrscht der USART auch die synchrone Datenübertragung, der Takt hierfür kann von extern kommen oder selbst generiert werden.
● 150
AVR Programmierung DE 160929.indd 150
25-10-16 11:45
AVR-Programmierung für Quereinsteiger
Kapitel 10 • Analog-Digital-Konverter 28 ADC5
2
27 ADC4
3
26 ADC3
4
25 ADC2
5
24 ADC1
6
23 ADC0
7 8 9
ATmega
1
22 21 20
10
19
11
18
12
17
13
16
14
15
Abbildung 19: Die Pin-Belegung Ein Analog-Digital-Konverter ist schaltungstechnisch recht aufwendig. Deshalb hat der ATmega nur einen davon auf dem Chip, aber das wäre für viele Anwendungen einfach zu wenig. Also arbeitet man mit einem Trick. Bis zu 8 Pins können als Eingang für den ADC programmiert werden (bei der DIP-Ausführung stehen nur 6 Eingänge zur Verfügung, wird in der Schaltung vom Two Wire Interface Gebrauch gemacht, bleiben nur noch 4 Analog-Eingänge übrig). Sie werden über einen Analog-Multiplexer mit dem ADC verbunden. Man kann also bis zu 8 analoge Spannungen messen, allerdings immer nur nacheinander. Der eigentliche ADC hat eine Auflösung von 10 Bits. Hat man eine Eingangsspannung, die irgendwo zwischen 0 und 12 Volt liegen kann, würde man Schritte von ungefähr 12 Millivolt unterscheiden können. In der Praxis wird die Auflösung normalerweise nicht so gut sein, denn man hat immer mit Einstrahlungen zu kämpfen und müsste eigentlich über viele Messungen mitteln, um einen guten Schätzwert zu erhalten. Da das recht aufwendig ist und man meistens auch keine so feine Auflösung braucht, erfolgt häufig die eigentliche Messung mit 10-Bit-Auflösung, aber man verwendet nur die oberen 8 Bits für die Verarbeitung. (Da man mit einer 8-Bit-CPU arbeitet, erleichtert man sich hierdurch die Programmierung zumindest in Assembler erheblich. Um das Ergebnis zu erhalten, genügt es, lediglich das ADCH-Register zu lesen, siehe gleich). Generell gilt für das Ergebnis einer Wandlung die folgende Formel:
● 182
AVR Programmierung DE 160929.indd 182
25-10-16 11:45
Kapitel 11 • Analog Comparator
Kapitel 11 • Analog Comparator Im ATmega gibt es einen analogen Vergleicher. Im einfachsten Fall werden die Spannungen an den Pins AIN0 (Pin 12) und AIN1 (Pin 13) miteinander verglichen. AIN0 wird auch als 'positiver' Pin bezeichnet und AIN1 als 'negativer' Pin. Rein elektrisch betrachtet ist das Unfug, denn an beiden Pins wird im Normalfall eine positive Spannung anliegen (die Spezifikation besagt, dass an einem beliebigen Pin maximal eine Spannung von Vcc + 0,5 Volt anliegen darf und minimal eine Spannung von GND - 0,5 Volt. Die Bezeichnung leitet sich davon ab, dass beide Leitungen mit einem Operationsverstärker verbunden sind, wobei AIN0 auf den nicht invertierenden Eingang geführt wird und AIN1 auf den invertierenden Eingang (AIN0 wird in Schaltplänen häufig mit '+' gekennzeichnet und der andere mit '-'). 28 ADC5
2
27 ADC4
3
26 ADC3
4
25 ADC2
5
24 ADC1
6
23 ADC0
7 8 9
ATmega
1
22 21 20
10
19
11
18
AIN0 12
17
AIN1 13
16
14
15
Abbildung 21: Die Pin-Belegung Wenn der Pegel an AIN0 höher ist als der an AIN1, können (je nach Konfiguration) zwei verschiedene Interrupts auslösen. Dies sind ANA_COMP (ANAlog COMParator) und / oder der 'TC1 CAPT' (Timer/Counter 1 CAPTure). Nichtinvertierender Eingang: Statt des Signals von Pin AIN0 kann auch eine Referenzspannung ausgewählt werden, die als Band-Gap bezeichnet wird (in einem Halbleiter entsteht am Übergang zwischen verschieden dotierten Bereichen eine Spannung, die eine Seite wird als Leitungsband bezeichnet und die andere als Valenzband, deshalb Band Gap Voltage).
● 189
AVR Programmierung DE 160929.indd 189
25-10-16 11:45
AVR-Programmierung für Quereinsteiger
Kapitel 12 • Das gibt es nur im ATmega328 12.1 Clock Prescaler
Je nach Situation benötigt man bisweilen die volle Rechenpower der MCU, zu anderen Zeiten stellt eine hohe Verarbeitungsgeschwindigkeit dagegen eine sinnlose Energieverschwendung dar, etwa weil die MCU über eine kleine Batterie mit Strom versorgt wird und nur wenig zu tun ist. Hierfür gibt es den Clock Prescaler. CLKPR (CLocK Prescaler Register) CLKPS0 bis CLKPS3 CLocK PreScaler Bit 0 bis 3 Mithilfe dieser Bits wird der Systemtakt entsprechend der folgenden Tabelle verlangsamt. CLKPS3
CLKPS2
CLKPS1
CLKPS0
Teilungsfaktor
0
0
0
0
1
0
0
0
1
2
0
0
1
0
4
0
0
1
1
8
0
1
0
0
16
0
1
0
1
32
0
1
1
0
64
0
1
1
1
128
1
0
0
0
256
Alle nicht angegebenen Kombinationen sind reserviert und dürfen nicht benutzt werden. CLKPCE CLocK Prescaler Change Enable Mit diesem Bit soll verhindert werden, dass der Prescaler 'versehentlich' verändert wird. Um den Prescaler-Wert zu verändern, muss CLKPCE auf 1 gesetzt werden, wobei alle anderen Bits 0 sein müssen. Dann müssen die neuen Werte von CLKPS0 bis CLKPS3 innerhalb von 4 Taktzyklen gesetzt werden. CLKPCE wird automatisch wieder auf 0 gesetzt. 12.2 General Purpose I/O-Register
GPIOR0, GPIOR1 und GPIOR2 General Purpose IO-Register 0 bis 2 In 'normalen' Programmen haben diese Register keinen Sinn. Wenn man aber irgendwo im Programm schnelle Bitzaubereien machen muss und es wirklich auf jeden Taktzyklus ankommt, kann man mit diesen Registern arbeiten, denn man kann in Assembler die schnellen Bit-Setz- und Bit-Lösch-Funktionen benutzen. Das geht aber eindeutig zu Lasten der Übersichtlichkeit des Programms.
● 194
AVR Programmierung DE 160929.indd 194
25-10-16 11:45
Kapitel 13 • Lock-Bits und Fuses
Kapitel 13 • Lock-Bits und Fuses Fuses und Lock-Bits werden zur Programmierung des Verhaltens der MCU verwendet. Zunächst ist der Unterschied zwischen den beiden nicht klar erkennbar. Er wird erst klar, wenn man sich mit dem Befehl 'Chip Erase' beschäftigt. Soll etwa der Flash-Speicher gegen unbefugtes Auslesen geschützt werden, muss es unmöglich sein, diesen Speicherschutz über Programmiergeräte auszuhebeln. Deshalb können Lock-Bits nur gesetzt, aber nicht einzeln gelöscht werden. Das Löschen geht nur mit 'Chip Erase'. Dieser Befehl löscht das EEPROM, den Flash-Speicher und die Lock-Bits. Die Inhalte der Fuses bleiben bei einem Chip-Erase erhalten, denn sie können sowieso separat umprogrammiert werden. Vorab noch ein Hinweis. Wenn Sie unbedingt Änderungen an den Lock-Bits und Fuses machen müssen, sollten Sie immer daran denken, dass eine '0' eine Aktivierung bedeutet und eine '1' eine Abschaltung. Also zweimal nachdenken, bevor man hier Änderungen macht. Es könnte sein, dass man ein teures Programmiergerät benötigt, um die Änderungen rückgängig zu machen. 13.1 ATmega: Lock-Bits
Die Informationen aus diesem Kapitel werden Sie nie brauchen, es sei denn, sie haben mithilfe einer MCU ein Produkt entwickelt und wollen die Software gegen Ausspähung schützen. Oder Sie haben ab und zu den Verdacht, dass sich gar merkwürdige Dinge auf Ihrer MCU abspielen, wenn Sie gerade nicht hinsehen. Es geht darum, wie man bestimmte Funktionalitäten, die Zugriff auf den Speicher gewähren, abschaltet. Es ist Sinn der Lock-Bits, dass man nur dann wieder vollen Zugriff auf den Programmspeicher bekommt, wenn man ihn zuvor komplett gelöscht hat. Alle Lock-Bits sind über die serielle Programmierung erreichbar und somit setzbar. Die Lock-Bits befinden sich im Lock-Bit-Byte, und es handelt sich um drei Gruppen. Die erste Gruppe von Bits bezieht sich auf den gesamten Flash-Speicher:
LB2 LB1 Bedeutung 1 1 keine Einschränkungen beim Lesen oder Schreiben 1 0 der Flash-Speicher kann weder seriell noch parallel beschrieben werden 0 0 von außen kann weder lesend noch schreibend zugegriffen werden
Im zweiten Block geht es um die Einschränkungen in Bezug auf den Anwendungssektor. Es geht darum, ob die Befehle LPM (Load Program Memory) oder SPM (Store Program Memory) auf den Anwendungssektor angewendet werden können/dürfen.
BLB02 BLB01 Bedeutung 1 1 keine Einschränkungen beim Gebrauch von LPM und SPM
● 197
AVR Programmierung DE 160929.indd 197
25-10-16 11:45
AVR-Programmierung für Quereinsteiger
Kapitel 14 • Programmierung des EEPROM Am Anfang des Buches ist angegeben, wie viele Bytes EEPROM die jeweilige MCU hat, die Anzahl der Schreibzyklen pro Byte ist auf 100.000 beschränkt. Da sich das EEPROM und der Flash-Speicher etwas Hardware teilen, könnte es zu Konflikten kommen, wenn man von einem Bootloader aus beide Speicher quasi gleichzeitig beschreiben will. Da der Bootloader ohnehin nicht benötigt wird (zumindest nicht beim Einstieg in die Thematik), erspare ich Ihnen weitere Erklärungen zu diesem Thema. Um ins EEPROM zu schreiben oder daraus zu lesen werden insgesamt 4 Register benötigt. Zunächst sind da die beiden Adressregister (je nach Größe des EEPROMs werden 8 bis 10 Adress-Bits benötigt). Es gibt ein Data-Register, in das zu schreibende Daten eingetragen werden oder von dem gelesene Daten abgeholt werden können, und es gibt ein Kontrollregister. Um es weitgehend verhindern zu können, dass der Inhalt des EEPROM durch ein abgestürztes Programm verändert wird, hat man sich eine Absicherung einfallen lassen (wenn aus dem Speicher gelesen wird, sind keine Sicherungsvorkehrungen notwendig). Zuerst wird das zu schreibende Byte in das Data-Register eingetragen. Dann muss man das Master-Write-Enable-Bit setzen und sofort danach das Write-Enable-Bit (es bietet sich an, diese Abfolge mittels Inline-Assembler zu realisieren). Werden diese beiden Bits nicht direkt nacheinander gesetzt, wird der Schreibbefehl von der MCU abgebrochen. Beim Schreiben auf das EEPROM sollte man folgendes Schema befolgen:
1. 2. 3. 4. 5. 6.
Arbeiten mit dem Flash-Speicher müssen abgeschlossen sein! Prüfen (und warten), bis auf das EEPROM geschrieben werden darf. Die gewünschte Adresse in den EEPROM-Adress-Registern eintragen. Das zu schreibende Byte in das Data-Register schreiben. Das Master-Write-Enable-Bit setzen (Rücksetzen erfolgt automatisch). Innerhalb von 4 Taktzyklen das Write-Enable-Bit setzen (Rücksetzen automatisch).
Wenn zwischen Schritt 5 und 6 ein Interrupt auftritt, kann das Schreiben nicht funktionieren. Wenn irgendwelche Interrupts aktiviert sind, sollte man diese beiden Schritte durch ein temporäres Interrupt-Verbot absichern. 14.1 ATmega: Die Register, um das EEPROM zu programmieren
EEARH & EEARL (EEprom AddRess High & Low) Vom Register EEARH wird nur ein einziges Bit benutzt. EEAR8 (EEprom Address Register bit 8)
Vom Register EEARL werden alle 8 Bits benutzt. EEAR0 bis EEAR7 (EEprom Address Register bit 0 bis 7)
● 202
AVR Programmierung DE 160929.indd 202
25-10-16 11:45
Kapitel 15 • Watchdog-Timer
Kapitel 15 • Watchdog-Timer Der Watchdog Timer ist letztlich ein zurücksetzbarer Zähler, der mit einem Takt versorgt wird. Die Idee ist, dass in einem Mikroprozessor die ganze Arbeit immer in einer Endlosschleife erledigt wird, denn es gibt ja normalerweise kein Betriebssystem im engeren Sinne. Am Ende dieser Schleife steht der Assembler-Befehl WDR, was WatchDog Reset bedeutet. Wenn dieser Befehl innerhalb des vorgegebenen Zeitrahmens ausgeführt wird, passiert nichts. Wenn sich die MCU jedoch 'verlaufen' hat (entweder ein Programmierfehler oder elektromagnetische Einstrahlung), schafft sie es nicht mehr, diese Schleife korrekt und komplett abzuarbeiten. Den WD-Timer stellt man so ein, dass das Programm noch eine zeitliche Reserve hat, bevor man zum Schleifenende kommt. Kommt es im Watchdog-Timer zu einem Overflow (Zählerstand geht vom größten Wert wieder auf 0), wird beim ATmega8 ein Neustart der MCU veranlasst. Beim ATmega328 kann man als Vorstufe zunächst einen Interrupt auslösen und abarbeiten lassen, wenn der keine Lösung bringt, erfolgt der eigentliche Reset. Für den Watchdog-Timer gibt es eine eigene Taktquelle (1 MHz beim ATmega8 und 128 kHZ beim ATmega328). Damit man mehr oder weniger sinnvolle Zeiten zwischen zwei Resets des Timers einstellen kann, gibt es jeweils einen Prescaler. Da der Watchdog-Timer eine Sicherungsmaßnahme gegen abgestürzte Programme ist, muss er selbst natürlich dagegen geschützt werden, dass eben diese Programme ihn zufällig abschalten könnten. Der Mechanismus wird gleich erklärt. Der umgekehrte Fall, nämlich dass ein abgestürztes Programm den Watchdog-Timer aktiviert, obwohl man das gar nicht wollte, ist gleichfalls verhängnisvoll. Da seine Nutzung nicht vorgesehen ist, wird der Timer natürlich in der Hauptschleife nicht zurückgesetzt. Der erneute Overflow kommt automatisch, die MCU wird wieder zurückgesetzt und ist 'programmtechnisch' gesehen so gut wie tot. Um solchen Fällen vorzubeugen, sollte man standardmäßig den Watchdog-Timer in der Initialisierung (also nach einem Reset) ausdrücklich deaktivieren, falls man ihn nicht nutzen will. Das Ausschalten des Watchdog-Timers muss vor zufälligen Veränderungen geschützt werden, weshalb folgende Sequenz angewendet werden muss. 1. Der Watchdog-Timer ist nach dem Power-On-Reset nicht eingeschaltet Dadurch, dass auf das WDE-Bit eine 1 geschrieben wird, wird der Timer gestartet. Um irgendetwas an den Einstellungen des Timers zu ändern, muss man in zwei Schritten arbeiten: Sowohl auf WDCE als auch auf WDE muss eine logische 1 geschrieben werden. Im nächsten Befehl kann man die Bits neu setzen, wobei das Bit WDCE auf logisch 0 liegen muss. 2. W enn der Watchdog-Timer über die Fuses aktiviert ist, kann man nur die Reaktionszeit ändern. Man setzt WDCE als auch WDE auf logisch 1 (Rest egal). Im nächsten Befehl
● 207
AVR Programmierung DE 160929.indd 207
25-10-16 11:45
Kapitel 16 • Taktversorgung
Kapitel 16 • Taktversorgung Interner RC-Taktgenerator Es gibt eine Vielzahl an Möglichkeiten, die MCU mit einem Systemtakt zu versorgen. Wenn die MCU ausgeliefert wird, ist sie so programmiert, dass sie mit einem Takt von 1 MHz arbeitet. Beim ATmega8 ist dies direkt die Frequenz des internen RC-Taktgenerators. Beim ATmega328 hat der RC-Taktgenerator eine Frequenz von 8 MHz, allerdings wird diese Frequenz in der Grundeinstellung durch 8 geteilt. Die Verarbeitungsgeschwindigkeiten sind also gleich. Diese Einstellung ist ideal, um mit der Programmierung dieser MCUs zu beginnen. Über die Fuses (siehe dort) lässt sich diese Frequenz verändern. Bevor ein ATmega das Werk verlässt, wird die RC-Taktversorgung kalibriert Wenn man eine andere Frequenz über die Fuses selektiert, stimmt natürlich diese Kalibrierung nicht mehr. Falls es notwendig ist, die neu eingestellten Frequenzen möglichst genau einzuhalten (höhere Anforderungen an das Timing, aber man will noch auf einen Quarz verzichten), kann man über das Register OSCCAL nachkalibrieren. 28
2
27
3
26
4
25
5
24
6
23
7 8 XTAL1/TOSC1
9
ATmega
1
22 21 20
XTAL2/TOSC2 10
19
11
18
12
17
13
16
14
15
Abbildung 22: Die Pin-Belegung In dieses Register kann man Werte zwischen 0 und 255 schreiben. Der Effekt ist, dass sich die Taktgeschwindigkeit um ungefähr 50% erhöhen oder auch verringern lässt. Aus der Praxis wird berichtet, dass dieser Taktgenerator nicht immer zuverlässig zu schwingen anfängt. Beim Einsatz in Geräten, die zuverlässig funktionieren müssen, sollte man vielleicht eine der anderen Taktquellen wählen.
● 211
AVR Programmierung DE 160929.indd 211
25-10-16 11:45
Kapitel 17 • Reset
Kapitel 17 • Reset Es gibt mehrere Quellen, von denen ein Reset ausgehen könnte. Normalerweise spielt es für einen Rechner keine Rolle, welche dieser Quellen ein Aufstarten veranlasst hat. Bei einer MCU sieht das etwas anders aus, denn es könnte schon einen Unterschied machen, ob ein normales Einschalten verantwortlich war oder ob der Watchdog-Timer zugeschlagen hat (man könnte dann ein Signal nach außen geben, dass eine Fehlersuche sinnvoll wird). Das Register, über das man den Grund des aktuellen Aufstartens erfahren kann, enthält 4 Flags. Diese Flags können zurückgesetzt werden, indem eine logische 0 an die Position geschrieben wird (so viel zu einheitlichen Lösungen!). Und es gibt noch eine Merkwürdigkeit, denn im ATmega8 nennt sich das Register, in dem diese Bits stehen, MCUCSR. Im ATmega328 wurde es umgetauft in MCUSR, dies hat eine gewisse Berechtigung, denn über das Register wird nichts kontrolliert. Hilfreich sind unnötige Umbenennungen sicherlich nicht. MCUCSR (Micro Controller Unit Controller and Status Register) im ATmega8 oder MCUSR (Micro Controller Unit Status Register) im ATmega328
WDRF (Watch Dog Reset Flag) Der Watchdog hat den Reset ausgelöst.
BORF (Brown Out Reset Flag) Der Brown-Out-Detektor (also eine Unterspannung) hat den Reset ausgelöst.
EXTRF (EXTernal Reset Flag) Der Reset-Pin (Pin 1, PC6) wurde auf GND gezogen.
PORF (Power On Reset Flag) Es gab einen normalen Power-On-Reset.
● 213
AVR Programmierung DE 160929.indd 213
25-10-16 11:45
AVR-Programmierung für Quereinsteiger
Kapitel 18 • Simulatoren und (In Circuit) Debugging Das Atmel Studio bietet die Möglichkeit, eine MCU auf einem PC zu simulieren. Das ist bei den ersten Schritten, die man mit einer MCU macht, sicherlich sehr interessant und lehrreich. Im nächsten Schritt kommen Stimulusdateien dazu, also Dateien, in denen man definiert, was an äußeren Reizen zur MCU gelangt, und in anderen Dateien werden die Reaktionen gespeichert. Wenn ich Programme in C schreibe, brauche ich diese Hilfe nicht wirklich, denn ich kann die Reaktionen in jeder beliebigen Umgebung austesten, wenn es um die Programmlogik geht und nicht spezifisch um die Hardware. Die Programmlogik eines Programms ändert sich nicht dadurch, ob sie für eine MCU kompiliert wird oder für einen PC. Es ist sogar so, dass man wesentlich effektiver ist, wenn man seine eigene Testumgebung definiert. Sonst muss man der vorgegebenen Notation folgen (was nicht unbedingt schlimm ist) und auch eine eventuell vorhandene automatische Auswertung daran anpassen (geht auch, aber warum umständlich, wenn es auch einen direkten Weg gibt?). Erste Schritte im Simulator sind also absolut in Ordnung (eine Kurzeinweisung folgt in einem späteren Kapitel), auch weil sie verhindern, dass man sich eventuell teure Hardware kaputt macht. Als generelles Mittel der Software-Entwicklung sind Simulatoren nur in Ausnahmefällen geeignet. Stellen Sie sich vor, Sie arbeiten in einer Firma mit mehreren Leuten an einer etwas aufwendigeren Schnittstelle. Wenn Sie jeden Mitarbeiter bei Vollkostenrechnung mit 80 € pro Stunde veranschlagen, liegen Sie wahrscheinlich nicht völlig falsch (Miete, Heizung, Strom, Schreibtischabnutzung, Arbeitgeberanteile zur Krankenversicherung etc.). Ein verlorener Arbeitstag kostet zirka 650 €. Nehmen wir an, Sie arbeiten zu dritt an dem Projekt, sind jeden Tag 2.000 € weg, nur weil Sie einen Fehler nicht finden. Für das Geld bekommt man schon einen kompletten In-Circuit-Debugger, ein kleines mehrkanaliges Speicheroszilloskop und sogar noch einen Datenlogger obendrein. Wenn Sie also kommerziell arbeiten, lohnt sich fast jedes Hilfsmittel, und das wahrscheinlich ziemlich schnell. Der Einsatz der schweren Kavallerie ist wirtschaftlich absolut berechtigt. Wenn Sie alleine und in Ihrer Freizeit an einem Projekt sitzen, geht es ja eher um die intellektuelle Herausforderung, wir haben es also mit der hohen Kunst des Florettfechtens zu tun. Aber es beruhigt ungemein, zu wissen, dass es auch noch die Kavallerie gibt, die man rufen könnte, bevor man das Projekt beerdigt. In der Liebe und im Krieg sind alle Mittel erlaubt. Ich würde sagen, das gilt auch für MCUs! Das Wort Debuggen bedeutet genau genommen entwanzen (wobei das Wort 'bugs' auch andere Käfer umfasst) und niemand weiß so ganz genau, ob die dahinterstehende Geschichte wirklich wahr ist. Auf jeden Fall heißt es, dass in der Computersteinzeit (es ging um einen Rechner, der noch nicht einmal mit elektrischen Röhren arbeitete, sondern noch mit offenen Relais) ein Programm plötzlich einen Fehler zeigte, der vorher nicht vorhan-
● 214
AVR Programmierung DE 160929.indd 214
25-10-16 11:45
Kapitel 19 • Hoffentlich hilfreiche Links
Kapitel 19 • Hoffentlich hilfreiche Links Die angegebenen Links wurden Mitte 2016 das letzte Mal auf Korrektheit überprüft. www.atmel.com/images/atmel-2486-8-bit-avr-microcontroller-atmega8_l_datasheet.pdf Diese Datei ist gemeint, wenn es um den Kommentar 'RTFM' geht, es ist sozusagen die Bibel der ATmega8-Programmierung, also das Original-Datenblatt. Wenn Sie irgendetwas hier im Buch nicht verstanden haben oder etwas nicht so funktioniert, wie es (Ihrer Meinung nach) sollte, müssen Sie sich dort schlau machen. www.atmel.com/images/Atmel-8271-8-bit-AVR-Microcontroller-ATmega48A-48PA-88A88PA-168A-168PA-328-328P_datasheet_Complete.pdf Ersatzweise ist diese Datei gemeint, wenn es um den Kommentar 'RTFM' geht. Es ist das Original-Datenblatt des ATmega328. www.atmel.com/Images/doc4064.pdf Eine Übersicht von Atmel über die verschiedenen Prozessoren und die verwendeten Gehäuseformen (wenn man wissen will, was es denn sonst noch so gibt). www.atmel.com/images/atmel-2521-avr-hardware-design-considerations_ applicationnote_avr042.pdf Eine 17 Seiten lange Zusammenfassung (auf Englisch) darüber, worauf man bei der Schaltungsentwicklung achten sollte oder muss. Wenn die Schaltung auf dem Steckbrett oder der Lochrasterplatine nicht funktioniert, ist hier ein guter Startpunkt, um mit der Fehlersuche zu beginnen. www.atmel.com/dyn/resources/prod_documents/doc0856.pdf Für die Leute, die es ganz genau wissen wollen, wird in diesem Dokument der 'Instruction Set' der 8-Bit-MCUs von Atmel erläutert, es geht also bis ins letzte Detail. www.avr-modelleisenbahn.de/atmega8/ Eine Übersetzung des Datenblattes des ATmega8 ins Deutsche von Rolf Bröcker. Für die Einarbeitung in die Thematik nicht unbedingt zu empfehlen. Da es eine Übersetzung ist, ist sie zwangsweise genauso gut für das Selbststudium geeignet wie das Datenblatt selbst. Allerdings sehr zu empfehlen für diejenigen, die arg mit dem Englischen zu kämpfen haben und Details wissen müssen. Ist als Referenz weitgehend geeignet, im Zweifelsfalle gilt trotzdem das englische Original. Hat im Gegensatz zum Original eine vernünftige Kapitelnummerierung. www.mikrocontroller.net/articles/AVR-Tutorial Recht umfangreiches Tutorial. Viele Beispiele in Assembler. Ohne Grundkenntnisse und ein gutes Glossar (also dieses Buch hier!) ist der Wissenserwerb auch dort etwas mühsam. Die Forengemeinde ist extrem aktiv (und manchmal auch extrem gemein/offen/ehrlich, knallharte Kerle eben, wenn man von den vielen Trollen absieht).
● 229
AVR Programmierung DE 160929.indd 229
25-10-16 11:45
AVR-Programmierung für Quereinsteiger
Kapitel 20 • Glossar Die hier gelisteten Begriffe und Abkürzungen sind nicht alle in den Datenblättern der ATmega zu finden, einige wurden im Zusammenhang mit MCUs in anderer Literatur gefunden. Wenn Sie, wie ich, zu der Spezies Mensch gehören, die sich Abkürzungen und (Spezial-) Vokabular nur schlecht einprägen können, werden Sie dieses Glossar sehr bald schätzen. AC
Alternating Current Wechselstrom, das Gegenstück ist DC (Direct Current), der Gleichstrom.
AC Analog Comparator Vergleicher von analogen Spannungen. Es können intern generierte Spannungen mit externen Spannungen verglichen werden, zudem steht (oft) eine Fensterfunktion zur Verfügung, bei der festgestellt werden kann, ob eine Spannung zwischen zwei vorgegebenen Spannungen liegt. ADC Analog-Digital-Converter Entweder ein eigener Baustein oder Teil einer MCU. Der ADC misst eine analoge Eingangsspannung und ordnet ihr eine natürliche Zahl zu, das heißt, der Messumfang (oft 0 bis 5 Volt) wird beispielsweise in 256 Schritte aufgeteilt. Der ADC ist das Gegenstück zum DAC (Digital Analog Converter). AES Advanced Encryption Standard Eine Verschlüsselungsmethode, die seit dem Jahr 2000 vom amerikanischen NIST (National Institute of Standards and Technology) für die Verwendung in Behörden freigegeben wurde. Dieser Standard ersetzte DES und TripleDES. Akkumulator Ein Akkumulator ist das, was heutzutage meist als Arbeitsregister bezeichnet wird. In einem Akku stehen Daten, die verarbeitet werden sollen, und anschließend steht das Ergebnis im Akkumulator. Der Begriff wird auch für wieder aufladbare Batterien benutzt. ALE Address Latch Enable Das ALE wird beim EBI (External Bus Interface, Ansprechen von memory mapped memory) benutzt, wenn nicht genügend Pins frei sind, um alle Leitungen parallel zu realisieren. Dann müssen Auffangregister benutzt werden und Port-Leitungen werden mit mehreren Funktionen nacheinander benutzt. ALU Arithmetic Logical Unit Dies ist der Teil in einer CPU (Central Processing Unit), der die eigentliche Arbeit ausführt, also etwa addiert, Bits verschiebt oder Inhalte über logische Funktionen (Oder, Und etc.) miteinander verknüpft. Oft wird auch der Befehlsinterpreter zur ALU hinzugerechnet (über den Befehlszähler wird ein Befehl geholt und der Befehlsinterpreter aktiviert den dazugehörigen Teil der ALU).
● 232
AVR Programmierung DE 160929.indd 232
25-10-16 11:45
AVR-Programmierung für Quereinsteiger
Kapitel 21 • Register alphabetisch In dieser Tabelle sind sowohl die Register des ATmega8 als auch die des ATmega328 enthalten. In den Spalten "ATmega8" sowie "ATmega328" befindet sich die Nummer des Kapitels, in dem dieses Register beschrieben wird. Wenn ein Register im ATmega328 exakt genauso benutzt wird, steht dort natürlich die gleiche Kapitelnummer. Register
Bedeutung
ATmega8
ATmega328
ACSR
Analog Comparator Status & Controller Reg.
11.1
11.1
ADC L&H
ADC Data Register High Byte
10.3
10.3
ADCSRA
ADc Controller & Status Register A
11.2
11.3
ADCSRB
ADc Controller & Status Register B
-
10.4 + 11.3
ADMUX
ADC Multiplexer select
10.3 + 11.2
10.3 + 11.3
ASSR
Asynchronous Status Register
8.4.1
8.4.2
CLKPR
CLocK Prescaler Register
-
12.1
DDRB
Data Direction Register, Port B
7.1
7.1
DDRC
Data Direction Register, Port C
7.1
7.1
DDRD
Data Direction Register, Port D
7.1
7.1
DIDR0
Digital Input Disbale Register 0
-
10.4 + 11.3
DIDR1
Digital Input Disbale Register 1
-
11.3
EEARH
EEPROM Address Register High
14
14
EEARL
EEPROM Address Register Low
14
14
EECR
EEPROM Controller Register
14
14
EEDR
EEPROM Data Register
14
14
EICRA
External Interrupt Controller Register A
-
5.4.2
EIFR
External Interrupt Flag Register
-
5.4.2
EIMSK
External Interrupt MaSK register
-
5.4.2
GICR
General Interrupt Controller Register
5.4.1
-
GIFR
General Interrupt Flag Register
5.4.1
-
GPIOR0
General Purpose I/O-Register 0
-
12.2
GPIOR1
General Purpose I/O-Register 1
-
12.2
GPIOR2
General Purpose I/O-Register 2
-
12.2
GTCCR
General Timer Counter Controller Register
-
8.4.2 + 8.5.3
ICR1H
Input-Capture-Register High Byte TC1
8.5.1
8.5.1
ICR1L
Input-Capture-Register Low Byte TC1
8.5.1
8.5.1
MCUCR
MCU Controller Register
5.4.1 + 6.1.1 5.4.2 + 6.1.2 + 7.1.2
MCUCSR
MCU Controller and Status Register
17
-
● 268
AVR Programmierung DE 160929.indd 268
25-10-16 11:46
Kapitel 22 • Alle Register-Bits alphabetisch
Kapitel 22 • Alle Register-Bits alphabetisch In der folgenden Tabelle sind sämtliche Registerbits von ATmega8 und ATmega328 alphabetisch gelistet und es wird jeweils auf das Register verwiesen, in dem es verwendet wird. Ein '-' bedeutet, dass dieses Bit im jeweiligen Prozessor nicht vorhanden ist. Bit-Name
Bedeutung
ATmega8
ATmega328
ACBG
Analog Comparator Band Gap select
ACSR
ACSR
ACD
Analog Comparator Disbale
ACSR
ACSR
ACI
Analog Comparator Interrupt flag
ACSR
ACSR
ACIC
Analog Comparator Input Capture enable
ACSR
ACSR
ACIE
Analog Comparator Interrupt Enable
ACSR
ACSR
ACIS0 und ACIS1
Analog Comparator Interrupt mode Select
ACSR
ACSR
ACME
Analog Comparator Multiplexer Enable
SFIOR
ADCSRB
ACO
Analog Comparator Output
ACSR
ACSR
ADATE
ADc Auto Trigger Enable
-
ADCSRA
ADC0 bis ADC9
ADC data register 10 bit
ADC L&H
ADC L&H
ADC0D bis ADC5D
ADC pin X Disable
-
DIDR0
ADEN
ADc ENable
ADCSRA
ADCSRA
ADFR
ADc Free Running mode
ADCSRA
-
ADIE
ADc Interupt Enable
ADCSRA
ADCSRA
ADIF
ADc Interrupt Flag
ADCSRA
ADCSRA
ADLAR
ADc Left Adjust Result
ADMUX
ADMUX
ADPS0 bis ADPS2
ADc Prescaler Select
ADCSRA
ADCSRA
ADSC
ADc Start Conversion
ADCSRA
ADCSRA
ADTS0 bis ADTS2
ADc auto Trigger Source 0 bis 2
-
ADCSRB
AIN0D und AIN1D
Analog digital Input X Disable
-
DIDR1
AS2
ASynchronous timer 2
ASSR
ASSR
BLBSET
Boot Lock Bit SET
SPMCR
SPMCSR
BODS
Brown Out Detector Sleep
-
MCUCR
BODSE
Brown Out Detector Sleep Enable
-
MCUCR
BORF
Brown Out Reset Flag
MCUCSR
MCUSR
C
Carry-Flag
SREG
SREG
CAL0–CAL7
oscillator CALibration value
OSCCAL
OSCCAL
CLKPCE
CLocK Prescaler Change Enable
-
CLKPR
CLKPS0 bis CLKPS3
CLocK Prescaler Select bits 0 bis 3
-
CLKPR
COM0A0 und COM0A1
COMpare match mode, timer 0 channel A
-
TCCR0A
● 271
AVR Programmierung DE 160929.indd 271
25-10-16 11:46
Kapitel 23 • Fuses und Lock-Bits alphabetisch
Kapitel 23 • Fuses und Lock-Bits alphabetisch Alle Lock-Bits und Fuses werden in Kapitel 13 beschrieben. Name
Bedeutung
BLB01 & BLB02
Lock-Bit-Anwendungssektor
BLB11 & BLB12
Lock-Bit-Bootsektor
BODEN
Festlegung, ob Brown-Out-Detektors immer an
BODLEVEL
Schaltspannung des Brown-Out-Detektors
BOOTRST
Start im Boot- oder Anwendungssektor
BOOTSZ0 & BOOTSZ1
Einstellung der Größe des Bootsektors
CKOPT
Kondensatoren für Quarz intern oder extern
CKSEL0 bis CKSEL3
Taktfrequenz des internen RC-Taktgenerators
EESAVE
Schützt das EEPROM beim Chip-Erase
LB1 & LB2
Lock-Bit-Flash-Speicher gesamt
RSTDISBL
Reset-Pin als IO-Port
SPIEN
Verbietet serielle Programmierung
SUT0 & SUT1
Einstellung des Start-Up-Timings
WDTON
Verbietet die Abschaltung des Watchdogs
● 279
AVR Programmierung DE 160929.indd 279
25-10-16 11:46
AVR-Programmierung für Quereinsteiger
Index
BSR 236
A
C
Addition 73
CAN 236
Address Latch Enable
232
Cast-Operator 68
Advanced Encryption Standard
232
CBI 236
AIN0 12
CCP 237
AIN1 12
CE 237
Akkumulator 232
CISC 237
Alternating Current
232
CLI 237
Analog Comparator
190
CLKO 14
Analog-Digital-Converter 232 Application Programmers Interface
233
Clock Prescaler
194
CMOS 237
Arbitration 158, 233
Compiler
Arduino 233
continue 77
AREF 12
Counter 124
232
CPU 238
ARM 233
CRC 238
ARP 233
CTC 238
Array 65
Cyclic Redundancy Check
Arithmetic Logical Unit
53, 237
168
ASCII 233 Assembler 233
D
asynchron 167
DAC 238
ATavrDragon 33
Datentypen 55
ATmega8 11
DCE 239
32
DDR 239
AVCC 12
DDS 239
AVR 234
Debugger 53
AvrDude 234
Debugging 195
AVR-libc 87
Default 239
Atmel Studio
Define-Anweisung 57 Deklaration 61
B 234
Demultiplexer 239
BASCOM 235
DES 239
Baud
167
DFLL 239
Betriebssystem 99
DIP 11
binär 235
Disassembly 226
Blöcke 60
Division 73
Bootloader 33, 235
DOR 240
BLS (Boot Loader Section)
235
Do-While-Schleife 78
Boundary Scan
235
DRAM 240
Breadboard 235
DSP 240
break 77
DTE 240
Brownout 236
DTI 240
Brown Out Detection
Dual Inline Plastic 11 duplex 241
Band Gap
235
BSP 236
● 280
AVR Programmierung DE 160929.indd 280
25-10-16 11:46
Index
E
I
EBI 241
I2C 247
EEPROM 28, 29, 202, 241
ICP1 12
else if
75
IDC 246
Else-Zweig 75
IDE 32
EMI 241
IEEE 246
ESD 241
If-Abfrage 75
ESR 241
inkrementieren 247
F
Interrupt 247
Input Capture
129
243
Interrupts 103
FireWire 242
Interrupt-Vektor 105
Flag 242
IO-Port 120
Flash 242
IrDA 248
Flash-Speicher 29
ISR 248
Field Programmable Gate Array
FLIP 242 Flip-Flop 242
J
FLOPS 242
JTAG 248
FOC 242
JTAGICE 248
132
Jumper 248
Forced Output Compare
For-Schleife 78 FPGA 243
K
FTDI 243
Kommentare 59
Fuse 197, 243
Konstante 55
Fuses 279 L G
LCD 249
Gatter 243
LDR 249
GCC 244
LED 249
GDB 244
Linker 249
General Interrupt Controller Register
105
Loader 53, 249
General Purpose I/O-Register
194
Lock-Bit 197, 199, 279
General-Purpose-Register 30
LPM 250
232
LPT 250
GND 12
LUFA 250
Glossar
goto 77 GUI 244
M MAC 250
H
Makefile 251
halbduplex 245
Makro 57
Handshake 168
Matrizen 67
HDL 245
MAX232 250
Heap 245
Microwire 251
HID 245
MIPS 251
HLL 245
MISO 12, 251
Hypertext 246
MLF 251
â—? 281
AVR Programmierung DE 160929.indd 281
25-10-16 11:46
AVR-Programmierung für Quereinsteiger
MMU 69, 252
Programm 31
Modulo-Division 73
Programmable Read Only Memory (PROM) 28
MOSFET 252
PROM 257
MOSI 12, 252
Prüfsumme 257
MPCM 252
PSR 257
MSPIM 252 MSPS 252
Q
Multiplexer 252
QDEC 257
Multiplikation 73
QFN 258
Multi Processor Communication Modus
QFP 258
171
QTouch 258 N Nebeneffekte 104 Nested Interrupting
104
NMI 253 Noise Canceller
129, 184
NVM 253
R Race Condition
258
Random Access Memory (RAM)
27
Read Only Memory (ROM)
28
Register 45, 46, 268 Register-Bits 271
O
Rekursive Programme
OC1A 12
Repeater 259
OCD 253
Reset 12
OCR 253
return 80
ODER-Verknüpfung 82
RISC 259
OOP 254
RMW 259
Opcode 254
RoHS 259
Overflow 254
ROM 259 Round Robin
259
P
RS232-Schnittstelle
168
Padding 254
RTC 260
PAL 254
RTOS 260
Parity-Bit 167
RXD 12, 168
258
PDIP 255 Perfboard 255
S
PIC 255
SBI 260
13
Scheduler 261
115
Schlafmodi 117
Pipelining 255
Schleifen 77
PLL 255
SCK 12, 261
Pointer 66
SCL 12
pollen 256
SDA 12
POR 256
SDRAM 261
Power Reduction Register
Semikolon 54
Pico Power Pin Change INTerrupt
195
PPI 256
Serial Programming Interface (SPI)
34
PQFP 256
serielle Schnittstelle
32
Preprocessor 57
SFTP 261
Prescaler 256
Shield 261
● 282
AVR Programmierung DE 160929.indd 282
25-10-16 11:46
Index
simplex 261
Variable 55
Slave Select
VCC 12
12
Sleep-Mode 118
verfusen 265
SMBus 261
Vergleiche 73
SMD 261
Vergleichsregister 130
SOC 261
Verschiebeoperationen 83
SOIC 262
Verzeichnisbaum 265
Speicher 27, 91
Vogelfutter 266
SPM 262
Vorteiler 256
SRAM 262 SSH 262
W
SSR 262
Watchdog Timer
Stack 47, 263
WDT 266
STK500 33
While-Schleife 78
207
170
WiFi 266
String 65
WLAN 266
Stop-Bit
Subtraktion 73 Switch-Case-Anweisung 76
X XCK 12
T
XTAL1 13
Taktrate 157 Task 263
Z
Tastverhältnis 263
ZIF 267
Temperatursensor 184
Zuweisung 72
TQFP 263 Trace-Anweisung 263 Tranceiver 264 Tri-State 264 TSOP 264 TTL 264 TWI 159, 264 TXD 12, 168 Typecast 264 Typen 70 U ULP 264 UND-Verknüpfung 81 Universal Serial Bus
265
Unterprogramme 61 USART 265 USB 265 USBasp 265 User Space
265
V
● 283
AVR Programmierung DE 160929.indd 283
25-10-16 11:46
ISBN 978-3-89576-322-9
Elektor-Verlag GmbH 52072 Aachen www.elektor.de
Das Buch wendet sich an alle, die bisher mit dem Arduino programmiert haben und nun nach technischen Möglichkeiten und Wegen suchen, ihre Elektronik- und Programmierkenntnisse zu erweitern. Dazu eignet sich die AVR-Programmierung im besonderen Maße.
AVR-PROGRAMMIERUNG FÜR QUEREINSTEIGER
AVR-Programmierung für Quereinsteiger besteht aus zwei Teilen. Im ersten Teil wird in einfachen Worten erklärt, wie eine MCU (= Micro Controller Unit) im Detail arbeitet. Dem folgt eine Einführung in die Programmiersprache C. Anschließend taucht der Leser im zweiten Teil des Buches in die Welt der Register und ihre Bits ein. Dort findet man auch ein umfangreiches Glossar aller Register- und Bit-Namen. Das Buch dient somit auch als Nachschlagewerk, wenn man sich durch das Datenblatt oder andere Texte arbeiten muss.
●
Auf ein abgeschlossenes Studium der Elektrotechnik (Schwerpunkt: Mess-, Regel- und Datentechnik) folgten etliche Jahre in der Industrie. Vor 20 Jahren brach er mit seinem Motorrad zu einer Weltumrundung auf (das war das Beste, was er sich in seinem Leben angetan hat).
Atmel AVR ist eine 8-Bit-Mikrocontroller-Familie des Herstellers Atmel. Diese Controller sind wegen ihres einfachen Aufbaus, ihrer leichten Programmierbarkeit, den kostenlosen Entwicklungswerkzeugen und der Verfügbarkeit in DIP-Gehäuseformen auch bei Elektronikern und Makern äußerst beliebt. Darüber hinaus sind diese Controller bereits ab zwei Euro erhältlich. Im Arduino UNO-Board wird der ATmega328 verwendet.
AVR-PROGRAMMIERUNG
JÜRGEN D. HENNING
Jürgen D. Henning
FÜR QUEREINSTEIGER
SHARE
AVR-PROGRAMMIERUNG
DESIGN
FÜR QUEREINSTEIGER
Jürgen D. Henning LEARN
DESIGN
SHARE
LEARN
LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● S RN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE SIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● RN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE
AVR-Programmierung für Quereinsteiger.indd All Pages
25-10-16 13:41