AVR Anleitungen

Aktualisiert im Oktober 2026

AVR Mikrocontroller sind kleine programmierbare 1-Chip Computer mit 8-Bit Prozessor. Sie enthalten einen nicht flüchtigen "Flash" Speicher, und haben eine Debug-Schnittstelle durch die man im laufenden Betrieb untersuchen kann, was sich im Innern abspielt.

Mein Buch "Einstieg in die Elektronik mit Mikrocontrollern" steht nicht mehr zur Verfügung. Stattdessen empfehle ich nun die Arbeitsbücher von Funduino. Auf dieser Seite stelle ich ergänzende Informationen zu den aktuell brauchbaren Arbeitsmitteln bereit.

Empfohlene Modelle

ATMega328 in THT ATMega328 in SMD

Ich empfehle für's Hobby die kleinen AVR Modelle der zweiten Generation, mit ISP Schnittstelle und debugWIRE. Sie laufen praktischerweise mit 1,8 bis 5,5 Volt und passen direkt auf Steckbretter und Lochraster Platinen. Für diese Modelle stehen jede Menge gute Anleitungen und Bücher zur Verfügung.

Zum Einstieg eignet sich das Arduino Nano Board besonders gut. Es hat einen ATmega328 mit Quarz und USB. Chinesische Händler bieten sehr billige Nachbauten davon an, die gut funktionieren.

Die großen Modelle haben mehr Pins und mehr Speicher, sind aber teuer. Zum Debuggen haben sie eine JTAG Schnittstelle.

Microchip hat günstigere neue AVR Mikrocontroller entwickelt, jedoch sind sie viel komplizierter als die klassischen AVR. Man hätte ihnen besser einen anderen Namen geben sollen. Wesentlich beliebter sind zur Zeit die ebenfalls preisgünstigen STM32 Mikrocontroller, der Raspberry Pi Pico, sowie programmierbare WLAN Module mit ESP8266 und ESP32. Zu diesen findet man auch wieder reichlich Anleitungen, sowohl mit als auch ohne Arduino.

  1. Nachfolger nur in SMD: ATtiny 441, 841
  2. Nachfolger nur in SMD: ATmega 48PB, 88PB, 168PB und 328PB. Die Unterschiede sind in AT06609 und AT15007 dokumentiert.

ISP Schnittstelle

Über die ISP Schnittstelle lädt man das selbst geschriebene und compilierte Programm in den Flash Speicher des Mikrocontrollers. Die oben genannten Modelle haben alle eine ISP Schnittstelle, es gibt aber auch andere mit TPI, PDI und UPDI. Der alte ISP Stecker hat 10 Pins, der neue hat 6 Pins:

ISP Pinbelegung

Diese Pins muss man 1:1 verbinden. Außerdem braucht der Mikrocontroller eine Stromversorgung, die mit einem Abblock-Kondensator (z.B. 100 nF) stabilisiert wird.

Die meisten Boards haben einen Kondensator am Reset Pin. Dieser soll (falls vorhanden) maximal 10 µF haben, um die Funktion des Programmieradapters nicht zu beeinträchtigen. Für die Nutzung als debugWIRE (DW) muss der Kondensator entfernt werden.

Programmieradapter

Ein Programmieradapter verbindet die Programmierschnittstelle des Mikrocontrollers mit dem PC. Manche eignen sich auch zum Debuggen. Für Arduino Boards brauchst du keinen Programmieradapter, denn sie sind mit einem USB Bootloader ausgestattet. Trotzdem haben sie einen entsprechenden Stecker, falls der Bootloader mal versagt.

Übersicht zum Vergleich:
Spannung Avrdude Arduino IDE MPLAB X IDE ISP DW JTAG TPI PDI UPDI
PICkit Basic 1,2...5V ✅ ❌ ✅ ✅ ✅ ✅ ✅ ✅ ✅
MPLAB Snap 1,4...5V ✅ ☑️1 ✅ ✅ ✅ ✅ ✅ ✅ ✅
Atmel ICE 1,6...5,5V ✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅
Atmel AVRISP mkII 1,6...5,5V ✅ ✅ ✅ ✅ ❌ ❌ ✅ ☑️4 ❌
STK500 kompatible meistens 3,3 und 5V ✅ ✅ ❌ ✅ ❌ ❌ ❌ ❌ ❌
USBasp 5V ✅ ✅ ❌ ✅ ❌ ❌ ❌ ❌ ❌
USBtiny 2...5.5V ✅ ✅ ❌ ☑️2 ❌ ❌ ❌ ❌ ❌
Arduino als ISP 5V ✅ ✅ ❌ ✅ ☑️3 ❌ ❌ ❌ ❌
  1. nur mit den Cores von MCUdude und Spence Konde
  2. maximal 64 kB
  3. debugWIRE nur mit der dw-link Firmware und den Cores von MCUdude
  4. viele ATxmega, nicht alle

Microchip MPLAB PICkit Basic

Mit dem MPLAB PICkit Basic kann man fast alle Mikrocontroller von Microchip und Atmel sowohl programmieren als auch debuggen.

Microchip MPLAB PICkit Basic

Der MPLAB PICkit Basic unterstützt PIC, PIC32 und dsPIC Mikrocontroller (mit ICSP, JTAG, SWD), SAM Mikrocontroller (mit SWD und JTAG) und AVR Mikrocontroller (mit ISP, debugWIRE, JTAG, TPI, PDI, UPDI). Er kann mit Spannungen von 1,2 bis 5 Volt arbeiten.

Der MPLAB PICkit Basic verwendet unter Windows den Standard-Treiber "winusb" und unter Linux "libusb". Er kann mit Avrdude (ab Version 8.1) und der MPLAB X IDE benutzt werden. Es gibt keine andere kompatible IDE.

Microchip MPLAB Snap

Der ältere MPLAB Snap wird ohne Gehäuse verkauft. Auch er kann inzwischen fast alle Mikrocontroller von Microchip und Atmel programmieren und debuggen.

Microchip MPLAB SNAP

Der MPLAB Snap unterstützte Anfangs nur PIC, PIC32 und dsPIC Mikrocontroller (mit ICSP, JTAG, SWD) und SAM Mikrocontroller (mit SWD und JTAG). Später wurde eine zweite Firmware zur Unterstützung von AVR Mikrocontrollern (mit ISP, debugWIRE, JTAG, TPI, PDI, UPDI) hinzugefügt. Er kann mit Spannungen von 1,4 bis 5 Volt arbeiten.

