<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="de">
		<id>https://rn-wissen.de/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Alexander.stohr</id>
		<title>RN-Wissen.de - Benutzerbeiträge [de]</title>
		<link rel="self" type="application/atom+xml" href="https://rn-wissen.de/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Alexander.stohr"/>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=Spezial:Beitr%C3%A4ge/Alexander.stohr"/>
		<updated>2026-04-11T21:16:27Z</updated>
		<subtitle>Benutzerbeiträge</subtitle>
		<generator>MediaWiki 1.25.1</generator>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=GCC&amp;diff=6561</id>
		<title>GCC</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=GCC&amp;diff=6561"/>
				<updated>2006-03-20T11:21:28Z</updated>
		
		<summary type="html">&lt;p&gt;Alexander.stohr: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;GCC ist ein sehr leistungsfähiger [[Compiler]], und er kann als die wichtigste freie Software überhaupt bezeichnet werden. Immerhin sind das freie [[Betriebssystem]] &amp;lt;tt&amp;gt;Linux&amp;lt;/tt&amp;gt; und viele andere Programme &amp;amp;#150; auch gcc und die Toolchains selbst &amp;amp;#150; mit gcc generiert.&lt;/div&gt;</summary>
		<author><name>Alexander.stohr</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=Avr-gcc&amp;diff=6560</id>
		<title>Avr-gcc</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=Avr-gcc&amp;diff=6560"/>
				<updated>2006-03-20T11:21:15Z</updated>
		
		<summary type="html">&lt;p&gt;Alexander.stohr: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Die GNU Compiler Collection ([[GCC]]) unterstützt das Zielsystem (Target) [[Avr|AVR]] für die Sprachen C und C++. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
