AVR-Programmierung für Quereinsteiger (Leseprobe)

Page 1

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


Turn static files into dynamic content formats.

Create a flipbook
Issuu converts static files into: digital portfolios, online yearbooks, online catalogs, digital photo albums and more. Sign up and create your flipbook.