Der MPLAB Snap verwendet unter Windows den Standard-Treiber "winusb" und unter Linux "libusb". Er kann mit Avrdude ab v7.1, Arduino und der MPLAB X IDE benutzt werden. Die Arduino IDE kann den MPLAB Snap nur mit den AVR Cores von MCUdude und Spence Konde. benutzen. Das ältere Microchip Studio 7 ist zur aktuellen Firmware nicht mehr kompatibel.

Du bekommst die aktuelle Firmware mit der MPLAB X IDE. Die IDE konfiguriert den Snap bei Bedarf automatisch auf den `avr` oder `pic` Modus um. Man kann dazu auch Avrdude ab Version 7.3 benutzen:

avrdude -c snap -x mode=avr
avrdude -c snap -x mode=pic

Nach dem Ändern des Modus muss man das USB Kabel entfernen und wieder anschließen. Außerdem muss der markierte Jumper J5 richtig eingestellt sein. Wenn der Jumper auf deiner Platine fehlt, ist für TPI, PDI und UPDI eine kleine Modifikation notwendig. Siehe auch diesen Hinweis.

Atmel ICE

Wer AVR Mikrocontroller nicht nur programmieren sondern auch debuggen wollte, musste lange Zeit diesen sauteuren Atmel ICE verwenden.

Atmel ICE

Der Atmel ICE unterstützt alle AVR Mikrocontroller mit ISP, debugWIRE, JTAG, TPI, PDI und UPDI Schnittstelle. Außerdem unterstützt er viele SAM ARM Controller mit SWD und JTAG. Er kann mit dem vollen Spannungsbereich von 1,6 bis 5,5 Volt arbeiten.

Der Atmel ICE wird von Avrdude, Arduino, Atmel Studio 6, Microchip Studio 7 und der MPLAB X IDE unterstützt. Arduino und Avrdude brauchen unter Windows den libusb-win32 Treiber. Unter Linux wird "libusb" verwendet.

Die Anschlüsse des Gerätes haben 1,27 mm Raster, so dass man auf spezielle Adapterkabel angewiesen ist. Bitte verwechsele das Produkt nicht mit den noch älteren "JTAGICE" Geräten.

Atmel AVRISP mkII

Der robuste Atmel AVRISP mkII kann nur programmieren, nicht debuggen. Er war viele Jahre lang mein Lieblings-Programmieradapter. Man kann ihn nicht mehr als Original kaufen.

Atmel AVRISP mkII

Der AVRISP mkII unterstützt alle AVR Mikrocontroller mit ISP, TPI und viele (nicht alle) ATxmega Modelle mit PDI Schnittstelle. Er kann mit dem vollen Spannungsbereich von 1,6 bis 5,5 Volt arbeiten.

Der AVRISP mkII wird von Avrdude, Arduino, AVR Studio 4/5, Atmel Studio 6 und Microchip Studio 7 unterstützt. Die MPLAB X IDE arbeitet nicht mit diesem Programmieradapter. Arduino und Avrdude brauchen unter Windows den libusb-win32 Treiber. Unter Linux wird "libusb" verwendet. Die Avrdude Version von Debian und Ubuntu meldet bei diesem Programmieradapter einen Fehler, dass libusb-0.1 nicht mehr unterstützt wird. Aber die Version von Arduino funktioniert noch.

Es gibt kompatible Nachbauten. Viele Geräte, die so aussehen und auch ähnlich heißen, sind allerdings Täuschungen, in denen sich ein einfacher STK500 befindet!

Atmel STK500

Das STK500 von Atmel ist ein altes Experientierbrett für zahlreiche AVR Mikrocontroller. Man kann es nicht mehr kaufen. Ich erwähne es hier, weil dessen Programmieradapter und sein Kommunikationsprotokoll für zahlreiche andere Programmieradapter als Vorlage diente.

STK500

Das STK500 Protokoll ist ausschließlich für die ISP Schnittstelle vorgesehen. Debuggen kann man damit nicht. Es gibt zwei zueinander inkompatible Protokoll-Versionen: v1 und v2. Wenn keine Version genannt wird, dann ist in der Regel die v2 gemeint, auch AVRISP genannt.

STK500 und kompatible Programmieradapter werden von Avrdude, Arduino, AVR Studio 4/5, Atmel Studio 6 und Microchip Studio 7 unterstützt. Die MPLAB X IDE unterstützt keine STK500.

Diamex USB ISP Stick

Von der Firma Diamex gibt es einige gute Programmieradapter ohne Debugger Funktion. Zum Beispiel diesen "USB ISP-Programmer Stick für AVR".

Diamex USB-ISP Stick

Der STK500 v2 kompatible Stick unterstützt alle AVR Mikrcocontroller mit ISP Schnittstelle. Er kann mit 3,3 und 5 Volt arbeiten und wahlweise auch die Zielschaltung versorgen. Der Stick wird von Avrdude, Arduino, AVR Studio 4/5, Atmel Studio 6 und Microchip Studio 7 unterstützt. Für die MPLAB X IDE hat Diamex keine passenden Programmieradapter im Angebot.

USBasp

Der USBasp ist ein ISP Programmieradapter ohne Debugger Funktion, von Thomas Fischl. Chinesische Händler bieten billige Nachbauten davon an. Sie sind im Arduino Umfeld weit verbreitet.

USBasp

Der USBasp unterstützt alle AVR Mikrcocontroller mit ISP Schnittstelle.

Wenn JP1 gesteckt ist liefert der Stick je nach Position eine Versorgungsspannung von 3,3 oder 5 Volt an die Zielschaltung. Die Signale haben aber immer 5 Volt Pegel! Ohne zusätzliche Pegelwandler eignen sich diese Sticks nur für 5 Volt. Notfalls tun es einfache Widerstände mit 220 Ω in den Signal-Leitungen, zusammen mit einer niedrigen Taktfrequenz.

Die ISP Taktfrequenz wird je nach Firmware Version unterschiedlich eingestellt:

Der USBasp ist zu keinem anderen Programmieradapter kompatibel. Die Software von Atmel und Microchip unterstützt den USBasp nicht. Du kannst ihn aber mit Avrdude und der Arduino IDE benutzen. Unter Windows brauchst du normalerweise den libusb-win32 Treiber. Es gibt eine modifizierte Firmware Version, die den "winusb" Treiber unterstützt. Unter Linux wird "libusb" verwendet.

USBtiny

Der USBtiny ist ein ISP Programmieradapter ohne Debugger Funktion, von Dick Streefland. Chinesische Händler bieten günstige Nachbauten davon an.

USBtiny

Der USBtiny unterstützt nur AVR Modelle mit ISP Schnittstelle und maximal 64 kB Flash. Er kann mit 2 bis 5,5 Volt arbeiten. Wenn JP3 gesteckt ist, liefert der Adapter eine Versorgungsspannung 5 Volt an die Zielschaltung. Für andere Spannungen muss der Jumper entfernt werden.

Die Ausgänge MOSI und SCK haben oft Widerstände mit 1,5 kΩ in Reihe geschaltet. Einerseits sind sie ein guter Schutz gegen Kurzschluss, andererseits können sie je nach Zielschaltung Probleme bereiten, wenn die betroffenen Pins in der Zielschaltung noch für etwas anderes verwendet werden. Ich würde sie durch 220 Ω oder Drahtbrücken ersetzen.

Der USBtiny ist zu keinem anderen Programmieradapter kompatibel. Die Software von Atmel und Microchip unterstützt den USBtiny nicht. Du kannst ihn aber mit Avrdude und der Arduino IDE benutzen. Unter Windows brauchst du den libusb-win32 Treiber.

Arduino als ISP

Arduino Uno R3 und Arduino Nano V3 Boards kann man mit der richtigen Firmware zum Programmieradapter machen.

Arduino UNO Arduino Nano

Ich kenne zwei Optionen:

  1. Die Arduino IDE enthält ein Beispiel Namens ArduinoISP, das man einfach auf das Board hochladen kann. Damit wird das Arduino Board zu einem ISP Programmieradapter. Die Pinbelegung ist
    Arduino als ISPZiel
    D10/Reset
    D11MOSI
    D12MISO
    D13SCK
    Nach dem Hochladen des ArduinoISP Sketches gehört ein 10 µF Kondensator an RESET und GND, um den Bootloader zu zu blockieren.
     
  2. Mit dw-link kann das Arduino Board nicht nur als ISP Programmieradapter sondern auch als Debugger dienen. Debuggen kann er nur die kleinen AVR Modelle mit debugWIRE. In der Arduino IDE verwendet man dazu den TinyCore oder den MiniCore. Die Pinbelegung ist:
    Arduino als ISPZiel
    D8/Reset
    D11MOSI
    D12MISO
    D13SCK
    An D7 und GND kann man eine gelbe LED zur Statusanzeige anschließen, natürlich mit Vorwiderstand.

In beiden Fällen wird ein STK500 v1 simuliert, der alle AVR Mikrcocontroller mit ISP unterstützt. Der einfache Aufbau eignet sich aber nur für 5 Volt. Die Dokumentation von dw-link enthält einen besseren Schaltungsvorschlag mit Pegelwandlern.

Die MPLAB X Ide kann diesen Programmieradapter nicht benutzen.

Software

USB Treiber

Arduino Boards, USB-UART Adapter und viele Programmieradapter stellen einen (virtuellen seriellen) COM Port zur Verfügung, über den sie ansprechbar sind.

Windows

USB Geräte mit COM Port lösen beim Anstecken die Installation des Treibers passend zum USB Chip aus. Teilweise geschieht das vollautomatisch. Allerdings gibt es oft Probleme mit alten und gefälschten Chips. Mehr dazu dort. Du kannst im Gerätemanager beobachten, welcher COM Port erscheint, sobald du das Gerät anschließt. Dort werden auch Fehlermeldungen angezeigt, falls der Treiber nicht geladen werden konnte.

Bei den Programmieradaptern ohne COM Port ist die Lage etwas chaotisch. WCID kompatible Programmieradapter werden automatisch vom winusb Treiber unterstützt, der im Lieferumfang von Windows enthalten ist. Für andere nicht WCID kompatible Programmieradapter und alte Programme benötigt man stattdessen meistens den libusb-win32 Treiber. Die Software von Atmel verwendet hingegen den eigens mitgelieferten Jungo Treiber. Dieser kann parallel zu "winusb" und "libusb-win32" installiert werden.

Linux

Linux enthält standardmäßig die Treiber für alle COM Ports. Die COM-Ports heissen dort `/dev/ttyUSB0`, `/dev/ttyACM0`, oder so ähnlich. Du kannst den Befehl sudo dmesg oder sudo journalctl -kn 20 direkt nach dem Anstecken des USB Kabels benutzen, um den Namen des COM Portes heraus zu finden. Normale (nicht root) Benutzer müssen Mitglied der Gruppe "dialout" sein, um diese Ports benutzen zu dürfen. Das geht mit dem Befehl sudo adduser deinusername dialout. Du musst dich danach neu einloggen.

Programmieradapter ohne COM Port werden in der Regel durch den libusb Treiber angesprochen, der in jeder Standardinstallation enthalten ist. Um normalen (nicht root) Benutzern Zugriff auf den USB Port zu gewähren, musst du eventuell udev Regeln anlegen: Kopiere die Datei 99-programmer.rules ins Verzeichnis /etc/udev/rules.d. Sie wird beim nächsten Einstecken des USB Kabels wirksam.

Avrdude

Avrdude ist ein sehr weit verbreitetes Bedienprogramm für viele Programmieradapter. Die Arduino IDE enthält es als Unterprogramm. Avrdude wird über Komandozeilen-Parameter gesteuert. Beispiele:

Programmieradapter Befehl
Microchip MPLAB PICkit Basic avrdude -c pickit_basic_isp -B 20 -p attiny85
Microchip MPLAB Snap avrdude -c snap_isp -B 20 -p attiny85
Atmel ICE avrdude -c atmelice_isp -B 20 -p attiny85
Atmel AVRISP mkII,
Diamex AVR-Prog
avrdude -c avrispmkii -B 20 -p attiny85
Atmel STK500,
Diamex Produkte,
SiSy Solutions mySmartUSB light
avrdude -c stk500v2 -P COM3 -B 20 -p attiny85
USBasp avrdude -c usbasp -B 20 -p attiny85
USBtiny avrdude -c usbtiny -B 20 -p attiny85
In-Circuit ICprog-AVR avrdude -c avr910 -P COM3 -b 115200 -p attiny85
Arduino als ISP, dw-link avrdude -c stk500v1 -P COM3 -p attiny85
Arduino Boards mit altem Bootloader avrdude -c arduino -P COM3 -b 57600 -p atmega328
Arduino Boards mit neuem Bootloader avrdude -c arduino -P COM3 -b 115200 -p atmega328

Unter Linux heißen die COM Ports `/dev/ttyUSB0`, `/dev/ttyACM0`, oder so ähnlich. Bei USB Geräten ohne COM Port gibt man `-P usb` an oder lässt den Parameter ganz weg.

Mit `-B 20` reduziert man vielen Programmieradaptern die Taktfrequenz der ISP Schnittstelle auf 1/20 µs = 50 kHz.

Ich hänge beim Verbindungstest noch den Parameter `-v` an, um mehr Details zu sehen:

Bildschirmfoto von Avrdude

Avrdude bestätigt, dass die Kommunikation funktioniert (ready to accept instructions). Mögliche Ursachen für Störungen sind:

Wenn das soweit klappt, kannst du Kommandos anhängen:

Aktion Kommando
Den Programmspeicher auslesen -U flash:r:dateiname.bin:r
Den Programmspeicher beschreiben (bin, hex oder elf Datei) -U flash:w:dateiname.hex
Das EEPROM auslesen -U eeprom:r:dateiname.bin:r
Das EEPROM beschreiben (bin, hex oder elf Datei) -U eeprom:w:dateiname.hex
Fuses auslesen (lfuse, hfuse, efuse) -U efuse:r:-:h
Fuses ändern (lfuse, hfuse, efuse) -U efuse:w:0xff:m
⚠️ Falsch gesetzte Fuses können den Mikrocontroller unbrauchbar machen! Die Webseiten Engbedded Fuse Calculator und Eleccelator helfen dabei.

Toolchains

Die GNU Toolchain enthält den GCC Compiler (samt seiner Unterprogramme), die Standard C-Bibliothek und das Make Programm. Der Boardmanager von Arduino installiert die passende Toolchain automatisch mit. In allen anderen Fällen musst dich selbst um die Installation kümmern.

Linux Distributionen stellen die Toolchain über ihren Paketmanager bereit. Bei Debian und Ubuntu heißen die Pakete gcc-avr, avr-libc und make.

Alternativ kann ich folgende Angebote empfehlen:

Die Dokumentation der AVR C Bibliothek findest du dort.

Integrierte Entwicklungsumgebungen

Um AVR Mikrocontroller zu programmieren, brauchst du im Prinzip nur drei Dinge:

Für mittlere bis große Projekte eignen sich integrierte Entwicklungsumgebungen (kurz IDE) besser, denn sie machen während der Eingabe Vorschläge (was Tipparbeit erspart) und markieren Fehler schon vor dem Compilieren. Wenn man mit gedrückter Strg Taste auf einen Namen klickt, springt der Editor automatisch zu der relevanten Datei. Die meisten Entwicklungsumgebungen unterstützen beim Refactoring. Auch das Generieren von Code gehört bei manchen Entwicklungsumgebungen zum Funktionsumfang.

Viele Entwicklungsumgebungen stellen eine dialog-basierte Projekt-Konfiguration bereit, wo man einstellen kann, mit welchen Parametern der Compiler aufgerufen werden soll. Diese werden oft automatisch sinnvoll konfiguriert so dass man sich direkt auf den Quelltext konzentrieren kann. Derartige Projekte brauchen kein Makefile, allerdings hängen sie von dieser einen IDE ab, mit der sie erstellt wurden. Ich bevorzuge Makefiles (Beispiel).

Wenn dir das Debuggen in der IDE wichtig ist, dann empfehle ich die Software und Hardware von Microchip. Die Open-Source Alternativen sind dagegen eine elende Frickelei. Der Hersteller bemüht sich nämlich sehr darum, die Kommunikationsprotokolle der Debugger-Schnittstellen geheim zu halten.

Die folgenden Entwicklungsumgebungen gibt es alle für Linux, Windows und macOS.

Microchip MPLAB X

Die MPLAB X Entwicklungsumgebung ist schon länger für die Programmierung der Produkte von Microchip bekannt. Inzwischen taugt sie auch für AVR Mikrocontroller. Die MPLAB X IDE enthält einen Debugger und einen Simulator für viele AVR Modelle, so dass man deren Programmierung ohne Hardware ein bisschen üben kann.

MPLAB X basiert auf Netbeans. Du brauchst einen PC mit mindestens 4 CPU Kernen, 8 GB RAM und 7 GiB Platz auf der SSD order NVMe. Rotierende Festplatten sind für diese IDE ungeeignet. Für Windows empfiehlt der Hersteller 16 bis 32 GB RAM.

Es ist nicht vorgesehen, bestehende Projekte mit Makefile zu importieren. Die IDE generiert immer ihr eigenes Makefile, das zwar an der Kommandozeile nutzbar ist, aber die IDE muss dennoch installiert sein.

Die Anzeige der Peripherie-Register wurde im Menü "Window / Debugging / I/O View" versteckt.

Wer ältere Entwicklungsumgebungen von Atmel gewöhnt ist wird womöglich die Unterstützung seines Programmieradapters vermissen. Für diese IDE empfehle ich den PICkit Basic oder den billigeren MPLAB Snap.

Arduino IDE

Die Arduino IDE richtet sich primär an Bastler, die schnelle Ergebnisse wollen. Du brauchst einen PC mit mindestens 8 GiB RAM und etwa 2 GiB freien Speicherplatz.

Das Arduino Framework vereinheitlicht die Programmierung unterschiedlicher Mikrocontroller-Boards so weit es geht. Auf diese Weise kann man nicht alle Funktionen der Mikrocontroller nutzen. Allerdings hindert Arduino niemanden daran, den Chip teilweise am Framework vorbei zu programmieren. Ein großer Vorteil ist die Verfügbarkeit zahlreicher Bibliotheken.