Im Gegensatz zu [[Bascom]] ist &amp;lt;tt&amp;gt;avr-gcc&amp;lt;/tt&amp;gt; ein reiner Compiler, bringt also keine umfangreiche Bibliothek an Funktionalitäten mit. Jedoch finden sich einige low-level Funktionen zum Lesen aus dem [[Flash]] oder Lesen/Schreiben des [[EEPROM|EEPROMs]] etc. in der &amp;lt;tt&amp;gt;avr-libc&amp;lt;/tt&amp;gt;. &lt;br /&gt;
--&amp;gt;&lt;br /&gt;
=How to Read=&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel bespricht &amp;lt;tt&amp;gt;avr-gcc&amp;lt;/tt&amp;gt; Version 3.x. Er ist kein Tutorial und kein AVR-Handbuch &amp;amp;ndash; das würde den Umfang des Artikels bei weitem sprengen.&lt;br /&gt;
&lt;br /&gt;
Der Artikel ist ein Handbuch zu &amp;lt;tt&amp;gt;avr-gcc&amp;lt;/tt&amp;gt;. Er bespricht zum Beispiel, wie man &amp;lt;tt&amp;gt;avr-gcc&amp;lt;/tt&amp;gt; anwendet und Besonderheiten von &amp;lt;tt&amp;gt;avr-gcc&amp;lt;/tt&amp;gt;-C,&lt;br /&gt;
die nicht zum Sprachumfang von C gehören.&lt;br /&gt;
Dazu zählen die Definition von [[#Interrupts|Interrupt]] Service Routinen ([[ISR|ISRs]]) &lt;br /&gt;
oder wie man Daten ins [[EEPROM]] legt.&lt;br /&gt;
&lt;br /&gt;
Es wird also besprochen, ''wie'' eine ISR zu definieren ist, aber nicht,&lt;br /&gt;
''warum'' das  gegebenenfalls notwendig oder nicht notwendig ist. &lt;br /&gt;
''Warum'' etwas gemacht wird, ist abhängig von der gestellten Aufgabe,&lt;br /&gt;
etwa ''&amp;quot;Initialisiere den [[UART]] zur Benutzung mit 9600 Baud&amp;quot;''.&lt;br /&gt;
Dafür enthält dieser Artikel zusammen mit dem AVR-Handbuch das Rüstzeug, &lt;br /&gt;
bietet aber keine Lösungen für konkrete Aufgaben.&lt;br /&gt;
&lt;br /&gt;
In den [[:Kategorie:Quellcode C|C-Codebeispielen]]&lt;br /&gt;
befindet sich das ausführlichere Beispiel &amp;quot;[[Hallo Welt für AVR (LED blinken)]]&amp;quot;,&lt;br /&gt;
das nur eine [[Diode#Lumineszenzdiode|LED]] blinkt und zeigt, &lt;br /&gt;
wie ein kleines Projekt mit &amp;lt;tt&amp;gt;avr-gcc&amp;lt;/tt&amp;gt; compiliert werden kann.&lt;br /&gt;
&lt;br /&gt;
Es gibt es ein allgemeines [[C-Tutorial]], das jedoch noch unvollständig und teilweise feherhaft ist (Stand 02/2006). Darüber hinaus gibt es ein [http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial C-Tutorial bei www.mikrocontroller.net].&lt;br /&gt;
&lt;br /&gt;
=Benutzer-Schnittstelle=&lt;br /&gt;
&lt;br /&gt;
Die Benutzer-Schnittstelle von GCC ist die Kommandozeile einer Shell, Console bzw. Eingabeaufforderung. &lt;br /&gt;
&lt;br /&gt;
Im einfachsten Fall sieht ein Aufruf von &amp;lt;tt&amp;gt;avr-gcc&amp;lt;/tt&amp;gt; also so aus:&lt;br /&gt;
 &amp;gt; avr-gcc&lt;br /&gt;
Dabei das '&amp;lt;tt&amp;gt;&amp;gt;&amp;lt;/tt&amp;gt;' nicht mittippen, und ein ENTER am Ende der Zeile drücken.&lt;br /&gt;
Die Antwort bei korrekter Installation ist dann&lt;br /&gt;
 avr-gcc: no input files&lt;br /&gt;
Was bedeutet: das Programm &amp;lt;tt&amp;gt;avr-gcc&amp;lt;/tt&amp;gt; wurde vom Betriebssystem gefunden und konnte/durfte gestartet werden. Dann gibt &amp;lt;tt&amp;gt;avr-gcc&amp;lt;/tt&amp;gt; eine Fehlermeldung aus und beendet die Ausführung, weil er keine Eingabedatei(en) bekommen hat &amp;amp;#150; was ja auch stimmt. Soweit ist also alles in Butter.&lt;br /&gt;
&lt;br /&gt;
GCC war immer Kommandozeilen-orientiert und wird es auch immer bleiben, denn das hat gute Gründe:&lt;br /&gt;
* ein Compiler ist ein Compiler ist ein Compiler (und keine grafische Bedienschnittstelle)&lt;br /&gt;
* die Plattformabhängigkeit wird auf ein Minimum reduziert&lt;br /&gt;
* es gibt die Möglichkeit, GCC per Skript oder [[make]] zu starten&lt;br /&gt;
* GCC kann durchaus in eine Umgebung integriert werden: in einen Editor oder in eine GUI wie neuere Versionen von AVR-Studio erfolgreich beweisen, etc. Der GCC-Aufruf kann sogar von einem Server-Socket oder einer Web-Application heraus erfolgen, welche ein C-Programm empfängt, es von GCC übersetzen lässt, und das Resultat zurückschickt oder sonst was damit anstellt.&lt;br /&gt;
* Lizenzgründe: eine Umgebung, die GCC integriert, kann durchaus proprietär oder nicht quelloffen sein und muss nicht der [[Freie Software|GPL]] unterliegen. Wieder ist AVR-Studio ein Beispiel.&lt;br /&gt;
&lt;br /&gt;
=Allgemeine Charakteristika von avr-gcc=&lt;br /&gt;
&lt;br /&gt;
;Groß- und Kleinschreibung: C unterscheidet generell zwischen Groß- und Kleinschreibung, sowohl bei Variablen- und Funktionsnamen, bei Sprungmarken als auch bei Makros, und je nach Betriebssystem auch bei Pfad- und Dateinamen/Dateierweiterungen.&lt;br /&gt;
&lt;br /&gt;
;Größe des Typs int: Der Standard-Typ &amp;lt;tt&amp;gt;int&amp;lt;/tt&amp;gt; ist 16 Bit groß&lt;br /&gt;
&lt;br /&gt;
;Größe von Pointern: Ein Pointer (Zeiger) ist 16 Bit groß&lt;br /&gt;
&lt;br /&gt;
;Endianess: &amp;lt;tt&amp;gt;avr-gcc&amp;lt;/tt&amp;gt; implementiert Datentypen als little-endian, d.h. bei Datentypen, die mehrere Bytes groß sind, wird das niederwertigste Byte an der niedrigsten Adresse gespeichert. Dies gilt auch für Adressen und deren Ablage auf dem [[Stack]] sowie die Ablage von Werten, die mehrere Register belegen.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;tt&amp;gt;size_t&amp;lt;/tt&amp;gt;: &amp;lt;tt&amp;gt;size_t&amp;lt;/tt&amp;gt; ist &amp;lt;tt&amp;gt;unsigned&amp;lt;/tt&amp;gt; und immer 16 Bit groß, unabhängig davon , ob mit &amp;lt;tt&amp;gt;-mint8&amp;lt;/tt&amp;gt; übersetzt wird oder nicht.&lt;br /&gt;
&lt;br /&gt;
==Binäre Konstanten==&lt;br /&gt;
Einige Versionen von &amp;lt;tt&amp;gt;avr-gcc&amp;lt;/tt&amp;gt; ermöglichen die Verwendung binärer Konstanten für Ganzzahl-Werte:&lt;br /&gt;
&amp;lt;pre&amp;gt;unsigned char value = 0b00000010;&amp;lt;/pre&amp;gt;&lt;br /&gt;
Davon sollte man absehen, denn zum einen hat man schnell eine 0 zu wenig oder zu viel getippselt, es ist kein Standard-C und man hat die leserlichere Alternative&lt;br /&gt;
&amp;lt;pre&amp;gt;unsigned char value = (1&amp;lt;&amp;lt;1);&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Registerverwendung==&lt;br /&gt;
;R0: ein temporäres Register, in dem man rumwutzen darf&lt;br /&gt;
;R1: enthält immer den Wert 0&lt;br /&gt;
;R1 &amp;amp;#150; R17, R28, R29: allgemeine Register, die durch einen Funktionsaufruf nicht verändert bzw wieder auf den ursprünglichen Wert restauriert werden&lt;br /&gt;
;R0, R18 &amp;amp;#150; R27, R30, R31: können durch Funktionsaufrufe verändert werden, ohne restauriert zu werden&lt;br /&gt;
&lt;br /&gt;
;Framepointer: R28 &amp;amp;#150; R29 (Y-Reg) enthält den Framepointer, sofern benötigt&lt;br /&gt;
;Argument-Register: Die Register R8 bis R25 finden Verwendung zur Übergabe von Funktionsparametern. Für den Ort, an dem das Argument übergeben wird, gilt:&lt;br /&gt;
:* Die Große in Bytes wird zur nächsten geraden Zahl aufgerundet, falls die Argumentgröße ungerade ist.&lt;br /&gt;
:* Ist in den verbleibenden Übergaberegistern kein Platz mehr oder ist das Argument namenlos (varargs), wird es im Memory übergeben und die Adresse als implizites erstes Argument.&lt;br /&gt;
:* Der Registerort fängt mit 26 an.&lt;br /&gt;
:* Von dem Registerort wird die berechete Größe abgezogen und (falls Platz) das Argument in diesen Registern übergeben. Ist das erste Argument z.B. ein &amp;lt;tt&amp;gt;long&amp;lt;/tt&amp;gt;, dann erfolgt die Übergabe in den Registern R22, R23, R24 und R25 (LSB zuerst). Danach wird die gerundete Größe des Arguments vom Registerort abgezogen, dieser also auf 22 gesetzt. Ist das nächste Argument ein &amp;lt;tt&amp;gt;char&amp;lt;/tt&amp;gt;, wird dessen Größe auf 2 aufgerundet und vom Ort abgezogen. Dieses Argument wird also in R20 übergeben und der Ort auf 20 gesetzt, etc.&lt;br /&gt;
;Return-Register: Ein Return-Wert wird in den gleichen Registern zurückgegeben, die auch für ein gleichgrosses erstes Funktionsargument genommen würden. Liefert eine Funktion ein &amp;lt;tt&amp;gt;long&amp;lt;/tt&amp;gt;, dann erfolgt die Rückgabe also in den Registern R22&amp;lt;tt&amp;gt;-&amp;lt;/tt&amp;gt;R25 (LSB zuerst). Bei einem &amp;lt;tt&amp;gt;short&amp;lt;/tt&amp;gt; sind es die Register R24 und R25.&lt;br /&gt;
&lt;br /&gt;
=Ablauf der Codegenerierung=&lt;br /&gt;
&lt;br /&gt;
Die Code-Erzeugung durch avr-gcc geschieht in mehreren, voneinander unabhängigen Schritten. Diese  Schritte sind für den Anwender nicht immer erkennbar, und es auch nicht unbedingt notwendig, sie zu kennen. Für ein besseres Verständnis der Code-Generierung und zur Einordnung von Fehlermeldungen ist eine Kenntnis aber hilfreich.&lt;br /&gt;
&lt;br /&gt;
==Übersichts-Grafik==&lt;br /&gt;
&lt;br /&gt;
[[Bild:Avr-gcc-1.png|Zusammenspiel zwischen avr-gcc und binutils]]&lt;br /&gt;
&lt;br /&gt;
==Schritte der Codegenerierung==&lt;br /&gt;
&lt;br /&gt;
Ohne die Angabe spezieller Optionen werden die Zwischenformate nur als temporäre Dateien angelegt und nach Beenden des gcc-Laufs wieder gelöscht. Dadurch fällt die Aufgliederung in Unterschritte nicht auf. In diesem Falle müssen Assembler und Linker/Locator auch nicht extra aufgerufen werden, sondern die Aufrufe erfolgen durch gcc. &lt;br /&gt;
&lt;br /&gt;
;Precompileren: Alle Preprozessor-Direktiven werden aufgelöst. Dazu gehören Direktiven wie&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;quot;meinzeug.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
#define MAKRONAME ERSATZTEXT&lt;br /&gt;
&lt;br /&gt;
#if !defined(__AVR__)&lt;br /&gt;
#error einen Fehler ausgeben und abbrechen&lt;br /&gt;
#else&lt;br /&gt;
/* Alles klar, wir koennen loslegen mit C-Code fuer AVR */&lt;br /&gt;
#endif &lt;br /&gt;
&lt;br /&gt;
MAKRONAME&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Precompilieren besteht also nur aus reinem Textersatz: Auflösen von Makros, kopieren von anderen Dateien in die Quelle, etc. &lt;br /&gt;
&lt;br /&gt;
;Compilieren: In diesem Schritt geschieht der eigentliche Compilier-Vorgang: &amp;lt;tt&amp;gt;avr-gcc&amp;lt;/tt&amp;gt; übersetzt die reine, precompilierte C-Quelle (*.i): Die Quelle wird auf Syntax-Fehler geprüft, es werden Optimierungen gemacht, und das übersetzte C-Programm als Assembler-Datei in (*.s) gespeichert.&lt;br /&gt;
&lt;br /&gt;
;Assemblieren: Der Assembler (&amp;lt;tt&amp;gt;avr-as&amp;lt;/tt&amp;gt;) übersetzt den Assembler-Code (*.s) in das  AVR-eigene Objektformat elf32-avr (*.o). Das Objekt enthält schon Maschinen-Code. Zusätzlich gibt es aber noch Lücken, die erst später gefüllt werden und Debug-Informationen und ganz viel anderes Zeug.&lt;br /&gt;
&lt;br /&gt;
;Linken und Lokatieren: Der Linker (&amp;lt;tt&amp;gt;avr-ld&amp;lt;/tt&amp;gt;) bindet die angegebenen Objekte (*.o) zusammen und löst externe Referenzen auf. Der Linker entscheidet anhand der Beschreibung im Linker-Script, in welchen Speicheradressen und [[#Sections|Sections]] die Daten landen: er ''lokatiert'' (von location, locate (en)). Module aus Bibliotheken (*.a) werden hinzugebunden (z.B. &amp;lt;tt&amp;gt;printf&amp;lt;/tt&amp;gt;) und die elf32-avr Ausgabedatei (üblicherweise *.elf) erzeugt.&lt;br /&gt;
&lt;br /&gt;
;Umwandeln ins gewünschte Objekt-Format: Ohne Angabe spezieller [[#Kommandozeilen-Optionen|Optionen]] erzeugen Linker und Assembler  ihre Ausgabe im Objektformat elf32-avr. Wird ein anderes Objektformat wie Intel-HEX (*.hex), binary (*.bin) oder srec (*.srec) benötigt, kann &amp;lt;tt&amp;gt;avr-objcopy&amp;lt;/tt&amp;gt; dazu verwendet werden, um diese zu erstellen. Der Inhalt einzelner Sections kann gezielt umkopiert oder ausgeblendet werden, so daß Dateien erstellt werden können, die nur den Inhalt des Flashs (Section &amp;lt;tt&amp;gt;.text&amp;lt;/tt&amp;gt;) oder des EEPROMs (Section &amp;lt;tt&amp;gt;.eeprom&amp;lt;/tt&amp;gt;) repräsentieren. Durch das Umwandeln in ein anderes Objektformat gehen üblicherweise Informationen wie Debug-Informationen verloren.&lt;br /&gt;
&lt;br /&gt;
:Es ist auch möglich, den Linker mit der Optione &amp;lt;tt&amp;gt;--oformat=...&amp;lt;/tt&amp;gt; zu starten, damit er direkt das gewünschte Ausgabeformat erzeugt.&lt;br /&gt;
&lt;br /&gt;
=Kommandozeilen-Optionen=&lt;br /&gt;
Die Codegenerierung bei &amp;lt;tt&amp;gt;avr-gcc&amp;lt;/tt&amp;gt; wird über Kommandozeilen-Optionen gesteuert. Diese legen fest, für welchen Controller Code zu erzeugen ist, wie stark optimiert wird, ob Debug-Informationen erzeugt werden, etc. Die Optionen teilen sich in zwei Gruppen: Optionen, die für alle GCC-Ports verfürgbar sind und maschinenspezifische Optionen, die nur für AVR verfügbar sind.&lt;br /&gt;
&lt;br /&gt;
Aus der Masse an GCC-Optionen kann hier nur ein kleiner Auszug der wichtigsten und am häufigsten verwendeten Optionen vorgestellt werden. Eine Auflistung aller GCC-Optionen mit Kurzbeschreibung umfasst knapp 1000 Zeilen &amp;amp;#150; ohne undokumentierte Optionen, versteht sich.&lt;br /&gt;
&lt;br /&gt;
==Allgemeine Optionen für GCC==&lt;br /&gt;
; &amp;lt;tt&amp;gt;--help&amp;lt;/tt&amp;gt;: Anzeige der wichtigsten Optionen&lt;br /&gt;
; &amp;lt;tt&amp;gt;--help -v&amp;lt;/tt&amp;gt;: Überschüttet einen mit Optionen&lt;br /&gt;
; &amp;lt;tt&amp;gt;--target-help&amp;lt;/tt&amp;gt;: Anzeige der wichtigsten maschinenspezifischen Optionen&lt;br /&gt;
; &amp;lt;tt&amp;gt;-O0&amp;lt;/tt&amp;gt;: keine Optimierung&lt;br /&gt;
; &amp;lt;tt&amp;gt;-O1&amp;lt;/tt&amp;gt;: Optimierung&lt;br /&gt;
; &amp;lt;tt&amp;gt;-Os&amp;lt;/tt&amp;gt;: optimiert für Code-Größe&lt;br /&gt;
; &amp;lt;tt&amp;gt;-O2&amp;lt;/tt&amp;gt;: stärkere Optimierung für bessere Laufzeit&lt;br /&gt;
; &amp;lt;tt&amp;gt;-g&amp;lt;/tt&amp;gt;: erzeugt Debug-Informationen&lt;br /&gt;
; &amp;lt;tt&amp;gt;-c&amp;lt;/tt&amp;gt;: (pre)compilert und assembliert nur bis zum Objekt (&amp;lt;tt&amp;gt;*.o&amp;lt;/tt&amp;gt;), kein Link-Lauf&lt;br /&gt;
; &amp;lt;tt&amp;gt;-S&amp;lt;/tt&amp;gt;: (pre)compilert nur und erzeugt Assembler-Ausgabe (*.s)&lt;br /&gt;
; &amp;lt;tt&amp;gt;-E&amp;lt;/tt&amp;gt;: nur Precompilat (&amp;lt;tt&amp;gt;*.i&amp;lt;/tt&amp;gt;) erzeugen, kein Compilieren, kein Assemblieren, kein Linken&lt;br /&gt;
; &amp;lt;tt&amp;gt;-o &amp;lt;filename&amp;gt;&amp;lt;/tt&amp;gt;: legt den Name der Ausgabedatei fest&lt;br /&gt;
; &amp;lt;tt&amp;gt;-v&amp;lt;/tt&amp;gt;: zeigt Versionsinformationen an und ist geschwätzig (verbose): Anzeige der aufgerufenen tools&lt;br /&gt;
; &amp;lt;tt&amp;gt;-I&amp;lt;path&amp;gt;&amp;lt;/tt&amp;gt;: Angabe eines weiteren Include-Pfads, in dem Dateien mit &amp;lt;tt&amp;gt;#include &amp;lt;...&amp;gt;&amp;lt;/tt&amp;gt; gesucht werden&lt;br /&gt;
; &amp;lt;tt&amp;gt;-E -dM &amp;lt;filename&amp;gt;&amp;lt;/tt&amp;gt;: Anzeige aller Defines&lt;br /&gt;
; &amp;lt;tt&amp;gt;-MM&amp;lt;/tt&amp;gt;: Für die angegebenen Eingabe-Dateien wird eine Ausgabe erzeugt, die als [[make|Makefile]]-Fragment dienen kann und die Anhängigkeiten (dependencies) der Objekte von den Quellen/Headern beschreibt.&lt;br /&gt;
; &amp;lt;tt&amp;gt;-D&amp;lt;name&amp;gt;&amp;lt;/tt&amp;gt;: Definiert Makro &amp;lt;tt&amp;gt;&amp;lt;name&amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
; &amp;lt;tt&amp;gt;-D&amp;lt;name&amp;gt;=&amp;lt;wert&amp;gt;&amp;lt;/tt&amp;gt;: Definiert Makro &amp;lt;tt&amp;gt;&amp;lt;name&amp;gt;&amp;lt;/tt&amp;gt; zu &amp;lt;tt&amp;gt;&amp;lt;wert&amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
; &amp;lt;tt&amp;gt;-U&amp;lt;name&amp;gt;&amp;lt;/tt&amp;gt;: Undefiniert Makro &amp;lt;tt&amp;gt;&amp;lt;name&amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
; &amp;lt;tt&amp;gt;-save-temps&amp;lt;/tt&amp;gt;: Temporäre Dateien (&amp;lt;tt&amp;gt;*.i&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;*.s&amp;lt;/tt&amp;gt;) werden nicht gelöscht. Teilweise fehlerhaft zusammen mit &amp;lt;tt&amp;gt;-c&amp;lt;/tt&amp;gt;&lt;br /&gt;
; &amp;lt;tt&amp;gt;-Wa,&amp;lt;options&amp;gt;&amp;lt;/tt&amp;gt;: übergibt Komma-getrennte Liste &amp;lt;tt&amp;gt;&amp;lt;options&amp;gt;&amp;lt;/tt&amp;gt; an den Assembler (&amp;lt;tt&amp;gt;avr-as&amp;lt;/tt&amp;gt;)&lt;br /&gt;
:;&amp;lt;tt&amp;gt;-Wa,-a=&amp;lt;filename&amp;gt;&amp;lt;/tt&amp;gt;: Assembler erzeugt ein Listing mit Name &amp;lt;tt&amp;gt;&amp;lt;filename&amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
; &amp;lt;tt&amp;gt;-Wp,&amp;lt;options&amp;gt;&amp;lt;/tt&amp;gt;:  übergibt Komma-getrennte Liste &amp;lt;tt&amp;gt;&amp;lt;options&amp;gt;&amp;lt;/tt&amp;gt; an den Preprozessor&lt;br /&gt;
; &amp;lt;tt&amp;gt;-Wl,&amp;lt;options&amp;gt;&amp;lt;/tt&amp;gt;:  übergibt Komma-getrennte Liste &amp;lt;tt&amp;gt;&amp;lt;options&amp;gt;&amp;lt;/tt&amp;gt; an den Linker (&amp;lt;tt&amp;gt;avr-ld&amp;lt;/tt&amp;gt;)&lt;br /&gt;
:;&amp;lt;tt&amp;gt;-Wl,-Map=&amp;lt;filename&amp;gt;&amp;lt;/tt&amp;gt;: Linker erzeugt ein Map-File mit Name &amp;lt;tt&amp;gt;&amp;lt;filename&amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
:;&amp;lt;tt&amp;gt;-Wl,--oformat=&amp;lt;format&amp;gt;&amp;lt;/tt&amp;gt;: Linker erzeugt Ausgabe im Format &amp;lt;tt&amp;gt;&amp;lt;format&amp;gt;&amp;lt;/tt&amp;gt;, z.b. &amp;lt;tt&amp;gt;ihex&amp;lt;/tt&amp;gt; für Intel-HEX-File&lt;br /&gt;
:;&amp;lt;tt&amp;gt;-Wl,--section-start&amp;lt;section&amp;gt;=&amp;lt;address&amp;gt;&amp;lt;/tt&amp;gt;: Linker legt die [[#Sections|Section]] &amp;lt;tt&amp;gt;&amp;lt;section&amp;gt;&amp;lt;/tt&amp;gt; ab Adresse &amp;lt;tt&amp;gt;&amp;lt;address&amp;gt;&amp;lt;/tt&amp;gt;, z.B: &amp;lt;tt&amp;gt;.eeprom=0x810001&amp;lt;/tt&amp;gt;&lt;br /&gt;
; &amp;lt;tt&amp;gt;-Wall&amp;lt;/tt&amp;gt;: gibt mehr Warnungen, aber immer noch nicht alle&lt;br /&gt;
; &amp;lt;tt&amp;gt;-pedantic&amp;lt;/tt&amp;gt;: geht besonders pedantisch mit Code um&lt;br /&gt;
; &amp;lt;tt&amp;gt;-ansi&amp;lt;/tt&amp;gt;: bricht mit einer Fehlermeldung ab, wenn kein ANSI-C verwendet wurde&lt;br /&gt;
; &amp;lt;tt&amp;gt;-ffreestanding&amp;lt;/tt&amp;gt;: Das erzeugte Programm läuft nicht in einer Umgebung wie einer Shell. Der Prototyp von &amp;lt;tt&amp;gt;main&amp;lt;/tt&amp;gt; ist&lt;br /&gt;
:&amp;lt;pre&amp;gt;void main (void);&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Maschinenspezifische Optionen für avr-gcc==&lt;br /&gt;
Maschinenabhängige Optionen beginnen immer mit '''-m'''&lt;br /&gt;
;-mmcu=xxx: Festlegen des Targets, für das Code generiert werden soll. Je nach Target werden unterschiedliche Instruktionen verwendet und andere Startup-Dateien (&amp;lt;tt&amp;gt;crtxxx.o&amp;lt;/tt&amp;gt;) eingebunden. Spezielle Defines werden gesetzt, um in der Quelle zwischen den Targets unterscheiden zu können: &lt;br /&gt;
:&amp;lt;tt&amp;gt;&lt;br /&gt;
 #ifdef __AVR_AT90S2313__&lt;br /&gt;
 /* Code fuer AT90S2313 */&lt;br /&gt;
 #elif defined (__AVR_ATmega8__) || defined (__AVR_ATmega32__)&lt;br /&gt;
 /* Code fuer Mega8 und Mega32 */ &lt;br /&gt;
 #else&lt;br /&gt;
 #error Das ist noch nicht implementiert für diesen Controller!&lt;br /&gt;
 #endif&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zwar gibt es für alle AVR-Derivate die &amp;lt;tt&amp;gt;avr/io.h&amp;lt;/tt&amp;gt;, aber die AVR-Familien unterscheiden sich in ihrer Hardware; z.B. darin, wie I/O-Register heissen oder wie Hardware zu initialisieren ist. Diese Abhängigkeit kann man in unterschiedlichen Codestücken aufteilen und wie oben gezeigt bedingt übersetzen. Dadurch hat man Funktionalitäten wie &amp;lt;tt&amp;gt;uart_init&amp;lt;/tt&amp;gt; auf unterschiedlichen Controllern und wahrt den Überblick, weil nicht für jede Controller-Familie eine extra Datei notwendig ist.&lt;br /&gt;
{| &lt;br /&gt;
|- valign=&amp;quot;top&amp;quot; &lt;br /&gt;
| &lt;br /&gt;
:{| {{Blauetabelle}}&lt;br /&gt;
|+ '''AVR classic, &amp;amp;lt;= 8 kByte'''&lt;br /&gt;
|- {{Hintergrund1}}&lt;br /&gt;
!|mcu || Builtin define&lt;br /&gt;
 |- &lt;br /&gt;
 |avr2 ||&amp;lt;tt&amp;gt;__AVR_ARCH__=2&amp;lt;/tt&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 |[[AT90S2313|at90s2313]]  ||&amp;lt;tt&amp;gt;__AVR_AT90S2313__&amp;lt;/tt&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 |at90s2323 ||&amp;lt;tt&amp;gt;__AVR_AT90S2323__&amp;lt;/tt&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 |at90s2333 ||&amp;lt;tt&amp;gt;__AVR_AT90S2333__&amp;lt;/tt&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 |at90s2343 ||&amp;lt;tt&amp;gt;__AVR_AT90S2343__&amp;lt;/tt&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 |attiny22 ||&amp;lt;tt&amp;gt;__AVR_ATtiny22__&amp;lt;/tt&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 |attiny26 ||&amp;lt;tt&amp;gt;__AVR_ATtiny26__&amp;lt;/tt&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 |at90s4414 ||&amp;lt;tt&amp;gt;__AVR_AT90S4414__&amp;lt;/tt&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 |at90s4433 ||&amp;lt;tt&amp;gt;__AVR_AT90S4433__&amp;lt;/tt&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 |at90s4434 ||&amp;lt;tt&amp;gt;__AVR_AT90S4434__&amp;lt;/tt&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 |at90s8515 ||&amp;lt;tt&amp;gt;__AVR_AT90S8515__&amp;lt;/tt&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 |at90c8534 ||&amp;lt;tt&amp;gt;__AVR_AT90C8534__&amp;lt;/tt&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 |at90s8535 ||&amp;lt;tt&amp;gt;__AVR_AT90S8535__&amp;lt;/tt&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 |at86rf401 ||&amp;lt;tt&amp;gt;__AVR_AT86RF401__&amp;lt;/tt&amp;gt;&lt;br /&gt;
 |}&lt;br /&gt;
 |  &amp;lt;!-----------------------------------------------------------&amp;gt;&lt;br /&gt;
:{| {{Blauetabelle}}&lt;br /&gt;
|+ '''AVR classic, &amp;amp;gt; 8 kByte'''&lt;br /&gt;
|- bgcolor=&amp;quot;#ccccff&amp;quot;&lt;br /&gt;
! |mcu ||Builtin define&lt;br /&gt;
 |- &lt;br /&gt;
 |avr3 ||&amp;lt;tt&amp;gt;__AVR_ARCH__=3&amp;lt;/tt&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 |atmega103 ||&amp;lt;tt&amp;gt;__AVR_ATmega103__&amp;lt;/tt&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 |atmega603 ||&amp;lt;tt&amp;gt;__AVR_ATmega603__&amp;lt;/tt&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 |at43usb320 ||&amp;lt;tt&amp;gt;__AVR_AT43USB320__&amp;lt;/tt&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 |at43usb355 ||&amp;lt;tt&amp;gt;__AVR_AT43USB355__&amp;lt;/tt&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 |at76c711 ||&amp;lt;tt&amp;gt;__AVR_AT76C711__&amp;lt;/tt&amp;gt;&lt;br /&gt;
 |}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
----&amp;lt;!-----------------------------------------------------------&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{| &lt;br /&gt;
 |- valign=&amp;quot;top&amp;quot;&lt;br /&gt;
 |&lt;br /&gt;
:{| {{Blauetabelle}}&lt;br /&gt;
|+ '''AVR enhanced, &amp;amp;lt;= 8 kByte'''&lt;br /&gt;
|- bgcolor=&amp;quot;#ccccff&amp;quot;&lt;br /&gt;
!|mcu || Builtin define&lt;br /&gt;
 |- &lt;br /&gt;
 |avr4 ||&amp;lt;tt&amp;gt;__AVR_ARCH__=4&amp;lt;/tt&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 |[[Atmel Controller Mega8|atmega8]] ||&amp;lt;tt&amp;gt;__AVR_ATmega8__&amp;lt;/tt&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 |atmega8515 ||&amp;lt;tt&amp;gt;__AVR_ATmega8515__&amp;lt;/tt&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 |atmega8535 ||&amp;lt;tt&amp;gt;__AVR_ATmega8535__&amp;lt;/tt&amp;gt;&lt;br /&gt;
 |}&lt;br /&gt;
 |&amp;lt;!-----------------------------------------------------------&amp;gt;&lt;br /&gt;
:{| {{Blauetabelle}}&lt;br /&gt;
|+ '''AVR enhanced, &amp;amp;gt; 8 kByte'''&lt;br /&gt;
|- bgcolor=&amp;quot;#ccccff&amp;quot;&lt;br /&gt;
!|mcu ||Builtin define&lt;br /&gt;
 |- &lt;br /&gt;
 |avr5 ||&amp;lt;tt&amp;gt;__AVR_ARCH__=5&amp;lt;/tt&amp;gt; &lt;br /&gt;
 |-&lt;br /&gt;
 |[[Atmel Controller Mega16 und Mega32|atmega16]] ||&amp;lt;tt&amp;gt;__AVR_ATmega16__&amp;lt;/tt&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 |atmega161 ||&amp;lt;tt&amp;gt;__AVR_ATmega161__&amp;lt;/tt&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 |atmega162 ||&amp;lt;tt&amp;gt;__AVR_ATmega162__&amp;lt;/tt&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 |atmega163 ||&amp;lt;tt&amp;gt;__AVR_ATmega163__&amp;lt;/tt&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 |atmega169 ||&amp;lt;tt&amp;gt;__AVR_ATmega169__&amp;lt;/tt&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 |[[Atmel Controller Mega16 und Mega32|atmega32]] ||&amp;lt;tt&amp;gt;__AVR_ATmega32__&amp;lt;/tt&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 |atmega323 ||&amp;lt;tt&amp;gt;__AVR_ATmega323__&amp;lt;/tt&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 |[[ATMega64|atmega64]] ||&amp;lt;tt&amp;gt;__AVR_ATmega64__&amp;lt;/tt&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 |[[Atmel Controller Mega128|atmega128]] ||&amp;lt;tt&amp;gt;__AVR_ATmega128__&amp;lt;/tt&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 |at94k ||&amp;lt;tt&amp;gt;__AVR_AT94K__&amp;lt;/tt&amp;gt;&lt;br /&gt;
 |}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
----&amp;lt;!-----------------------------------------------------------&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
:{| {{Blauetabelle}}&lt;br /&gt;
|+ '''AVR, nur Assembler'''&lt;br /&gt;
|- bgcolor=&amp;quot;#ccccff&amp;quot;&lt;br /&gt;
! |mcu ||Builtin define&lt;br /&gt;
 |- &lt;br /&gt;
 |avr1 ||&amp;lt;tt&amp;gt;__AVR_ARCH__=1&amp;lt;/tt&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 |at90s1200 ||&amp;lt;tt&amp;gt;__AVR_AT90S1200__&amp;lt;/tt&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 |attiny11 ||&amp;lt;tt&amp;gt;__AVR_ATtiny11__&amp;lt;/tt&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 |attiny12 ||&amp;lt;tt&amp;gt;__AVR_ATtiny12__&amp;lt;/tt&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 |attiny15 ||&amp;lt;tt&amp;gt;__AVR_ATtiny15__&amp;lt;/tt&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 |attiny28 ||&amp;lt;tt&amp;gt;__AVR_ATtiny28__&amp;lt;/tt&amp;gt;&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
; -minit-stack=xxx: Festlegen der Stack-Adresse&lt;br /&gt;
; -mint8: Datentyp &amp;lt;tt&amp;gt;int&amp;lt;/tt&amp;gt; ist nur 8 Bit breit, anstatt 16 Bit. Datentypen mit 32 Bit wie  &amp;lt;tt&amp;gt;long&amp;lt;/tt&amp;gt; sind nicht verfügbar&lt;br /&gt;
; -mno-interrupts: Ändert den Stackpointer ohne Interrupts zu deaktivieren&lt;br /&gt;
; -mcall-prologues: Funktions-Prolog und -Epilog werden als Unterroutinen umgesetzt, um die Codegröße zu verkleinern&lt;br /&gt;
; -mtiny-stack: Nur die unteren 8 Bit des Stackpointers werden verändert&lt;br /&gt;
; -mno-tablejump: Für ein &amp;lt;tt&amp;gt;switch&amp;lt;/tt&amp;gt;-Statement werden keine Sprungtabellen angelegt&lt;br /&gt;
; -mshort-calls: Verwendet &amp;lt;tt&amp;gt;rjmp&amp;lt;/tt&amp;gt;/&amp;lt;tt&amp;gt;rcall&amp;lt;/tt&amp;gt; (begrenzte Sprungweite) auf Devices mit mehr als 8 kByte Flash&lt;br /&gt;
; -msize: Ausgabe der Instruktonslängen im asm-File&lt;br /&gt;
; -mdeb: (undokumentiert) Ausgabe von Debug-Informationen für GCC-Entwickler&lt;br /&gt;
; -morder1: (undokumentiert) andere Register-Allokierung&lt;br /&gt;
; -morder2: (undokumentiert) andere Register-Allokierung&lt;br /&gt;
&lt;br /&gt;
=Builtins=&lt;br /&gt;
&lt;br /&gt;
Zur bedingten Codeerzeugung und zur Erkennung, welcher Compiler sich an der Quelle zu schaffen macht, sind folgende Builtins hilfreich.&lt;br /&gt;
&lt;br /&gt;
Siehe auch: [[#Maschinenspezifische Optionen für avr-gcc|Maschinenspezifische Optionen]]&lt;br /&gt;
&lt;br /&gt;
==Builtin Defines==&lt;br /&gt;
&lt;br /&gt;
===GCC===&lt;br /&gt;
;&amp;lt;tt&amp;gt;__GNUC__&amp;lt;/tt&amp;gt;: X wenn GCC-Version X.Y.Z&lt;br /&gt;
;&amp;lt;tt&amp;gt;__GNUC_MINOR__&amp;lt;/tt&amp;gt;: Y wenn GCC-Version X.Y.Z&lt;br /&gt;
;&amp;lt;tt&amp;gt;__GNUC_PATCHLEVEL__&amp;lt;/tt&amp;gt;: Z wenn GCC-Version X.Y.Z&lt;br /&gt;
;&amp;lt;tt&amp;gt;__VERSION__&amp;lt;/tt&amp;gt;: &amp;quot;X.Y.Z&amp;quot; wenn GCC-Version X.Y.Z&lt;br /&gt;
;&amp;lt;tt&amp;gt;__GXX_ABI_VERSION&amp;lt;/tt&amp;gt;: Version der ABI (Application Binary Interface)&lt;br /&gt;
;&amp;lt;tt&amp;gt;__STDC__&amp;lt;/tt&amp;gt;: Ist 1, wenn Standard-C übersetzt wird&lt;br /&gt;
;&amp;lt;tt&amp;gt;__OPTIMIZE__&amp;lt;/tt&amp;gt;: Optimierung ist aktiviert&lt;br /&gt;
;&amp;lt;tt&amp;gt;__NO_INLINE__&amp;lt;/tt&amp;gt;: Ohne Schalter &amp;lt;tt&amp;gt;-finline&amp;lt;/tt&amp;gt; resp. &amp;lt;tt&amp;gt;-finline-all-functions&amp;lt;/tt&amp;gt; etc.&lt;br /&gt;
;&amp;lt;tt&amp;gt;__ASSEMBLER__&amp;lt;/tt&amp;gt;: Definiert, falls GCC die Eingabe als Assembler-Code betrachtet und nicht compiliert. Weiterleitung an den Assembler.&lt;br /&gt;
;&amp;lt;tt&amp;gt;__cplusplus&amp;lt;/tt&amp;gt;: Es wird C++ übersetzt (Quell-Endung &amp;lt;tt&amp;gt;*.cpp&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;*.c++&amp;lt;/tt&amp;gt; oder Option &amp;lt;tt&amp;gt;-x c++&amp;lt;/tt&amp;gt;).&lt;br /&gt;
;&amp;lt;tt&amp;gt;__FILE__&amp;lt;/tt&amp;gt;: Löst auf zum Dateinamen der Quelldatei, in der das &amp;lt;tt&amp;gt;__FILE__&amp;lt;/tt&amp;gt; steht.&lt;br /&gt;
;&amp;lt;tt&amp;gt;__LINE__&amp;lt;/tt&amp;gt;: Löst auf zur Zeilennummer der Quelldatei, in der das &amp;lt;tt&amp;gt;__LINE__&amp;lt;/tt&amp;gt; steht.&lt;br /&gt;
;&amp;lt;tt&amp;gt;__DATE__&amp;lt;/tt&amp;gt;: Löst auf zum Datum (precompile-date)&lt;br /&gt;
;&amp;lt;tt&amp;gt;__TIME__&amp;lt;/tt&amp;gt;: Löst auf zur Zeit (precompile-time)&lt;br /&gt;
&lt;br /&gt;
===avr-gcc===&lt;br /&gt;
;&amp;lt;tt&amp;gt;__AVR&amp;lt;/tt&amp;gt;: Definiert für Target avr, d.h. &amp;lt;tt&amp;gt;avr-gcc&amp;lt;/tt&amp;gt; ist am Werk&lt;br /&gt;
;&amp;lt;tt&amp;gt;__AVR__&amp;lt;/tt&amp;gt;: dito&lt;br /&gt;
;&amp;lt;tt&amp;gt;__AVR_ARCH__&amp;lt;/tt&amp;gt;: codiert den AVR-Kern, für den Code erzeugt wird (Classic, Mega, ...). &lt;br /&gt;
;&amp;lt;tt&amp;gt;__AVR_XXXX__&amp;lt;/tt&amp;gt;: Gesetzt, wenn &amp;lt;tt&amp;gt;-mmcu=xxxx&amp;lt;/tt&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
==Builtin Variablen==&lt;br /&gt;
;&amp;lt;tt&amp;gt;__func__&amp;lt;/tt&amp;gt;: Eine magische Variable, die den aktuellen Funktionsnamen enthält. Gerade so, als hätte man ihn selbst mit &lt;br /&gt;
:&amp;lt;pre&amp;gt;static const char __func__[] = &amp;quot;main&amp;quot;;&amp;lt;/pre&amp;gt;&lt;br /&gt;
:definiert.&lt;br /&gt;
&lt;br /&gt;
=Sections=&lt;br /&gt;
&lt;br /&gt;
Sections sind mit Fächern vergleichbar, in die Daten, Code, Debug-Informationen usw. einsortiert werden. Zur Section &amp;lt;tt&amp;gt;.text&amp;lt;/tt&amp;gt; gehört z.B. der ausführbare Code, welcher letztendlich im Flash landet. Wo genau das ist, braucht man nicht zu wissen und es spielt auch keine Rolle, wo eine bestimmte Funktion landet.&lt;br /&gt;
&lt;br /&gt;
Für 'normalen' Code und 'normale' Daten braucht man sich nicht um die Sections zu kümmern, sie werden von &amp;lt;tt&amp;gt;avr-gcc&amp;lt;/tt&amp;gt; automatisch richtig zugeordnet. Für spezielle Anwendungen kann es aber notwendig sein, die Ablage in eine andere Section zu machen; etwa wenn man Daten im EEPROM lesen/schreiben will. Wie das genau gemacht wird, steht im Abschnitt &amp;quot;[[avr-gcc#Attribute|Attribute]]&amp;quot; und es gibt ein Beispiele in den Abschnitten &lt;br /&gt;
&amp;quot;[[avr-gcc#SRAM, Flash, EEPROM: Datenablage am Beispiel Strings|Datenablage am Beispiel Strings]]&amp;quot; und &amp;quot;[[Zufallszahlen mit avr-gcc|Zufall]]&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|+ '''Tabelle: Bedeutung der Sections bei &amp;lt;tt&amp;gt;avr-gcc&amp;lt;/tt&amp;gt;'''&lt;br /&gt;
|- {{Hintergrund1}}&lt;br /&gt;
! |Section ||Ablage ||Betrifft ||Beschreibung&lt;br /&gt;
 |-&lt;br /&gt;
 |&amp;lt;tt&amp;gt;.text&amp;lt;/tt&amp;gt; ||Flash ||Code  ||normaler Programm-Code&lt;br /&gt;
 |-&lt;br /&gt;
 |&amp;lt;tt&amp;gt;.data&amp;lt;/tt&amp;gt; ||SRAM  ||Daten ||wird vom Startup-Code initialisiert, u.a. aus &amp;lt;tt&amp;gt;.progmem&amp;lt;/tt&amp;gt;&lt;br /&gt;
 |- &lt;br /&gt;
 |&amp;lt;tt&amp;gt;.bss&amp;lt;/tt&amp;gt;  ||SRAM  ||Daten ||wird vom Startup-Code zu 0 initialisiert&lt;br /&gt;
 |- &lt;br /&gt;
 |colspan=&amp;quot;4&amp;quot; bgcolor=&amp;quot;#bbbbff&amp;quot;|&lt;br /&gt;
 |-&lt;br /&gt;
 |&amp;lt;tt&amp;gt;.progmem&amp;lt;/tt&amp;gt; ||Flash  ||Daten ||wird vom Startup-Code nach &amp;lt;tt&amp;gt;.data&amp;lt;/tt&amp;gt; kopiert&lt;br /&gt;
 |-&lt;br /&gt;
 |&amp;lt;tt&amp;gt;.eeprom&amp;lt;/tt&amp;gt;  ||EEPROM ||Daten ||Daten im EEPROM&lt;br /&gt;
 |-&lt;br /&gt;
 |&amp;lt;tt&amp;gt;.noinit&amp;lt;/tt&amp;gt;  ||SRAM   ||Daten ||wird nicht initialisiert&lt;br /&gt;
 |- &lt;br /&gt;
 |colspan=&amp;quot;4&amp;quot; bgcolor=&amp;quot;#bbbbff&amp;quot;|&lt;br /&gt;
 |-&lt;br /&gt;
 |&amp;lt;tt&amp;gt;.init''n''&amp;lt;/tt&amp;gt; ||Flash ||Code ||wird vor &amp;lt;tt&amp;gt;main&amp;lt;/tt&amp;gt; ausgeführt, ''n'' = 0...9&lt;br /&gt;
 |-&lt;br /&gt;
 |&amp;lt;tt&amp;gt;.fini''n''&amp;lt;/tt&amp;gt; ||Flash ||Code ||wird nach &amp;lt;tt&amp;gt;main&amp;lt;/tt&amp;gt; ausgeführt, ''n'' = 9...0&lt;br /&gt;
 |-&lt;br /&gt;
 |&amp;lt;tt&amp;gt;.vectors&amp;lt;/tt&amp;gt;   ||Flash ||Code ||Vektor-Tabelle: Tabelle mit Sprüngen zur jeweiligen ISR&lt;br /&gt;
 |-&lt;br /&gt;
 |&amp;lt;tt&amp;gt;.bootloader&amp;lt;/tt&amp;gt; ||Flash||Code ||für den Bootloader&lt;br /&gt;
 |}&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
Der Anfang einer Section kann auch dem Linker mitgegeben werden, etwa wenn wie üblich &amp;lt;tt&amp;gt;avr-gcc&amp;lt;/tt&amp;gt; als Treiber für den Linker verwendet wird:&lt;br /&gt;
 avr-gcc ...  -Wl,--section-start=.eeprom=0x810001&lt;br /&gt;
Damit beginnt Section &amp;lt;tt&amp;gt;.eeprom&amp;lt;/tt&amp;gt; nicht an der (virtuellen) Adresse &amp;lt;tt&amp;gt;0x810000&amp;lt;/tt&amp;gt;, &lt;br /&gt;
sondern ein Byte später. &lt;br /&gt;
Manche AVRs haben einen [[AVR-Errata|Silicon-Bug]], der bei Verwendung der EEPROM-Adresse 0 zu Fehlern führt. &lt;br /&gt;
Mit der obigen Linker-Option wird diese Adresse nicht mehr verwendet.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- &lt;br /&gt;
=Adressen=&lt;br /&gt;
&lt;br /&gt;
Der Speicher der AVR-Mikrocontroller ist in einer Harvard-Struktur organisiert: Der Adressraum ist nicht linear, sondern es gibt unterschiedliche Adressbereiche für SRAM, Flash, EEPROM, externes RAM, etc. Adresse&amp;amp;nbsp;0 hat also eine unterschiedliche Bedeutung, ja nachdem, ob damit die SRAM-Zelle&amp;amp;nbsp;0 gemeint ist (an diese Adresse des SRAM wird Register &amp;lt;tt&amp;gt;r0&amp;lt;/tt&amp;gt; abgebildet) oder zB Flash-Adresse&amp;amp;nbsp;0 (Reset-Einsprungpunkt). &lt;br /&gt;
&lt;br /&gt;
GCC geht jedoch davon aus, daß der Adressraum linear organisiert ist (von-Neumann-Struktur). In GCC gibt es keine Möglichkeit, diese unterschiedlichen Adressbereiche zu kennzeichnen. Zwar gibt es [[#Attribute|Attribute]], um die Lokatierung &amp;amp;ndash; also die Daten/Codeablage &amp;amp;ndash; zu beeinflussen, aber beim Datenzugriff über eine Adresse wird immer in den SRAM gegriffen. Attribute sind leider nicht wirklich geeignet, die verschiedenen Pointer-Arten zu unterscheiden. Dazu wären Qualifier das Mittel der Wahl. Das Einführen neuer Qualifier würde eine Spracherweiterung von C bedeuten und tiefgreifende Änderung in GCC erfordern, die weit über die Backend-Beschreibung für AVR hinausgingen und in absehbarer Zeit nicht zu erwarten sind.&lt;br /&gt;
&lt;br /&gt;
Daher verwendet &amp;lt;tt&amp;gt;avr-gcc&amp;lt;/tt&amp;gt; intern virtuelle Adressen, die erst später in die tatsächlichen Speicheradressen umgewandelt werden. Die Startadressen für die Speicherbereiche sind:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Flash:  ab 0x0&lt;br /&gt;
SRAM:   ab 0x80060&lt;br /&gt;
EEPROM: ab 0x81000&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Attribute=&lt;br /&gt;
&lt;br /&gt;
Mit Attributen kann man die Codeerzeugung beeinflussen. Es gibt verschiedene Attribute, die auf Daten, Typen, und/oder Funktionen anwendbar sind.&lt;br /&gt;
&lt;br /&gt;
'''Syntax:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
__attribute__ ((&amp;amp;lt;name&amp;amp;gt;))&lt;br /&gt;
__attribute__ ((&amp;amp;lt;name1&amp;amp;gt;, &amp;amp;lt;name2&amp;amp;gt;, ...))&lt;br /&gt;
__attribute__ ((&amp;amp;lt;name&amp;amp;gt; (&amp;amp;quot;&amp;amp;lt;wert&amp;amp;gt;&amp;amp;quot;)))&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Nützliche Attribute von GCC==&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|+ '''Tabelle: Attribute von GCC''' (Auszug)&lt;br /&gt;
|- {{Hintergrund1}}&lt;br /&gt;
! |Attribut ||Funktionen ||Daten ||Typen ||Beschreibung&lt;br /&gt;
 |-&lt;br /&gt;
 | &amp;lt;tt&amp;gt;section&amp;amp;nbsp;(&amp;quot;&amp;amp;lt;name&amp;amp;gt;&amp;quot;)&amp;lt;/tt&amp;gt;&lt;br /&gt;
!| (x) || (x) || (x)&lt;br /&gt;
 | Lokatiert nach Section &amp;lt;tt&amp;gt;&amp;amp;lt;name&amp;amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 | &amp;lt;tt&amp;gt;noreturn&amp;lt;/tt&amp;gt;&lt;br /&gt;
!| x ||  ||&lt;br /&gt;
 | Die Funktion wird nie zurückkehren&lt;br /&gt;
 |-&lt;br /&gt;
 |&amp;lt;tt&amp;gt;inline&amp;lt;/tt&amp;gt;&lt;br /&gt;
!| x  || ||&lt;br /&gt;
 |Funktion wird geinlinet falls möglich&lt;br /&gt;
 |-&lt;br /&gt;
 |&amp;lt;tt&amp;gt;noinline&amp;lt;/tt&amp;gt;&lt;br /&gt;
!|x  ||  ||&lt;br /&gt;
 |Funktion wird keinesfalls geinlinet&lt;br /&gt;
 |-&lt;br /&gt;
 |&amp;lt;tt&amp;gt;packed&amp;lt;/tt&amp;gt;&lt;br /&gt;
!| || x || x&lt;br /&gt;
 |Datenablage in Strukturen erfolgt dicht, also ohne eventuelle Füllbytes&lt;br /&gt;
 |-&lt;br /&gt;
 |&amp;lt;tt&amp;gt;unused&amp;lt;/tt&amp;gt;&lt;br /&gt;
!| || x || &lt;br /&gt;
 |Variable wird nicht verwendet, z.B. bei Funktionsparametern, die nicht gebraucht werden. Vermeidet entsprechende Warnungen.&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
==Attribute von avr-gcc==&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|+ '''Tabelle: Attribute von &amp;lt;tt&amp;gt;avr-gcc&amp;lt;/tt&amp;gt;'''&lt;br /&gt;
|- {{Hintergrund1}}&lt;br /&gt;
! |Attribut ||Funktionen ||Daten ||Typen ||Beschreibung &lt;br /&gt;
|-&lt;br /&gt;
 | &amp;lt;tt&amp;gt;progmem&amp;lt;/tt&amp;gt;&lt;br /&gt;
!| x || x || x&lt;br /&gt;
 | Lokatiert ins Flash&lt;br /&gt;
 |-&lt;br /&gt;
 | &amp;lt;tt&amp;gt;naked&amp;lt;/tt&amp;gt;&lt;br /&gt;
!| x || || &lt;br /&gt;
 |Funktion wird ohne Prolog/Epilog erzeugt&lt;br /&gt;
 |-&lt;br /&gt;
 |&amp;lt;tt&amp;gt;interrupt&amp;lt;/tt&amp;gt;&lt;br /&gt;
!| x || ||&lt;br /&gt;
 |Hier nur wegen der Vollständigkeit erwähnt&lt;br /&gt;
 |-&lt;br /&gt;
 |&amp;lt;tt&amp;gt;signal&amp;lt;/tt&amp;gt;&lt;br /&gt;
!| x ||  ||&lt;br /&gt;
 |Hier nur wegen der Vollständigkeit erwähnt&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
'''Beispiele:'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#define EEPROM __attribute__ ((section (&amp;quot;.eeprom&amp;quot;)))&lt;br /&gt;
&lt;br /&gt;
const char EE_HALLO_WELT[] EEPROM = &amp;quot;Hallo Welt&amp;quot;;&lt;br /&gt;
const int EE_wert EEPROM = 0x1234;&lt;br /&gt;
&lt;br /&gt;
void __attribute__ ((noinline))&lt;br /&gt;
foo()&lt;br /&gt;
{&lt;br /&gt;
   /* Code */&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Dynamische Speicherallokierung=&lt;br /&gt;
&lt;br /&gt;
[[Bild:Avr-ram.png|right|thumb|RAM-Layout für ein AVR mit 1kByte SRAM]]&lt;br /&gt;
Zur dynamischen Speicherallokierung stehen Standard-Funktionen wie &amp;lt;tt&amp;gt;malloc&amp;lt;/tt&amp;gt; zur Verfügung.&lt;br /&gt;
Damit kann man zur Laufzeit Speicher anfordern und wenn man ihn nicht mehr benötigt, wieder freigeben.&lt;br /&gt;
Funktionen wie &amp;lt;tt&amp;gt;malloc&amp;lt;/tt&amp;gt; und &amp;lt;tt&amp;gt;calloc&amp;lt;/tt&amp;gt; sind jedoch recht aufwändig. &lt;br /&gt;
Die allokierten Speicherstücke werden intern in einer verketteten Liste verwaltet,&lt;br /&gt;
und das verbraucht wertvollen Platz im Flash und im SRAM sowie Laufzeit.&lt;br /&gt;
&lt;br /&gt;
Resourcen-schonendere Möglichkeiten, zur Laufzeit an Speicher zu kommen, &lt;br /&gt;
bieteten &amp;lt;tt&amp;gt;__builtin_alloca&amp;lt;/tt&amp;gt; und dynamische Arrays. &lt;br /&gt;
Der Speicher, der damit belegt wird, wird nicht auf dem Heap angelegt, &lt;br /&gt;
sondern im Frame der Funktion. Das ist wesentlich effektiver als die Standard-Methoden,&lt;br /&gt;
denn es muss nur ein Wert zum Framepointer addiert werden.&lt;br /&gt;
Den so erhaltenen Speicher braucht man auch nicht freizugeben. Das geschieht automatisch beim Verlassen der Funktion in deren Epilog, indem der Wert wieder vom Framepointer subtrahiert wird. &lt;br /&gt;
&lt;br /&gt;
{{FarbigerRahmen|&lt;br /&gt;
Von der Verwendung ist der mittels &amp;lt;tt&amp;gt;__builtin_alloca&amp;lt;/tt&amp;gt; und dynamischer Arrays erhaltene '''Speicher also wie eine lokale Variable, mitsamt den bekannten Regeln für den Gültigkeitsbereich'''.&lt;br /&gt;
&lt;br /&gt;
Insbesondere darf dieser Speicher nicht mit &amp;lt;tt&amp;gt;return&amp;lt;/tt&amp;gt; an die darüberliegende Funktion zurückgegeben werden, weil er dann nicht mehr gültig ist und ein Zugriff darauf zu einem&lt;br /&gt;
Laufzeitfehler führt!&lt;br /&gt;
&lt;br /&gt;
Der Speicherbereich ist dort gültig, wo auch die Adresse einer 'normalen' lokalen Variablen gültig wäre, wenn diese an der gleichen Stelle definiert würde.&lt;br /&gt;
&lt;br /&gt;
Das Programm/der Algorithmus muss daher beim Beschreiten dieses Wegs darauf angepasst sein.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
'''Verwendung:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
void function (size_t num_data)&lt;br /&gt;
{&lt;br /&gt;
   // data_t hat man irgendwo selber definiert, oder es ist ein elementarer Typ&lt;br /&gt;
   data_t * const p = (data_t * const) __builtin_alloca (num_data * sizeof (data_t));&lt;br /&gt;
&lt;br /&gt;
   // Mach was mit p[0] ... p[num_bytes-1]&lt;br /&gt;
   ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
oder mittels eines dynamischen Arrays:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
void function (size_t num_data)&lt;br /&gt;
{&lt;br /&gt;
   // data_t hat man irgendwo selber definiert, oder es ist ein elementarer Typ&lt;br /&gt;
   data_t p[num_data];&lt;br /&gt;
&lt;br /&gt;
   // Mach was mit p[0] ... p[num_bytes-1]&lt;br /&gt;
   ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=C++=&lt;br /&gt;
&lt;br /&gt;
Aus Effizienzgründen sollte der Einsatz von C++ sehr kritisch betrachtet werden:&lt;br /&gt;
:''&amp;quot;When programming C++ in space- and runtime-sensitive environments like microcontrollers, extra care should be taken to avoid unwanted side effects of the C++ calling conventions like implied copy constructors that could be called upon function invocation etc. These things could easily add up into a considerable amount of time and program memory wasted. Thus, casual inspection of the generated assembler code (using the &amp;lt;tt&amp;gt;-S&amp;lt;/tt&amp;gt; compiler option) seems to be warranted.&amp;quot;''&lt;br /&gt;
&lt;br /&gt;
Zudem unterliegt der Einsatz von C++ je nach Compiler/Lib-Version bestimmten Einschränkungen:&lt;br /&gt;
*Einer kompletten C++ Implementierung fehlt die Unterstützung durch die &amp;lt;tt&amp;gt;libstdc++&amp;lt;/tt&amp;gt;, dadurch fehlen Standardfunktionen, -Klassen und -Templates&lt;br /&gt;
* Die Operatoren &amp;lt;tt&amp;gt;new&amp;lt;/tt&amp;gt; und &amp;lt;tt&amp;gt;delete&amp;lt;/tt&amp;gt; sind nicht implementiert, ihre Verwendung führt zu unauflösbaren externen Referenzen (Linker-Fehler)&lt;br /&gt;
*Nicht alle Header sind C++-sicher und müssen in &amp;lt;tt&amp;gt;extern &amp;quot;C&amp;quot; {...}&amp;lt;/tt&amp;gt; eingeschlossen werden.&lt;br /&gt;
*Exceptions werden nicht unterstützt und müssen via &amp;lt;tt&amp;gt;-fno-exceptions&amp;lt;/tt&amp;gt; abgeschaltet werden, oder der Linker beschwert sich über eine unauflösbare externe Referenz zu &amp;lt;tt&amp;gt;__gxx_personality_sj0&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Als Treiber verwendet man wie immer &amp;lt;tt&amp;gt;avr-gcc&amp;lt;/tt&amp;gt;. Standard-Endungen für C++ sind &amp;lt;tt&amp;gt;.c++&amp;lt;/tt&amp;gt; und &amp;lt;tt&amp;gt;.cpp&amp;lt;/tt&amp;gt;. Bei anderen Endungen teilt man mit &amp;lt;tt&amp;gt;-x c++&amp;lt;/tt&amp;gt; mit, daß es sich um C++ Dateien handelt, oder ruft &amp;lt;tt&amp;gt;avr-c++&amp;lt;/tt&amp;gt; direkt auf.&lt;br /&gt;
&lt;br /&gt;
Interrupt-Service-Routinen (ISRs) sind C-Funktionen und werden definiert wie gehabt. Siehe auch [[#Interrupts|Interrupts]].&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/signal.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#if defined (__cplusplus)&lt;br /&gt;
extern &amp;quot;C&amp;quot; {&lt;br /&gt;
#endif /* __cplusplus */   &lt;br /&gt;
&lt;br /&gt;
SIGNAL (SIG_NAME)&lt;br /&gt;
{&lt;br /&gt;
   /* machwas */&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
INTERRUPT (SIG_NAME)&lt;br /&gt;
{&lt;br /&gt;
   /* mach was */&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#if defined (__cplusplus)&lt;br /&gt;
}&lt;br /&gt;
#endif /* __cplusplus */   &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;__cplusplus&amp;lt;/tt&amp;gt; ist ein Standard [[#Builtin Defines|GCC-Builtin-Define]].&lt;br /&gt;
&lt;br /&gt;
Globale Konstruktoren werden in [[#Sections|Section]] &amp;lt;tt&amp;gt;.init6&amp;lt;/tt&amp;gt; ausgeführt, die Destruktoren in &amp;lt;tt&amp;gt;.fini6&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=Code-Beispiele=&lt;br /&gt;
Dieser Abschnitt enthält Code-Schnippsel für &amp;lt;tt&amp;gt;avr-gcc&amp;lt;/tt&amp;gt;. Es werden Besonderheiten besprochen, die für &amp;lt;tt&amp;gt;avr-gcc&amp;lt;/tt&amp;gt; zu beachten sind. &lt;br /&gt;
&lt;br /&gt;
Dieser Abschnitt ist ''kein'' Tutorial zur C-Programmierung und ''keine'' Einführung in die Programmiersprache C im allgemeinen. Dafür sei auf einschlägige Tutorials/Bücher verwiesen.&lt;br /&gt;
&lt;br /&gt;
==Zugriff auf Special Function Registers (SFRs)==&lt;br /&gt;
&lt;br /&gt;
===Zugiff auf Bytes und Worte===&lt;br /&gt;
Auf SFRs wird generell über deren Adresse zugegriffen:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   // Liest den Inhalt von SREG an Adresse 0x5f&lt;br /&gt;
   unsigned char sreg = *((unsigned char volatile*) 0x5f);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Das bedeutet in etwa: &amp;quot;Lies ein flüchtiges (&amp;lt;tt&amp;gt;volatile&amp;lt;/tt&amp;gt;) Byte (&amp;lt;tt&amp;gt;unsigned char&amp;lt;/tt&amp;gt;) von Adresse &amp;lt;tt&amp;gt;0x5f&amp;lt;/tt&amp;gt;&amp;quot;. Der Speicherinhalt von SFRs ist flüchtig, denn er kann sich ändern, ohne daß &amp;lt;tt&amp;gt;avr-gcc&amp;lt;/tt&amp;gt; dies mitbekommt. Daher muss bei jedem C-Zugriff auf ein SFR dieses wirklich gelesen/geschrieben werden, was der Qualifier &amp;lt;tt&amp;gt;volatile&amp;lt;/tt&amp;gt; sicherstellt. Ansonst geht der Compiler u.U. davon aus, daß der Inhalt bekannt ist und verwendet einen alten, in einem GPR befindlichen Wert.&lt;br /&gt;
&lt;br /&gt;
Um lesbaren, weniger fehleranfälligen und unter AVRs halbwegs portierbaren Code zu erhalten, gibt es Makrodefinitionen im Controller-spezifischen Header &amp;lt;tt&amp;gt;ioxxxx.h&amp;lt;/tt&amp;gt;, der neben anderen Dingen mit &amp;lt;tt&amp;gt;avr/io.h&amp;lt;/tt&amp;gt; includet wird:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
   // SREG lesen&lt;br /&gt;
   uint8_t sreg = SREG;&lt;br /&gt;
   ...&lt;br /&gt;
   // SREG schreiben&lt;br /&gt;
   SREG = sreg;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Die Bezeichner der SFRs sind die gleichen wie im Manual. Evtl verschafft ein Blick in den Header Klarheit. Dieser befinden sich in&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt; &amp;amp;lt;AVR_INSTALL_DIR&amp;amp;gt;/avr/include/avr/io****.h&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dieser Zugriff geht auch für 16-Bit Register wie &amp;lt;tt&amp;gt;TCNT1&amp;lt;/tt&amp;gt;, für die eine bestimmte Reihenfolge für den Zugriff auf Low- und High-Teil eingehalten werden muss: &amp;lt;tt&amp;gt;avr-gcc&amp;lt;/tt&amp;gt; generiert die Zugriffe in der richtigen Reihenfolge.&lt;br /&gt;
  uint16_t tcnt1 = TCNT1;&lt;br /&gt;
&lt;br /&gt;
{{FarbigerRahmen|&lt;br /&gt;
Zu beachten ist, daß dieser Zugriff nicht atomar erfolgt. Das Lesen/Schreiben mehrbytiger Werte muss vom Compiler in mehrere Byte-Zugriffe zerlegt werden. Zwischen diesen Zugriffen kann ein Interrupt auftreten, was zu fehlerhaften Resultaten führen kann. Entsprechende Codestücke müssen daher atomar gehalten werden!&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
===Zugriff auf einzelne Bits===&lt;br /&gt;
Zugriff auf Bits geht wie gewohnt mit den Bitoperationen &lt;br /&gt;
&amp;lt;tt&amp;gt;&amp;amp;amp;&amp;lt;/tt&amp;gt; (and),&lt;br /&gt;
&amp;lt;tt&amp;gt;|&amp;lt;/tt&amp;gt; (or),&lt;br /&gt;
&amp;lt;tt&amp;gt;^&amp;lt;/tt&amp;gt; (xor) und&lt;br /&gt;
&amp;lt;tt&amp;gt;~&amp;lt;/tt&amp;gt; (not)&lt;br /&gt;
&lt;br /&gt;
Wieder gibt es Defines in den AVR-Headern, mit denen man Masken für den Zugriff erhalten kann, etwa:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/* GIMSK / GICR */&lt;br /&gt;
#define INT1    7&lt;br /&gt;
#define INT0    6&lt;br /&gt;
#define IVSEL   1&lt;br /&gt;
#define IVCE    0&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Masken ergeben sich durch Schieben von &amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt; an die richtige Position:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// Ports B_0 und B_1 als Ausgang&lt;br /&gt;
DDRB |= (1&amp;amp;lt;&amp;amp;lt;PB0) | (1&amp;amp;lt;&amp;amp;lt;PB1);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
erzeugt&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
87 b3           in      r24, 0x17&lt;br /&gt;
83 60           ori     r24, 0x03&lt;br /&gt;
87 bb           out     0x17, r24&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Etwas anders sieht der Code aus, wenn die Bits einzeln gesetzt werden und das Register im bitadressierbaren Bereich liegt (SRAM &amp;lt;tt&amp;gt;0x20&amp;lt;/tt&amp;gt; bis &amp;lt;tt&amp;gt;0x3f&amp;lt;/tt&amp;gt; resp. I/O &amp;lt;tt&amp;gt;0x0&amp;lt;/tt&amp;gt; bis &amp;lt;tt&amp;gt;0x1f&amp;lt;/tt&amp;gt;):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// Ports B_0 und B_1 als Ausgang&lt;br /&gt;
DDRB |= (1&amp;amp;lt;&amp;amp;lt;PB0);&lt;br /&gt;
DDRB |= (1&amp;amp;lt;&amp;amp;lt;PB1);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
erzeugt&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
b8 9a           sbi     0x17, 0&lt;br /&gt;
b9 9a           sbi     0x17, 1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
{{FarbigerRahmen| &lt;br /&gt;
Auch hier ist zu beachten, daß es Probleme geben kann, wenn nicht atomarer Code erzeugt wird, weil der AVR-Befehlssatz nicht mehr hergibt:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// toggle PORT B_0: wechseln 0 &amp;amp;lt;--&amp;amp;gt; 1 &lt;br /&gt;
PORTB ^= (1&amp;amp;lt;&amp;amp;lt;PB0);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
ergibt&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
88 b3           in      r24, 0x18&lt;br /&gt;
; Wenn hier ein Interrupt auftritt, in dessen ISR PORTB verändert wird,&lt;br /&gt;
; dann wird die Änderung durch die letzte Instruktion wieder überschrieben!&lt;br /&gt;
91 e0           ldi     r25, 0x01&lt;br /&gt;
; dito&lt;br /&gt;
89 27           eor     r24, r25&lt;br /&gt;
; dito&lt;br /&gt;
88 bb           out     0x18, r24&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
}} &amp;lt;!-- /FarbigerRahmen --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Auch das Lesen einzelner Port-Pins geht über das Maskieren von SFRs:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
DDRB &amp;amp;= ~(1 &amp;lt;&amp;lt; PB2);    // PortB.2 als INPUT &lt;br /&gt;
&lt;br /&gt;
if (PINB &amp;amp; (1 &amp;lt;&amp;lt; PB2))&lt;br /&gt;
   // PortB.2 ist HIGH&lt;br /&gt;
else&lt;br /&gt;
   // PortB.2 ist LOW&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
if (!(PINB &amp;amp; (1 &amp;lt;&amp;lt; PB2)))&lt;br /&gt;
   // PortB.2 ist LOW&lt;br /&gt;
else&lt;br /&gt;
   // PortB.2 ist HIGH&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Interrupts==&lt;br /&gt;
&lt;br /&gt;
Um zu kennzeichnen, daß es sich bei einer Funktion um eine Interrupt Sevice Routine (ISR) handelt, gibt es spezielle Attribute. Diese brauchen nicht explizit hingeschrieben zu werden, ebensowenig wie die genaue Nummer des Interrupt Requests (IRQ). Dafür gibt es die Includes und die Makros:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/signal.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
SIGNAL (SIG_OUTPUT_COMPARE1A)&lt;br /&gt;
{&lt;br /&gt;
   /* ISR-Code */&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
INTERRUPT (SIG_OUTPUT_COMPARE1B)&lt;br /&gt;
{&lt;br /&gt;
   /* ISR-Code */&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dadurch wird die Funktion mit dem richtigen Prolog/Epilog erzeugt, und es wird ein Eintrag in die Interrupt-Vektortabelle gemacht &amp;amp;#150; bei obigem Beispiel also zwei Einträge.&lt;br /&gt;
&lt;br /&gt;
{{FarbigerRahmen|&lt;br /&gt;
Die Schreibweise des Signal-Names muss genau die sein wie im Header, das schliesst auch Leerzeichen ein! Nicht alle GCC-Versionen bringen Fehler/Warnung, wenn die Schreibweise nicht stimmt.&lt;br /&gt;
 SIGNAL (SIG_OUTPUT_COMPARE1A )  // !!! Macht NICHT das, was man will (Blank am Ende)!!!&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;tt&amp;gt;SIGNAL&amp;lt;/tt&amp;gt;: Mit Ausführung einer ISR deaktiviert die AVR-Hardware die Interrupts, sodaß die ISR nicht durch andere Interrupt-Anforderungen unterbrochen wird. Beim Verlassen der ISR werden Interrupts wieder aktiviert. Tritt während der ISR ein IRQ auf, wird diese erst nach Beenden des ISR-Codes ausgeführt. Der Interrupt geht also nicht verloren. Zwischen zwei ISRs wird zusätzlich mindestens ein Befehl des normalen Programm-Codes abgearbeitet.&lt;br /&gt;
;&amp;lt;tt&amp;gt;INTERRUPT&amp;lt;/tt&amp;gt;: Früh im ISR-Prolog werden mit &amp;lt;tt&amp;gt;sei&amp;lt;/tt&amp;gt; die von der AVR-Hardware temporär deaktivierten Interrupts reaktiviert. Dadurch kann die ISR von einer IRQ unterbrochen werden. Das bietet die Möglichkeit, so etwas wie Interrupt-Priorisierung nachzubilden, was AVRs selbst nicht können. Weiterhin kann man schneller auf bestimmte Ereignisse reagieren. Tritt während der ISR ein anderer IRQ auf, der schnell bedient werden muss, kann sofort der dringende ISR-Code ausgeführt werden. Ansonsten (Verwendung von &amp;lt;tt&amp;gt;SIGNAL&amp;lt;/tt&amp;gt;) würde der Code erst ausgeführt werden, nachdem die aktuelle ISR beendet ist.&lt;br /&gt;
&lt;br /&gt;
{{FarbigerRahmen|Dauert die ISR zu lange und wird sie nochmals von ihrem eigenen IRQ unterbrochen, stürzt man ab.}} &lt;br /&gt;
&lt;br /&gt;
Nachschlagen kann man den Namen in&lt;br /&gt;
:&amp;lt;tt&amp;gt;&amp;amp;lt;GCC_HOME&amp;amp;gt;/avr/include/avr/ioxxxx.h&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Interrupts aktivieren===&lt;br /&gt;
&lt;br /&gt;
Damit eine ISR überhaupt zur Ausführung kommt, müssen drei Bedingungen erfüllt sein&lt;br /&gt;
* Interrupts müssen global aktiviert sein&lt;br /&gt;
* Der entsprechen IRQ muss aktiviert worden sein&lt;br /&gt;
* Das zum IRQ gehörende Ereignis muss eintreten&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/interrupt.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
   ...&lt;br /&gt;
   // enable OutputCompareA Interrupt für Timer1&lt;br /&gt;
   TIMSK |= (1 &amp;lt;&amp;lt; OCIE1A);&lt;br /&gt;
&lt;br /&gt;
   // disable OutputCompareA Interrupt für Timer1&lt;br /&gt;
   TIMSK &amp;amp;= ~(1 &amp;lt;&amp;lt; OCIE1A);&lt;br /&gt;
&lt;br /&gt;
   // Interrupts aktivieren&lt;br /&gt;
   sei();&lt;br /&gt;
&lt;br /&gt;
   // Interrupts abschalten&lt;br /&gt;
   cli();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Sperrt man eine Code-Sequenz durch Einschachteln in ein &amp;lt;tt&amp;gt;cli&amp;lt;/tt&amp;gt;/&amp;lt;tt&amp;gt;sei&amp;lt;/tt&amp;gt; Paar (man macht das Codestück &amp;quot;atomar&amp;quot;, also ununterbrechbar), gehen währenddessen keine Interrupt-Anforderungen verloren. Die entsprechenden IRQ-Flags bleiben gesetzt, und nach dem &amp;lt;tt&amp;gt;sei&amp;lt;/tt&amp;gt; werden die IRQs in der Reihenfolge ihrer Prioritäten abgearbeitet. Ausnahme ist, wenn in einem atomaren Block der selbe IRQ mehrfach auftritt. Der ISR-Code wird dann trotzdem nur einmal ausgeführt.&lt;br /&gt;
&lt;br /&gt;
===default Interrupt===&lt;br /&gt;
&lt;br /&gt;
Für nicht implementierte Interrupts macht &amp;lt;tt&amp;gt;avr-gcc&amp;lt;/tt&amp;gt; in die Vektortabelle einen Eintrag,&lt;br /&gt;
der zu &amp;lt;tt&amp;gt;__bad_interrupt&amp;lt;/tt&amp;gt; (definiert im Startup-Code &amp;lt;tt&amp;gt;crt*.o&amp;lt;/tt&amp;gt;) springt&lt;br /&gt;
und von dort aus weiter zu Adresse&amp;amp;nbsp;0. &lt;br /&gt;
Dadurch läuft der AVR wieder von neuem los, wenn ein Interrupt auftritt, &lt;br /&gt;
zu dem man keine ISR definiert hat &lt;br /&gt;
&amp;amp;#150; allerdings ohne die Hardware zurückzusetzen wie bei einem echten Reset.&lt;br /&gt;
&lt;br /&gt;
Möchte man diesen Fall abfangen, dann geht das über eine globale Funktion &lt;br /&gt;
namens &amp;lt;tt&amp;gt;__vector_default&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/signal.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
SIGNAL (__vector_default)&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Damit wird von &amp;lt;tt&amp;gt;__bad_interrupt&amp;lt;/tt&amp;gt; aus nicht nach Adresse&amp;amp;nbsp;0 gesprungen,&lt;br /&gt;
sondern weiter zu &amp;lt;tt&amp;gt;__vector_default&amp;lt;/tt&amp;gt;, welches durch &amp;lt;tt&amp;gt;SIGNAL&amp;lt;/tt&amp;gt; oder&lt;br /&gt;
&amp;lt;tt&amp;gt;INTERRUPT&amp;lt;/tt&amp;gt; den üblichen ISR-Prolog/Epilog bekommt.&lt;br /&gt;
&lt;br /&gt;
So kann man z.B. eine Meldung ausgeben, eine Warnlampe blinken, in einer Endlosschleife landen, oder über den [[Watchdog]] einen richtigen Hardware-Reset auslösen, siehe auch Abschnitt &amp;quot;[[#Reset auslösen|Reset auslösen]]&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
===ISR mit eigenem Prolog/Epilog===&lt;br /&gt;
&lt;br /&gt;
Wenn man in einer ISR komplett eigenes Zeug machen will, &lt;br /&gt;
dann definiert man eine nackte Funktion.&lt;br /&gt;
Mit &amp;lt;tt&amp;gt;naked&amp;lt;/tt&amp;gt; befreit man die Routine vom Standard-Prolog/Epilog.&lt;br /&gt;
{{FarbigerRahmen|&lt;br /&gt;
Dabei ist darauf zu achten, daß die ISR mit &amp;lt;tt&amp;gt;reti&amp;lt;/tt&amp;gt; (return from interrupt) &lt;br /&gt;
zurückkehrt und evtl. verwendete Register und den Status (&amp;lt;tt&amp;gt;SREG&amp;lt;/tt&amp;gt;) sichert.&lt;br /&gt;
}}&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
void __attribute__ ((naked)) &lt;br /&gt;
SIG_OVERFLOW0 (void)&lt;br /&gt;
{&lt;br /&gt;
   /* Port B.6 = 0                                                         */&lt;br /&gt;
   /* Diese Instruktion verändert nicht das SREG und kein anderes Register */&lt;br /&gt;
   /* so daß der eigentliche Code nur 1 Befehl lang ist                    */&lt;br /&gt;
   __asm__ __volatile (&lt;br /&gt;
      &amp;quot;cbi %0, %1&amp;quot; &amp;quot;\n\t&amp;quot;&lt;br /&gt;
      &amp;quot;reti&amp;quot;&lt;br /&gt;
         : &lt;br /&gt;
         : &amp;quot;M&amp;quot; (_SFR_IO_ADDR (PORTB)), &amp;quot;i&amp;quot; (6)&lt;br /&gt;
   );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Die ISR sieht dann so aus:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
__vector_9:&lt;br /&gt;
   c6 98       	cbi   0x18, 6&lt;br /&gt;
   18 95       	reti&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wiederum kann man als Funktionsname &amp;lt;tt&amp;gt;__vector_default&amp;lt;/tt&amp;gt; nehmen,&lt;br /&gt;
um nicht-implementierte IRQs abzufangen:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
void __attribute__ ((naked)) &lt;br /&gt;
__vector_default (void)&lt;br /&gt;
 ...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==SRAM, Flash, EEPROM: Datenablage am Beispiel Strings==&lt;br /&gt;
Die Programmiersprache C kennt selber keine Strings; das einzige, was C bekannt ist, ist der Datentyp &amp;lt;tt&amp;gt;char&amp;lt;/tt&amp;gt;, der ein einzelnes Zeichen repräsentiert. &lt;br /&gt;
===Darstellung in C===&lt;br /&gt;
Ein String im Sinne von C ist ein Array von Charactern bzw. ein Zeiger auf den Anfang des Arrays. Die einzelnen Zeichen folgen im Speicher direkt aufeinander und werden in aufsteigenden Adressen gespeichert. Am String-Ende folgt als Abschluss der Character &amp;lt;tt&amp;gt;'\0'&amp;lt;/tt&amp;gt;, um das Ende zu kennzeichnen. Dies ist besonders bei der Berechnung des Speicherplatzes für Strings zu berücksichtigen, denn für die 0 muss auch Platz reserviert werden.&lt;br /&gt;
&lt;br /&gt;
===Bestimmen der Stringlänge===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 /* Bestimmt die Laenge des Strings ohne die abschliessende '\0' zu zaehlen */&lt;br /&gt;
 unsigned int strlength (const char *str)&lt;br /&gt;
 {&lt;br /&gt;
   unsigned int len = 0;&lt;br /&gt;
   &lt;br /&gt;
   while (*str++)&lt;br /&gt;
      len++;&lt;br /&gt;
   &lt;br /&gt;
   return len;&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Stringlänge kann auch mit der Standard-Funktion &amp;lt;tt&amp;gt;strlen&amp;lt;/tt&amp;gt; bestimmt werden, deren Prototyp sich in &amp;lt;tt&amp;gt;string.h&amp;lt;/tt&amp;gt; befindet:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
 size_t strlen (const char*);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===String im Flash belassen===&lt;br /&gt;
Oftmals werden Strings nur zu Ausgabezwecken verwendet und nicht verändert. Verwendet man Sequenzen der Gestalt&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 char *str1 = &amp;quot;Hallo Welt!&amp;quot;;&lt;br /&gt;
 char str2[] = &amp;quot;Hallo Welt!&amp;quot;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
dann werden die Strings im SRAM abgelegt. Im Startup-Code werden die Strings vom Flash ins SRAM kopiert und belegen daher sowohl Platz im SRAM als auch im Flash. Wird ein String nicht verändert, braucht er nicht ins SRAM kopiert zu werden. Das spart Platz im knapp bemessenen SRAM. Allerdings muss anders auf den String zugegriffen werden, denn wegen der Harvard-Architektur des AVR-Kerns kann &amp;lt;tt&amp;gt;avr-gcc&amp;lt;/tt&amp;gt; anhand der Adresse nicht unterscheiden, ob diese ins SRAM, ins Flash oder ins EEPROM zeigt.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 #include &amp;lt;avr/pgmspace.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 const prog_char str3[] = &amp;quot;Hallo Welt!&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 unsigned int strlen_P (const prog_char *str)&lt;br /&gt;
 {&lt;br /&gt;
    unsigned int len = 0;&lt;br /&gt;
 &lt;br /&gt;
    while (1)&lt;br /&gt;
    {&lt;br /&gt;
       char c = (char) pgm_read_byte (str);&lt;br /&gt;
       if ('\0' == c)&lt;br /&gt;
          return len;&lt;br /&gt;
       len++;&lt;br /&gt;
       str++; &lt;br /&gt;
    }&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void foo()&lt;br /&gt;
 {&lt;br /&gt;
    unsigned int len;&lt;br /&gt;
    len = strlen_P (str3);&lt;br /&gt;
    len = strlen_P (PSTR(&amp;quot;String im Flash&amp;quot;));&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===String ins EEPROM legen===&lt;br /&gt;
Dies geht nach dem gleichen Muster, nach dem Strings ins Flash gelegt werden. Der Zugriff wird vergleichsweise langsam, denn der EEPROM ist langsamer als SRAM bzw. Flash.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 #include &amp;lt;avr/eeprom.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 const char str4[] __attribute__ ((section(&amp;quot;.eeprom&amp;quot;))) = &amp;quot;Hallo Welt!&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 unsigned int strlen_EE (const char *str)&lt;br /&gt;
 {&lt;br /&gt;
    unsigned int len = 0;&lt;br /&gt;
 &lt;br /&gt;
    while (1)&lt;br /&gt;
    {&lt;br /&gt;
       char c = (char) eeprom_read_byte (str);&lt;br /&gt;
       if ('\0' == c)&lt;br /&gt;
          return len;&lt;br /&gt;
       len++;&lt;br /&gt;
       str++; &lt;br /&gt;
    }&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Reset auslösen==&lt;br /&gt;
Falls ein Reset per Software ausgelöst werden soll, dann geht das am besten über den [[Watchdog]].&lt;br /&gt;
Einfach nur an den RESET-Punkt an Adresse&amp;amp;nbsp;0 zu springen mit&lt;br /&gt;
 goto *((void**) 0);&lt;br /&gt;
initialisiert zwar den Controller von neuem, aber es macht keinen wirkliches RESET mit Zurücksetzen der Hardware und allen I/O-Registern. &lt;br /&gt;
&lt;br /&gt;
Durch den Watchdog kann man ein 'richtiges' RESET-Signal erzeugen lassen, so daß die AVR-Hardware genau so initialisiert ist, wie nach einem externen RESET. So kann man z.B. via [[UART]] ein RESET-Kommando schicken. Allerdings lässt sich der Watchdog nur minimal auf 15ms einstellen:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/wdt.h&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/interrupt.h&amp;gt;&lt;br /&gt;
...   &lt;br /&gt;
   cli();                     // Interrupts global abschalten&lt;br /&gt;
   wdt_enable (WDTO_15MS);    // Watchdog aufziehen auf 15ms&lt;br /&gt;
   while (1);                 // warten, bis er zubeisst...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Welches Ereignis einen RESET ausgelöst hat, kann man im Register '''MCUCSR''' (''MCU Control and Status Register'') erfahren. Es gibt 4 mögliche RESET-Quellen:&lt;br /&gt;
* Power-On Reset&lt;br /&gt;
* External Reset&lt;br /&gt;
* Brown-Out Reset&lt;br /&gt;
* Watchdog Reset&lt;br /&gt;
&lt;br /&gt;
Soll der Inhalt von Variablen einen Reset überleben &amp;amp;ndash; eine Variable also nicht initialisiert werden &amp;amp;ndash; dann geht das so:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
// status informiert z.B. darüber, ob wir selber den Watchdog ausgelöst haben&lt;br /&gt;
// oder nicht, oder andere Informationen&lt;br /&gt;
unsigned char status __attribute__ ((section (&amp;quot;.noinit&amp;quot;)));&lt;br /&gt;
&lt;br /&gt;
void main (void)&lt;br /&gt;
{&lt;br /&gt;
   // Wert von MCUSCR merken, möglichst früh im Programm&lt;br /&gt;
   unsigned char mcucsr = MCUCSR;&lt;br /&gt;
&lt;br /&gt;
   // MCUCSR zurücksetzen&lt;br /&gt;
   MCUCSR = 0;&lt;br /&gt;
&lt;br /&gt;
   // Watchdog-Reset&lt;br /&gt;
   if (mcuscr &amp;amp; (1 &amp;lt;&amp;lt; WDRF))&lt;br /&gt;
   {&lt;br /&gt;
       // status auswerten &lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
   // Power-On Reset: status auf definierten Wert setzen&lt;br /&gt;
   if (mcuscr &amp;amp; (1 &amp;lt;&amp;lt; PORF))&lt;br /&gt;
   {&lt;br /&gt;
       status = 0;&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
   // status auswerten&lt;br /&gt;
   ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Frühe Codeausführung vor main()==&lt;br /&gt;
&lt;br /&gt;
Mitunter ist es notwendig, Code unmittelbar nach dem Reset auszuführen, noch bevor man in &amp;lt;tt&amp;gt;main()&amp;lt;/tt&amp;gt; mit der eigentlichen Programmausführung beginnt. Das kann zB zur Bedienung eines [[Watchdog]]-Timers erforderlich sein.&lt;br /&gt;
&lt;br /&gt;
Nach einen Reset und vor Aufruf von &amp;lt;tt&amp;gt;main&amp;lt;/tt&amp;gt; werden Initialisierungen ausgeführt wie&lt;br /&gt;
* setzen des Stackpointers&lt;br /&gt;
* Vorbelegung globaler Datenobjekte: Daten ohne Initializer werden zu 0 initialisert (Section &amp;lt;tt&amp;gt;.bss&amp;lt;/tt&amp;gt;). Für Daten mit Initializer (Section &amp;lt;tt&amp;gt;.data&amp;lt;/tt&amp;gt;) werden die Werte aus dem Flash ins SRAM kopiert.&lt;br /&gt;
* Initialisierung von Registern wie R1, in dem bei &amp;lt;tt&amp;gt;avr-gcc&amp;lt;/tt&amp;gt; immer die Konstante 0 gehalten wird.&lt;br /&gt;
&lt;br /&gt;
Im Linker-Script werden Sections von &amp;lt;tt&amp;gt;.init0&amp;lt;/tt&amp;gt; bis &amp;lt;tt&amp;gt;.init9&amp;lt;/tt&amp;gt; definiert, die nacheinander abgearbeitet werden. Erst danach wird &amp;lt;tt&amp;gt;main&amp;lt;/tt&amp;gt; betreten. Um Code früh auszuführen, legt man die Funktion in eine dieser Sections:&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
 /* !!! never call this function !!! */&lt;br /&gt;
 void __attribute__ ((naked, section (&amp;quot;.init3&amp;quot;)))&lt;br /&gt;
 code_init3 (void)&lt;br /&gt;
 {&lt;br /&gt;
     /* Code */&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
Zu beachten ist dabei&lt;br /&gt;
* Eine so definierte Funktion darf keinesfalls aufgerufen werden!&lt;br /&gt;
* Zuweisungen wie &amp;lt;tt&amp;gt;i=0;&amp;lt;/tt&amp;gt; ergeben vor &amp;lt;tt&amp;gt;.init3&amp;lt;/tt&amp;gt; inkorrekten Code, da vor Ende von &amp;lt;tt&amp;gt;.init2&amp;lt;/tt&amp;gt; Register R1 noch nicht mit 0 besetzt ist, &amp;lt;tt&amp;gt;avr-gcc&amp;lt;/tt&amp;gt; aber davon ausgeht, daß es eben diesen Wert enthält.&lt;br /&gt;
* Lokale Variablen müssen in Registern liegen, denn vor Ende von &amp;lt;tt&amp;gt;.init2&amp;lt;/tt&amp;gt; ist der Stackpointer noch nicht initialisiert. Zudem ist die Funktion &amp;lt;tt&amp;gt;naked&amp;lt;/tt&amp;gt;, hat also insbesondere keinen Prolog, der den Framepointer (Y-Register) setzen könnte, falls er benötigt wird. &lt;br /&gt;
* Gegebenenfalls ist daher die Verwendung von inline-Assembler angezeigt oder die Implementierung in einem eigenen Assembler-Modul, das dazu gelinkt wird. Der erzeugte Code ist im List-File zu überfrüfen.&lt;br /&gt;
* Werden mehrere Funktionen in die gleiche init-Section gelegt, ist die Reihenfolge ihrer Ausführung nicht spezifiziert und i.a. nicht die gleiche wie in der Quelle.&lt;br /&gt;
Unbenutzte init-Sections haben die Nummern 0, 1, 3 und 5 bis 8. Die verbleibenden werden vom Startup-Code verwendet:&lt;br /&gt;
;&amp;lt;tt&amp;gt;.init2&amp;lt;/tt&amp;gt;: Initialisieren von R1 mit 0 und setzen des Stackpointers&lt;br /&gt;
;&amp;lt;tt&amp;gt;.init4&amp;lt;/tt&amp;gt;: Kopieren der Daten vom Flash ins SRAM (&amp;lt;tt&amp;gt;.data&amp;lt;/tt&amp;gt;) und löschen von &amp;lt;tt&amp;gt;.bss&amp;lt;/tt&amp;gt;&lt;br /&gt;
;&amp;lt;tt&amp;gt;.init6&amp;lt;/tt&amp;gt;: C++ Konstruktoren&lt;br /&gt;
;&amp;lt;tt&amp;gt;.init9&amp;lt;/tt&amp;gt;: Sprung zu &amp;lt;tt&amp;gt;main&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Includes=&lt;br /&gt;
&lt;br /&gt;
Die mit&lt;br /&gt;
 #include &amp;lt;...&amp;gt;&lt;br /&gt;
angegebenen Includes werden von &amp;lt;tt&amp;gt;avr-gcc&amp;lt;/tt&amp;gt; in den &lt;br /&gt;
mit der Option '&amp;lt;tt&amp;gt;-I&amp;lt;/tt&amp;gt;' anegegenen Pfaden gesucht. &lt;br /&gt;
Dem Compiler bekannt ist der Pfad &amp;lt;tt&amp;gt;&amp;lt;GCC_HOME&amp;gt;/avr/include&amp;lt;/tt&amp;gt;.&lt;br /&gt;
Gibt man z.B. an &lt;br /&gt;
 #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
dann wird automatisch in diesem Verzeichnis nach &amp;lt;tt&amp;gt;stdio.h&amp;lt;/tt&amp;gt; gesucht.&lt;br /&gt;
In dem Verzeichnis stehen Standard-Includes die benötigt werden, wenn man libc-Funktionen &lt;br /&gt;
oder mathematische Funktionen verwendet. &lt;br /&gt;
AVR-spezifische Dinge stehen im Unterverzeichnis &amp;lt;tt&amp;gt;avr&amp;lt;/tt&amp;gt;, etwa:&lt;br /&gt;
 #include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
{{FarbigerRahmen|&lt;br /&gt;
Als Pfad-Separator wird immer ein '''&amp;lt;tt&amp;gt;/&amp;lt;/tt&amp;gt;''' verwendet, auch auf Windows-Betriebssystemen! Also kein '''&amp;lt;tt&amp;gt;\&amp;lt;/tt&amp;gt;'''&amp;amp;nbsp;!&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
==Standard==&lt;br /&gt;
&lt;br /&gt;
 ctype.h                   character conversion macros and ctype macros&lt;br /&gt;
 errno.h                   provides symbolic names for various error codes&lt;br /&gt;
 inttypes.h                Use [u]intN_t if you need exactly N bits.&lt;br /&gt;
                           These typedefs are mandated by the C99 standard.&lt;br /&gt;
 math.h                    mathematical functions&lt;br /&gt;
 setjmp.h                  The C library provides the setjmp() and longjmp() functions&lt;br /&gt;
                           to jump directly to another (non-local) function. &lt;br /&gt;
 stdio.h                   Standard IO facilities&lt;br /&gt;
 stdlib.h                  Declares some basic C macros and functions as defined by&lt;br /&gt;
                           the ISO standard, plus some AVR-specific extensions&lt;br /&gt;
 string.h                  perform string operations on NULL terminated strings&lt;br /&gt;
&lt;br /&gt;
==AVR-spezifisch==&lt;br /&gt;
&lt;br /&gt;
Die AVR-spezifischen Includes finden sich wie gesagt im Unterverzeichnis &amp;lt;tt&amp;gt;avr&amp;lt;/tt&amp;gt;.&lt;br /&gt;
Die meisten dort befindlichen Header wird man nie direkt durch Angabe im C-File erhalten,&lt;br /&gt;
sondern durch Angabe von&lt;br /&gt;
 #include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
Dadurch werden z.B. genau der I/O-Header eingebunden, der zum AVR-Modell passt, also&lt;br /&gt;
*&amp;lt;tt&amp;gt;avr/iom8.h&amp;lt;/tt&amp;gt; für [[ATmega8]], &lt;br /&gt;
*&amp;lt;tt&amp;gt;avr/iotn2313.h&amp;lt;/tt&amp;gt; für ATtiny2313, &lt;br /&gt;
*&amp;lt;tt&amp;gt;avr/io2313.h&amp;lt;/tt&amp;gt; für [[AT90S2313]], etc. &lt;br /&gt;
&lt;br /&gt;
Verantwortlich dafür ist der Schalter '&amp;lt;tt&amp;gt;-mmcu=xxx&amp;lt;/tt&amp;gt;'.&lt;br /&gt;
&lt;br /&gt;
Obwohl diese Header nicht explizit angegeben werden müssen, &lt;br /&gt;
kann ein Blick dorthin hilfreich sein, um die Namen von [[SFR|SFRs]] &lt;br /&gt;
oder Signals nachzuschlagen. &lt;br /&gt;
Diese Header werden im folgenden nicht alle einzeln aufgelistet. &lt;br /&gt;
Ihre Namen sind immer &amp;lt;tt&amp;gt;avr/io*.h&amp;lt;/tt&amp;gt;.&lt;br /&gt;
* für ATmega: &amp;lt;tt&amp;gt;avr/iom*.h&amp;lt;/tt&amp;gt; &lt;br /&gt;
* für ATtiny: &amp;lt;tt&amp;gt;avr/iotn*.h&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
avr/boot.h            Bootloader Support&lt;br /&gt;
avr/crc16.h           Prüfsumme CRC16&lt;br /&gt;
avr/delay.h           Verzögerungsschleife - loops for small accurate delays&lt;br /&gt;
avr/eeprom.h          EEPROM-Routinen&lt;br /&gt;
avr/ina90.h           Kompatibilität mit IAR-AVR-Compiler&lt;br /&gt;
avr/interrupt.h       sei(), cli(), ...&lt;br /&gt;
avr/io.h              --&amp;gt; inttypes.h, io*.h&lt;br /&gt;
avr/io*.h             SFRs, SIG_****, SPM_PAGESIZE, RAMEND, XRAMEND, E2END, FLASHEND&lt;br /&gt;
avr/parity.h          Parität&lt;br /&gt;
avr/pgmspace.h        Zugriff aufs Flash: Byte lesen, PROGMEM, prog_char, prog_uint8_t, ...&lt;br /&gt;
avr/portpins.h        Makros für Port-Pins&lt;br /&gt;
avr/signal.h          Makros SIGNAL() und INTERRUPT(), ...&lt;br /&gt;
avr/sleep.h           Power-Safe&lt;br /&gt;
avr/twi.h             I2C&lt;br /&gt;
avr/wdt.h             Watchdog&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Optimierungen, Tipps &amp;amp; Tricks=&lt;br /&gt;
&lt;br /&gt;
Beim Programmieren in C möchte man sich möglichst wenig mit der Codeerzeugung selbst auseinandersetzen. Man verwendet ja gerade deshalb einen Compiler und programmiert nicht in Assembler, weil man sich nicht um Register-Belegungen o.ä. kümmern will, sondern nur um die zu lösende Aufgabe.&lt;br /&gt;
GCC erzeugt zwar recht guten Code, aber er ist nicht perfekt. Gerade auf Systemen wie AVR mit nur sehr begrenzten Resourcen muss man daher dem Compiler hilfreich zur Seite stehen, wenn man noch dichteren/schnelleren Code erhalten möchte.&lt;br /&gt;
&lt;br /&gt;
Um das Ergebnis zu beurteilen, hilft ein Blick ins Listfile. &lt;br /&gt;
Siehe dazu auch die Abschnitte &lt;br /&gt;
&amp;quot;[[Hallo Welt für AVR (LED blinken)#Listfile erstellen|Listfile erstellen]]&amp;quot; &lt;br /&gt;
und&lt;br /&gt;
&amp;quot;[[Hallo Welt für AVR (LED blinken)#Die Größe ermitteln|Die Größe ermitteln]]&amp;quot; &lt;br /&gt;
im [[Hallo Welt für AVR (LED blinken)|Hallo Welt für AVR]].&lt;br /&gt;
&lt;br /&gt;
==Optimierungsgrad==&lt;br /&gt;
Als Optimierungsgrad erweist sich &amp;lt;tt&amp;gt;-Os&amp;lt;/tt&amp;gt; (Optimize for Size) als der beste, evtl. noch &amp;lt;tt&amp;gt;-O2&amp;lt;/tt&amp;gt;. Ohne Angabe eines Optimierungsgrades wird nicht optimiert, was gleichbedeutend mit der Option &amp;lt;tt&amp;gt;-O0&amp;lt;/tt&amp;gt; ist. Abzuraten ist von der maximalen Optimierung &amp;lt;tt&amp;gt;-O3&amp;lt;/tt&amp;gt;, die wegen function inlining und loop unrolling zu sehr breitem Code führt und für AVR absolut nicht angesagt ist.&lt;br /&gt;
&lt;br /&gt;
==Vermeide printf, scanf, malloc==&lt;br /&gt;
Funktionen von diesem Kaliber sind die absoluten Platz- und Zeitfresser. &lt;br /&gt;
&lt;br /&gt;
Alternativen findet man reichlich in der &amp;lt;tt&amp;gt;avr-libc&amp;lt;/tt&amp;gt; wie &amp;lt;tt&amp;gt;itoa&amp;lt;/tt&amp;gt; und &amp;lt;tt&amp;gt;atoi&amp;lt;/tt&amp;gt;.&lt;br /&gt;
Und für &amp;lt;tt&amp;gt;malloc&amp;lt;/tt&amp;gt; und Konsorten sind dynamische Arrays und das Compiler-Builtin &amp;lt;tt&amp;gt;__builtin_alloca&amp;lt;/tt&amp;gt; effizientere Alternativen, siehe auch im Abschnitt &amp;quot;[[avr-gcc#Dynamische Speicherallokierung|Dynamische Speicherallokierung]]&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
==Konstante Strings ins Flash== &lt;br /&gt;
Konstante Strings, wie sie zu Ausgabezwecken Verwendung finden, werden im Programm oft nicht verändert und brauchen nicht SRAM zu belegen (und damit auch Flash, von wo aus sie vom Startup-Code ins SRAM kopiert werden), sondern gehören ins Flash! &lt;br /&gt;
&lt;br /&gt;
Entsprechende Routinen, um auf Strings im Flash zuzugreifen, tragen die Suffix &amp;lt;tt&amp;gt;_P&amp;lt;/tt&amp;gt;, wie z.B. &amp;lt;tt&amp;gt;strcmp_P&amp;lt;/tt&amp;gt; mit dem Prototyp&lt;br /&gt;
 extern int *strcmp_P (char *, const prog_char *)&lt;br /&gt;
Die Implementierungen befinden sich in der &amp;lt;tt&amp;gt;avr-libc&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''Anwendung:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/pgmspace.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
const prog_char str_p[]     = &amp;quot;Ein String im Flash&amp;quot;;&lt;br /&gt;
const char str2_p[] PROGMEM = &amp;quot;Noch ein String im Flash&amp;quot;;&lt;br /&gt;
...&lt;br /&gt;
   // String im SRAM mit String im Flash vergleichen&lt;br /&gt;
   if (!strcmp_P (str_sram, str_p))&lt;br /&gt;
   {&lt;br /&gt;
       // mach was bei Gleichheit&lt;br /&gt;
   }&lt;br /&gt;
...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Sprungtabelle===&lt;br /&gt;
Genauso macht man auch eine Sprungtabelle, um anhand von Kommando-Strings dazugehörige Funktionen ausführen zu lassen:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/pgmspace.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
int func1 (int arg)&lt;br /&gt;
{&lt;br /&gt;
   ...&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#define TEXT_LEN 15&lt;br /&gt;
&lt;br /&gt;
// Die Kommandostruktur&lt;br /&gt;
typedef struct &lt;br /&gt;
{&lt;br /&gt;
   int (*func)(int);     // Zeiger auf die auszuführende Funktion&lt;br /&gt;
   int arg;              // das Argument, das mitübergeben wird&lt;br /&gt;
   char text[1+TEXT_LEN]; // Text, maximal TEXT_LEN Zeichen lang&lt;br /&gt;
} command_t;&lt;br /&gt;
&lt;br /&gt;
// Das Array mit den Kommandos.&lt;br /&gt;
// Die funcx sind vom Prototyp (z.B. func1 oben)&lt;br /&gt;
// int funcx (int arg);&lt;br /&gt;
const command_t commands[] PROGMEM =&lt;br /&gt;
{&lt;br /&gt;
   { func1, 0, &amp;quot;Befehl 1&amp;quot; },&lt;br /&gt;
   { func2, 3, &amp;quot;Befehl für func2&amp;quot; }&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
// Sucht in commands[] nach text und führt gegebenenfalls&lt;br /&gt;
// die dazugehörige Funktion funcx mit Argument arg aus.&lt;br /&gt;
// Liefert den Rückgabewert von funcx &lt;br /&gt;
// oder -1, falls text nicht gefunden wurde.&lt;br /&gt;
int execute (const char *text)&lt;br /&gt;
{&lt;br /&gt;
   // Schleifenvariable&lt;br /&gt;
   unsigned char i;&lt;br /&gt;
&lt;br /&gt;
   // Wandert durch das Array mit Kommando-Strukturen&lt;br /&gt;
   const command_t * cmd = commands;&lt;br /&gt;
&lt;br /&gt;
   // sizeof wird von gcc ausgewertet und ist wie eine Konstante,&lt;br /&gt;
   // denn beide sizeofs sind zur Compilezeit bekannt&lt;br /&gt;
   for (i=0; i &amp;lt; sizeof(commands) / sizeof(command_t); i++)&lt;br /&gt;
   {&lt;br /&gt;
      // Ist das der gesuchte String? &lt;br /&gt;
      if (strcmp_P (text, cmd-&amp;gt;text))&lt;br /&gt;
      {&lt;br /&gt;
        // Nein, dann weitersuchen&lt;br /&gt;
        cmd++;&lt;br /&gt;
        continue;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      // Ja&lt;br /&gt;
      int (*func)(int), arg;&lt;br /&gt;
&lt;br /&gt;
      // Dann Funktionszeiger und Argument besorgen,&lt;br /&gt;
      func = (int(*)(int)) pgm_read_word (&amp;amp; cmd-&amp;gt;func);&lt;br /&gt;
      arg  = (int)         pgm_read_word (&amp;amp; cmd-&amp;gt;arg);&lt;br /&gt;
&lt;br /&gt;
      // Funktion ausführen und deren Wert zurückliefern      &lt;br /&gt;
      return func (arg);&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
   // text ist nicht in commands&lt;br /&gt;
   return -1;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nachteil dabei ist, daß jeder String den maximalen Platz von TEXT_LEN+1 Zeichen belegt.&lt;br /&gt;
Falls man da noch weiter sparen will, dann kann man die Strings wieder ins Flash legen und ihre Adresse in der Struktur merken. Dadurch belegt ein String nur noch Länge+3 Zeichen (+3 wegen 1 Endezeichen und 2 Bytes für seine in der Struktur gemerkte Adresse). Die Definition der Tabelle wird aber umständlicher, weil jeder String einzeln angegeben werden muss:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/pgmspace.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
// Die Kommandostruktur&lt;br /&gt;
typedef struct &lt;br /&gt;
{&lt;br /&gt;
   ...&lt;br /&gt;
   char *text; // Zeiger auf Text&lt;br /&gt;
} command_t;&lt;br /&gt;
&lt;br /&gt;
const prog_char str_1[] = &amp;quot;Befehl 1&amp;quot;;&lt;br /&gt;
const prog_char str_2[] = &amp;quot;Befehl für func2&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
const command_t commands[] PROGMEM =&lt;br /&gt;
{&lt;br /&gt;
   { func1, 0, str_1 },&lt;br /&gt;
   { func2, 3, str_2 }&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
// Sucht in commands[] nach text und führt gegebenenfalls&lt;br /&gt;
// die dazugehörige Funktion funcx mit Argument arg aus.&lt;br /&gt;
// Liefert den Rückgabewert von funcx &lt;br /&gt;
// oder -1, falls text nicht gefunden wurde.&lt;br /&gt;
int execute (const char *text)&lt;br /&gt;
{&lt;br /&gt;
   // Schleifenvariable&lt;br /&gt;
   unsigned char i;&lt;br /&gt;
&lt;br /&gt;
   // Wandert durch das Array mit Kommando-Strukturen&lt;br /&gt;
   const command_t * cmd = commands;&lt;br /&gt;
&lt;br /&gt;
   // sizeof wird von gcc ausgewertet und ist wie eine Konstante,&lt;br /&gt;
   // denn beide sizeofs sind zur Compilezeit bekannt&lt;br /&gt;
   for (i=0; i &amp;lt; sizeof(commands) / sizeof (command_t); i++)&lt;br /&gt;
   {&lt;br /&gt;
      const prog_char * text_P;&lt;br /&gt;
&lt;br /&gt;
      // Liest die Startadresse von str_x&lt;br /&gt;
      text_P = (const prog_char *) pgm_read_word (&amp;amp; cmd-&amp;gt;text);&lt;br /&gt;
&lt;br /&gt;
      // Ist das der gesuchte String?	&lt;br /&gt;
      if (strcmp_P (text, text_P))&lt;br /&gt;
      {&lt;br /&gt;
         ...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Lokale Variablen verwenden==&lt;br /&gt;
&lt;br /&gt;
Beim Manipulieren globaler Variablen kann es günstig sein, diese in eine lokale Variable zu kopieren, dort zu verändern, und sie danach wieder zu schreiben &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
char var;&lt;br /&gt;
&lt;br /&gt;
void foo1()&lt;br /&gt;
{&lt;br /&gt;
   var++;&lt;br /&gt;
   if (var &amp;gt; 10)&lt;br /&gt;
      var = 1;&lt;br /&gt;
} &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Dadurch wird einmal unnötig gespeichert (der dritte Befehl kann vermieden werden).&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
foo1:&lt;br /&gt;
  lds r24,var        ; *movqi/4	[length = 2]&lt;br /&gt;
  subi r24,lo8(-(1)) ; addqi3/2	[length = 1]&lt;br /&gt;
  sts var,r24        ; *movqi/3	[length = 2]&lt;br /&gt;
  cpi r24,lo8(11)    ; cmpqi/2	[length = 1]&lt;br /&gt;
  brlt .L3           ; branch	[length = 1]&lt;br /&gt;
  ldi r24,lo8(1)     ; *movqi/2	[length = 1]&lt;br /&gt;
  sts var,r24        ; *movqi/3	[length = 2]&lt;br /&gt;
.L3:&lt;br /&gt;
  ret	&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Indem man eine lokale Variable (&amp;lt;tt&amp;gt;var2&amp;lt;/tt&amp;gt;) verwendet für die Änderung von &amp;lt;tt&amp;gt;var&amp;lt;/tt&amp;gt; vermeidet man dies:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
char var;&lt;br /&gt;
&lt;br /&gt;
void foo2()&lt;br /&gt;
{&lt;br /&gt;
   char var2 = var;&lt;br /&gt;
   &lt;br /&gt;
   var2++;&lt;br /&gt;
   if (var2 &amp;gt; 10)&lt;br /&gt;
      var2 = 1;&lt;br /&gt;
      &lt;br /&gt;
   var = var2;&lt;br /&gt;
} &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Dadurch wird erst am Ende gespeichert. &amp;lt;tt&amp;gt;var2&amp;lt;/tt&amp;gt; lebt in Register &amp;lt;tt&amp;gt;r24&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
foo2:&lt;br /&gt;
  lds r24, var       ; *movqi/4   [length = 2]&lt;br /&gt;
  subi r24,lo8(-(1)) ; addqi3/2   [length = 1]&lt;br /&gt;
  cpi r24,lo8(11)    ; cmpqi/2    [length = 1]&lt;br /&gt;
  brlt .L2           ; branch     [length = 1]&lt;br /&gt;
  ldi r24,lo8(1)     ; *movqi/2   [length = 1]&lt;br /&gt;
.L2:&lt;br /&gt;
  sts var, r24       ; *movqi/3   [length = 2]&lt;br /&gt;
  ret&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bei diesem einfachen Beispiel spart man lediglich eine Instruktion. Bei komplexeren Rechnungen oder längeren Datentypen kann es aber durchaus lohnender sein, in lokale Register zu kopieren.&lt;br /&gt;
&lt;br /&gt;
==Arithmetik==&lt;br /&gt;
&lt;br /&gt;
=== Daten zerlegen/zusammensetzen ===&lt;br /&gt;
&lt;br /&gt;
In systemnahen Programmen hat man oft was Problem, auf die einzelnen Bytes oder Bitfelder einer grösseren Datenstruktur zuzugreifen. Indem man sich ein Komposit baut, das die gewünschten Strukturen überlagert, kann man effizient z.B. auf Bytes zugreifen. Ausnahme sind Bitfelder, deren Verwendung etwas breiten Code ergibt. Bitfelder &amp;quot;von Hand&amp;quot; zu manipulieren, ist da manchmal effizienter, führt jedoch zu schlecht lesbarem Code.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
typedef ... foo_t;&lt;br /&gt;
&lt;br /&gt;
typedef union&lt;br /&gt;
{&lt;br /&gt;
   unsigned char byte[4];       // Zugriff als Bytes (8 Bit)&lt;br /&gt;
   unsigned short word[2];      // Zugriff als Words (16 Bit)&lt;br /&gt;
   signed long slong;           // Zugriff als signed long (32 Bit)&lt;br /&gt;
&lt;br /&gt;
   struct                       // Zugriff auf einzelne Bitgruppen&lt;br /&gt;
   {&lt;br /&gt;
      unsigned bit_0_3  : 4;    //  4 Bits (0..3)&lt;br /&gt;
      unsigned bit_4_8  : 5;    //  5 Bits (4..8)&lt;br /&gt;
      unsigned bit_9_21 : 13;   // 13 Bits (9..21)&lt;br /&gt;
      unsigned bit_22_31: 10;   // 10 Bits (22..31)&lt;br /&gt;
   };   &lt;br /&gt;
&lt;br /&gt;
   foo_t foo;                   // Zugriff als foo-Struktur&lt;br /&gt;
} data_t;&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
{&lt;br /&gt;
   data_t data;&lt;br /&gt;
&lt;br /&gt;
   data.b[2] = 12;             // setzt byte 2 auf 12&lt;br /&gt;
   data.bit_4_8 = 0x1f;        // setzt bits 4..8 (5 Stück) alle auf 1&lt;br /&gt;
&lt;br /&gt;
   int anInt = data.foo.anInt; // liest ein Feld von foo (hier ein int)&lt;br /&gt;
   ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===libgcc2 verwenden===&lt;br /&gt;
&lt;br /&gt;
In der libgcc2 sind einige Arithmetik-Routinen in Assembler implementiert. Dazu gehören ein paar Algorithmen zu Division (mit Rest) und Multiplikation. &lt;br /&gt;
&lt;br /&gt;
Von diesen Algorithmen werden durch die avr-libc jedoch nur zwei Strukturen und Funktionen veröffentlicht: &amp;lt;tt&amp;gt;div_t&amp;lt;/tt&amp;gt; und &amp;lt;tt&amp;gt;ldiv_t&amp;lt;/tt&amp;gt; resp. die Funktionen &amp;lt;tt&amp;gt;div()&amp;lt;/tt&amp;gt; und &amp;lt;tt&amp;gt;ldiv()&amp;lt;/tt&amp;gt;. Siehe dazu deine Dokumentation zur avr-libc. Damit kann man Quotient und zusätzlich den Rest bei einer Division 16/16 bzw. 32/32 berechnen lassen; den Rest bekommt man quasi kostenlos als Nebenprodukt. Das ist praktisch, wenn man z.b. eine Zahl in Dezimaldarstellung umwandeln möchte oder von/nach [[BCD]].&lt;br /&gt;
&lt;br /&gt;
Zusätzlich zu den via avr-libc veröffentlichten Funktionen gibt es aber noch Routinen, die z.B. auf 8-Bit-Werten operieren oder mit &amp;lt;tt&amp;gt;unsigned&amp;lt;/tt&amp;gt; Typen und dementsprechend effizienter sind.&lt;br /&gt;
&lt;br /&gt;
'''Beispiel: Umwandeln nach Dezimalstring'''&lt;br /&gt;
&lt;br /&gt;
Hier ein Beispiel, das Division mit Rest für &amp;lt;tt&amp;gt;unsigned short&amp;lt;/tt&amp;gt; verwendet, um eine 16-Bit-Zahl in Dezimaldarstellung zu wandeln:&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
 extern udiv_t __udivmodhi4 (unsigned short, unsigned short);&lt;br /&gt;
 #define udiv __udivmodhi4&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// Struktur definieren und Funktion bekannt machen&lt;br /&gt;
typedef struct&lt;br /&gt;
{&lt;br /&gt;
	unsigned short quot;&lt;br /&gt;
	unsigned short rem;&lt;br /&gt;
} udiv_t;&lt;br /&gt;
&lt;br /&gt;
extern udiv_t udiv (unsigned short, unsigned short) __asm__(&amp;quot;__udivmodhi4&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
// 5 Ziffern (0...65535) und evtl. noch eine führende 0&lt;br /&gt;
#define DIGITS 6&lt;br /&gt;
&lt;br /&gt;
// +1 wegen String-Ende (wird im Startup auf 0 gesetzt)&lt;br /&gt;
char string[DIGITS+1];&lt;br /&gt;
&lt;br /&gt;
// Wandelt zahl in Dezimaldarstellung um.&lt;br /&gt;
// Der return-Wert zeigt irgendwo ins string[]-Array.&lt;br /&gt;
// string[] wird verändert.&lt;br /&gt;
char* toString (unsigned short zahl)&lt;br /&gt;
{&lt;br /&gt;
	// s zeigt auf das Ende von string&lt;br /&gt;
	// string wird von hinten nach vorne gefüllt&lt;br /&gt;
	char *s = string + DIGITS;&lt;br /&gt;
	&lt;br /&gt;
	// qrem enthält Quotient (quot) und Rest (rem) der Divisionen&lt;br /&gt;
	udiv_t qrem = {.quot = zahl};                  &lt;br /&gt;
&lt;br /&gt;
	do&lt;br /&gt;
	{&lt;br /&gt;
		// Division mit Rest durch 10&lt;br /&gt;
		// quot: Ergebnis für den nächsten Durchlauf&lt;br /&gt;
		// rem:  Rest ist die Ziffer im 10er-System&lt;br /&gt;
		qrem = udiv (qrem.quot, 10);&lt;br /&gt;
		&lt;br /&gt;
		// Ziffer in Zeichen wandeln und speichern&lt;br /&gt;
		*(--s) = '0' + qrem.rem;&lt;br /&gt;
	}	&lt;br /&gt;
	while (0 != qrem.quot);&lt;br /&gt;
	&lt;br /&gt;
	// Falls eine führende '0' gespeichert wurde: weg damit&lt;br /&gt;
	// ausser zahl war selbst schon 0&lt;br /&gt;
	if (*s == '0' &amp;amp;&amp;amp; *(s+1) != '\0')&lt;br /&gt;
		s++;&lt;br /&gt;
&lt;br /&gt;
	return s;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Falls man eine Division und/oder Rest für 8-Bit braucht, dann geht für &amp;lt;tt&amp;gt;unsigned&amp;lt;/tt&amp;gt; analog. &lt;br /&gt;
&lt;br /&gt;
'''Beispiel: BCD-Umrechnung'''&lt;br /&gt;
&lt;br /&gt;
Wandeln einer 8-Bit-Zahl &amp;lt;tt&amp;gt;0 &amp;lt;= num &amp;lt; 100&amp;lt;/tt&amp;gt; nach [[BCD]]&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
typedef struct&lt;br /&gt;
{&lt;br /&gt;
	unsigned char quot;  // Quotient&lt;br /&gt;
	unsigned char rem;   // Rest (remainder)&lt;br /&gt;
} udiv8_t;&lt;br /&gt;
&lt;br /&gt;
extern udiv8_t udiv8 (unsigned char, unsigned char) __asm__ (&amp;quot;__udivmodqi4&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
// Wandelt num nach BCD um, 0 &amp;lt;= num &amp;lt;= 99&lt;br /&gt;
// return-Wert ist dann 0x0 &amp;lt;= return &amp;lt;= 0x99&lt;br /&gt;
unsigned char to_bcd (unsigned char num)&lt;br /&gt;
{&lt;br /&gt;
	udiv8_t qrem = udiv8 (num, 10);&lt;br /&gt;
	&lt;br /&gt;
	return (unsigned char) (qrem.quot &amp;lt;&amp;lt; 4) | qrem.rem;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Division durch Multiplikation===&lt;br /&gt;
===Vermeiden von float und double===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Bugs=&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;tt&amp;gt;__builtin_return_address(0)&amp;lt;/tt&amp;gt;: ist entgegen der Spezifikation nicht implementiert und liefert in der Regel ein falsches Ergebnis.&lt;br /&gt;
;gcc 4.x: In der 4er-Version gab es tiefgreifende interne Änderungen im Compiler; er ist noch instabil und kann momentan noch nicht für den Produktiv-Einsatz empfohlen werden (Stand 02/2006).&lt;br /&gt;
&lt;br /&gt;
=Abkürzungen und Bezeichnungen=&lt;br /&gt;
; GCC: GNU Compiler Collection&lt;br /&gt;
; gcc: GNU C-Compiler&lt;br /&gt;
; GPR: '''G'''eneral '''P'''urpose '''R'''egister&lt;br /&gt;
; ISR: '''I'''nterrupt '''S'''ervice '''R'''outine&lt;br /&gt;
; IRQ: '''I'''nterrupt '''R'''e'''q'''uest&lt;br /&gt;
; Prolog/Epilog: Code am Anfang/Ende jeder Funktionen/ISR, der dazu dient, verwendete Register zu sichern, den Stack-Frame für lokale [[Variable|Variablen]] anzulegen (falls benötigt), Stackpointer zu setzen, zurück zu springen (&amp;lt;tt&amp;gt;ret&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;reti&amp;lt;/tt&amp;gt;), etc.&lt;br /&gt;
; SFR: '''S'''pecial '''F'''unction '''R'''egister&lt;br /&gt;
; Target: Zielsystem, in unserem Falle avr&lt;br /&gt;
&lt;br /&gt;
=Siehe auch=&lt;br /&gt;
* [[WinAVR]]&lt;br /&gt;
* [[Hallo Welt für AVR (LED blinken)]] - ein erstes Beispiel für avr-gcc&lt;br /&gt;
* [[Fallstricke bei der C-Programmierung]]&lt;br /&gt;
* [[Inline-Assembler in avr-gcc|Inline-Assembler]]&lt;br /&gt;
* [[Sourcevergleich]]&lt;br /&gt;
* [[AVR]]&lt;br /&gt;
* [[Compiler]]&lt;br /&gt;
&lt;br /&gt;
*[[:Kategorie:Quellcode_C|C-Codebeispiele]]&lt;br /&gt;
&lt;br /&gt;
=Weblinks=&lt;br /&gt;
* [http://gcc.gnu.org/ Offizielle Homepage von GCC (en)]&lt;br /&gt;
* [http://de.wikipedia.org/wiki/GNU_Compiler_Collection GCC in der deutschen Wikipedia]&lt;br /&gt;
* [http://sourceforge.net/projects/winavr/ WinAVR-Projekt bei sourceforge.net (en)]&lt;br /&gt;
* [http://cdk4avr.sourceforge.net/ avr-gcc und toolchain als Linux-Paket bei sourceforge.net (en)]&lt;br /&gt;
* [http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial avr-gcc-Tutorial auf mikrocontroller.net]&lt;br /&gt;
* [http://www.linuxfocus.org/Deutsch/November2004/article352.shtml Tipps zu Build und Installation von avr-gcc, binutils und avr-libc unter Linux bei linuxfocus.org]&lt;br /&gt;
* [http://www.avrfreaks.net/AVRGCC/ avr-gcc bei avrfreaks.net (en)]&lt;br /&gt;
* [http://savannah.nongnu.org/projects/avr-libc/ Nützliche GCC Runtime-Libary]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Autor=&lt;br /&gt;
&lt;br /&gt;
--[[Benutzer:SprinterSB|SprinterSB]] 11:27, 7. Dez 2005 (CET)&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Grundlagen]]&lt;br /&gt;
[[Kategorie:Microcontroller]]&lt;br /&gt;
[[Kategorie:Praxis]]&lt;br /&gt;
[[Kategorie:Quellcode C|!]]&lt;br /&gt;
[[Kategorie:Software]]&lt;/div&gt;</summary>
		<author><name>Alexander.stohr</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=Programmer%27s_Notepad&amp;diff=6559</id>
		<title>Programmer's Notepad</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=Programmer%27s_Notepad&amp;diff=6559"/>
				<updated>2006-03-20T11:20:08Z</updated>
		
		<summary type="html">&lt;p&gt;Alexander.stohr: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Das '''Programmer's Notepad''' ist ein freier Editor im Stil von [[Microsoft Visual Studio]] 8 (z.B. Teil von MS VC++ Express), der derzeit ein begrenztes Subset der dort implementierten Funktionen beinhaltet. Das Projekt wird auf Sourceforge.net gehostet. [[WinAVR]] beinhaltet dieses Tool.&lt;/div&gt;</summary>
		<author><name>Alexander.stohr</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=Avr&amp;diff=6558</id>
		<title>Avr</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=Avr&amp;diff=6558"/>
				<updated>2006-03-20T11:17:19Z</updated>
		
		<summary type="html">&lt;p&gt;Alexander.stohr: /* Siehe auch */ +WinAVR&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Bild:AtmelController.jpg|thumb|Beispiel eines AVR Controllers]]&lt;br /&gt;
'''AVR''' ist eine 8-Bit [[Microcontroller]]-Familie mit RISC-Architektur.&lt;br /&gt;
Im Gegensatz zu vielen anderen Microcontroller-Architekturen hat die AVR-Architektur keine Vorgänger. Sie ist ein komplettes Neudesign, das Anfang der 90-Jahre an der Universität von Trondheim/Norwegen entwickelt und vom (bis heute einzigen) Hersteller [[Atmel]] aufgekauft wurde. Es gibt eine ganze Serie von AVR-Controllern. Sie alle werden ähnlich programmiert, haben vergleichbaren Befehlssatz und physikalische Eigenschaften, bieten jedoch unterschiedliche Features und Peripherie. &lt;br /&gt;
&lt;br /&gt;
Es gibt zahlreiche und kostenlose Entwicklungssysteme in den Sprachen Basic, C/C++, Pascal und Assembler für diese Controller-Familie. &lt;br /&gt;
&lt;br /&gt;
==Wofür steht AVR?==&lt;br /&gt;
&amp;quot;AVR&amp;quot; steht angeblich für ''Advanced Virtual RISC'' (in einem Paper der Entwickler des AVR-Kerns Alf Egin Bogen und Vegard Wollan). Laut [[Atmel]] bedeutet es nichts.&lt;br /&gt;
&lt;br /&gt;
==Hardware==&lt;br /&gt;
AVR-Controller besitzen eine zweistufige Pipeline (fetch and execute), die es ermöglicht, die meisten Befehle innerhalb eines einzigen Prozessortaktes auszuführen. Dadurch ist ein AVR wesentlich schneller als etwa 8051-Controller, bei denen der Prozessortakt intern noch durch 12 geteilt wird.&lt;br /&gt;
&lt;br /&gt;
*AVR-Kern&lt;br /&gt;
** Harvard-Architektur (getrennter Befehls- und Datenspeicher) &lt;br /&gt;
** 32 Register, kein Akkumulator, 3 Pointerregister &lt;br /&gt;
** EEPROM-Datenspeicher&lt;br /&gt;
** [[Watchdog]], [[Bootloader]]-Support, verschiedene Stromspar-Modi, Brownout-Erkennung, Interner Oszillator&lt;br /&gt;
** Lineares Speichermodell (keine Segmentierung)&lt;br /&gt;
** 8-Bit Architektur ist für Hochsprachen (C) optimiert &lt;br /&gt;
* In-System programmierbar: die Controller können sehr einfach über ein  Programmierkabel (oft ISP-Kabel genannt), das mit dem PC verbunden wird, programmiert werden &amp;amp;ndash; auch dann, wenn sie sich nicht in einer Schaltung befindet.&lt;br /&gt;
* umfangreiche Peripherie&lt;br /&gt;
** 8- und 16-Bit-Timer/Counter mit [[PWM]], Capture/Compare, externe Betaktung, asynchrone Operation&lt;br /&gt;
** Kommunikation: [[UART|USART]], [[SPI]], [[I2C]] ([[TWI]])&lt;br /&gt;
** Analog-Comparator, Analog-Digital-Wandler &lt;br /&gt;
** unterschiedlichste externe und interne Interrupt-Quellen (UART, SPI, Timer, A/D-Wandler, Analog-Comparator, ...)&lt;br /&gt;
** JTAG (Debugerinterface)&lt;br /&gt;
* AVR Typen (AT90 &amp;quot;Classic AVR&amp;quot;, ATtiny, ATmega) &lt;br /&gt;
* erhältlich in unterschiedlichen Gehäusen, idR Durchsteck und als [[SMD]]&lt;br /&gt;
* Viele Entwicklungsboards erhältlich, z.B. das Roboternetzboard [[RN-Control]]&lt;br /&gt;
&lt;br /&gt;
==Einige Pinbelegungen der populärsten AVR-Controller==&lt;br /&gt;
(in etwa nach Leistungsfähigkeit sortiert)&lt;br /&gt;
&lt;br /&gt;
* [[AT90S2313]]&lt;br /&gt;
&lt;br /&gt;
[[Bild:at90s2313tiny.png|center]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[Atmel Controller Mega8]]&lt;br /&gt;
* [[Atmel Controller Mega48 Mega88 Mega168]]&lt;br /&gt;
&lt;br /&gt;
[[Bild:mega8kompatibel.png|center]]&lt;br /&gt;
&lt;br /&gt;
* [[Atmel Controller Mega16 und Mega32]]&lt;br /&gt;
&lt;br /&gt;
[[Bild:Mega1632.gif|center]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[Atmel Controller Mega128]] ([[SMD]]-Chip)&lt;br /&gt;
&lt;br /&gt;
[[Bild:mega128pin.gif|center]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
===Die AVR-Pin-Bezeichnungen und deren Funktion===&lt;br /&gt;
Die meisten Ports sind doppelt belegt und besitzen neben der normalen Port-Funktion noch eine Sonderfunktion. Die verschiedenen Pinbezeichnungen und Sonderfunktionen werden hier beschrieben:&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|+ '''Tabelle: Die AVR-Pin-Bezeichnungen und deren Funktion'''&lt;br /&gt;
&amp;lt;!-------------------------------------------------------------------------------------&amp;gt;&lt;br /&gt;
|- {{Hintergrund1}}&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot;| Versorgungs- und Referenzpins, Reset&lt;br /&gt;
|-&lt;br /&gt;
 |'''VCC''' &lt;br /&gt;
 | Versorgungsspannung von 2,7 Volt bis 6 V bei den L-Varianten (low power), ansonsten 4,5V bis 6V. Die nächste AVR-Generation soll ab 1,8 Volt funktionieren.&lt;br /&gt;
|-&lt;br /&gt;
 |'''GND''' &lt;br /&gt;
 |Masse &lt;br /&gt;
|-&lt;br /&gt;
 |'''AREF''' &lt;br /&gt;
 |Referenzspannung für den Analog-Digital-Wandler (kann auf 5V gesetzt werden). Auch die interne Bandgap-Referenzspannung kann über diesen Pin entstört werden (dann KEINE externe Spannung an diesen Pin geben (Kurzschluss)!). &lt;br /&gt;
|-&lt;br /&gt;
 |'''AGND''' &lt;br /&gt;
 |Alternative Masse, etwa um ein Verbindungspunkt mit GND zu haben und bei empfindlichen Messungen  Masseschleifen zu vermeiden.&lt;br /&gt;
|-&lt;br /&gt;
 |'''AVCC''' &lt;br /&gt;
 | &lt;br /&gt;
Die Betriebsspannung für den Analog-Digital-Wandler (siehe Beschaltungsskizze). Die Pins AVCC, AGND und AREF sollten immer beschaltet werden, da es sonst passieren kann, dass Port A nicht richtig funktioniert, selbst wenn man den AD-Wandler nicht benutzt. &lt;br /&gt;
|-&lt;br /&gt;
 |'''RESET''' &lt;br /&gt;
 |Rücksetz-Eingang, intern über einen [[Pullup]] mit VCC verbunden. Ein LOW–Pegel an diesem Pin für die Dauer von mindestens zwei Zyklen des Systemtaktes bei aktivem Oszillator setzt den Controller zurück. Rücksetzen der Ports erfolgt unabhängig von einem evtl. anliegenden Systemtakt.&lt;br /&gt;
|-&lt;br /&gt;
|'''PEN'''&lt;br /&gt;
|Programming Enable - Diesen Pin gibt es nur beim Mega128/64 u.ä. Wird dieser Pin beim Power-On Reset nach Masse gezogen, geht der Controller in den [[ISP]] Programmiermodus. Man kann ihn also alternativ zu Reset verwenden. In der Regel verwendet man aber die Reset-Leitung und PEN sollte man direkt mit VCC verbinden.&lt;br /&gt;
&amp;lt;!-------------------------------------------------------------------------------------&amp;gt;&lt;br /&gt;
|- {{Hintergrund1}}&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot;| System-Takt&lt;br /&gt;
|-&lt;br /&gt;
 |'''XTAL1''' &lt;br /&gt;
 |Eingang des internen Oszillators zur Erzeugung des Systemtaktes bzw. Eingang für ein externes Taktsignal, wenn der interne Oszillator nicht verwendet werden soll bzw. Anschluss von Quarz/Keramik-Resonator/RC-Glied.&lt;br /&gt;
|-&lt;br /&gt;
 |'''XTAL2''' &lt;br /&gt;
 |Anschluss von Quarz oder Keramik-Resonator oder Ausgang des integrierten Oszillators zur Nutzung als Systemtakt (Je nach Fuse-Einstellungen). &lt;br /&gt;
&amp;lt;!-------------------------------------------------------------------------------------&amp;gt;&lt;br /&gt;
|- {{Hintergrund1}}&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot;| Digitale bidirektionale  I/O-Ports&lt;br /&gt;
|- &lt;br /&gt;
| colspan=&amp;quot;2&amp;quot;| Jeder Pin der Ports kann individuell als Eingang oder Ausgang konfiguriert werden. Die I/O-Ports sind maximal 8 Bit breit und verfügen ja nach AVR-Typ über eine unterschiedliche Anzahl von Pins. An jedem als Eingang (Input) geschalteten Pin gibt es zuschaltbare [[Pullup]]-Widerstände, die teilweise auch bei aktivierter Sonderfunkton verfügbar sind.&lt;br /&gt;
&lt;br /&gt;
Bei eingeschalteten Sonderfunktionen wie UART, SPI, ADC, etc. sind die entsprechenden Pins nicht als &amp;quot;normale&amp;quot; digitale I/O verwendbar, sondern dienen der Sonderfunktion. Die Anzahl der als I/O verwendbaren Pins ist auch abhängig von den Fuse-Einstellungen (Vorsicht beim Umstellen, Handbuch GENAU lesen!).&lt;br /&gt;
|-&lt;br /&gt;
|'''PA 0 – 7''' || Port A &lt;br /&gt;
|-&lt;br /&gt;
|'''PB 0 – 7''' || Port B &lt;br /&gt;
|-&lt;br /&gt;
|'''PC 0 – 7''' || Port C &lt;br /&gt;
|-&lt;br /&gt;
|'''PD 0 – 7''' || Port D &lt;br /&gt;
|-&lt;br /&gt;
|'''PE 0 – 7''' || Port E &lt;br /&gt;
|-&lt;br /&gt;
|'''PF 0 – 7''' || Port F &lt;br /&gt;
|-&lt;br /&gt;
|'''PG 0 – 7''' || Port G &lt;br /&gt;
&amp;lt;!-------------------------------------------------------------------------------------&amp;gt;&lt;br /&gt;
|- {{Hintergrund1}}&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot;| Externe Interrupts&lt;br /&gt;
|- &lt;br /&gt;
| colspan=&amp;quot;2&amp;quot;| Die PCINT-Interrupts gibt es nur für neuere AVRs wie den [[ATmega88]]. Falls die Anzahl an externen Interrupts nicht ausreicht, kann evtl. auch andere Hardware dafür eingesetzt werden, etwa der Analog-Comparator mit interner Bandgap-Referenz, falls er anderwärtig nicht gebraucht wird.&lt;br /&gt;
|-&lt;br /&gt;
 |'''INT0''' ||Externer Interrupt 0&lt;br /&gt;
|-&lt;br /&gt;
 |'''INT1''' ||Externer Interrupt 1&lt;br /&gt;
|-&lt;br /&gt;
 |'''INT2''' ||Externer Interrupt 2 &lt;br /&gt;
|-&lt;br /&gt;
 |'''PCINTx''' ||Pin-Change Interrupt&lt;br /&gt;
&amp;lt;!-------------------------------------------------------------------------------------&amp;gt;&lt;br /&gt;
|- {{Hintergrund1}}&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot;| [[Timer]] und [[PWM]]&lt;br /&gt;
|-&lt;br /&gt;
 |'''T0''' &lt;br /&gt;
 |Timer-Eingang. Timer kann gestartet, gestoppt oder getaktet werden &lt;br /&gt;
|-&lt;br /&gt;
 |'''T1''' &lt;br /&gt;
 |Timer-Eingang. Timer kann gestartet, gestoppt oder getaktet werden &lt;br /&gt;
|-&lt;br /&gt;
 |'''OC0''' &lt;br /&gt;
 |PWM bzw. Output Compare Ausgang des Timers 0 &lt;br /&gt;
|-&lt;br /&gt;
 |'''OC1A''' &lt;br /&gt;
 |Ausgang für die Compare-Funktion des integrierten Zeitgeber- / Zählerbausteines &lt;br /&gt;
Der erste PWM-Ausgang des Timers1. Er kann zum Regeln der Bot-Motogeschwindigkeit benutzt werden. &lt;br /&gt;
|-&lt;br /&gt;
 |'''OC1B''' &lt;br /&gt;
 |Ausgang für die Compare-Funktion des integrierten Zeitgeber- / Zählerbausteines &lt;br /&gt;
Der zweite PWM-Ausgang des Timers1. Er kann zum Regeln der Bot-Motogeschwindigkeit benutzt werden. &lt;br /&gt;
|-&lt;br /&gt;
 |'''ICP1''' &lt;br /&gt;
 |Eingang für die Capture-Funktion des integrierten Zeitgebers / Zählerbausteines &lt;br /&gt;
|-&lt;br /&gt;
 |'''OC2''' &lt;br /&gt;
 |[[Pwm]] bzw. Output Compare Ausgang des Timers2. Er kann zum Regeln der Bot-Motogeschwindigkeit benutzt werden. &lt;br /&gt;
|-&lt;br /&gt;
 |'''TOSC1, TOSC2''' &lt;br /&gt;
 |TOSC1 und TOSC2 sind Eingänge für den asynchronen Modus von Timer2. Sie sind vorgesehen für den Anschluss eines externen Uhrenquarzes ( 32.768 kHz ). Damit lassen sich zum Beispiel sehr genaue Ein-Sekunden-Impulse für eine Uhr generien. &lt;br /&gt;
&amp;lt;!-------------------------------------------------------------------------------------&amp;gt;&lt;br /&gt;
|- {{Hintergrund1}}&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot;| Analog-Digital-Wandler&lt;br /&gt;
|-&lt;br /&gt;
 |'''ADC0''' bis '''ADC7''' &lt;br /&gt;
 |Eingänge des AD-Wandlers. Spannungen können hier gemessen werden oder an den Analog-Komparator weiter geleitet werden. &lt;br /&gt;
&amp;lt;!-------------------------------------------------------------------------------------&amp;gt;&lt;br /&gt;
|- {{Hintergrund1}}&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot;| Analog-Komparator&lt;br /&gt;
|-&lt;br /&gt;
 |'''AIN0, AIN1''' &lt;br /&gt;
 |Die beiden externen Eingänge des Analog-Komparators. &lt;br /&gt;
Mit AIN0(+) und AIN1(-) kann man zwei Spannungen miteinander vergleichen. Wenn die Spannung an AIN0 höher als bei AIN1 ist, liefert der Komparator &amp;quot;High&amp;quot;, ansonsten ein &amp;quot;Low&amp;quot;. Als interne Eingänge des Komparators können die Interne Bandgap-Referenzspannung oder Ausgänge des ADC-Multiplexers dienen.&lt;br /&gt;
&amp;lt;!-------------------------------------------------------------------------------------&amp;gt;&lt;br /&gt;
|- {{Hintergrund1}}&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot;| Serielle Schnittstelle ([[UART|USART]])&lt;br /&gt;
|-&lt;br /&gt;
 |'''RXD''' &lt;br /&gt;
 |Eingang der Seriellen Schnittstelle (Receive Data), TTL-Pegel &lt;br /&gt;
|-&lt;br /&gt;
 |'''TXD''' &lt;br /&gt;
 |Ausgang Serielle Schnittstelle (Transmit Data), TTL-Pegel &lt;br /&gt;
|-&lt;br /&gt;
 |'''XCK''' &lt;br /&gt;
 |Externe Takt für den USART. Wird nur in Sonderfällen für den Takt benötigt. &lt;br /&gt;
USART (&amp;quot;Universal Synchronous/Asynchronous Receiver and Transmitter&amp;quot;). Das ist die serielle Schnittstelle, die zur Datenübertragung zwischen Mikrocontroller und PC genutzt wird. Zur bidirektionalen Übertragung werden zwei Pins am Controller benötigt: TXD und RXD. Über TXD (&amp;quot;Transmit Data&amp;quot;) werden Daten gesendet, RXD (&amp;quot;Receive Data&amp;quot;) dient zum Empfang. &lt;br /&gt;
&amp;lt;!-------------------------------------------------------------------------------------&amp;gt;&lt;br /&gt;
|- {{Hintergrund1}}&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot;| [[SPI]]-Schnittstelle&lt;br /&gt;
|-&lt;br /&gt;
 |'''SS''' &lt;br /&gt;
 |SPI-Interface – wird beneötigt um den richtigen Slave am Bus zu wählen &lt;br /&gt;
|-&lt;br /&gt;
 |'''MOSI''' &lt;br /&gt;
 |SPI-Interface – Datenausgang (als Master) oder Dateneingang (als Slave), verwendet bei ISP (In-System-Programmierung)&lt;br /&gt;
|-&lt;br /&gt;
 |'''MISO''' &lt;br /&gt;
 |SPI-Interface – Dateneingang (als Master) oder Datenausgang (als Slave), verwendet bei ISP (In-System-Programmierung)&lt;br /&gt;
|-&lt;br /&gt;
 |'''SCK''' &lt;br /&gt;
 |SPI-Interface – Bustakt vom Master, verwendet bei ISP (In-System-Programmierung)&lt;br /&gt;
&amp;lt;!-------------------------------------------------------------------------------------&amp;gt;&lt;br /&gt;
|- {{Hintergrund1}}&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot;| [[I2C|I&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;C]]-Schnittstelle ([[TWI]])&lt;br /&gt;
|-&lt;br /&gt;
 |'''SDA''' &lt;br /&gt;
 |I2C-Schnittstelle (Bus aus 2 Leitungen) Datenleitung &lt;br /&gt;
|-&lt;br /&gt;
 |'''SCL''' &lt;br /&gt;
 |I2C-Schnittstelle (Bus aus 2 Leitungen) Clockleitung &lt;br /&gt;
&amp;lt;!-------------------------------------------------------------------------------------&amp;gt;&lt;br /&gt;
|- {{Hintergrund1}}&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot;| [[JTAG]]-Interface&lt;br /&gt;
|-&lt;br /&gt;
 |'''TDI''' &lt;br /&gt;
 |JTAG-Debug Interface - Über dieses Interface kann man den AVR programmieren und debuggen. Die Schnittstelle ist ähnlich wie die SPI Schnittstelle und hat getrennte Dateneingangs- und Datenausgangsleitungen sowie eine Taktleitung. TDI ist die Dateneingangsleitung&lt;br /&gt;
|-&lt;br /&gt;
 |'''TDO''' &lt;br /&gt;
 |JTAG-Debug Interface - TDO ist die Datenausgangsleitung des JTAG Interface&lt;br /&gt;
|-&lt;br /&gt;
 |'''TMS''' &lt;br /&gt;
 |JTAG-Debug Interface&lt;br /&gt;
|-&lt;br /&gt;
 |'''TCK''' &lt;br /&gt;
 |JTAG-Debug Interface &lt;br /&gt;
|}&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Timer der AVRs ==&lt;br /&gt;
&lt;br /&gt;
Die Mikrocontroller der AVR-Familie besitzen je nach Typ eine unterschiedliche Anzahl an programmierbaren [[Timer|Timern]]. Bei den aktuellen ATmegas sind das mindestens ein 8-Bit Timer und bei größeren Ausführungen der Serie auch 16-Bit Timer. Die Timer werden immer Timerx benannt, wobei x für die Timernummer steht (also 0, 1, 2, usw.). &lt;br /&gt;
Die Konfigurationsmöglichkeiten sind von Timer zu Timer unterschiedlich.&lt;br /&gt;
&lt;br /&gt;
'''Hinweis:''' Die folgenden Code-Beispiele sind in C programmiert und wurden für einen [[ATMega32|ATmega32]] entwickelt. Sie lassen sich also ohne große Änderungen auch auf anderen Mikrocontrollern der AVR-Familie einsetzen.&lt;br /&gt;
&lt;br /&gt;
=== Allgemeine Funktionsweise ===&lt;br /&gt;
Timer funktionieren nach dem allgemeinen Prinzip, dass sie eine Ganzzahl (im weiteren als Zähler bezeichnet) je nach Betriebsmodus auf- oder abwärtszählen, d.h. inkrementieren bzw. dekrementieren.&lt;br /&gt;
&lt;br /&gt;
Angenommen, der Timer arbeitet im einfachsten Betriebsmodus, dem normalen Modus (siehe [[Avr#Normaler Modus (Normal Mode)|Normaler Modus (Normal Mode)]]). Die Zählrichtung des Timers ist aufsteigend gerichtet. Je nach Auflösung, also 8-Bit oder 16-Bit, erreicht der Zähler irgendwann einen bestimmten Zustand. Möglich wäre, dass er überläuft, wenn z.B. bei einem 8-Bit Timer der Wert 255 inkrementiert wird (siehe Grafik).&lt;br /&gt;
&lt;br /&gt;
[[Bild:AbstrakterZaehlvorgang.png]]&lt;br /&gt;
&lt;br /&gt;
=== Der Prescaler ===&lt;br /&gt;
Der Prescaler (eng. = Vorteiler) kann dazu genutzt werden, den Takt, der den Timern zugeführt wird, zu verkleinern. U.a. kann man damit die Timer so konfigurieren, damit diese in den unterschiedlichsten Frequenzen takten. Hier eine Grafik die den Prescaler veranschaulicht:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Prescaler.png]]&lt;br /&gt;
&lt;br /&gt;
Das obere Diagramm zeigt den Betrieb ohne Prescaler, das untere mit Prescaler. Die gestrichelte Linie zeigt, wann ein Interrupt eintritt.&lt;br /&gt;
&lt;br /&gt;
Im Teil [[Avr#Die Betriebsmodi|Die Betriebsmodi]] wird weiter auf die praktische Verwendung des Prescalers eingegangen.&lt;br /&gt;
&lt;br /&gt;
=== Die Betriebsmodi ===&lt;br /&gt;
Die AVR-Timer können in unterschiedlichen Betriebsmodi betrieben werden. Diese sind:&lt;br /&gt;
* Normaler Modus&lt;br /&gt;
* CTC Modus&lt;br /&gt;
* PWM&lt;br /&gt;
&lt;br /&gt;
==== Normaler Modus (Normal Mode) ====&lt;br /&gt;
Der einfachste Betriebsmodus ist der normale Modus. Er funktioniert wie im Abschnitt  &amp;quot;[[Avr#Allgemeine Funktionsweise|Allgemeine Funktionsweise]]&amp;quot; beschrieben. Die Zählrichtung des Timers ist immer aufsteigend, und irgendwann kommt es zu dem Interrupt Timer-Overflow (welcher in einer passend ISR aufgefangen werden kann). Im einfachsten Fall kann man diesen Modus in folgendem Diagramm darstellen:&lt;br /&gt;
&lt;br /&gt;
[[Bild:NormalerModus_1.png]]&lt;br /&gt;
&lt;br /&gt;
Der Zähler des Timers (im Diagramm oben, die aufsteigende und dann wieder zurückgesetzte Linie) ist in dem Register TCNTx gespeichert, wobei x für eine Zahl steht. Soll z.B. auf den Timer0 (siehe Datenblatt des jeweiligen Controllers) des Controllers zugegriffen werden, so ist an TCNT eine 0 anzuhängen, also TCNT0.&lt;br /&gt;
Wie lange es braucht, bis der Zähler einen Overflow auslöst, ist von der Taktfrequenz des Controllers, dem eingestellten Prescaler-Wert und von der Timerauflösung abhängig. Nun wäre es ja sehr unpraktisch, wenn wir den Zähler nicht anpassen könnten. Denn sonst müssten wir unsere Software die den Timer benutzt evtl. anpassen und viel rechnen um z.B. für 1000 ms zu schlafen. Deswegen kann auf den Zähler zugreifen und ihn vorladen bevor dieser wieder vom eigentlichen Timer hochgezählt wird. Dies veranschaulicht folgendes Diagramm:&lt;br /&gt;
&lt;br /&gt;
[[Bild:NormalerModus_1_Vorladen.png]]&lt;br /&gt;
&lt;br /&gt;
Dadurch kann man den Timer beeinflussen, und beeinflussen wie lange es dauert, bis ein Overflow auftritt. Um zu berechnen, welchen Wert wir vorladen müssen, kann man auch ein Java-Applet nutzen, siehe unter [[Avr#Weblinks|Weblinks Java Applet]].&lt;br /&gt;
&lt;br /&gt;
Natürlich kann man das auch &amp;quot;von Hand&amp;quot; rechnen. Die Berechnung des Preloader- sowie Prescalerwerts bei Verwendung der Overflow-Interrupts, eines Prescalers von 64 (nicht alle Prescaler können verwendet werden) und eines Quarzes mit der Frequenz von 8 MHz sieht folgendermaßen aus (gesuchte Frequenz beträgt 1000 Hz unter der Verwendung des Timer0 eines ATmega32):&lt;br /&gt;
# &amp;lt;math&amp;gt;Prescale = Frequenz * 1000000 [Hz] = 8000000&amp;lt;/math&amp;gt;&lt;br /&gt;
# Wir definieren den maximalen Zählerwert. Dieser ist bei einem 8-Bit Timer 256, bei einem 16-Bit Timer 65536. In unserem Fall ist der maximale Zählerwert 256, weil Timer0 verwendet wird.&lt;br /&gt;
# Nun wird die Variable ''Prescale'' (s.o.) durch den verwendeten Prescaler (64) geteilt (&amp;lt;math&amp;gt;8000000 Hz / 64 = 125000&amp;lt;/math&amp;gt;).&lt;br /&gt;
# Als nächstes wird der im dritten Punkt errechnete Wert durch die gesuchte Frequenz geteilt &amp;lt;math&amp;gt;=125000 / 1000Hz = 125&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Nun wird mathematisch überprüft, ob der errechnete Wert aus dem vierten Punkt kleiner als der maximale Zählerwert ist. Trifft dies zu, so subtrahiert man den errechneten Wert vom maximalen Zählerwert (&amp;lt;math&amp;gt;= 256 - 125 = 131&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Damit haben wir den Wert errechnet, der bei jedem Interrupt, den der Timer0 auslöst, in TCNTx (in diesem Fall TCNT0) nachgeladen werden muss, damit die Interrupts in dem gewünschten Zeitabstand von einer Millisekunde ausgelöst werden.&lt;br /&gt;
&lt;br /&gt;
Allerdings bleibt zu bemerken, dass bei der Verwendung einer &amp;quot;ungeraden&amp;quot; Quarzfrequenz (z.B. 7,3728 MHz) der Timer mit einer bestimmten Ungenauigkeit arbeitet. Würden wir z.B. den Quarz oben mit einem Quarz mit 7,3728 MHz austauschen, so wäre die Fehlerrate 0,17%. Diese Ungeauigkeit varriert von verwendetem Prescaler zu Prescaler. D.h. wenn wir einen Prescaler von 1024 (und einer Quarzfrequenz von 8 MHz) verwendet hätten, so hätten wir eine inakzeptable Ungeauigkeit von 11,61%. Deswegen sollte sie eines der genannten Programme unter [[Avr#Weblinks]] verwenden, denn diese zeigen nur die bestmögliche Konfiguration an.&lt;br /&gt;
&lt;br /&gt;
Die Fehlerrate kann natürlich auch ausgerechnet werden. Hier die Rechenschritte (sie sind erweiternd zu der oberen Berechnung):&lt;br /&gt;
# Als erstes wird mathematisch überprüft, ob der Preloaderwert (siehe fünften Schritt oben) größer als 1 ist.&lt;br /&gt;
# Trifft dies zu, so wird als nächstes die resultierende Frequenz errechnet. Die geschieht folgendermaßen: Der errechnete Preloaderwert aus der Rechnung oben wird vom maximalen Zählerwert subtrahiert, anschließend mit dem Prescaler multipliziert und dann das Ganze durch die Variable Prescale geteilt &lt;br /&gt;
&amp;lt;math&amp;gt;(256 - 131) \cdot 64 / 8\,000\,000 \mathrm{Hz} \cdot 1\,000\,000 = 1000&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Nun wird die gesuchte Frequenz vom errechneten Wert aus dem dritten Punkt subtrahiert und dann wiederum durch diese geteilt &amp;lt;math&amp;gt;(1000-1000) / 1000 = 0&amp;lt;/math&amp;gt;. Damit läuft dieser Timer genau mit einer Fehlerrate von 0 %.&lt;br /&gt;
&lt;br /&gt;
Betreibt man den Timer im Overflow-Modus, so muss man, wie bereits erwähnt, nach/bei jedem Overflow-Interrupt den Timer nachladen. Der Interrupt heißt in diesem Fall SIG_OVERFLOWx (x steht für die Nummer des Timers). Dieser muss in einer ISR abgefangen werden.&lt;br /&gt;
&lt;br /&gt;
Zusammenfassend ein Beispielprogramm:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/* Es wird der Timer2 (8-Bit) eines ATmega32 verwendet, der mit einem Quarz mit 7,3728 MHz&lt;br /&gt;
betrieben wird. Im Abstand von 0,001 ms erzeugt der Timer einen Interrupt, also eine&lt;br /&gt;
Frequenz von 1000000 Hz (oder 100 kHz). Der Timer wird auf einen Prescaler von 1 und&lt;br /&gt;
einem Preloader von  183 konfiguriert.*/&lt;br /&gt;
&lt;br /&gt;
volatile uint8_t countTimer2;	// Speichert den aktuellen Zählerwert&lt;br /&gt;
&lt;br /&gt;
// ISR zum auffangen der Interrupts:&lt;br /&gt;
SIGNAL(SIG_SIG_OVERFLOW2)&lt;br /&gt;
{&lt;br /&gt;
	countTimer2++;&lt;br /&gt;
	TCNT2 = 183;		// Nachladen&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Initialisierung:&lt;br /&gt;
TCCR2 = (1&amp;lt;&amp;lt;CS22);		// Prescaler von 1&lt;br /&gt;
TCNT2  = 183;			// Vorladen&lt;br /&gt;
TIMSK |= (1&amp;lt;&amp;lt;TOIE2);		// Interrupts aktivieren und damit Timer starten&lt;br /&gt;
sei();&lt;br /&gt;
&lt;br /&gt;
// Funktionen zum benutzen der Timer:&lt;br /&gt;
/** Diese Funktion nicht aufrufen. Wird von sleep_millisec aufgerufen.&lt;br /&gt;
Bei t=100 schläft die Funktion 1 ms. */&lt;br /&gt;
inline void sleep (uint8_t t)&lt;br /&gt;
{&lt;br /&gt;
	// countTimer2 wird in der ISR oben inkrementiert&lt;br /&gt;
	countTimer2 = 0;&lt;br /&gt;
	while (countTimer2 &amp;lt; t);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/** Schläft x-Millisekunden. */&lt;br /&gt;
inline void sleep_millisec(uint16_t msec)&lt;br /&gt;
{&lt;br /&gt;
	uint16_t i;&lt;br /&gt;
	for(i=0; i&amp;lt;msec; i++) {&lt;br /&gt;
		sleep(100);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Allerdings wird auf diese leicht veraltete Technik nun nicht weiter eingegangen. Der Artikel wendet sich nun dem neueren &amp;quot;Compare Output&amp;quot;-Betriebsmodus zu.&lt;br /&gt;
&lt;br /&gt;
Beim &amp;quot;Compare Output&amp;quot;-Betriebsmodus wird genauso ein Zähler hochgezählt. Allerdings wird der Zählerwert nach jeder Inkrementierung mit einem vom Benutzer festgelegten Wert verglichen. Entspricht der Zählerwert dem gespeicherten Wert, so kommt es zu einem Interrupt. Dieser Wert wird in das Register OCRx (x steht wieder für die Timernummer) gespeichert. Je nach Auflösung des Timers ist dieses Register 8-Bit oder 16-Bit breit. &lt;br /&gt;
&lt;br /&gt;
Hinweis: Siehe CTC Modus unten. Dieser wird benötigt um den Timer entsprechend im &amp;quot;Compare Output&amp;quot;-Betriebsmodus vernünftig zu betreiben.&lt;br /&gt;
&lt;br /&gt;
Hier ein typisches Diagramm dieses Betriebsmodus (Hinweis: Das Diagramm wurde unter Verwendung des CTC Modus erstellt. Für Begriffserklärung siehe CTC Modus):&lt;br /&gt;
&lt;br /&gt;
[[Bild:NormalerModus_CompareMatch.png]]&lt;br /&gt;
&lt;br /&gt;
Das Ausrechnen des Werts, der in OCRx geschrieben werden muss, damit Frequenz x entsteht, ist nicht sonderlich schwer. Man geht wie bei der Berechnung des Werts für den Overflow-Modus vor (s.o.) nur daß man das resultierende Ergebnis vom maximalen Zählerwert (bei 8-Bit Auflösung ist dieser 256, bei 16-Bit Auflösung 65536) subtrahiert. Das Ergebnis wird dann einmalig in das Register OCRx geschrieben. Mann muss also nicht wie beim Overflow-Modus den Timer nach jedem Interrupt nachladen. Der enstehende Interrupt heißt in diesem Fall SIG_OUTPUT_COMPAREx (x steht für die Nummer des Timers). Dieser muss in einer ISR abgefangen werden.&lt;br /&gt;
&lt;br /&gt;
Wiederum zusammenfassend ein Beispielprogramm:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/* Es wird der Timer2 (8-Bit) eines ATmega32 verwendet, der mit einem Quarz mit 7,3728 MHz&lt;br /&gt;
betrieben wird. Im Abstand von 0,001 ms erzeugt der Timer einen Interrupt, also eine Frequenz&lt;br /&gt;
von 1000000 Hz (oder 100 kHz). Der Timer wird auf einen Prescaler von 1 und einem OCR2-Wert&lt;br /&gt;
von 73 konfiguriert.*/&lt;br /&gt;
&lt;br /&gt;
volatile uint8_t countTimer2;	// Speichert den aktuellen Zählerwert&lt;br /&gt;
&lt;br /&gt;
// ISR zum auffangen der Interrupts:&lt;br /&gt;
SIGNAL(SIG_OUTPUT_COMPARE2)&lt;br /&gt;
{&lt;br /&gt;
  countTimer2++;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Initialisierung:&lt;br /&gt;
TCCR2 = (1&amp;lt;&amp;lt;CS22) | (1&amp;lt;&amp;lt;WGM21);	// Prescaler von 1 | CTC-Modus (siehe unten für Beschreibung)&lt;br /&gt;
OCR2  = 73;			// Vergleichswert&lt;br /&gt;
TIMSK |= (1&amp;lt;&amp;lt;OCIE2);		// Interrupts aktivieren und damit Timer starten&lt;br /&gt;
sei();&lt;br /&gt;
&lt;br /&gt;
// Funktionen zum benutzen der Timer:&lt;br /&gt;
/** Diese Funktion nicht aufrufen. Wird von sleep_millisec aufgerufen.&lt;br /&gt;
Bei t=100 schläft die Funktion 1 ms. */&lt;br /&gt;
inline void sleep(uint8_t t)&lt;br /&gt;
{&lt;br /&gt;
	// countTimer2 wird in der ISR oben inkrementiert&lt;br /&gt;
	countTimer2 = 0;&lt;br /&gt;
	while (countTimer2 &amp;lt; t);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/** Schläft x-Millisekunden. */&lt;br /&gt;
inline void sleep_millisec(uint16_t msec)&lt;br /&gt;
{&lt;br /&gt;
	uint16_t i;&lt;br /&gt;
	for(i=0; i&amp;lt;msec; i++) {&lt;br /&gt;
		sleep(100);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== CTC Modus (Clear Timer on Compare Match mode) ====&lt;br /&gt;
Der CTC Modus ist eine Erweiterung des &amp;quot;Compare Output&amp;quot;-Betriebsmodus. Der CTC Modus wird z.B. für das obere Beispielprogramm benötigt. Wird der Timer nämlich im normalen Betriebsmodus betrieben, so ist seine Zählergrenze je nach Auflösung 255 oder entsprechend für die 16-Bit Timer. Erst wenn diese Grenze erreicht wurde, wird der Timer zurückgesetzt (also auf 0). Durch den CTC Modus wird der Timer augenblicklich automatisch nachdem ein &amp;quot;Compare Output&amp;quot;-Interrupt auftrat zurückgesetzt. Man kann also die maximalen Zählergrenze selber definieren.&lt;br /&gt;
Dieses Diagramm veranschaulicht den CTC Modus. Nach dem Interrupt wird der Timer sofort wieder zurückgesetzt.&lt;br /&gt;
&lt;br /&gt;
[[Bild:NormalerModus_CompareMatch.png]]&lt;br /&gt;
&lt;br /&gt;
==== PWM ====&lt;br /&gt;
Für PWM siehe [[Pwm]].&lt;br /&gt;
&lt;br /&gt;
=== Registerübersicht ===&lt;br /&gt;
&lt;br /&gt;
'''Hinweis:''' Diese Registertabelle wurde für den aktuellen [[Atmel Controller Mega16 und Mega32]] erstellt. Wenn Sie ein anderes Modell verwenden, kann es sein, dass ein oder mehrere Register nicht existieren, oder sie eine andere Bezeichnung haben.&lt;br /&gt;
&lt;br /&gt;
{| {{Blaueschmaltabelle}} width=100%&lt;br /&gt;
 |'''TIMSK'''&lt;br /&gt;
 |-&lt;br /&gt;
 |Mit diesem Register, der von allen Timern verwendet wird, lässt sich die Interruptausführung und Art des jeweiligen Timers bestimmen.&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{Registertabelle8Bit|OCIE2|TOIE2|TICIE1|OCIE1A|OCIE1B|TOIE1|OCIE0|TOIE0}}&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
*'''OCIE2 (Timer/Counter2 Output Compare Match Interrupt Enable'''&amp;lt;br/&amp;gt;Wenn dieses Bit gesetzt wird, wird der Timer/Counter2 Compare Match Interrupt aktiviert (vorrausgesetzt die Interrupts sind global aktiviert).&lt;br /&gt;
*'''TOIE2 (Timer/Counter2 Overflow Interrupt Enable)'''&amp;lt;br/&amp;gt;Wenn dieses Bit gesetzt wird, wird der Timer/Counter2 Overflow Interrupt aktiviert (vorrausgesetzt die Interrupts sind global aktiviert).&lt;br /&gt;
*'''TICIE1 (Timer/Counter1, Input Capture Interrupt Enable)'''&amp;lt;br/&amp;gt;Wenn dieses Bit gesetzt wird, wird der Timer/Counter1 Input Capture Interrupt aktiviert (vorrausgesetzt die Interrupts sind global aktiviert).&lt;br /&gt;
*'''OCIE1A (Timer/Counter1 Output Compare A Match Interrupt Enable)'''&amp;lt;br/&amp;gt;Wenn dieses Bit gesetzt wird, wird der Timer/Counter1 Output Compare A Match Interrupt aktiviert (vorrausgesetzt die Interrupts sind global aktiviert).&lt;br /&gt;
*'''OCIE1B (Timer/Counter1 Output Compare B Match Interrupt Enable)'''&amp;lt;br/&amp;gt;Wenn dieses Bit gesetzt wird, wird der Timer/Counter1 Output Compare B Match Interrupt aktiviert (vorrausgesetzt die Interrupts sind global aktiviert).&lt;br /&gt;
*'''TOIE1 (Timer/Counter1 Overflow Interrupt Enable)'''&amp;lt;br/&amp;gt;Wenn dieses Bit gesetzt wird, wird der Timer/Counter1 Overflow Interrupt aktiviert (vorrausgesetzt die Interrupts sind global aktiviert).&lt;br /&gt;
*'''OCIE0 (Timer/Counter0 Output Compare Match Interrupt Enable)'''&amp;lt;br/&amp;gt;Wenn dieses Bit gesetzt wird, so wird der Timer/Counter0 Compare Match Interrupt aktiviert (vorrausgesetzt die Interrupts sind global aktiviert).&lt;br /&gt;
*'''TOIE0 (Timer/Counter0 Overflow Interrupt Enable)'''&amp;lt;br/&amp;gt;Wenn dieses Bit gesetzt wird, so wird der Timer/Counter0 Overflow Interrupt aktiviert  (vorrausgesetzt die Interrupts sind global aktiviert).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
==Die Fusebits==&lt;br /&gt;
Fusebits nennt man bestimmte Bits zur Konfigurierung eines AVR-Controllers. Bei der Auslieferung neuer AVR Controller sind die Fusebits bereits vorkonfiguriert. In vielen Fällen kann man die Konfiguration unverändert belassen, je nach Controllertyp. Bei den Typen Mega xxx bestimmen einige Fusebits beispielsweise, dass der interne Taktgeber aktiviert ist. Möchte man dagegen einen externen Quarz anschließen oder die Taktfrequenz ändern, so müssen auch die Fusebits geändert werden. Auch das Deaktivieren des &amp;quot;[[On Chip Debugging]]&amp;quot; Modus ist oft notwendig, wenn man alle Ports ausnutzen möchte. &lt;br /&gt;
&lt;br /&gt;
Die Fusebits werden in der Regel über die Software eingestellt, welche auch für das Übertragen des Programmcodes zuständig ist. Besonders einfach geht dies beispielsweise mit der Entwicklungsumgebung [[Bascom]]. Aber auch andere Programme wie [[PonyProg]] können für die Umstellung der Fusebits genutzt werden. Einmal eingestellte Fusebits bleiben bis zur erneuten Fusebit-Änderung erhalten. Der normale Programmiermodus verändert die Fusebits nicht. &lt;br /&gt;
&lt;br /&gt;
Je nach AVR Controllertyp sind unterschiedliche Fusebits (Einstellungen) vorhanden. Die genaue Beschreibung findet man im jeweiligen Datenblatt. Da aber falsch gesetzte Fusebit-Einstellungen zu den häufigsten Problemen gehören, liste ich hier die Funktion der üblichen Fusebits nochmals genauer auf:&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
 |'''CKSEL0, CKSEL1, CKSEL2, CKSEL3'''&lt;br /&gt;
 |Die Kombination dieser 4 Fusebits bestimmt die Taktquelle des Controllers. Das kann eine interner Taktgenerator, ein Quarz, Quarzoszillator, RC-Glied und ähnliches sein.&lt;br /&gt;
|-&lt;br /&gt;
 |'''JTAGEN'''&lt;br /&gt;
 |Hiermit wird die &amp;quot;[[On Chip Debugging]]&amp;quot; Schnittstelle aktiviert bzw. deaktiviert. Das sind die Bits mit den Bezeichnungen TDI, TDO, TMS und TCK. Möchte man diese Pins als normalen Port nutzen, so muss diese Schnittstelle immer deaktiviert werden. &lt;br /&gt;
|-&lt;br /&gt;
 |'''SUT0, SUT1'''&lt;br /&gt;
 |Die sogenannte StartUp-Zeit (PowerOn delay). Diese Einstellung muss abhängig von der Art des Taktgenerators eingestellt werden, genaueres im jeweiligen Datenblatt. &lt;br /&gt;
|-&lt;br /&gt;
 |'''SPIEN'''&lt;br /&gt;
 |Hiermit kann die serielle [[AVR-ISP Programmierkabel|ISP-Programmierung]], welche die meisten Programmierkabel nutzen, deaktiviert werden. Dies sollte man lieber vermeiden, denn wenn dieser Programmiermodus deaktiviert wurde, kann nur noch der Parallel-Programmiermodus genutzt werden. Der Parallel-Programmiermodus benötigt jedoch ein spezielles Programmiergerät, das die wenigsten Bastler besitzen. ''Also Vorsicht!''&lt;br /&gt;
|-&lt;br /&gt;
 |'''BODEN'''&lt;br /&gt;
 |Über dieses Bit wird der '''Brown-out Detector''' aktiviert bzw. deaktiviert. Dies ist eine Überwachung der Betriebsspannung. Diese Überwachung soll dafür sorgen, dass bei Spannungseinbrüchen ein ordentlicher RESET durchgeführt wird. Dadurch wird verhindert, dass ein Controller in einen undefinierten Zustand gerät (hängen bleibt).&lt;br /&gt;
|-&lt;br /&gt;
 |'''BOOTLEVEL'''&lt;br /&gt;
 |Über dieses  Bit kann die Spannung festgelegt werden, ab welcher der '''Brown-out Detector''' den Controller neu startet (also RESET ausführt). &lt;br /&gt;
|-&lt;br /&gt;
 |'''BOOTRST'''&lt;br /&gt;
 |Gewöhnlich startet ein Programm im Controller nach einem RESET ab Adresse 0. Durch dieses Fusebit kann der Controller jedoch veranlasst werden, nach einem Reset einen sogenannten Bootloader-Bereich auszuführen. Ein [[Bootloader]] kann genutzt werden, um Controller über andere Schnittstellen (z.B. RS232) zu programmieren.&lt;br /&gt;
|-&lt;br /&gt;
 |'''BOOTSZ0, BOOTSZ1'''&lt;br /&gt;
 |Der zuvor genannte Bootloaderbereich kann bei AVR-Controllern verschieden groß sein. Über diese beiden Bits können vier verschiedene Größen eingestellt werden. Siehe unter [[Bootloader]].&lt;br /&gt;
|-&lt;br /&gt;
 |'''EESAVE'''&lt;br /&gt;
 |Dieses Bit legt fest, ob beim Programmieren des Controllers (man nennt es auch brennen) immer das EEPROM gelöscht werden soll.&lt;br /&gt;
|-&lt;br /&gt;
 |'''CKOPT'''&lt;br /&gt;
 |Abhängig von den Einstellungen von CKSEL kann hier dir Oszillator-Verstärkung eingestellt werden. Genaueres im Datenblatt des jeweiligen Controllers.&lt;br /&gt;
|-&lt;br /&gt;
 |'''WDTON'''&lt;br /&gt;
 |Schaltet den WatchDog-Timer beim Booten ein/aus. Dies ist auch per Software möglich&lt;br /&gt;
|-&lt;br /&gt;
 |'''RSTDISBL'''&lt;br /&gt;
 |Durch dieses Bit kann man den RESET-Pin deaktivieren und dann als normalen I/O-Port nutzen. Aber Vorsicht! Da die RESET-Leitung beim Programmieren (Brennen) des Chips genutzt wird, kann man nach dessen Deaktivierung den Controller mit den üblichen [[AVR-ISP Programmierkabel|ISP-Adaptern]] nicht mehr programmieren. In diesem Fall könnte man zwar den Controlle noch mit speziellen Programmiergeräten im Parallelmodus programmieren, aber in der Praxis verfügen nur wenige Bastler über ein Programmiergerät, das dies leistet.&lt;br /&gt;
|-&lt;br /&gt;
 |'''LB1, LB2'''&lt;br /&gt;
 |Das sind die sogenannten Lockbits, mit denen sich das Auslesen des Flash- als auch EEPROM-Speichers verhindern läßt. Zwar können andere Anwender immer noch Daten lesen, allerdings handelt es sich dabei nicht mehr um den wirklichen Inhalt sondern lediglich um wirre Datenbytefolgen. Programmierer, die den erarbeiteten Code vor Raubkopierern schützen wollen, nutzen diese Lockbits. Das Programmieren ist auch bei gesetzen Lockbits noch möglich. Der Bootloader-Bereich wird nicht durch die Lockbits geschützt.&lt;br /&gt;
|-&lt;br /&gt;
 |'''BLB01, BLB02'''&lt;br /&gt;
 |Durch diese Bits kann der Code sogar vor dem Zugriff durch den Bootloader geschützt werden&lt;br /&gt;
|-&lt;br /&gt;
 |'''BLB11, BLB12'''&lt;br /&gt;
 |Diese Bits schützen den Bootloaderbereich selbst&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Wie man die Fusebits mit [[Bascom]] einstellt, wird im Beitrag [[Bascom - Erstes Programm in den AVR Controller übertragen]] erläutert.&lt;br /&gt;
&lt;br /&gt;
''Autoren des Artikels: Frank, Luma'' &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Siehe auch==&lt;br /&gt;
* [[Atmel]]&lt;br /&gt;
* [[AVR-Einstieg leicht gemacht]]&lt;br /&gt;
* [[Avr-gcc|avr-gcc]] - Leistungsfähiger AVR-Port des freien Compilers GCC&lt;br /&gt;
* [[WinAVR]] - Ein freies Werkzeugpaket auf Basis avr-gcc für die Windows-Platform, integriert unter anderem das [[Programmer's Notepad]]&lt;br /&gt;
* [[AVR_Assembler_Einf%C3%BChrung|AVR Assembler Einführung (AvrStudio)]]&lt;br /&gt;
* [[AVR-ISP Programmierkabel]] - Bauanleitung für die AVR Controller Programmierkabel&lt;br /&gt;
* [[RN-Control]] - Eines der beliebtestet AVR-Boards im Roboternetz&lt;br /&gt;
* [[RNBFRA-Board]] - Größeres Board mit zwei Atmel Controllern&lt;br /&gt;
* [[Bascom]] - Sehr gutes Basic-Entwicklungssystem&lt;br /&gt;
* [[Bascom - Erstes Programm in den AVR Controller übertragen]]&lt;br /&gt;
* [[On Chip Debugging]]&lt;br /&gt;
* [[Bootloader]]&lt;br /&gt;
* [[Timer]]&lt;br /&gt;
* [[TWI]] - I2C beim AVR&lt;br /&gt;
&lt;br /&gt;
==Weblinks==&lt;br /&gt;
* [http://www.atmel.com/dyn/products/param_table.asp?family_id=607&amp;amp;OrderBy=part_no&amp;amp;Direction=ASC Aktuelle AVR Vergleichstabelle]&lt;br /&gt;
* [http://www.atmel.com/dyn/products/devices.asp?family_id=607 Die Datenblätter zu Atmel Controllern]&lt;br /&gt;
* [https://mpg.dnsalias.com/~magerlu/rn-wiki/avrtimer_applet Java Applet Timer Berechnung]&lt;br /&gt;
* [http://www.roboternetz.de/phpBB2/dload.php?action=file&amp;amp;file_id=169 AvrTimer Windows Berechnungstool]&lt;br /&gt;
* [http://people.freenet.de/gjl/helferlein/avr-uart-rechner.html AVR-Baudraten-Rechner (JavaScript)]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Microcontroller]]&lt;br /&gt;
[[Kategorie:Grundlagen]]&lt;br /&gt;
[[Kategorie:Elektronik]]&lt;br /&gt;
[[Kategorie:Abkürzung|AVR]]&lt;/div&gt;</summary>
		<author><name>Alexander.stohr</name></author>	</entry>

	</feed>