Das folgende Programm (auch "Sketch" genannt) gibt den Text "Hello World!" aus und lässt eine LED blinken:

#include <Arduino.h>

void setup() {  
  Serial.begin(9600);
  Serial.println(F("Hello World!"));
  pinMode(LED_BUILTIN, OUTPUT);
}

void loop() {
  digitalWrite(LED_BUILTIN, HIGH);
  delay(100);
  digitalWrite(LED_BUILTIN, LOW);
  delay(900);
}

Mit F("...") spart man Platz im RAM. Solche Zeichenketten werden direkt aus den Flash Speicher gelesen.

Obwohl alle Arduino Funktionen angenehm einfach Dokumentiert sind, solltest du dennoch immer die Dokumente der Chip-Hersteller lesen, denn in der Arduino Dokumentation fehlen oft wichtige Details. Kläre vor der Verwendung fremder Bibliotheken, ob sie zu deiner Arduino Version und deinem Mikrocontroller kompatibel sind. Das ist nicht immer der Fall.

Der originale "Arduino AVR Boards" Manager enthält die Toolchain und Beispiele für:

Diese Boards brauchen keinen Programmieradapter, weil sie einen USB Bootloader haben. Du kannst in den Einstellungen zusätzliche Boardmanager URLs hinzufügen, um weitere AVR Modelle zu unterstützen. Ich empfehle:

Lies auf jeden Fall immer die Dokumentation der Cores, bevor du damit arbeitest. Cores für die neueren AVR Modelle findest du bei Spence Konde.

Arduino setzt zur Fehlersuche auf Textausgaben, die der "Serial Monitor" anzeigt. Der Debugger ist eigentlich nur für 32 Bit ARM Controller vorgesehen. Aber die Cores von MCUdude ermöglichen das Debuggen trotzdem, indem sie das Programm PyAvrOCD integrieren. Als Adapter eignen sich MPLAB Snap, PICkit 4, Atmel ICE und Arduino Boards mit dw-link. Ich bin dabei auf zwei Probleme gestoßen: PyAvrOCD #24 und MiniCore #383 (beide noch nicht gelöst aber mit Workaround).

Die alte Arduino IDE Version 1.8 kann man auf einen mobilen Datenträger auspacken und dann ohne Installation auf anderen Computern benutzen. Dazu muss man einfach nur einen Ordner mit Name "portable" anlegen (dort wo die arduino.exe liegt). Mit der Arduino IDE 2.x geht das nicht mehr, da sie zahlreiche Dateien in das Home-Verzeichnis des Benutzers installiert.

Qt Creator

Qt Creator ist eine kostenlose IDE für C/C++ Projekte mit speziellen Features für das Qt Framework. Qt Creator hat von allen hier genannten IDEs die beste Quelltext-Analyse (ohne KI), was das Erkennen von potentiellen Fehlern betrifft. Die IDE läuft auf jedem Computer flott.

Du kannst bestehende Projekte über das Menü "Datei/Neu/Projekt importieren/Import eines existierenden Projekts" importieren. In der Datei "Projektname.files" gibst du an, welche Dateien du in Qt Creator sehen willst.

In der Datei "Projektname.includes" gibst du alle Verzeichnisse an, wo die Header Dateien der C-Bibliotheken gesucht werden sollen. Zum Beispiel:

/usr/lib/avr/include

Definiere in der Datei "Projektname.config" ein Makro mit dem Typ des Mikrocontrollers. Die richtige Schreibweise findest du in der Datei avr/io.h. Zum Beispiel:

#define __AVR_ATtiny2313__

Zum Compilieren rufst du "make" im Terminalfenster auf.

Der integrierte Debugger von dieser IDE ist nicht für AVR Mikrocontroller geeignet.

Visual Studio Code

Visual Studio Code (vscode) ist eine kostenlose Entwicklungsumgebung von Microsoft. Visual Studio Code enthält KI Agenten von "GitHub Copilot".

{
    "configurations": [
        {
            "name": "AVR",
            "includePath": [
                "${workspaceFolder}/**"
            ],
            "defines": [
                "__AVR_ATtiny2313__"
            ],
            "compilerPath": "/usr/bin/avr-gcc",
            "cStandard": "c11",
            "cppStandard": "c++11"
        }
    ],
    "version": 4
}
Gebe bei den defines den passenden Wert für deinen Mikrocontroller an. Die richtige Schreibweise findest du in der Datei avr/io.h.

Zum Compilieren rufst du "make" im Terminalfenster auf.

Der integrierte Debugger von dieser IDE ist nicht für AVR Mikrocontroller geeignet.

NetBeans

NetBeans war primär für Java Anwendungen gedacht, hat aber auch einen guten C/C++ Editor als Plugin. Du musst vorher eine Java Runtime installieren. Im Menü Tools/Plugins kannst du das C/C++ Plugins nachinstallieren. Konfiguriere es so:

Dieses Bildschirmfoto zeigt die richtigen Einstellungen für Linux:

Bildschirmfoto von Einstellungen in Netbeans

Anschließend kannst du das Mikrocontroller-Projekt über das Datei Menü von NetBeans öffnen:

Damit NetBeans die SFR Register (zum Beispiel PORTB) erkennt,

Bildschirmfoto von Einstellungen in Netbeans

Ich habe diese Anleitung gefunden, wo erklärt wird, wie man den Editor von NetBeans benutzt.

Zum Compilieren rufst du "make" im Terminalfenster auf.

Der integrierte Debugger von dieser IDE ist nicht für AVR Mikrocontroller geeignet.

Eclipse

Eclipse war ebenfalls ursprünglich eine Entwicklungsumgebung für Java, unterstützt nun jedoch viele andere Sprachen. Eclipse fällt durch extrem viele Einstellmöglichkeiten und Plugins auf. Die Einarbeitungszeit ist deutlich länger, als bei den anderen Alternativen. Du musst vorher eine Java Runtime installieren.

Downloade die Eclipse IDE für C/C++ Entwickler oder installiere das C/C++ Plugin in eine bereits vorhandene Eclipse IDE. Importiere das Projekt über das Menü "File/New/Makefile Projekt With Existing Code".

Klicke dann mit der Rechten Maustaste auf den Namen des soeben importierten Projektes, und dann auf Properties.

Zum Compilieren rufst du "make" im Terminalfenster auf.

Der integrierte Debugger von dieser IDE ist nicht für AVR Mikrocontroller geeignet.

Hello World! Vorlage

Dies ist eine Kopiervorlage zum Starten neuer Bare-Metal Projekte (also ohne Arduino). Es stellt eine serielle Konsole bereit und nutzt den Timer 0, um Millisekunden zu zählen.

HelloWorld.zip nutzt den Hardware UART bidirektional. Für ATtiny 441, 841, 2313, 4313, sowie ATmega 48, 88, 164, 168, 324, 328, 640, 644, 1280, 1281, 1284, 2560, 2561.

HelloTiny.zip mit soft-serial Emulation, nur Ausgabe. Für ATtiny 13, 24, 25, 44, 45, 84, 85, 261, 441, 461, 841, 861, 2313, 4313 sowie ATmega 48, 88, 164, 168, 324, 328, 640, 644, 1280, 1281, 1284, 2560, 2561.

Das Projekt enthält ein Makefile, so dass du die freie Wahl hast, ob und welche Entwicklungsumgebung du verwenden willst. Ein einfacher Text-Editor tut es auch.

Anwendungsbeispiel für den ATtiny2313:

int main(void) {
    initSerialConsole();
    initSystemTimer();
    DDRA |= (1<<PA1); // PA1 = output for the LED
    
    while(1){
        delay(500);
        PORTA |= (1<<PA1); // LED on
        puts_P(PSTR("Hello World"));

        delay(500);
        PORTA &= ~(1<<PA1); // LED off
        
        char buffer[6];
        utoa(milliseconds(),buffer,10);
        puts(buffer);
    }
}

Das Ausgeben von Text mit puts(), putchar() und printf() ist bei der Fehlersuche sehr hilfreich. Für das komfortable printf() hat der kleine ATtiny2313 allerdings nicht genug Speicher, deswegen nehme ich hier stattdessen utoa() und puts().

Das Programm benutzt PSTR("...") und puts_P() um RAM zu sparen. Dieser Text wird direkt aus dem Flash Speicher gelesen. Normale Zeichenketten würden hingegen im RAM liegen.

Die größere HelloWorld Variante kann auch Empfangen, also gets(), getchar() und scanf() verwenden. Außerdem stehen die standard Streams `stdin` und `stdout` zur Verfügung.

Die genannten Funktionen sind Bestandteil der AVR C Bibliothek und dort dokumentiert. Die beiden init-Funktionen, delay() und milliseconds() habe ich selbst programmiert. Sie sind in den *.h Dateien dokumentiert.

Probeaufbau

Foto vom Probeaufbau mit Steckbrett

Zur Stromversorgung benutze ich Akkus mit 3,6 Volt an VCC und GND, da mein Programmieradapter keine Stromversorgung bereit stellt.

Der Probeaufbau nutzt den internen R/C Oszillator, dessen Frequenz für serielle Kommunikation zu instabil ist. Für kurze Tests hat er bei mir jedoch bisher immer genügt. Ernsthafte Anwendungen benutzen einen Quarz.

Makefile

Das Programm "Make" erkennt Änderungen und Abhängigkeiten, um die nötigen Kommandos der Toolchain in der richtigen Reihenfolge auszuführen. Schaue dir mal den oberen Teil des Makefiles vom HelloTiny Projekt an:

# Makefile for this AVR project

# make code       Compiles the source code
# make program    Program FLASH and EEPROM
# make fuses      Program fuses
# make list       Create Assembler listing
# make clean      Delete all generated files

# Parameters for the programming adapter
AVRDUDE = avrdude -c avrispmkii -B 20

# Microcontroller type and clock frequency
MCU = attiny2313
F_CPU = 1000000

# Optional fuse settings, for example
# LFUSE = 0x64
# HFUSE = 0xDF
# EFUSE = 0xFF

# Name of the program
PRG = HelloTiny

# Sources to compile
SRC = main.c driver/serialconsole.c driver/systemtimer.c

Hier stehen zuerst Hinweise, mit welchen Parametern man "make" aufrufen kann. Mit make code compiliert man den Quelltext1. Als Resultat entsteht die Datei HelloTiny.elf mit dem ausführbaren Maschinencode (vergleichbar mit *.exe bei Windows). Mit make program überträgt man das Programm auf den Mikrocontroller.

Hinter AVRDUDE stehen die Parameter für den Programmieradapter.

MCU und F_CPU sind passend zum Mikrocontroller eingestellt. Man kann die Taktfrequenz nicht mit F_CPU verändern, sondern F_CPU muss mit der tatsächlichen Frequenz überein stimmen.

Fuses werden mit dem Befehl make fuses geändert. Ich habe die Fuses auskommentiert, weil die Werkseinstellung schon passt. Falls du sie doch ändern willst, vergewissere dich unbedingt vorher, dass die Werte richtig sind. Sie sind bei jedem AVR Modell anders! Falsche Fuses können den Mikrocontroller dauerhaft unbrauchbar machen. Die Online Fuse-Kalkulatoren von Engbedded und Eleccelator helfen bei der Berechnung der Hexadezimal-Zahlen.

Hinter SRC sind alle C Quelltexte aufgelistet, die zusammen das Programm bilden. Das Makefile unterstützt auch C++.

Weiter unten im Makefile findest du erweiterte Einstellmöglichkeiten, die für künftige Projekte relevant werden könnten. Für das vorliegende Projekt gibt es dort nichts zu ändern.

  1. Änderungen an *.h Dateien werden von diesem Makefile nicht zuverlässig erkannt. Rufe im Zweifelsfall make clean code auf, damit wirklich alle Dateien erneut compiliert werden.

Quelltext an die Hardware anpassen

Trage die richtigen Parameter für Avrdude in das Makefile ein. Passe MCU und F_CPU an deinen Mikrocontroller an, falls du einen anderen verwendest. Dann wirst du wohl auch die drei Zeilen in main.c für die Ansteuerung der LED auf den richtigen Port-Pin ändern müssen.

Werfe einen Blick in die Datei driver/serialconsole.h, dort wird die serielle Schnittstelle konfiguriert:

// Serial bitrate
#define SOFTSERIAL_BITRATE 2400

// Macros to control the TxD Pin
#define SOFTSERIAL_TXD_INIT   { DDRD  |=  (1<<PD1); }
#define SOFTSERIAL_TXD_HIGH   { PORTD |=  (1<<PD1); }
#define SOFTSERIAL_TXD_LOW    { PORTD &= ~(1<<PD1); }

Hier wird PD1 für die serielle Ausgabe verwendet.

Da der ATtiny2313 eine echte UART Schnittstelle hat, könntest du dafür auch die HelloWorld Vorlage benutzen. Du wirst sehen, dass die Datei driver/serialconsole.h dort andere Konfigurationsparameter hat, nämlich die Nummer der seriellen Schnittstelle (manche Modelle haben mehr als eine) und die Größe des Empfangspuffers.

Compilieren und Ausführen

Danach müsste die LED Blinken.

Schließe einen USB-UART Adapter an. Die Signale gehören in der Regel über Kreuz verbunden:

AVRRichtungPC
TxD→RxD
RxD←TxD
GND↔GND

Wobei wir mit dem vorliegenden Testprogramm nur die Richtung vom AVR zum PC hin nutzen.

Ein Terminalprogramm (z.B. Hammer Terminal oder Cutecom) zeigt jede Sekunde den Text "Hello World" und den Zählerstand des Systemtimers an. Mit Cutecom sieht das so aus:

Bildschirmfoto von Cutecom

Wenn der Text falsche Zeichen enthält, erinnere dich daran, dass es mit einem Quarz besser funktioniert.

AVR Verfused?

Ich glaube, jedem passiert es irgendwann, dass sein AVR Mikrocontroller nach dem Ändern von Fuses plötzlich nicht mehr ansprechbar ist. Ich erkläre hier, was schief gehen kann und welche Notlösungen es gibt.

Dieses Kapitel gilt nur für AVR Modelle mit ISP Schnittstelle.

Fuses

Fuses dienen dazu, ein paar Eigenschaften des Mikrocontrollers zu konfigurieren. Früher hätte man dafür Jumper oder Drahtbrücken verwendet. Drei Fuses bedürfen besonderer Aufmerksamkeit:

⚠️ Gemeiner Fallstrick: In der numerischen Darstellung haben eingeschaltete (=gebrannte) Fuses den Wert 0. Wenn man z.B. das SPIEN Bit auf 1 setzt, dann wird die SPI Schnittstelle dadurch aus geschaltet!

Für die Taktfrequenz sind folgende Fuses zuständig:

Standardvorgabe ist der interne R/C Oszillator mit 8 MHz1. Die Frequenz wird durch 8 geteilt, damit der Mikrocontroller auch mit niedriger Versorgungsspannung zuverlässig startet. Bei den meisten AVR Modellen kann man den Frequenzteiler auch per Software durch Beschreiben des CLKPR Registers ändern, wobei dann auch andere Werte als 1 und 8 möglich sind.

Fuses soll man nur vorsichtig mit Bedacht ändern. Die Webseiten Engbedded Fuse Calculator und Eleccelator helfen dabei. Kontrolliere Änderungen lieber dreimal, damit du deinen Mikrocontroller nicht unbrauchbar machst.

  1. Der ATtiny13 hat ausnahmsweise einen 9,6 MHz Oszillator.

debugWIRE

Viele AVR Mikrocontroller unterstützten das Debugging über den debugWIRE, das ist physikalisch der Reset Pin. Der debugWIRE wird immer in Kombination mit der ISP Schnittstelle benutzt.

DebugWIRE kommuniziert mit mehreren Megahertz bidirektional. Deswegen muss die Leitung kurz sein und darf nicht durch einen Kondensator oder allzu niedrigen Pull-Up Widerstand (weniger als 4,7 kΩ) belastet werden. Außerdem brauchst einen Programmieradapter, der ausdrücklich debugWIRE unterstützt. Prüfe das, bevor du eine Debug Sitzung beginnst, sonst kommst du da nicht mehr heraus!

Beim Beginn einer Debug Sitzung kommuniziert die IDE über ISP mit dem Mikrocontroller, um die DWEN Fuse zu aktivieren. Danach kann nur noch über den debugWIRE kommuniziert werden. ISP ist nun dauerhaft deaktiviert.

Am Ende einer Debug Sitzung sendet die IDE ein Debugger-Kommando, dass die ISP Schnittstelle temporär wieder aktiviert. Danach kommuniziert die IDE via ISP mit dem Mikrocontroller, um die DWEN Fuse zu deaktivieren. Erst dann ist der Mikrocontroller permanent zurück im ISP Modus.

Lösungen

Falsch eingestellte Fuses kann man mit einem "High Voltage Programmer" korrigieren. Bei den Fuses SPIEN und RSTDISBL ist dies die einzige Lösung. High Voltage Programmer legen 12 Volt an den Reset Pin und kommunizieren dann je nach Modell mit unterschiedlichen seriellen oder parallelen Protokollen. In der Regel muss man den Mikrocontroller dazu vorher auslöten und auf eine spezielle Adapterplatine bringen. Ob sich der Aufwand lohnt ist fragwürdig.

Die ISP Frequenz vom Programmieradapter darf maximal 1/4 der CPU Frequenz betragen. Wenn die CPU weniger als 8 MHz hat muss der ISP Programmieradapter dazu passend eingestellt sein. Bei Avrdude kannst du dazu den Parameter `-B 20` für 50 kHz oder gar `-B 200` für 5 kHz versuchen.

Wenn du den Mikrocontroller für eine externe Taktquelle konfiguriert hast, musst du diese auch anschließen, sonst geht gar nichts mehr. Im Zweifelsfall hilft meistens ein externer Oszillator wie der rechts gezeigte an Pin XTAL1. Der Pin XTAL2 bleibt in dem Fall unbeschaltet.

Wenn du den Chip für einen externen 32 kHz Quarz eingestellt hast, muss der Oszillator aber manchmal (immer?) an XTAL2 angeschlossen werden. Jemand berichtete mir, dass der Oszillator dann maximal 300 kHz haben darf. Bei meinen Versuchen mit einem ATtiny85 gingen auch 4 MHz.

Wenn du eine Debug-Sitzung nicht ordentlich beendet hast, fungiert der Reset-Pin weiterhin als debugWIRE, so dass ISP nicht nutzbar ist. In diesem Fall musst du deinen Debugger (Adapter und passende IDE) mit dem Mikrocontroller verbinden und dann in der Software den Debug-Modus mit "Disable debugWIRE" beenden. Avrdude macht das bei Bedarf automatisch, sofern ein dazu fähiger Programmieradpater verwendet wird. Denke daran, daß der DebgugWire (= Reset Pin) nicht mit einem Kondensator belastet werden darf.

Unter Umständen bringt dein Programm den Mikrocontroller zum Absturz oder es setzt die Taktfrequenz der CPU extrem herab, so dass die ISP Kommunikation danach versagt. In diesem Fall kannst du den RESET Pin des Mikrocontrollers fest mit GND verbinden und erst dann die Stromversorgung einschalten. So verhinderst du den Start des Programmes. Die ISP Schnittstelle ist im Dauer-Reset ansprechbar.

I²C Routine

Ich möchte an dieser Stelle kurz eine I²C Routine vorstellen, die sich in meinen AVR Projekten (ohne Arduino) mehrfach bewährt hat. Du darfst sie gerne kopieren.

/*
  Sendet beliebig viele Bytes an den adressierten Slave und empfängt
  anschließend beliebig viele Bytes von dem Slave. 

  Es ist erlaubt, den selben Puffer sowohl zum Senden als auch zum Empfangen zu benutzen.

  Wenn man nur senden will, gibt man rcv_data=0 und rcv_bytes=0 an.
  Wenn man nur empfangen will, gibt man send_data=0 und send_bytes=0 an.

  Der Rückgabewert ist im Fehlerfall -1, sonst 0.
*/
int8_t i2c_communicate(
    uint8_t slave_address, // Adresse des Slave in 7bit Schreibweise (0-127 bzw. 0x7F)
    void*   send_data,     // zeigt auf die zu sendenden Daten, z.B. ein Array von Bytes
    uint8_t send_bytes,    // wieviele Bytes gesendet werden sollen
    void*   rcv_data,      // zeigt auf einen Puffer für die empfangenen Daten, z.B. ein Array von Bytes
    uint8_t rcv_bytes      // wieviele Bytes empfangen werden sollen
    ) {
            
    // Adresse ein Bit nach links verschieben, um Platz für das r/w Flag zu schaffen
    slave_address=slave_address<<1;
        
    if (send_bytes>0) {
    
        // Sende Start 
        TWCR=(1<<TWINT) | (1<<TWEN) | (1<<TWSTA);
        while (!(TWCR & (1<<TWINT)));
        uint8_t status=TWSR & 0xf8;
        if (status != 0x08 && status != 0x10) goto error;
    
        // Sende Adresse (write mode)
        TWDR=slave_address;
        TWCR=(1<<TWINT) | (1<<TWEN);
        while (!(TWCR & (1<<TWINT)));
        if ((TWSR & 0xf8) != 0x18) goto error;
        
        // Sende Daten
        while (send_bytes>0) {
            TWDR=*((uint8_t*)send_data);
            TWCR=(1<<TWINT) | (1<<TWEN);
            while (!(TWCR & (1<<TWINT)));
            if ((TWSR & 0xf8) != 0x28) goto error;
            send_data++;
            send_bytes--;
        }
    }
    
    if (rcv_bytes>0) { 
    
        // Sende START
        TWCR=(1<<TWINT) | (1<<TWEN) | (1<<TWSTA);
        while (!(TWCR & (1<<TWINT)));
        uint8_t status=TWSR & 0xf8;
        if (status != 0x08 && status != 0x10) goto error;
        
        // Sende Adresse (read mode)
        TWDR=slave_address + 1;
        TWCR=(1<<TWINT) | (1<<TWEN);
        while (!(TWCR & (1<<TWINT)));
        if ((TWSR & 0xf8) != 0x40) goto error;
    
        // Empfange Daten
        while (rcv_bytes>0) {    
            if (rcv_bytes==1) {
                // das letzte Byte nicht mit ACK quittieren
                TWCR=(1<<TWINT) | (1<<TWEN); 
            } 
            else  {   
                // alle anderen Bytes mit ACK quittieren
                TWCR=(1<<TWINT) | (1<<TWEN) | (1<<TWEA);
            }
            while (!(TWCR & (1<<TWINT)));
            uint8_t status=TWSR & 0xf8;
            if (status!=0x50 && status != 0x58) goto error;
            *((uint8_t*)rcv_data)=TWDR;
            rcv_data++;
            rcv_bytes--;
        }
    }
    
    // Sende STOP
    TWCR=(1<<TWINT) | (1<<TWEN) | (1<<TWSTO);
    return 0;

    error:
    // Sende STOP
    TWCR=(1<<TWINT) | (1<<TWEN) | (1<<TWSTO);
    return -1;
}

Anwendungsbeispiele für I²C Bausteine ohne Register, wie dem PCF8574:

// Bus-Taktfrequenz einstellen (=100kHz bei 16Mhz CPU Takt)
TWBR=72;

// Sende ein einzelnes Byte
uint8_t value=0xFF
i2c_communicate(0x20,&value,1,0,0);

// Sende drei Bytes aus einem Array
uint8_t buffer[1]={0xFF,0xEE,0xDD};
i2c_communicate(0x20,buffer,3,0,0);

// Empfange ein einzelnes Byte
uint8_t value;
i2c_communicate(0x20,0,0,&value,1);

// Empfange drei Bytes in das Array
uint8_t buffer[3];
i2c_communicate(0x20,0,0,buffer,3);

Anwendungsbeispiele für I²C Bausteine mit Registern:

// Bus-Taktfrequenz einstellen (=100kHz bei 8Mhz CPU Takt)
TWBR=32;

// Sende Register Nummer 2, dann drei Bytes die in Register 2, 3 und 4 landen
uint8_t buffer[4]={2,10,20,30};
i2c_communicate(0x70,buffer,4,0,0);

// Sende Register Nummer 3, lese dann fünf Bytes aus diesem und den folgenden Registern aus
uint8_t buffer[5];
buffer[0]=3;
i2c_communicate(0x70,buffer,1,buffer,5);

// Sende Register Nummer 12, lese dann sechs Bytes (= drei Integer) aus diesem und den folgenden Registern aus
uint8_t register=12;
uint16_t buffer[3];
i2c_communicate(0x70,&register,1,buffer,6);
Startseite