<?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=Heigro</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=Heigro"/>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=Spezial:Beitr%C3%A4ge/Heigro"/>
		<updated>2026-04-12T04:46:06Z</updated>
		<subtitle>Benutzerbeiträge</subtitle>
		<generator>MediaWiki 1.25.1</generator>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=Inline-Assembler_in_avr-gcc&amp;diff=9920</id>
		<title>Inline-Assembler in avr-gcc</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=Inline-Assembler_in_avr-gcc&amp;diff=9920"/>
				<updated>2006-12-29T10:49:56Z</updated>
		
		<summary type="html">&lt;p&gt;Heigro: Typo&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;In C versteht man unter '''Inline Assembler''' die Möglichkeit, direkt Assembler-Befehle in den Code einzufügen bzw. die eingefügten Assembler-Befehle selbst. &lt;br /&gt;
&lt;br /&gt;
Neben den einzufügenden Befehlen muss beschrieben werden, welche Nebeneffekte die Befehle auf die Maschine haben und wo/wie Parameter übergeben werden, bzw. wie die Zuordnung von Variablen zu den Registern ist. Diese Beschreibung ist notwendig weil der [[Compiler]] keine Vorstellung davon hat, welche Effekte und Nebenwirkungen die Assembler-Kommandos auf Register, Variablen und Speicher haben, denn der Assembler-Schnippsel ist für den Compiler lediglich eine &amp;quot;Black Box&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Obgleich das dazu verwendete Schlüsselwort &amp;lt;tt&amp;gt;__asm&amp;lt;/tt&amp;gt; zum ANSI-C-Standard gehört, ist dies in jedem C-Compiler anders implementiert. Das gilt insbesondere für die Schnittstellenbeschreibung Variablen/Register. Dieser Artikel bezieht sich auf den Inline Assembler von [[avr-gcc]]. &lt;br /&gt;
Viele Erklärungen aus diesem Artikel sind auch gültig für Inline-Assembler anderer C-Compiler der  [[gcc]]-Familie. Instruktionen und Registerklassen werden sich aber unterscheiden, weil diese natürlich abhängig sind vom verwendeten Controller bzw. der Controller-Familie.&lt;br /&gt;
&lt;br /&gt;
=Assembler oder Inline-Assembler?=&lt;br /&gt;
;Assembler: Längere und komplexere Code-Stücke sind komfortabler direkt in Assembler auszudrücken. Dazu schreibt man Assembler-Funktionen und ruft diese von C aus auf. Natürlich können auch C-Funktionen von Assembler aus aufgerufen werden. Zudem kann man im Assembler den C-Präprozessor nutzen, was bei Inline-Assembler nur auf C-Ebene geht. Der Build-Prozess wird allerdings komplizierter, da extra asm-Dateien übersetzt werden müssen.&lt;br /&gt;
;Inline-Assembler: Mit Inline-Assembler kann man kleine Assembler-Stückchen direkt in den C-Code einbetten. Es muss dann keine Assembler-Funktion aufgerufen werden. Dies kann von der Registerverwendung her deutlich günstiger sein, da [[avr-gcc]] genau weiß, welche Register gebraucht werden und welche nicht. Eine Funktion hingegen ist eine Black Box, bei der von der Standard-[[avr-gcc/Interna#Registerverwendung|Registerverwendung]] ausgegangen werden muss, auch wenn weniger Register in einer Funktion verwendet werden. Ein Funktionsaufruf bedeutet also meistens einen Laufzeit-Overhead im Vergleich zu einem Inline-Code. Bei mehrfacher Verwendung einer längeren Codesequenz ist eine Funktion jedoch sparsamer im Flash-Verbrauch. Legt man eine Funktion als C-Funktion an und ihren Body als Inline-Assembler (eine s.g. Stub-Funktion, von engl. ''Stub'' = Stumpf), dann übernimmt gcc das Verwalten von Funktions-Argumenten, return-Wert, etc. und man brauch sich nicht selber um die Aufruf-Konvention zu kümmern. Auch innerhalb einer Funktion kann C mit Assembler gemischt werden.&lt;br /&gt;
&lt;br /&gt;
=Begriffe=&lt;br /&gt;
;Assembler-Template: Das Template (''Schablone'') ist ein statischer, konstanter String im Sinne von C. Es enthält die Assembler-Befehle sowie Platzhalter, in deren Stelle später die Operanden treten&lt;br /&gt;
;Constraint: Die Constraints (''Nebenbedingungen'') beschreiben Einschränkungen an die zu verwendeten Register. Dies ist notwendig, da nicht alle Maschinenbefehle auf alle Register anwendbar sind&lt;br /&gt;
;Clobber-List: Das ist eine Liste von Registern, deren Inhalt durch den Inline-Assembler zerstört wird&lt;br /&gt;
&lt;br /&gt;
=Syntax und Semantik=&lt;br /&gt;
Das Schlüsselwort, um eine Inline-Assembler Sequenz einzuleiten, ist &amp;lt;tt&amp;gt;__asm&amp;lt;/tt&amp;gt; (ANSI). Oft ist auch &amp;lt;tt&amp;gt;asm&amp;lt;/tt&amp;gt; oder &amp;lt;tt&amp;gt;__asm__&amp;lt;/tt&amp;gt; verwendbar. Um zu kennzeichnen, daß die Sequenz keinesfalls wegoptimiert werden darf &amp;amp;ndash; etwa dann, wenn der Assembler keine Wirkung auf C-Variablen hat &amp;amp;ndash; wird dem &amp;lt;tt&amp;gt;asm&amp;lt;/tt&amp;gt; ein &amp;lt;tt&amp;gt;volatile&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;__volatile&amp;lt;/tt&amp;gt; nachgestellt. Danach folgen in runden Klammern die durch &amp;lt;tt&amp;gt;''':'''&amp;lt;/tt&amp;gt; getrennten Abschnitte des Inline-Assemblers:&lt;br /&gt;
 asm volatile ([[#Assembler-Template|asm-template]] : [[#Operanden und Constraints|output-operand-list]] : [[#Operanden und Constraints|input-operand-list]] : [[#Clobbers|clobber-list]]);&lt;br /&gt;
&lt;br /&gt;
Abschnitte, die leer sind, können auch weggelassen werden, wenn dahinter kein weiterer Abschnitt folgt:&lt;br /&gt;
 asm volatile (asm-template);&lt;br /&gt;
&lt;br /&gt;
Oder, wenn weder Input- noch Output-Operanden gebraucht werden, aber Register oder Speicher verändert werden:&lt;br /&gt;
 asm volatile (asm-template ::: clobber-list);&lt;br /&gt;
&lt;br /&gt;
{{FarbigerRahmen |&lt;br /&gt;
Aus Compiler-Sicht werden die Assembler-Befehle im Template parallel, also ''gleichzeitig'' ausgeführt! Dies ist zu bedenken, wenn Register sowohl als Input als auch als Output verwendet werden.&lt;br /&gt;
}} &lt;br /&gt;
&lt;br /&gt;
==Assembler-Template==&lt;br /&gt;
&lt;br /&gt;
Im Template stehen die durch Zeilenumbrüche getrennten Assembler-Befehle. Das Template kann zudem &amp;lt;tt&amp;gt;%&amp;lt;/tt&amp;gt;-Ausdrücke als Platzhalter enthalten, welche durch die Operanden ersetzt werden. Dabei bezieht sich &amp;lt;tt&amp;gt;%0&amp;lt;/tt&amp;gt; auf den ersten Operanden, &amp;lt;tt&amp;gt;%1&amp;lt;/tt&amp;gt; auf den zweiten Operanden, etc. Die Operanden selbst werden im zweiten und dritten Abschnitt des Templates als Komma-getrennte Liste angegeben.&lt;br /&gt;
&lt;br /&gt;
Ein Platzhalter kann zusätzlich einen einbuchstabigen Modifier enthalten, um ein Register in einem speziellen Format darzustellen. Wird z.B. ein Wert ab Register &amp;lt;tt&amp;gt;r28&amp;lt;/tt&amp;gt; (dem Y-Register) gehalten, dann wären folgende Ersetzungen denkbar (als erstes Argument):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;%0&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;rarr;&amp;amp;nbsp;&amp;amp;nbsp;r28&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;%A0&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;rarr;&amp;amp;nbsp;&amp;amp;nbsp;r28&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;%B0&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;rarr;&amp;amp;nbsp;&amp;amp;nbsp;r29&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;%C0&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;rarr;&amp;amp;nbsp;&amp;amp;nbsp;r30&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;%D0&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;rarr;&amp;amp;nbsp;&amp;amp;nbsp;r31&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;%a0&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;rarr;&amp;amp;nbsp;&amp;amp;nbsp;y&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im einfachsten Falle enthält das Templater nur einen Befehl:&lt;br /&gt;
 &amp;quot;nop&amp;quot;&lt;br /&gt;
oder sogar garkeinen Befehl und lediglich einen Kommentar:&lt;br /&gt;
 &amp;quot;; ein Kommentar&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|+ '''Tabelle: asm-Platzhalter und ihre Modifier, Sonderzeichen'''&lt;br /&gt;
|- {{Hintergrund1}}&lt;br /&gt;
! Platzhalter || wird ersetzt durch&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;%''n''&amp;lt;/tt&amp;gt; || Wird ersezt durch Argument &amp;lt;tt&amp;gt;''n''&amp;lt;/tt&amp;gt; mit &amp;lt;tt&amp;gt;''n''&amp;lt;/tt&amp;gt; = 0...9&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;%A''n''&amp;lt;/tt&amp;gt; || das erste (untere) Register des Arguments &amp;lt;tt&amp;gt;''n''&amp;lt;/tt&amp;gt; (Bits 0...7)&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;%B''n''&amp;lt;/tt&amp;gt; || das zweite Register des Arguments &amp;lt;tt&amp;gt;''n''&amp;lt;/tt&amp;gt; (Bits 8...15)&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;%C''n''&amp;lt;/tt&amp;gt; || das dritte Register des Arguments &amp;lt;tt&amp;gt;''n''&amp;lt;/tt&amp;gt; (Bits 16...23)&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;%D''n''&amp;lt;/tt&amp;gt; || das vierte Register des Arguments &amp;lt;tt&amp;gt;''n''&amp;lt;/tt&amp;gt; (Bits 24...31)&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;%a''n''&amp;lt;/tt&amp;gt; || Ausgabe des Arguments als Adress-Register,&amp;lt;br/&amp;gt;also als &amp;lt;tt&amp;gt;x&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;y&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;z&amp;lt;/tt&amp;gt;. Erlaubt zusammen mit Constraint &amp;lt;tt&amp;gt;b&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;e&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;x&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;y&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;z&amp;lt;/tt&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;%~&amp;lt;/tt&amp;gt; || wird auf AVR mit Flash bis max. 8kByte durch ein &amp;lt;tt&amp;gt;r&amp;lt;/tt&amp;gt; ersetzt, ansonsten bleibt es leer.&amp;lt;br/&amp;gt;Zum Aufbau von Sprungbefehlen, etwa &amp;quot;&amp;lt;tt&amp;gt;%~call foo&amp;lt;/tt&amp;gt;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;%=&amp;lt;/tt&amp;gt; || eine für dieses asm-Template und die Übersetzungseinheit eindeutige Zahl.&amp;lt;br/&amp;gt;Zum Aufbau  lokaler Sprungmarken.&lt;br /&gt;
|- {{Hintergrund1}}&lt;br /&gt;
! Sequenz || wird ersetzt durch Sonderzeichen&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;%%&amp;lt;/tt&amp;gt; || das &amp;lt;tt&amp;gt;%&amp;lt;/tt&amp;gt;-Zeichen selbst&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;\n&amp;lt;/tt&amp;gt; || ein Zeilenumbruch&amp;lt;br/&amp;gt;zum Trennen mehrerer asm-Befehle/Zeilen&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;\t&amp;lt;/tt&amp;gt; || ein TAB, zur Übersichtlichkeit im erzeugten asm&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;\&amp;quot;&amp;lt;/tt&amp;gt; || ein &amp;lt;tt&amp;gt;&amp;quot;&amp;lt;/tt&amp;gt; wird eingefügt&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;\\&amp;lt;/tt&amp;gt; || das &amp;lt;tt&amp;gt;\&amp;lt;/tt&amp;gt;-Zeichen selbst&lt;br /&gt;
|- {{Hintergrund1}}&lt;br /&gt;
! Kommentar || Beschreibung&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;; ''Text''&amp;lt;/tt&amp;gt; || einzeiliger Kommentar bis zum Ende des Templates bzw. nächsten Zeilenumbruch&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;/* ''Text'' */&amp;lt;/tt&amp;gt; || mehrzeiliger Kommentar wie in C&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Operanden und Constraints==&lt;br /&gt;
&lt;br /&gt;
Ein Operand besteht aus der Angabe des Constraint-Strings (also der Registerklasse und Kennzeichnung, ob es sich um einen Output-Operanden handelt) und dahinter in runden Klammern der C-Ausdruck, der in Register der angegebenen Klasse geladen werden soll. Die Operanden werden mit 0 beginnend von links nach rechts durchnumeriert und über diese Nummer angesprochen, um sie ins Assembler-Schnippsel einzufügen.&lt;br /&gt;
&lt;br /&gt;
Mehrere Input- bzw. Output-Operanden werden durch Komma getrennt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|+ '''Tabelle: Constraints und ihre Bedeutung'''&lt;br /&gt;
|- {{Hintergrund1}}&lt;br /&gt;
! Constraint || Register || Wertebereich&lt;br /&gt;
|rowspan=&amp;quot;14&amp;quot;|&amp;amp;nbsp;&lt;br /&gt;
! Constraint || Konstante || Wertebereich&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;a&amp;lt;/tt&amp;gt;||einfache obere Register||&amp;lt;tt&amp;gt;r16&amp;lt;/tt&amp;gt;...&amp;lt;tt&amp;gt;r23&amp;lt;/tt&amp;gt;&lt;br /&gt;
|&amp;lt;tt&amp;gt;G&amp;lt;/tt&amp;gt;||Floatingpoint-Konstante ||&amp;lt;tt&amp;gt;0.0&amp;lt;/tt&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;b&amp;lt;/tt&amp;gt;||Pointer-Register ||&amp;lt;tt&amp;gt;y&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;z&amp;lt;/tt&amp;gt;&lt;br /&gt;
|&amp;lt;tt&amp;gt;i&amp;lt;/tt&amp;gt;||Konstante ||&amp;amp;nbsp;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;d&amp;lt;/tt&amp;gt;||obere Register ||&amp;lt;tt&amp;gt;r16&amp;lt;/tt&amp;gt;...&amp;lt;tt&amp;gt;r31&amp;lt;/tt&amp;gt;&lt;br /&gt;
|&amp;lt;tt&amp;gt;I&amp;lt;/tt&amp;gt;||positive 6-Bit-Konstante ||0...63&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;e&amp;lt;/tt&amp;gt;||Pointer-Register ||&amp;lt;tt&amp;gt;x&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;y&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;z&amp;lt;/tt&amp;gt;&lt;br /&gt;
|&amp;lt;tt&amp;gt;J&amp;lt;/tt&amp;gt;||negative 6-Bit Konstante ||&amp;lt;tt&amp;gt;-&amp;lt;/tt&amp;gt;63...0&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;l&amp;lt;/tt&amp;gt;||untere Register ||&amp;lt;tt&amp;gt;r0&amp;lt;/tt&amp;gt;...&amp;lt;tt&amp;gt;r15&amp;lt;/tt&amp;gt;&lt;br /&gt;
|&amp;lt;tt&amp;gt;M&amp;lt;/tt&amp;gt;||8-Bit Konstante ||0...255&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;q&amp;lt;/tt&amp;gt;||Stack-Pointer ||&amp;lt;tt&amp;gt;SPH:SPL&amp;lt;/tt&amp;gt;&lt;br /&gt;
|colspan=&amp;quot;3&amp;quot; |&amp;amp;nbsp;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;r&amp;lt;/tt&amp;gt;||ein Register ||&amp;lt;tt&amp;gt;r0&amp;lt;/tt&amp;gt;...&amp;lt;tt&amp;gt;r31&amp;lt;/tt&amp;gt;&lt;br /&gt;
!{{Hintergrund1}}| Constraint ||{{Hintergrund1}}| Memory ||{{Hintergrund1}}| Wertebereich&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;t&amp;lt;/tt&amp;gt;||Scratch-Register ||&amp;lt;tt&amp;gt;r0&amp;lt;/tt&amp;gt;&lt;br /&gt;
|&amp;lt;tt&amp;gt;m&amp;lt;/tt&amp;gt;|| Memory || &amp;amp;nbsp;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;w&amp;lt;/tt&amp;gt;||obere Register-Paare ||&amp;lt;tt&amp;gt;r24&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;r26&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;r28&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;r30&amp;lt;/tt&amp;gt;&lt;br /&gt;
|colspan=&amp;quot;3&amp;quot; rowspan=&amp;quot;5&amp;quot;|&amp;amp;nbsp;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;x&amp;lt;/tt&amp;gt;||Pointer-Register X ||&amp;lt;tt&amp;gt;x&amp;lt;/tt&amp;gt; (&amp;lt;tt&amp;gt;r27:r26&amp;lt;/tt&amp;gt;)&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;y&amp;lt;/tt&amp;gt;||Pointer-Register Y ||&amp;lt;tt&amp;gt;y&amp;lt;/tt&amp;gt; (&amp;lt;tt&amp;gt;r29:r28&amp;lt;/tt&amp;gt;)&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;z&amp;lt;/tt&amp;gt;||Pointer-Register Z ||&amp;lt;tt&amp;gt;z&amp;lt;/tt&amp;gt; (&amp;lt;tt&amp;gt;r31:r30&amp;lt;/tt&amp;gt;)&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;...&amp;lt;tt&amp;gt;9&amp;lt;/tt&amp;gt;||colspan=&amp;quot;2&amp;quot;|Identisch mit dem angegebenen Operanden&amp;lt;br/&amp;gt;Wird verwendet, wenn ein Operand sowohl als Input&amp;lt;br/&amp;gt;als auch als Output dient, um sich auf diesen&amp;lt;br/&amp;gt;Operanden zu beziehen&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|+ '''Tabelle: Constraint Modifier'''&lt;br /&gt;
|- {{Hintergrund1}}&lt;br /&gt;
!Modifier || Bedeutung&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;=&amp;lt;/tt&amp;gt; || der Operand ist Output-Operand&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;&amp;amp;&amp;lt;/tt&amp;gt; || diesen Operanden ''nicht'' als Input-Operanden verwenden,&amp;lt;br/&amp;gt;sondern nur als Output-Operand&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein Input-Operand könnte also so aussehen, wobei &amp;lt;tt&amp;gt;foo&amp;lt;/tt&amp;gt; eine C-Variable ist. Als Register dient ein (je nach Typ von &amp;lt;tt&amp;gt;foo&amp;lt;/tt&amp;gt; auch mehrere) obere Register, irgendwo von &amp;lt;tt&amp;gt;r16&amp;lt;/tt&amp;gt; bis &amp;lt;tt&amp;gt;r31&amp;lt;/tt&amp;gt; (Constraint &amp;lt;tt&amp;gt;&amp;quot;d&amp;quot;&amp;lt;/tt&amp;gt;):&lt;br /&gt;
 &amp;quot;d&amp;quot; (foo)&lt;br /&gt;
&lt;br /&gt;
In den Klammern kann ein beliebiger, gültiger C-Ausdruck stehen, der beim folgenden Beispiel in irgendeinem Register landet (Constraint &amp;lt;tt&amp;gt;&amp;quot;r&amp;quot;&amp;lt;/tt&amp;gt;), ohne weitere Einschränkung an das Register:&lt;br /&gt;
 &amp;quot;r&amp;quot; ((foo &amp;gt;= 0) ? foo : -foo)&lt;br /&gt;
&lt;br /&gt;
Um einen Operanden als Output-Operanden zu kennzeichnen, wird dem Constraint ein &amp;lt;tt&amp;gt;&amp;quot;=&amp;quot;&amp;lt;/tt&amp;gt; vorangestellt.&lt;br /&gt;
Soll &amp;lt;tt&amp;gt;foo&amp;lt;/tt&amp;gt; ein Output-Operand sein, der in den Registern &amp;lt;tt&amp;gt;r0&amp;lt;/tt&amp;gt;...&amp;lt;tt&amp;gt;r15&amp;lt;/tt&amp;gt; landen soll (Constraint &amp;lt;tt&amp;gt;&amp;quot;l&amp;quot;&amp;lt;/tt&amp;gt;, sieht es so aus. Dabei muss &amp;lt;tt&amp;gt;foo&amp;lt;/tt&amp;gt; ein sogenannter Lvalue sein, also ein Wert, dem etwas zugewiesen werden kann:&lt;br /&gt;
 &amp;quot;=l&amp;quot; (foo)&lt;br /&gt;
&lt;br /&gt;
Ist &amp;lt;tt&amp;gt;foo&amp;lt;/tt&amp;gt; sowohl Input als auch Output, schreibt man &amp;lt;tt&amp;gt;foo&amp;lt;/tt&amp;gt; als Output- und als Input-Operand hin. In der Input-Constraint bezieht man sich dann auf die Operanden-Nummer von &amp;lt;tt&amp;gt;foo&amp;lt;/tt&amp;gt;. Hier ein komplettes Beispiel, das die Nibbles von &amp;lt;tt&amp;gt;foo&amp;lt;/tt&amp;gt; tauscht. Weil &amp;lt;tt&amp;gt;swap&amp;lt;/tt&amp;gt; auf alle Register anwendbar ist, kann als Registerklasse &amp;lt;tt&amp;gt;&amp;quot;r&amp;quot;&amp;lt;/tt&amp;gt; genommen werden:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
unsigned char foo;&lt;br /&gt;
...&lt;br /&gt;
asm volatile (&amp;quot;swap %0&amp;quot; : &amp;quot;=r&amp;quot; (foo) : &amp;quot;0&amp;quot; (foo));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;foo&amp;lt;/tt&amp;gt; als Input-Operand soll im gleichen Register liegen wie &amp;lt;tt&amp;gt;foo&amp;lt;/tt&amp;gt; als Output-Operand. Daher wird als Constraint &amp;lt;tt&amp;gt;&amp;quot;0&amp;quot;&amp;lt;/tt&amp;gt; angegeben, d.h. es wird ins gleiche Register geladen wie der Operand Numero&amp;amp;nbsp;0 &amp;lt;tt&amp;gt;&amp;quot;r&amp;quot; (foo)&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Instruktionen und Constraints===&lt;br /&gt;
Die folgende Tabelle enhält eine Auflistung von AVR-Instruktionen und dazu passende Argumente bzw. Constraints. Nicht alle Shorthands sind in der Tabelle enthalten, so ist &amp;quot;&amp;lt;tt&amp;gt;clr Rn&amp;lt;/tt&amp;gt;&amp;quot; nur eine Abkürzung für &amp;quot;&amp;lt;tt&amp;gt;eor Rn, Rn&amp;lt;/tt&amp;gt;&amp;quot;, ähnliches gilt für den Zoo von Instruktionen rund um das SREG wie  branch, bit set, bit clear, etc., die im Endeffekt auf nur vier Instruktionen abbilden. Instruktionen wie &amp;lt;tt&amp;gt;nop&amp;lt;/tt&amp;gt;, die keine Argumente brauchen, sind ebenfalls nicht in der Tabelle enthalten.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;&amp;quot;load&amp;quot;&amp;lt;/tt&amp;gt; ist ein &amp;lt;tt&amp;gt;&amp;quot;load from SRAM&amp;quot;&amp;lt;/tt&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;&amp;quot;store&amp;quot;&amp;lt;/tt&amp;gt; ist &amp;lt;tt&amp;gt;&amp;quot;store to SRAM&amp;quot;&amp;lt;/tt&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|+'''Tabelle: Übersicht AVR-Instruktionen und passende Constraints'''&lt;br /&gt;
|- {{Hintergrund1}}&lt;br /&gt;
!Mnemonic || Constraint ||Bedeutung ||rowspan=&amp;quot;30&amp;quot;|&amp;amp;nbsp;&lt;br /&gt;
!Mnemonic || Constraint ||Bedeutung&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;adc&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;r,r&amp;lt;/tt&amp;gt;  || add with carry&lt;br /&gt;
| &amp;lt;tt&amp;gt;add&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;r,r&amp;lt;/tt&amp;gt;  || add&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;adiw&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;w,I&amp;lt;/tt&amp;gt; || add immediate to word&lt;br /&gt;
| &amp;lt;tt&amp;gt;and&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;r,r&amp;lt;/tt&amp;gt;  || and&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;andi&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;d,M&amp;lt;/tt&amp;gt; || and with immediate &lt;br /&gt;
| &amp;lt;tt&amp;gt;asr&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;r&amp;lt;/tt&amp;gt;    || arithmetic shift right&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;bclr&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;I&amp;lt;/tt&amp;gt;   || bit clear in SREG&lt;br /&gt;
| &amp;lt;tt&amp;gt;bld&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;r,I&amp;lt;/tt&amp;gt;  || bit load from T&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;brbc&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;I,label&amp;lt;/tt&amp;gt; || branch if bit in SREG clear&lt;br /&gt;
| &amp;lt;tt&amp;gt;brbs&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;I,label&amp;lt;/tt&amp;gt; || branch if bit in SREG set&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;bset&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;I&amp;lt;/tt&amp;gt;  || bit set in SREG&lt;br /&gt;
| &amp;lt;tt&amp;gt;bst&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;r,I&amp;lt;/tt&amp;gt; || bit store from T&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;cbi&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;I,I&amp;lt;/tt&amp;gt; || clear bit in I/O&lt;br /&gt;
| &amp;lt;tt&amp;gt;com&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;r&amp;lt;/tt&amp;gt;   || complement&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;cp&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;r,r&amp;lt;/tt&amp;gt;  || compare&lt;br /&gt;
| &amp;lt;tt&amp;gt;cpc&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;r,r&amp;lt;/tt&amp;gt; || compare with carry&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;cpi&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;d,M&amp;lt;/tt&amp;gt; || compare against immediate&lt;br /&gt;
| &amp;lt;tt&amp;gt;cpse&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;r,r&amp;lt;/tt&amp;gt;|| compare, skip if equal&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;dec&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;r&amp;lt;/tt&amp;gt;   || decrement&lt;br /&gt;
| &amp;lt;tt&amp;gt;elpm&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;t,z&amp;lt;/tt&amp;gt;|| extern: load from prog mem&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;eor&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;r,r&amp;lt;/tt&amp;gt; || exclusive-or&lt;br /&gt;
| &amp;lt;tt&amp;gt;in&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;r,I&amp;lt;/tt&amp;gt;  || input from I/O&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;inc&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;r&amp;lt;/tt&amp;gt;   || increment&lt;br /&gt;
| &amp;lt;tt&amp;gt;ld&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;r,e&amp;lt;/tt&amp;gt;  || load indirect&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;ld&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;r,e+&amp;lt;/tt&amp;gt;  || load indirect, post-increment&lt;br /&gt;
| &amp;lt;tt&amp;gt;ld&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;r,-e&amp;lt;/tt&amp;gt;  || load indirect, pre-decrement&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;ldd&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;r,b+I&amp;lt;/tt&amp;gt; || load indirect with displacement&lt;br /&gt;
| &amp;lt;tt&amp;gt;ldi&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;d,M&amp;lt;/tt&amp;gt; || load immediate&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;lds&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;r,label&amp;lt;/tt&amp;gt; || load direct from SRAM&lt;br /&gt;
| &amp;lt;tt&amp;gt;lpm&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;t,z&amp;lt;/tt&amp;gt;     || load from prog mem&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;lsr&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;r&amp;lt;/tt&amp;gt;    || logical shift right&lt;br /&gt;
| &amp;lt;tt&amp;gt;mov&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;r,r&amp;lt;/tt&amp;gt;  || move&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;movw&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;r,r&amp;lt;/tt&amp;gt; || move word&lt;br /&gt;
| &amp;lt;tt&amp;gt;mul&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;r,r&amp;lt;/tt&amp;gt;  || mul &lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;neg&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;r&amp;lt;/tt&amp;gt;    || negate&lt;br /&gt;
| &amp;lt;tt&amp;gt;or&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;r,r&amp;lt;/tt&amp;gt;   || or&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;ori&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;d,M&amp;lt;/tt&amp;gt;  || or with immediate&lt;br /&gt;
| &amp;lt;tt&amp;gt;out&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;I,r&amp;lt;/tt&amp;gt;  || output to I/O&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;pop&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;r&amp;lt;/tt&amp;gt;    || pop from Stack&lt;br /&gt;
| &amp;lt;tt&amp;gt;push&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;r&amp;lt;/tt&amp;gt;   || push to Stack&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;ror&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;r&amp;lt;/tt&amp;gt;    || rotate right&lt;br /&gt;
|colspan=&amp;quot;3&amp;quot;| &amp;amp;nbsp;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;sbc&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;r,r&amp;lt;/tt&amp;gt;  || subtract with carry&lt;br /&gt;
| &amp;lt;tt&amp;gt;sbci&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;d,M&amp;lt;/tt&amp;gt; || subtract with carry immediate&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;sbic&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;I,I&amp;lt;/tt&amp;gt; || skip if bit in I/O clear&lt;br /&gt;
| &amp;lt;tt&amp;gt;sbis&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;I,I&amp;lt;/tt&amp;gt; || skip if bit in I/O set&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;sbi&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;I,I&amp;lt;/tt&amp;gt;  || set Bit in I/O&lt;br /&gt;
| &amp;lt;tt&amp;gt;sbiw&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;w,I&amp;lt;/tt&amp;gt; || subtract immediate from word&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;sbrc&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;r,I&amp;lt;/tt&amp;gt; || skip if bit in register clear&lt;br /&gt;
| &amp;lt;tt&amp;gt;sbrs&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;r,I&amp;lt;/tt&amp;gt; || skip if bit in register set&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;st&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;e,r&amp;lt;/tt&amp;gt;  || store indirect&lt;br /&gt;
| &amp;lt;tt&amp;gt;st&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;e+,r&amp;lt;/tt&amp;gt;  || store indirect, post-increment&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;st&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;-e,r&amp;lt;/tt&amp;gt;  || store indirect, pre-decrement&lt;br /&gt;
| &amp;lt;tt&amp;gt;std&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;b,r&amp;lt;/tt&amp;gt; || store indirect with displacement&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;sts&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;label,r&amp;lt;/tt&amp;gt; || store direct&lt;br /&gt;
| &amp;lt;tt&amp;gt;sub&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;r,r&amp;lt;/tt&amp;gt;  || subtract&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;subi&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;d,M&amp;lt;/tt&amp;gt; || subtract immediate&lt;br /&gt;
| &amp;lt;tt&amp;gt;swap&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;r&amp;lt;/tt&amp;gt;   || swap nibbles&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
|-&lt;br /&gt;
|colspan=&amp;quot;3&amp;quot;|&amp;amp;nbsp;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier noch ein paar der gebräuchlichsten Shorthands und deren Abbildung auf &amp;quot;Basis&amp;quot;-Instruktionen:&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|+'''Tabelle: Shorthands'''&lt;br /&gt;
|- {{Hintergrund1}}&lt;br /&gt;
!Shorthand || gleichbedeutend mit || Bedeutung ||rowspan=&amp;quot;5&amp;quot;|&amp;amp;nbsp;&lt;br /&gt;
!Shorthand || gleichbedeutend mit || Bedeutung&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;asl r&amp;lt;/tt&amp;gt;   || &amp;lt;tt&amp;gt;addc r,r&amp;lt;/tt&amp;gt;    || arithmetic shift left&lt;br /&gt;
| &amp;lt;tt&amp;gt;cbr r,M&amp;lt;/tt&amp;gt; || &amp;lt;tt&amp;gt;andi  r, ~M&amp;lt;/tt&amp;gt; || clear bits in reg&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;clr r&amp;lt;/tt&amp;gt;   || &amp;lt;tt&amp;gt;eor  r,r&amp;lt;/tt&amp;gt;   || clear reg to zero &lt;br /&gt;
| &amp;lt;tt&amp;gt;lsl r&amp;lt;/tt&amp;gt;   || &amp;lt;tt&amp;gt;add  r,r&amp;lt;/tt&amp;gt;   || logical shift left&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;sbr d,M&amp;lt;/tt&amp;gt; || &amp;lt;tt&amp;gt;ori  d, M&amp;lt;/tt&amp;gt; || set bits in reg&lt;br /&gt;
| &amp;lt;tt&amp;gt;ser d&amp;lt;/tt&amp;gt;   || &amp;lt;tt&amp;gt;ldi  d, 0xff&amp;lt;/tt&amp;gt; || set all bits in reg&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;tst r&amp;lt;/tt&amp;gt;   || &amp;lt;tt&amp;gt;and  r,r&amp;lt;/tt&amp;gt;   || test against zero&lt;br /&gt;
|colspan=&amp;quot;3&amp;quot;|&amp;amp;nbsp;&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Clobbers==&lt;br /&gt;
&lt;br /&gt;
In der Komma-getrennten Clobber-Liste kann man angeben, welche Register durch den Inline-Assembler ihren Wert ändern. Ändern z.B. &amp;lt;tt&amp;gt;r2&amp;lt;/tt&amp;gt; und &amp;lt;tt&amp;gt;r3&amp;lt;/tt&amp;gt; ihre Werte, dann ist die Clobber-Liste&lt;br /&gt;
 &amp;quot;r2&amp;quot;, &amp;quot;r3&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Wird schreibend auf das RAM zugegriffen, dann muss man das auch mitteilen, damit RAM-Inhalte, die sich evtl. in Registern befinden, nach dem Inline-Assembler neu gelesen werden. Der Clobber dafür ist:&lt;br /&gt;
 &amp;quot;memory&amp;quot;&lt;br /&gt;
&lt;br /&gt;
'''Beispiel:'''&lt;br /&gt;
&lt;br /&gt;
Es soll ein Inline-Assembler geschrieben werden, das den Inhalt zweier aufeinanderfolgender Speicherstellen austauscht. Die Adresse soll in &amp;lt;tt&amp;gt;addr&amp;lt;/tt&amp;gt; stehen. Sie ist Input-Operand und muss in Register X, Y oder Z stehen, um den &amp;lt;tt&amp;gt;ld&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;st&amp;lt;/tt&amp;gt;-Befehl anwenden zu können. Die passende Constraint ist also &amp;lt;tt&amp;gt;&amp;quot;e&amp;quot;&amp;lt;/tt&amp;gt;. Nach der Sequenz liegt &amp;lt;tt&amp;gt;addr&amp;lt;/tt&amp;gt; unverändert vor.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   asm volatile (&lt;br /&gt;
      &amp;quot;ld r2,  %a0+&amp;quot;   &amp;quot;\n\t&amp;quot;&lt;br /&gt;
      &amp;quot;ld r3,  %a0&amp;quot;    &amp;quot;\n\t&amp;quot;&lt;br /&gt;
      &amp;quot;st %a0,  r2&amp;quot;    &amp;quot;\n\t&amp;quot;&lt;br /&gt;
      &amp;quot;st -%a0, r3&amp;quot;&lt;br /&gt;
         : /* keine Output-Operanden */&lt;br /&gt;
         : &amp;quot;e&amp;quot; (addr)&lt;br /&gt;
         : &amp;quot;r2&amp;quot;, &amp;quot;r3&amp;quot;, &amp;quot;memory&amp;quot;&lt;br /&gt;
   );&lt;br /&gt;
&amp;lt;/pre&amp;gt; &lt;br /&gt;
avr-gcc entscheidet sich dazu, das Z-Register für &amp;lt;tt&amp;gt;addr&amp;lt;/tt&amp;gt; zu verwenden:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	ld r2,  Z+&lt;br /&gt;
	ld r3,  Z&lt;br /&gt;
	st Z,  r2&lt;br /&gt;
	st -Z, r3&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Günstiger ist es jedoch, dem Compiler auch die Entscheidung zu überlassen, welche(s) Register als Hilfsregister verwendet werden sollen. Ein Register kann &amp;lt;tt&amp;gt;__tmp_reg__&amp;lt;/tt&amp;gt; sein, für das zweite  legen wir eine lokale 8-Bit-Variable &amp;lt;tt&amp;gt;hilf&amp;lt;/tt&amp;gt; an:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   {&lt;br /&gt;
      char hilf;&lt;br /&gt;
	&lt;br /&gt;
      asm volatile (&lt;br /&gt;
         &amp;quot;ld __tmp_reg__,  %a1+&amp;quot;           &amp;quot;\n\t&amp;quot;&lt;br /&gt;
         &amp;quot;ld %0,           %a1&amp;quot;            &amp;quot;\n\t&amp;quot;&lt;br /&gt;
         &amp;quot;st %a1,          __tmp_reg__&amp;quot;    &amp;quot;\n\t&amp;quot;&lt;br /&gt;
         &amp;quot;st -%a1,         %0&amp;quot;&lt;br /&gt;
            : &amp;quot;=&amp;amp;r&amp;quot; (hilf)&lt;br /&gt;
            : &amp;quot;e&amp;quot;   (addr)&lt;br /&gt;
            : &amp;quot;memory&amp;quot;&lt;br /&gt;
      );&lt;br /&gt;
   }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;__tmp_reg__&amp;lt;/tt&amp;gt; (also &amp;lt;tt&amp;gt;r0&amp;lt;/tt&amp;gt;) brauch nicht in die Clobber-Liste aufgenommen zu werden. Um das zweite benötigte Register (hier &amp;lt;tt&amp;gt;r24&amp;lt;/tt&amp;gt;, in dem &amp;lt;tt&amp;gt;hilf&amp;lt;/tt&amp;gt; lebt) kümmert sich avr-gcc und sichert es, falls nötig&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
       	ld	r0, Z+&lt;br /&gt;
       	ld	r24, Z&lt;br /&gt;
       	st	Z, r0&lt;br /&gt;
       	st	-Z, r24&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{FarbigerRahmen |&lt;br /&gt;
Falls das Register &amp;lt;tt&amp;gt;r1&amp;lt;/tt&amp;gt; verändert wird &amp;amp;ndash; was z.B. geschieht, wenn man Multiplikationsbefehle verwendet &amp;amp;ndash; dann muss am Ende des Templates das Register wieder auf&amp;amp;nbsp;0 gesetzt werden, denn bei avr-gcc enthält dieses Register immer den Wert&amp;amp;nbsp;0.&lt;br /&gt;
Das Register in die Clobber-Liste aufzunehen bleibt wirkungslos. Hat man es zerstört,&lt;br /&gt;
dann schreibt man ans Ende des Templates ein&lt;br /&gt;
 clr __zero_reg__&lt;br /&gt;
und stellt es dadurch wieder her.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=Vordefinierte Bezeichner und Makros=&lt;br /&gt;
Je nach Assembler, für den avr-gcc Code erzeugt, gibt es unterschiedliche vordefinierte Funktionen/Makros, die von Inline-Assembler aus verwendbar sind.&lt;br /&gt;
== GNU-Assembler ==&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|+ '''Tabelle: vordefinierte Bezeichner/Makros&lt;br /&gt;
|- {{Hintergrund1}}&lt;br /&gt;
! Bezeichner || Bedeutung&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;__SP_L__&amp;lt;/tt&amp;gt; || unteres Byte des Stack-Pointers, für &amp;lt;tt&amp;gt;in&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;out&amp;lt;/tt&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;__SP_H__&amp;lt;/tt&amp;gt; || oberes Byte des Stack-Pointers, für &amp;lt;tt&amp;gt;in&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;out&amp;lt;/tt&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;__SREG__&amp;lt;/tt&amp;gt; || Status-Register, für &amp;lt;tt&amp;gt;in&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;out&amp;lt;/tt&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;__tmp_reg__&amp;lt;/tt&amp;gt; || ein Register zur temporären Verwendung (&amp;lt;tt&amp;gt;r0&amp;lt;/tt&amp;gt;)&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;__zero_reg__&amp;lt;/tt&amp;gt; || ein Register, das 0 enthält (&amp;lt;tt&amp;gt;r1&amp;lt;/tt&amp;gt;)&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;lo8(''const'')&amp;lt;/tt&amp;gt; || die unteren 8 Bit der Konstanten &amp;lt;tt&amp;gt;''const''&amp;lt;/tt&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;hi8(''const'')&amp;lt;/tt&amp;gt; || Bits 8...15 der Konstanten &amp;lt;tt&amp;gt;''const''&amp;lt;/tt&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;hlo8(''const'')&amp;lt;/tt&amp;gt; || Bits 16...23 der Konstanten &amp;lt;tt&amp;gt;''const''&amp;lt;/tt&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;hhi8(''const'')&amp;lt;/tt&amp;gt; || Bits 24...31 der Konstanten &amp;lt;tt&amp;gt;''const''&amp;lt;/tt&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Beispiele=&lt;br /&gt;
&lt;br /&gt;
==nop==&lt;br /&gt;
Mit den bisherigen Vorkenntnissen ist zu &amp;lt;tt&amp;gt;nop&amp;lt;/tt&amp;gt; nicht viel zu sagen:&lt;br /&gt;
 asm volatile (&amp;quot;nop&amp;quot;);&lt;br /&gt;
Oder als C-Makro:&lt;br /&gt;
 #define nop() \&lt;br /&gt;
    asm volatile (&amp;quot;nop&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;nop&amp;lt;/tt&amp;gt; hat weder Input- noch Output-Operanden, und Register/RAM ändern sich natürlich nicht. Bei der Makro-Definition ist lediglich darauf zu achten, daß das Makro nicht mit einem&amp;amp;nbsp;&amp;lt;tt&amp;gt;;&amp;lt;/tt&amp;gt; endet, damit man den C-Code wie gewohnt mit&amp;amp;nbsp;&amp;lt;tt&amp;gt;;&amp;lt;/tt&amp;gt; schreiben kann:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if (x)&lt;br /&gt;
   nop();&lt;br /&gt;
else&lt;br /&gt;
   ...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==swap Nibbles==&lt;br /&gt;
Ein einfaches Beispiel für &amp;lt;tt&amp;gt;swap&amp;lt;/tt&amp;gt; haben wir bereits oben kennen gelernt. Der Inline-Assembler dreht die Nibbles von &amp;lt;tt&amp;gt;foo&amp;lt;/tt&amp;gt; um:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
unsigned char foo;&lt;br /&gt;
...&lt;br /&gt;
asm volatile (&amp;quot;swap %0&amp;quot; : &amp;quot;=r&amp;quot; (foo) : &amp;quot;0&amp;quot; (foo));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wünschenswert wäre eher, &amp;lt;tt&amp;gt;swap&amp;lt;/tt&amp;gt; wie eine normale C-Funktion verwenden zu können und hinzuschreiben:&lt;br /&gt;
 a = swap(b);&lt;br /&gt;
ohne daß &amp;lt;tt&amp;gt;b&amp;lt;/tt&amp;gt; seinen Wert ändert. Soll &amp;lt;tt&amp;gt;b&amp;lt;/tt&amp;gt; geswappt werden, dann via&lt;br /&gt;
 b = swap(b);&lt;br /&gt;
zudem soll das Argument ein Ausdruck sein können:&lt;br /&gt;
 if (b == swap (b+1))&lt;br /&gt;
    ...&lt;br /&gt;
&lt;br /&gt;
Dazu verwenden wir eine lokale Variable &amp;lt;tt&amp;gt;__x__&amp;lt;/tt&amp;gt;, in die der ursprüngliche Wert &amp;lt;tt&amp;gt;x&amp;lt;/tt&amp;gt; gesichert wird:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#define swap(x)                                            \&lt;br /&gt;
 ({                                                        \&lt;br /&gt;
    unsigned char __x__ = (unsigned char) x;               \&lt;br /&gt;
    asm volatile (&amp;quot;swap %0&amp;quot; : &amp;quot;=r&amp;quot; (__x__) : &amp;quot;0&amp;quot; (__x__)); \&lt;br /&gt;
    __x__;                                                 \&lt;br /&gt;
  })&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
alternativ könnten wie eine inline-Funktion definieren:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
static inline unsigned char swap (unsigned char x)&lt;br /&gt;
{&lt;br /&gt;
    asm volatile (&amp;quot;swap %0&amp;quot; : &amp;quot;=r&amp;quot; (x) : &amp;quot;0&amp;quot; (x));&lt;br /&gt;
    return x;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==swap Bytes==&lt;br /&gt;
Werden Zahlen zwischen verschiedenen Plattformen übertragen, kann es sein, daß diese unterschiedlich dargestellt werden: Das low-Byte kann in sich im unteren Byte befinden (AVR), es kann aber auch im oberen Byte sein. Ist das so, dann müssen die Werte beim Senden/Empfang umgewandelt werden, indem die Bytes getauscht werden. Liegt der 16-Bit-Wert in &amp;lt;tt&amp;gt;x_in&amp;lt;/tt&amp;gt; und soll der konvertierte Wert nach &amp;lt;tt&amp;gt;x_out&amp;lt;/tt&amp;gt;gespeichert werden, dann könnte man auf die Idee kommen, so etwas zu schreiben:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   asm volatile (&lt;br /&gt;
      &amp;quot;mov %A0, %B1&amp;quot;   &amp;quot;\n\t&amp;quot;&lt;br /&gt;
      &amp;quot;mov %B0, %A1&amp;quot;&lt;br /&gt;
         : &amp;quot;=r&amp;quot; (x_out)&lt;br /&gt;
         : &amp;quot;r&amp;quot;  (x_in)&lt;br /&gt;
   );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Daraus könnte folgender Code entstehen:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
      	mov	r24, r25&lt;br /&gt;
       	mov	r25, r24&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Das ist offenbar Käse! Was ist passiert? &lt;br /&gt;
&lt;br /&gt;
avr-gcc hat sich dazu entschieden, &amp;lt;tt&amp;gt;x_in&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;r25:r24&amp;lt;/tt&amp;gt; anzulegen. Auch &amp;lt;tt&amp;gt;x_out&amp;lt;/tt&amp;gt; wird in diesen Registern angelegt. Das ist erst mal in Ordnung, wenn &amp;lt;tt&amp;gt;x_in&amp;lt;/tt&amp;gt; nach dem Inline nicht mehr gebraucht wird. Allerdings wird das Inline nicht en bloc &amp;amp;ndash; also nicht zeitparallel &amp;amp;ndash; ausgeführt, sondern sequenziell. Bei ''gleichzeitiger'' Ausführung der beiden &amp;lt;tt&amp;gt;mov&amp;lt;/tt&amp;gt;-Instruktionen wäre auch nichts dagegen zu sagen. Ein &amp;lt;tt&amp;gt;swap&amp;lt;/tt&amp;gt;-Kommando z.B. tauscht die Nibbles gleichzeitig, und der Input-Operand kann im gleichen Register leben wie der Output-Operand, wenn der Input nicht weiter verwendet wird. Mit den beiden Bytes geht es aber nicht. Wir müssen kennzeichnen, daß sich &amp;lt;tt&amp;gt;x_out&amp;lt;/tt&amp;gt; in einem Register befindet, das ''nur'' als Output dient, was durch das &amp;lt;tt&amp;gt;&amp;amp;&amp;lt;/tt&amp;gt; in der Output-Constraint erreicht wird:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   asm volatile (&lt;br /&gt;
      &amp;quot;mov %A0, %B1&amp;quot;   &amp;quot;\n\t&amp;quot;&lt;br /&gt;
      &amp;quot;mov %B0, %A1&amp;quot;&lt;br /&gt;
         : &amp;quot;=&amp;amp;r&amp;quot; (x_out)&lt;br /&gt;
         : &amp;quot;r&amp;quot;   (x_in)&lt;br /&gt;
   );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Damit erfolgt eine korrekte Registerzuordnung. &amp;lt;tt&amp;gt;x_out&amp;lt;/tt&amp;gt; steht jetzt in &amp;lt;tt&amp;gt;r19:r18&amp;lt;/tt&amp;gt; und überschneidet nich nicht mehr mit &amp;lt;tt&amp;gt;x_in&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
       	mov	r18, r25&lt;br /&gt;
       	mov	r19, r24&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Alternativ können wir wie bei [[#swap Nibbles|swap Nibbles]] eine lokale Variable verwenden, und alles als (inline-)Funktion machen. In dem folgenden Beispiel wird ein etwas anderer Code zum Tauschen verwendet:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
static inline unsigned short swap_16 (unsigned short x_in)&lt;br /&gt;
{&lt;br /&gt;
   asm volatile (&lt;br /&gt;
      &amp;quot;eor %A0, %B0&amp;quot;   &amp;quot;\n\t&amp;quot;&lt;br /&gt;
      &amp;quot;eor %B0, %A0&amp;quot;   &amp;quot;\n\t&amp;quot;&lt;br /&gt;
      &amp;quot;eor %A0, %B0&amp;quot;&lt;br /&gt;
         : &amp;quot;=r&amp;quot; (x_in)&lt;br /&gt;
         : &amp;quot;0&amp;quot;  (x_in)&lt;br /&gt;
   );&lt;br /&gt;
	&lt;br /&gt;
   return x_in;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Die &amp;lt;tt&amp;gt;eor&amp;lt;/tt&amp;gt;-Sequenz tauscht die Inhalte von &amp;lt;tt&amp;gt;r24&amp;lt;/tt&amp;gt; und &amp;lt;tt&amp;gt;r25&amp;lt;/tt&amp;gt;. Sie ist genauso schnell und knapp wie ein &amp;quot;Dreiecks-Tausch&amp;quot;, kommt aber ohne Hilfsregister aus. Nachrechnen, es stimmt!&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
       	eor	r24, r25&lt;br /&gt;
       	eor	r25, r24&lt;br /&gt;
       	eor	r24, r25&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Zugriff auf SFRs ==&lt;br /&gt;
Um auf SFRs zuzugreifen, können im asm-Template keine Defines aus &amp;lt;tt&amp;gt;avr/io.h&amp;lt;/tt&amp;gt; verwendet werden, weil der Präprozessor nicht mehr über den erzeugten Assembler-Code läuft (er läuft vor dem Compilieren). Um nicht die hex-Codes des SFRs angeben zu müssen, kann man dem Inline die Adressen als Konstanten übergeben. Weil die Adressen RAM-Adressen sind, müssen sie in das &amp;lt;tt&amp;gt;_SFR_IO_ADDR&amp;lt;/tt&amp;gt; Makro verpackt werden, um den Offset für den I/O-Bereich abzuziehen. &amp;lt;tt&amp;gt;tcnt1&amp;lt;/tt&amp;gt; wird auf den Inhalt von &amp;lt;tt&amp;gt;TCNT1&amp;lt;/tt&amp;gt; gesetzt:&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;
   uint16_t tcnt1;&lt;br /&gt;
&lt;br /&gt;
   asm volatile (&lt;br /&gt;
      &amp;quot;in %A0, %1&amp;quot;    &amp;quot;\n\t&amp;quot;&lt;br /&gt;
      &amp;quot;in %B0, %1+1&amp;quot;&lt;br /&gt;
         : &amp;quot;=r&amp;quot; (tcnt1)&lt;br /&gt;
         : &amp;quot;M&amp;quot; (_SFR_IO_ADDR (TCNT1))&lt;br /&gt;
   );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
wird umgesetzt zu&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	in r24, 44&lt;br /&gt;
	in r25, 44+1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Das nur als Beispiel. Von C aus geht das natürlich auch mit&lt;br /&gt;
 uint16_t tcnt1 = TCNT1;&lt;br /&gt;
&lt;br /&gt;
== Zugriff aufs SRAM ==&lt;br /&gt;
Auf bekannte globale Symbole kann man direkt von Assembler aus zugreifen:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   extern int einInt;&lt;br /&gt;
&lt;br /&gt;
   asm volatile (&lt;br /&gt;
      &amp;quot;lds %A0, einInt&amp;quot;   &amp;quot;\n\t&amp;quot;&lt;br /&gt;
      &amp;quot;lds %B0, einInt+1&amp;quot;&lt;br /&gt;
         : &amp;quot;=r&amp;quot; (...)&lt;br /&gt;
   );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
ergibt&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	lds r24, einInt&lt;br /&gt;
	lds r25, einInt+1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
alternativ ginge&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   asm volatile (&lt;br /&gt;
      &amp;quot;lds %A0, %A1&amp;quot;   &amp;quot;\n\t&amp;quot;&lt;br /&gt;
      &amp;quot;lds %B0, %B1&amp;quot;&lt;br /&gt;
         : &amp;quot;=r&amp;quot; (...)&lt;br /&gt;
         : &amp;quot;m&amp;quot; (einInt)&lt;br /&gt;
   );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Falls die Adresse eines Objekts zur Compilezeit bekannt ist, kann man auch die Adresse von C aus übergeben:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
struct foo_t {&lt;br /&gt;
   int a[2], b[2];&lt;br /&gt;
} foo;&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
{&lt;br /&gt;
   asm volatile (&lt;br /&gt;
      &amp;quot;lds %A0, %1&amp;quot;    &amp;quot;\n\t&amp;quot;&lt;br /&gt;
      &amp;quot;lds %B0, %1+1&amp;quot;&lt;br /&gt;
         : &amp;quot;=r&amp;quot; (...)&lt;br /&gt;
         : &amp;quot;i&amp;quot; (&amp;amp; foo.b[1])&lt;br /&gt;
   );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
ergibt&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	lds r24, einStruct+6&lt;br /&gt;
	lds r25, einStruct+6+1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Falls die Adresse zur Compilezeit nicht bekannt ist, muss sie natürlich in einem Adress- oder Basisregister übergeben werden:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
void blah (struct foo_t * pfoo)&lt;br /&gt;
{&lt;br /&gt;
   asm volatile (&lt;br /&gt;
      &amp;quot;ld  %A0, %a1&amp;quot;    &amp;quot;\n\t&amp;quot;&lt;br /&gt;
      &amp;quot;ldd %B0, %a1+1&amp;quot;&lt;br /&gt;
         : &amp;quot;=&amp;amp;r&amp;quot; (...)&lt;br /&gt;
         : &amp;quot;b&amp;quot; (&amp;amp; pfoo-&amp;gt;b[1])&lt;br /&gt;
   );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
ergibt&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	ld  r24, Z&lt;br /&gt;
	ldd r25, Z+1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Auch hier muss der Output-Operand mit einem&amp;amp;nbsp;&amp;lt;tt&amp;gt;&amp;amp;&amp;lt;/tt&amp;gt; gekennzeichnet werden, damit er nicht ins gleiche Register geladen wird wie die Adresse.&lt;br /&gt;
&lt;br /&gt;
== Labels und Schleifen ==&lt;br /&gt;
Für Labels in Sprüngen und Schleifen können keine festen Bezeichner verwendet werden, weil ein Label, der via Makro oder inline-Funktion in den Code eingefügt wird, nicht mehrfach vorkommen darf. Dazu kann man sich durch Einfügen von &amp;lt;tt&amp;gt;&amp;quot;%=&amp;quot;&amp;lt;/tt&amp;gt; Labels zusammenbauen, etwa &amp;lt;tt&amp;gt;L_a%=&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;L_b%=&amp;lt;/tt&amp;gt;, etc. Das &amp;lt;tt&amp;gt;&amp;quot;%=&amp;quot;&amp;lt;/tt&amp;gt; wird durch eine für die Übersetzungseinheit und den Code-Schnippsel eindeutige Zahl ersetzt. Die obigen Sequenzen könnten also z.B. umgesetzt werden als &amp;lt;tt&amp;gt;L_a14&amp;lt;/tt&amp;gt; und &amp;lt;tt&amp;gt;L_b14&amp;lt;/tt&amp;gt;, wenn sie im gleichen Schnippsel stehen.&lt;br /&gt;
&lt;br /&gt;
Etwas bequemer ist die Verwendung einer Ziffer als Label. Beim Sprung gibt man direkt hinter der Ziffer an, in welche Richtung das Label gesucht wird. Ist das Label &amp;lt;tt&amp;gt;''n''&amp;lt;/tt&amp;gt;, dann sucht und springt&lt;br /&gt;
*&amp;lt;tt&amp;gt;''n''b&amp;lt;/tt&amp;gt; zurück (backward)&lt;br /&gt;
*&amp;lt;tt&amp;gt;''n''f&amp;lt;/tt&amp;gt; nach vorne (forward)&lt;br /&gt;
&lt;br /&gt;
Es wird zum nächsten auffindbaren Label in der angegebenen Richtung gesprungen.&lt;br /&gt;
&lt;br /&gt;
===Bits zählen===&lt;br /&gt;
Dieses Assembler-Schnippsel zählt die Anzahl der gesetzten Bits in einem Byte &amp;lt;tt&amp;gt;eingabe&amp;lt;/tt&amp;gt;. Die Eingabe wird nach rechts ins Carry geschoben, und das Carry zum Ergebnis dazu addiert.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
static inline unsigned char count_bits (unsigned char eingabe)&lt;br /&gt;
{                                              &lt;br /&gt;
   unsigned char count;&lt;br /&gt;
&lt;br /&gt;
   asm volatile ( &lt;br /&gt;
      &amp;quot;clr %0&amp;quot;                &amp;quot;\n&amp;quot;&lt;br /&gt;
      &amp;quot;0:&amp;quot;                    &amp;quot;\n\t&amp;quot;&lt;br /&gt;
      &amp;quot;lsr %1&amp;quot;                &amp;quot;\n\t&amp;quot;&lt;br /&gt;
      &amp;quot;adc %0, __zero_reg__&amp;quot;  &amp;quot;\n\t&amp;quot;&lt;br /&gt;
      &amp;quot;tst %1&amp;quot;                &amp;quot;\n\t&amp;quot;&lt;br /&gt;
      &amp;quot;brne 0b&amp;quot;&lt;br /&gt;
         : &amp;quot;=&amp;amp;r&amp;quot; (count), &amp;quot;=r&amp;quot; (eingabe)&lt;br /&gt;
         : &amp;quot;1&amp;quot;  (eingabe)&lt;br /&gt;
   );&lt;br /&gt;
&lt;br /&gt;
   return count;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Damit kann man sich ein Parity bauen:&lt;br /&gt;
 #define parity(x) (count_bits(x) &amp;amp; 1)&lt;br /&gt;
und hätte eine schlankere (aber etwas langsamere) Parity-Implementierung als in &amp;lt;tt&amp;gt;avr/parity.h&amp;lt;/tt&amp;gt;. Ein &lt;br /&gt;
 if (parity(foo))&lt;br /&gt;
    ...&lt;br /&gt;
wird in Assembler dann zu (&amp;lt;tt&amp;gt;r24 = eingabe&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;r25 = count&amp;lt;/tt&amp;gt;):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	lds r24,foo&lt;br /&gt;
/* #APP */&lt;br /&gt;
	clr r25&lt;br /&gt;
0:&lt;br /&gt;
	lsr r24&lt;br /&gt;
	adc r25, __zero_reg__&lt;br /&gt;
	tst r24&lt;br /&gt;
	brne 0b&lt;br /&gt;
/* #NOAPP */&lt;br /&gt;
	sbrs r25,0&lt;br /&gt;
	rjmp .L1&lt;br /&gt;
        ...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Bugs=&lt;br /&gt;
* Um das Sonderzeichen &amp;lt;tt&amp;gt;&amp;quot;%~&amp;quot;&amp;lt;/tt&amp;gt; benutzen zu können, muss bei parameterlosen Inline Assembler dem Template ein Doppelpunkt folgen:&lt;br /&gt;
:&amp;lt;pre&amp;gt;asm volatile (&amp;quot;%~call some_function&amp;quot; :);&amp;lt;/pre&amp;gt;&lt;br /&gt;
=Quellen=&lt;br /&gt;
* Doku zur avr-libc&lt;br /&gt;
* Doku zu avr-gcc&lt;br /&gt;
* Quellen von gcc&lt;br /&gt;
&lt;br /&gt;
=Siehe auch=&lt;br /&gt;
* [[AVR Assembler Einführung]]&lt;br /&gt;
* [[:Kategorie:Quellcode Assembler|Quellcode Assembler]]&lt;br /&gt;
* [[Sourcevergleich#GCC (Assembler einfügen)]]&lt;br /&gt;
* [[avr-gcc]]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Microcontroller]]&lt;br /&gt;
[[Kategorie:Software]]&lt;br /&gt;
[[Kategorie:Grundlagen]]&lt;br /&gt;
[[Kategorie:Quellcode Assembler AVR]]&lt;br /&gt;
[[Kategorie:Quellcode C]]&lt;/div&gt;</summary>
		<author><name>Heigro</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=AVR_Assembler_Einf%C3%BChrung&amp;diff=9758</id>
		<title>AVR Assembler Einführung</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=AVR_Assembler_Einf%C3%BChrung&amp;diff=9758"/>
				<updated>2006-12-03T12:46:43Z</updated>
		
		<summary type="html">&lt;p&gt;Heigro: Typo&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==AVR Assembler Einführung==&lt;br /&gt;
Es gibt mehrere Gründe, sich mit dem AVR-Assembler zu beschäftigen: &lt;br /&gt;
* reines Interesse&lt;br /&gt;
* Man hat eben keinen anderen Compiler, Bascom kostet ja was und GCC-C kann man möglicherweise genausowenig, also warum nicht gleich. &lt;br /&gt;
* Endlich Programmieren ohne Sprach-Restriktionen&lt;br /&gt;
* (theoretisch) sagenhaft schneller und kurzer Code&lt;br /&gt;
&lt;br /&gt;
Dadurch ergeben sich aber auch verschiedene Haupt-Zielgruppen für eine Einführung. Die eine ist in einer oder mehreren anderen Sprachen durchaus versiert, und möchte endlich auch mal richtig in die Tiefen der Hardware steigen. Die andere ist totaler Neueinsteiger und hat gehört, daß man Micro-Controller am besten mit Assembler programmiert.&lt;br /&gt;
&lt;br /&gt;
Es soll hier nur eine Starthilfe zum Einstieg gegeben werden. Viele Details und Varianten werden hier bei weitem nicht erschöpfend behandelt.&lt;br /&gt;
&lt;br /&gt;
==Unterschiede zu anderen Sprachen==&lt;br /&gt;
Man kann Assembler nicht direkt mit anderen Hochsprachen vergleichen. Es ist falsch gesagt Assembler ist viel besser als C, oder C ist viel besser als Assembler.&lt;br /&gt;
Hochsprachen haben generell ihren Vorteil in kürzerer (Programmier-) Zeit viel mehr erreichen zu können. Während man in Assembler jedes Detail programmieren muss schreibt man in der Hochsprache was man genau möchte und der Compiler erledigt das dann für einen, indem er den Code dann in Assembler übersetzt.&lt;br /&gt;
Der Vorteil liegt also klar auf der Hand, man spart sich eine Menge (unnötiger) Arbeit in dem man schneller sagen kann was man eigentlich machen möchte. Wie das jetzt genau funktioniert und was man dabei beachten muss übernimmt der Compiler.&lt;br /&gt;
Da gibts dann aber auch schon den ersten Nachteil. Fängt man mit einer Hochsprache an, braucht man sich hardwaremäßig kaum mit dem µC auseinander zu setzen und weiß deshalb auch nicht genau drüber Bescheid. Funktioniert dann etwas nicht sitzt man auf dem Schlauch.&lt;br /&gt;
Die Compiler werden aber immer besser, so kommen immer seltener Fehler zustande.&lt;br /&gt;
&lt;br /&gt;
Ein weiterer Nachteil ist eine Glaubens Frage, da man sich kaum mehr mit der Hardware auseinander setzt und nicht wissen muss wie ein µC eigentlich funktioniert geht die &amp;quot;Kultur&amp;quot; verloren. Man lernt gar nicht zu schätzen was das Ding jetzt eigentlich leistet. Die Ansprüche werden immer höher gesetzt und jeder Aussetzer ist umso schlimmer.&lt;br /&gt;
&lt;br /&gt;
Ein extremes Beispiel:&lt;br /&gt;
Ein eisener Geschäftsmann geht nach Spanien und braucht Arbeiter, er schickt einen Gehilfen auf die Suche nach Arbeiter und schickt diese dann aufs Feld arbeiten. Ohne auch nur irgend etwas über deren Kultur zu wissen verlangt er das hart gearbeitet wird.&lt;br /&gt;
Doch schon in der ersten Woche gibt es Probleme, die Arbeiter möchten Mittags eine Pause. &amp;quot;Was, eine 3 Stündige Siesta? Seit ihr verrückt? Die in Japan arbeiten die Mittagszeit ja auch durch! Wie kommt ihr auf die Idee 3 Stunden Pause zu machen?&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Vorteile von Assembler sind also dass man weiß, was der µC genau macht (bzw. für Anfänger &amp;quot;was er tun sollte&amp;quot;).&lt;br /&gt;
Man hat die volle Kontrolle und fast jeder Befehl wird bei einem AVR mit einem Takt ausgeführt.&lt;br /&gt;
Man kann immer noch auf eine andere Hochsprache umsteigen, diese beherscht man dann um so besser.&lt;br /&gt;
&lt;br /&gt;
Einziger Nachteil, man muss alles genau definieren, so wie es der µC haben möchte und kann nicht direkt auf fertige funktionen zurück greifen.&lt;br /&gt;
Man schafft in der selben Zeit zwar genau so viel Code, der Code macht dann aber weniger als in C.&lt;br /&gt;
&lt;br /&gt;
Bildhaft ist der Unterschied der: Beim Assembler hat man ein weißes Stück Papier (ohne Linien) und ein Alphabet von A-Z. Aus diesen Buchstaben soll man nun erstmal Worte suchen und dann damit einen sinnvollen Text verfassen.  &lt;br /&gt;
&lt;br /&gt;
Bei &amp;quot;höheren&amp;quot; Sprachen ist das Papier zumindest mal liniert, und dazu kriegt man auch ein Wörtebuch und die Grammatik. Teile des Textes sind schon vorgeschrieben und ich muß nurmehr bei den ..... Punkten was einsetzen.   &lt;br /&gt;
&lt;br /&gt;
Anders kann man auch sagen, Hochsprachen sind wie ein Baukasten, man muss nur nach seinen Bedürfnissen sich die Teile zusammen &amp;quot;stecken&amp;quot;, ab und zu fertigt man sich auch eigene Teile. Aber das meiste ist vorgefertigt und nach eigenen Bedürfnissen schnell angepasst.&lt;br /&gt;
In Assembler muss man sich alles selber anfertigen, fertige Module gibt es nicht, es sei denn man hat es schon einmal gemacht und zufällig da.&lt;br /&gt;
&lt;br /&gt;
* Daten&lt;br /&gt;
Höhere Sprachen kennen alle möglichen Datentypen in allen möglichen Längen, integer, floating point, Strings. Dadurch sind aber auch gleich die möglichen und zulässigen Operationen schon eingeschränkt. &lt;br /&gt;
&lt;br /&gt;
Beim (AVR) Assembler gibt auch einige Datentypen. Sie unterscheiden sich aber nur durch die Größe, d.h. die Anzahl der Bytes, die sie belegen. Es gibt aber keine Einschränkungen bezüglich der Befehle, die man darauf anwenden kann.&lt;br /&gt;
&lt;br /&gt;
* Vor- und Nachteile&lt;br /&gt;
Wenn man den Assembler mit höheren Sprachen vergleicht, um vielleicht Vor- und Nachteile herausarbeiten zu können, kommt man schnell drauf, daß in jedem Vorteil für eine der Seiten auch schon der Nachteil drinnen steckt. Was ich beim Assembler an Performance heraushole, weil ich z.B. &amp;quot;Goodies&amp;quot; eines Controllers ausnutze, bezahle ich, wenn ich mir einen anderen kaufe und dann das ganze Programm umbauen muß.&lt;br /&gt;
&lt;br /&gt;
==Installation AVR-Studio==&lt;br /&gt;
Die Installation des ATMEL AVR Studios ist herzergreifend einfach. &lt;br /&gt;
* Man bekommt von Atmel das AStudio4b01.exe (oder was halt gerade aktuell ist) , das man einfach startet und schon ist es passiert. &lt;br /&gt;
* Wenn man nun das Käferchen doppelklickt und startet, &lt;br /&gt;
**erzeugt man am besten gleich mal ein neues Project. &lt;br /&gt;
**Man wählt den Pfad des Projects, und &lt;br /&gt;
**Wenn man seinen Brennadapter im Menü nicht findet, wählt man eben den Simulator und verwendet dann halt das PonyProg, oder was man halt hat. &lt;br /&gt;
**avrstudio erzeugt ein leeres Projekt und eine leere Assemblersource, die so heißt wie das Projekt. Das Gewurstel mit der Make-file nimmt uns AvrStudio ab. &lt;br /&gt;
==Struktur eines AVR-Maschinenprogrammes==&lt;br /&gt;
Bei höheren Sprachen wird diese Struktur vom Compiler/Linker erzeugt, beim Assembler muß man sich selbst darum kümmern. &lt;br /&gt;
&lt;br /&gt;
[[Bild:Asm_Flow.jpg]]&lt;br /&gt;
&lt;br /&gt;
Der Controller beginnt mit der Abarbeitung links oben bei der Programmspeicheradresse 0000. Wenn man Interrupts verwenden will, muß man gleich das nächste Bereich (ISR-Vectoren) überspringen (mit &amp;quot;JMP&amp;quot;). Wenn nicht, kann man sich diese Vektoren aber auch wegdenken. &lt;br /&gt;
&lt;br /&gt;
Man landet so oder so bei den Befehlen, die der Initialisierung dienen (Setzen der Startbedingung). Das ist zumindest die Festlegung des Stack-Pointers, sonst kann man keine &amp;quot;CALLS&amp;quot; oder Interrupts durchführen.  &lt;br /&gt;
&lt;br /&gt;
Danach kommt man von oben in die Haupt-Programm-Schleife, die (üblicherweise) immer wieder ohne Ende durchlaufen wird.  &lt;br /&gt;
&lt;br /&gt;
Das &amp;quot;End&amp;quot; ist bei Microcontrollern daher auch kaum wirklich notwendig. Wenn es da ist, ist das eine ewige Wiederholung eines einzigen Befehls.&lt;br /&gt;
&lt;br /&gt;
==Source-Code Muster==&lt;br /&gt;
Das folgende Codebeispiel ist eine reine Basis-Initialisierung ohne irgendeine erkennbare Funktion. Für den Einstieg ist es am besten, das einfach abzuschreiben, wie es ist, und dann an den bezeichnenten Stellen mit eigenen Befehlen nach und nach zu erweitern. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 .NOLIST                    ; List-Output unterdrücken&lt;br /&gt;
 .INCLUDE &amp;lt;m8def.inc&amp;gt;       ; das gibt es für jeden Controllertyp&lt;br /&gt;
 .LIST                      ; List-Output wieder aufdrehen&lt;br /&gt;
 .CSEG                      ; was nun folgt, gehört in den FLASH-Speicher&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 ;------------------------------------------------------&lt;br /&gt;
 ;     Start Adresse 0000&lt;br /&gt;
 ;------------------------------------------------------&lt;br /&gt;
 RESET:&lt;br /&gt;
     jmp INIT           ; springen nach &amp;quot;INIT&amp;quot;&lt;br /&gt;
&lt;br /&gt;
 ;------------------------------------------------------&lt;br /&gt;
 ;     ISR VECTORS&lt;br /&gt;
 ;------------------------------------------------------&lt;br /&gt;
 ;    .....    hier kommen dann die Sprungadressen für die Interrupts rein&lt;br /&gt;
 ;             dazu kommen wir noch&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 .ORG INT_VECTORS_SIZE    ; dadurch haben wir für die Vektoren Platz gelassen&lt;br /&gt;
 INIT:  &lt;br /&gt;
 ;------------------------------------------------------&lt;br /&gt;
 ;     INITIALIZE&lt;br /&gt;
 ;------------------------------------------------------&lt;br /&gt;
     ldi r24,high(RAMEND)     ;Stack Pointer setzen &lt;br /&gt;
     out SPH,r24              ; &amp;quot;RAMEND&amp;quot; ist in m8def.inc (s.o.) festgelegt&lt;br /&gt;
     ldi r24,low(RAMEND)      ; &lt;br /&gt;
     out SPL,r24              ;&lt;br /&gt;
&lt;br /&gt;
 ;------------------------------------------------------&lt;br /&gt;
 ;   eigene Initialisierungen&lt;br /&gt;
 ;------------------------------------------------------&lt;br /&gt;
 ;....&lt;br /&gt;
 ;....&lt;br /&gt;
 ;....&lt;br /&gt;
&lt;br /&gt;
 ;------------------------------------------------------&lt;br /&gt;
 ;   HAUPTSCHLEIFE&lt;br /&gt;
 ;------------------------------------------------------&lt;br /&gt;
 Hauptschleife: &lt;br /&gt;
 ;....   eigene befehle&lt;br /&gt;
 ;....   eigene befehle&lt;br /&gt;
 ;....   eigene befehle&lt;br /&gt;
        rjmp Hauptschleife         ; immer wiederholen &lt;br /&gt;
&lt;br /&gt;
 ;------------------------------------------------------&lt;br /&gt;
 ;   ENDE&lt;br /&gt;
 ;------------------------------------------------------&lt;br /&gt;
 Ende:  &lt;br /&gt;
        rjmp Ende&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===Der Ablauf der Übersetzung===&lt;br /&gt;
Der Assembler ist ja selbst auch nur ein Programm und zu Beginn recht spartanisch ausgestattet: Er hat einen Daten-Buffer zur Verfügung, in den er den Maschinencode hineinschreiben soll, einen Pointer (Zeiger) dazu, damit er immer weiß, wo er grad ist, und eine allgemeine Tabelle, wo er Texte mit Zahlen verknüpfen kann. Alles ist zu Beginn leer bzw. auf NULL. &lt;br /&gt;
Mit diesen Voraussetzungen fängt er an, unseren Source-Text zeilenweise zu lesen. Und in jeder Zeile (die nicht leer ist) erwartet er eine Anweisung, was zu tun ist&lt;br /&gt;
====Assembler Direktiven/Präprozessor====&lt;br /&gt;
Das sind Anweisungen an den Assembler selbst und erzeugen keine Maschinenbefehle. Im obigen Source-Beispiel sind einige enthalten.&lt;br /&gt;
 .NOLIST                    &lt;br /&gt;
Normalerweise schreibt der Assembler ja eine Übersetzungsliste. Nach dieser Anweisung läßt er das bleiben&lt;br /&gt;
 .INCLUDE &amp;lt;m8def.inc&amp;gt;       ; das gibt es für jeden Controllertyp&lt;br /&gt;
sagt ihm, er soll jetzt erstmal die (text) datei &amp;quot;m8def.inc&amp;quot; lesen und genauso behandeln, als wäre diese Datei mit dem Editor hier reinkopiert worden. &lt;br /&gt;
 .LIST&lt;br /&gt;
Ab nun wird wieder alles in der Übersetzungsliste protokolliert. &lt;br /&gt;
 .CSEG&lt;br /&gt;
was danach folgt, bezieht sich auf den FLASH-Programm-Speicher&lt;br /&gt;
&lt;br /&gt;
 Gleich ein Hinweis: Der &amp;quot;AVR Assembler 2&amp;quot; geht dazu über, die C-Syntax für &lt;br /&gt;
 Präprozessoranweisungen zu verwenden. Diese haben dann als Kennzeichen ein &amp;quot;#&amp;quot; vorangestellt.&lt;br /&gt;
&lt;br /&gt;
====Bemerkungen / Kommentare====&lt;br /&gt;
 ;------------------------------------------------------&lt;br /&gt;
Alles, was NACH einem Strichpunkt steht, schreibt er einfach nur in die Übersetzungsliste, sonst macht er nix.&lt;br /&gt;
====Label (Sprungmarke)====&lt;br /&gt;
 RESET:&lt;br /&gt;
Was gleich ganz links in der Zeile beginnt (und mit einem Doppelpunkt abgeschlossen ist) schreibt er einfach in die genannte Tabelle und den momentanen Wert des Instruction Pointers (IP) dazu. Sonst hat das im Moment keine weitere Bedeutung. Natürlich, wenn er den gleichen Text schon mal hatte, gibt es eine Fehlermeldung, denn '''ein Label muss eindeutig sein'''&lt;br /&gt;
&lt;br /&gt;
====Commands====&lt;br /&gt;
     jmp INIT           ; springen nach &amp;quot;INIT&amp;quot;&lt;br /&gt;
Alles, was nicht ganz links steht und auch nix anderes ist, betrachtet der Assembler als &amp;quot;Command&amp;quot;. Normalerweise ist das eben eine AVR-Instruktion aus dem &amp;quot;Instruction Set&amp;quot;. Hier ist das &amp;quot;JMP&amp;quot;, also im Programm einfach woanders weitermachen. Gut, aber wo ? Der Rechner braucht nun unbedingt eine Zahl, denn &amp;quot;INIT&amp;quot; sagt ihm ja nichts. Also sieht er nun in der Tabelle nach, ob er den Text &amp;quot;INIT&amp;quot; schon mal hatte. Hatte er nicht, den zu der Stelle weiter hinten, wo &amp;quot;INIT:&amp;quot; als Sprungmarke steht (s.o) ist er ja noch garnicht gekommen. &lt;br /&gt;
&lt;br /&gt;
Ich kann leider nicht genau sagen, welche Strategie der AVR-Assembler nun anwendet, dazu gibt es keine Doku. Manche Assembler lesen erstmal überhaupt nur den Sourcetext von vorn bis hinten durch, um alle &amp;quot;Sprungmarken&amp;quot; zu sammeln (Pass I) und fangen dann nochmal von vorne an (Pass II), diesmal mit schon gefüllter Tabelle. Andere machen das etwas gefinkelter. Ist uns aber eigentlich egal. &lt;br /&gt;
&lt;br /&gt;
Jedenfalls findet er letztlich den Text &amp;quot;INIT&amp;quot; und daneben steht die Nummer der Speicherstelle, wo wir eben &amp;quot;INIT:&amp;quot; hingeschrieben haben. Und nun schreibt der Assembler also den Maschinencode für &amp;quot;JMP&amp;quot; in den Buffer und dazu die Zahl aus der Tabelle. Das war mal ein Befehl, also addiert er auf seinen Zeiger eins drauf und ist mit diesem Befehl fertig.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====ORG / JMP====&lt;br /&gt;
Das, was für den Controller beim Ablauf dann ein &amp;quot;JMP&amp;quot; ist, ist das &amp;quot;.ORG&amp;quot; für den Compiler. Wenn also bislang der Assembler den FLASH-Speicher von 0 - nn mit Befehlen befüllt hat, macht er durch &lt;br /&gt;
 .ORG INT_VECTORS_SIZE    &lt;br /&gt;
mit der Stelle weiter, die er über die gleiche Tabelle unter &amp;quot;INT_VECTORS_SIZE&amp;quot; gefunden hat. Dieser Tabelleneintrag, genauso wie &amp;quot;RAMEND&amp;quot; an anderer Stelle, entsteht aus der Datei &amp;quot;m8def.inc&amp;quot;. Wie im vorliegenen Fall macht man diese &amp;quot;Assembler-Jumps&amp;quot;, um Speicherstellen freizuhalten.&lt;br /&gt;
&lt;br /&gt;
==Merkwürdiges==&lt;br /&gt;
===Befehlsadressen / Byteadressen ===&lt;br /&gt;
[[Atmel Controller Mega16 und Mega32#Maschinen-Code|Ein Maschinenbefehl besteht aus maximal drei, bit-mäßig verschachtelten Teilen]]. Die meisten Befehle brauchen dafür genau 16 Bit (also zwei Byte), manchmal reicht das nicht, da gehören dann nochmal 16 Bit dazu. Kleiner als 16 Bit ist aber keiner. Aus diesem Grund wäre es natürlich sinnlos, Adressen für Befehle in Bytes auszudrücken, wenn es eh immer Vielfache von 2 sein müssen, das kleinste Bit einer solchen Adresse wäre ja immer null. &lt;br /&gt;
&lt;br /&gt;
 Also adressiert man Commands in &amp;quot;Worten&amp;quot; von 16 - Bit bzw. 2 Bytes&lt;br /&gt;
&lt;br /&gt;
Beim Ablegen eines Labels (Sprungmarke) werden also Wortadressen in der Tabelle angelegt. Solange der Wert auch als Befehls-Adresse verwendet wird (z.B. &amp;quot;JMP ''Label''&amp;quot;), braucht das nicht zu kümmern, denn genauso will es der AVR ja dann auch haben. '''Wenn dort aber Daten stehen''' und wir wollen diese adressieren, müssen wird '''den Wert mal 2 nehmen''' (oder einmal nach links schieben, was dasselbe ist), sonst landen wir im Nirwana.   &lt;br /&gt;
===3 ist nicht gleich 3 ===&lt;br /&gt;
Eine Zahl bedeutet also bei der Maschinensprache unter Umständen ganz was anderes, je nachdem, in welchem Zusammenhang sie verwendet wird. Bei allen Befehlen, die nur für die Register 16 - 31 gehen, steht im Maschinencode für das Register 16 nicht 16 drin, sondern 0. die &amp;quot;16&amp;quot; addiert er dann bei der Befehlsausführung drauf (für den Techniker: er braucht ja nur das Bit 2&amp;lt;sup&amp;gt;4&amp;lt;/sup&amp;gt; hochzuziehen)&lt;br /&gt;
===GPR ist nicht gleich GPR===&lt;br /&gt;
Was auch beim Einstieg leicht irritieren kann ist der Umstand, daß die 32 sogenannten &amp;quot;'''G'''eneral '''P'''urpose '''R'''egister&amp;quot; irgendwie so gar nicht generell und gleich sind. Manche Befehle kann ich mit allen 32 Registern machen, einige nur mit R16-R31, andere von R24 aufwärts und dann sind da noch R26 bis R31, die heissen dann manchmal auch noch X, Y und Z &lt;br /&gt;
===SFR ist gar nicht gleich GPR===&lt;br /&gt;
'''S'''pecial '''F'''unction '''R'''egister sind überhaupt seltsam, die meisten GPR-Befehle gehen da gleich garnicht, dafür gibt es andererseits ein paar Bit-Manipulationen, die gehen wiederum nur mit diesen. Dann gibt es auch Bit-Abfragen, die gehen da wie dort und bewirken auch das Gleiche, aber dafür heissen sie dann anders. &lt;br /&gt;
===Assembler-Befehle===&lt;br /&gt;
Viele dieser Probleme nimmt uns der Assembler ab, viele aber nicht. Dort erscheinen die Instruktionen immer so&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
 | ''' '''&lt;br /&gt;
 | '''CMD'''&lt;br /&gt;
 | '''ARG&amp;lt;sub&amp;gt;1&amp;lt;/sub&amp;gt;'''&lt;br /&gt;
 | '''ARG&amp;lt;sub&amp;gt;2&amp;lt;/sub&amp;gt;'''&lt;br /&gt;
 |}&lt;br /&gt;
wobei die Argumente 1 u. 2 optionell, d.h. bei Bedarf erscheinen. Command ist natürlich immer da.&lt;br /&gt;
Trotz der Hilfe des Assemblers durch &amp;quot;Warnings&amp;quot; und &amp;quot;Errors&amp;quot; ist bei den Argumenten aber immer Vorsicht geboten. Wir haben gehört, daß Arg 1 und Arg 2 im Grunde einfach nur zwei Zahlen sind, die dann zusammen mit dem Command-Code zum Maschinenbefehl werden. Wenn es dem Assembler also auch nur irgendwie gelingt, aus dem, was wir da hinschreiben, Zahlen zu machen die er umwandeln kann, nimmt er sie auch.   &lt;br /&gt;
&lt;br /&gt;
===Zwischenbilianz===&lt;br /&gt;
Einiges dieser sonderbaren Dinge lassen sich leicht erklären, manche schwer, manche mangels Unterlagen darüber garnicht. Deswegen versuch ich es hier auch gleich garnicht. &lt;br /&gt;
&lt;br /&gt;
So oder so sind es Fakten, an die man sich am besten einfach gewöhnt. Das scheint und ist am Anfang sicher schwer, solange man noch mit den Befehlen einzeln kämpft. RISC-Befehle werden aber erst in bestimmten Gruppierungen überhaupt wirklich sinnvoll, und durch diese sich immer wieder wiederholenden Gruppen wird es sehr schnell leichter. &lt;br /&gt;
&lt;br /&gt;
Beim Briefe schreiben denkt man ja auch nicht in Buchstaben, das wäre mühsam, sondern in Worten oder in ganzen Sätzen.  &lt;br /&gt;
&lt;br /&gt;
==Load &amp;amp; Store==&lt;br /&gt;
Die meisten Befehle für den AVR laufen nach dem Load &amp;amp; Store (Laden und Speichern) Prinzip ab. Das heißt, die Daten werden zuerst aus dem SRAM-Speicher (oder den I/O bzw. SFR Registern) in die allgemeinen Register (GPR) geladen, dort verarbeitet, und danach wieder in den SRAM oder die SFR zurückgestellt.  &lt;br /&gt;
&lt;br /&gt;
[[Bild:Asm_cmd.jpg]]&lt;br /&gt;
&lt;br /&gt;
Das ist natürlich eine recht allgemeine Darstellung, aber es hilft, das Instruction Set des AVR schon ein wenig besser zu verstehen. &lt;br /&gt;
&lt;br /&gt;
Es bedeutet, um z.B. ein Byte aus der einen Ecke des SRAM in eine andere zu kopieren, brauchen wir wenigstens 2 Maschineninstruktionen, einmal Load und einmal Store. Und wenn wir was an dem Byte ändern wollen, kommt diese Befehle natürlich dazu. &lt;br /&gt;
&lt;br /&gt;
Es gibt zu (fast) jeder Art &amp;quot;Load&amp;quot;-Befehl ein Äquivalent als &amp;quot;Store&amp;quot;, und zum Finden genügt es meist, statt &amp;quot;L&amp;quot; an der selben Stelle ein &amp;quot;S&amp;quot; zu nehmen. &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  LDS    GPR, adresse  ; lade das Byte von der Adresse in ein GPR  &lt;br /&gt;
  STS    adresse, GPR  ; speichere den Inhalt von GPR in der Adresse&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Wenn es um die I/O Register (SFR) geht:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  IN     GPR, I/O-Register    ; GPR &amp;lt;-----I/O Register &lt;br /&gt;
  OUT    I/O-Register, GPR    ; I/O Register &amp;lt;---- GPR&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Für feste Werte (Literals) gibt es natürlich keine Store-Variante, denn diese Werte stehen ja im FLASH (Programm) Speicher, und da kann man nicht einfach einzelne Bytes verändern.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  LDI    GPR, wert&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Beispiel===&lt;br /&gt;
&lt;br /&gt;
An PORTC haben wir (mit Vorwiderständen) ein paar LED angeschlossen. Und die sollen einfach nur zeigen, welche 0-er und 1-er am PORTB anliegen. &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 ; Eigene Initialisierungen&lt;br /&gt;
  LDI R24, 0            ; der wert &amp;quot;0&amp;quot; ins allgemeine Register R24&lt;br /&gt;
  OUT DDRB, R24         ; das kommt ins Controll-register f. PortB&lt;br /&gt;
                        ; dadurch sind diese PINs als INPUT festgelegt&lt;br /&gt;
  LDI R24, 255          ; der wert &amp;quot;255&amp;quot; = FF ins allgemeine Register R24&lt;br /&gt;
  OUT DDRC, R24         ; das kommt ins Controll-register f. PortC&lt;br /&gt;
                        ; dadurch ist das Port auf OUTPUT gestellt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 ; Eigene Befehle (in der Hauptschleife)&lt;br /&gt;
  IN  R24, PINB         ; die Bits vom PortB ins allgemeine Register R24&lt;br /&gt;
  OUT PORTC, r24        ; schreiben wir nach PortC&lt;br /&gt;
                        ; wo ein 1-er ist, leuchtet nun die LED&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn wir diese Befehle in das Programm-Schema oben einfügen, haben wir also das erste Assemblerprogramm schon geschrieben.&lt;br /&gt;
====Programm-Map====&lt;br /&gt;
Eine interessanter Output, wenn wir dieses Programm mit F7 übersetzen lassen, ist die Map-File. Sie ist ein Abbild der oben genannten &amp;quot;Text &amp;lt;--&amp;gt; Adresse&amp;quot;-Tabelle&lt;br /&gt;
&lt;br /&gt;
(gekürzt)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AVRASM ver. 2.0.28  D:\avr_c\avrstudio\Dokutest\Dokutest.asm Sat Dec 10 11:23:45 2005&lt;br /&gt;
....&lt;br /&gt;
EQU  sram_start   00000060&lt;br /&gt;
EQU  sram_size    00000800&lt;br /&gt;
EQU  ramend       0000085f&lt;br /&gt;
......&lt;br /&gt;
EQU  sph          0000003e&lt;br /&gt;
EQU  spl          0000003d&lt;br /&gt;
EQU  portb        00000018&lt;br /&gt;
EQU  ddrb         00000017&lt;br /&gt;
EQU  pinb         00000016&lt;br /&gt;
EQU  portc        00000015&lt;br /&gt;
EQU  ddrc         00000014&lt;br /&gt;
EQU  pinc         00000013&lt;br /&gt;
EQU  int_vectors_size 0000002a&lt;br /&gt;
CSEG reset        00000000&lt;br /&gt;
CSEG init         0000002a&lt;br /&gt;
CSEG hauptschleife 00000032&lt;br /&gt;
CSEG ende         00000035&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Wir finden darin alle Sprungadressen und alle sonstigen Werte, die wir verwendet haben. Tatsächlich in den Maschinencode eingesetzt werden vom Assembler immer die Zahlen, die daneben stehen&lt;br /&gt;
&lt;br /&gt;
===Pointer-Register===&lt;br /&gt;
In vielen Fällen ist es nicht sinnvoll, für Load &amp;amp; Store explizit jedesmal die Speicheradresse dazuschreiben zu müssen. Es können auch die Pointer Register X, Y und Z verwendet werden. Das sind die Register &lt;br /&gt;
 R26:R27 = X &lt;br /&gt;
 R28:R29 = Y &lt;br /&gt;
 R30:R31 = Z &lt;br /&gt;
Da wir ja oft mehr Speicher haben als 256 Byte, werden immer zwei Register zusammengefaßt und können dadurch die Bereiche 0 - 65535 abdecken (64k). Gut, aber wie kriegen wir so große Zahlen da rein ? Wir haben ja nur einen 8-Bit Processor und nicht 16. &lt;br /&gt;
&lt;br /&gt;
Wir müssen also die Adresse 8-Bit-weise übergeben, aber der Assembler hilft uns ja dabei. &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 LDI   R26, LOW(Adresse)        ; R28 für &amp;quot;Y&amp;quot; u. R30 für &amp;quot;Z&amp;quot;&lt;br /&gt;
 LDI   R27, HIGH(Adresse)       ; R29 für &amp;quot;Y&amp;quot; u. R31 für &amp;quot;Z&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Mit diesem &amp;quot;LOW&amp;quot; und &amp;quot;HIGH&amp;quot; teilt uns der Assembler die Adresse genau in die richtigen 8-Bit Portionen, die wir also so in den &amp;quot;X&amp;quot; Pointer laden können.&lt;br /&gt;
&lt;br /&gt;
Noch eine Hilfe gibt es: Wir können, besser zu merken, auch schreiben:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 LDI   XL, LOW(Adresse)        ; YL für &amp;quot;Y&amp;quot; u. ZL für &amp;quot;Z&amp;quot;&lt;br /&gt;
 LDI   XH, HIGH(Adresse)       ; YH für &amp;quot;Y&amp;quot; u. ZH für &amp;quot;Z&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Also &amp;quot;LOW&amp;quot; für &amp;quot;L&amp;quot; und &amp;quot;HIGH&amp;quot; für &amp;quot;H&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Indirekte Adressierung====&lt;br /&gt;
Mit den Pointer-Register kann man also Indirekte Adressieren(=einmal um die Ecke). Statt:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  LDS    GPR, adresse  ; lade das Byte von der Adresse in ein GPR  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Schreiben wir&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  LDI   XL, LOW(Adresse)&lt;br /&gt;
  LDI   XH, HIGH(Adresse)&lt;br /&gt;
  LD    GPR, X        ; '''Indirekt''': lade das Byte, wo der Pointer X hinzeigt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
beziehungsweise &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  LDI   XL, LOW(Adresse)&lt;br /&gt;
  LDI   XH, HIGH(Adresse)&lt;br /&gt;
  ST    X, GPR        ; '''Indirekt''': speichern, wo der Pointer X hinzeigt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Warum sollte man sowas kompliziertes tun ? Nun, zum Beispiel dann, &lt;br /&gt;
* wenn man an einer Stelle im Programm die Adresse festlegt, aber ganz woanders braucht (Subroutinen) &lt;br /&gt;
* wenn man für mehrere Folge-Befehle die gleiche Adresse wieder braucht&lt;br /&gt;
* wenn man mit der Adresse (als Zahl) rechnen will&lt;br /&gt;
&lt;br /&gt;
====Post-Increment/Pre-Decrement====&lt;br /&gt;
Wenn ich zum Beispiel 4 Byte hintereinander im Speicher auf &amp;quot;0&amp;quot; löschen will&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  LDI   XL, LOW(Adresse)&lt;br /&gt;
  LDI   XH, HIGH(Adresse)&lt;br /&gt;
  LDI   GPR, 0&lt;br /&gt;
  ST    X+, GPR   ;speichern, wo X hinzeigt, und dann 1 auf X addieren&lt;br /&gt;
  ST    X+, GPR   ;das 2.Byte dahinter&lt;br /&gt;
  ST    X+, GPR   ;das 3.Byte dahinter&lt;br /&gt;
  ST    X+, GPR   ;das 4.Byte dahinter&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Durch das automatische Addieren brauche ich nichts weiter zu tun. Als Gegenstück dazu kann man auch jedesmal 1 abziehen lassen, das aber immer '''vorher'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  ST    -X, GPR   ;1 von X abziehen und dann speichern, wo X hinzeigt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
All das gibt's für X, Y und Z. Es geht aber immer nur &lt;br /&gt;
* Load &amp;amp; Store und '''dann''' addieren&lt;br /&gt;
* '''erst''' subtrahieren und '''dann''' Load &amp;amp; Store &lt;br /&gt;
Diese Kombinationen werden einfach am häufigsten gebraucht&lt;br /&gt;
&lt;br /&gt;
====Displacement====&lt;br /&gt;
Für die beiden Pointer Y und Z kann man auch mit Displacement arbeiten&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  LDD   GPR, Y+4   ; wo Y hinzeigt, aber 4 Byte dahinter&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Welches Register ?==&lt;br /&gt;
Bei den Load &amp;amp; Store Befehlen könnten als GPR alle 32 Allgemeinen Register beliebig verwendet werden, um das entsprechende Byte aufzunehmen oder abzugeben. Aber als Zwischenspeicher oder Arbeitsregister ist es am besten, Registern wie r26-&amp;gt;r31, die möglicherweise als Pointer gebraucht werden, eher auszuweichen. &lt;br /&gt;
&lt;br /&gt;
 Wird das Assemblerprogramm durch inline oder libraries in eine Hochsprache &lt;br /&gt;
 eingebunden, muß man bei sich natürlich an die Register-Konventionen dieser&lt;br /&gt;
 Umgebung halten. &lt;br /&gt;
&lt;br /&gt;
 Schreibt man ein &amp;quot;stand-alone&amp;quot; Programm, kann (und sollte) man sich seinen eigenen&lt;br /&gt;
 Konventionen und Regeln schaffen. Das ist das, was der Assembler-Fan so liebt.&lt;br /&gt;
&lt;br /&gt;
==Benutzerdaten==&lt;br /&gt;
Daten wie Variable oder Felder werden üblicherweise im SRAM abgelegt und (s.o) von dort auch geholt. Bei allen Compilern und natürlich auch beim Assembler können zum Programmierzeitpunkt nur die Adressen davon festgelegt werden, aber keine Inhalte. Erst zur Laufzeit des Programmes kommen hier Werte rein. Manche Compiler gaukeln es zwar vor, aber (ein C-Beispiel):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 char  MeinName[] = &amp;quot;Sepp Meier&amp;quot; &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
bewirkt in Wirklichkeit drei Dinge: Im SRAM wird die nächste, noch nicht benutzte Adresse dem Text &amp;quot;MeinName&amp;quot; in der oben genannten Tabelle abgelegt, der String &amp;quot;Sepp Meier&amp;quot; wird im FLASH Programmspeicher bereitgestellt, und es wird eine Transfer-Routine generiert, die beim tatsächlichen Start des fertigen Programmes diesen String in das Feld &amp;quot;MeinName&amp;quot; transferiert. &lt;br /&gt;
&lt;br /&gt;
Im Assembler ist es eben genauso: Wir können durch die Anfangsadressen und einen Namen dazu Felder festlegen, die dann zur Laufzeit benützt werden. Mehr eigentlich nicht. Und erst, wenn wir Befehle schreiben, die diese Daten verwenden, ergibt sich daraus ein Datentyp. Vorher sind das einfach nur Bytes.&lt;br /&gt;
&lt;br /&gt;
Das ist bei Hochsprachen anders: Schon in der Source legen wir durch verschiedene Angaben den Datentyp (char, integer, etc.) fest und daraus entscheidet dann der Compiler, welche Maschinen-Instruktionen er dafür verwenden wird. Wir können das nurmehr eingeschränkt beeinflussen. &lt;br /&gt;
&lt;br /&gt;
===Daten im SRAM===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
.DSEG           ; Das ist eine Datensegment, d.h. es werden SRAM-Adressen festgelegt&lt;br /&gt;
CharBuf: 	.byte 24&lt;br /&gt;
OtherData: 	.byte 4 &lt;br /&gt;
....     &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
'''Anmerkung:''' Standardgemäß beginnt der Assembler mit der kleinsten SRAM Adresse. Bei den meisten AVRs ist das die tatsächliche Byte-Adresse 0x0060 (d.i. 96 dezimal). &lt;br /&gt;
[[Atmel_Controller_Mega16_und_Mega32#Adressen_Mapping|Siehe Adress-Mapping]]&lt;br /&gt;
&lt;br /&gt;
Dadurch, daß wir geschrieben haben &amp;quot;.byte 24&amp;quot; bestimmen wir, daß als nächste Datenadresse automatisch dann 96 + 24 = 120 gilt. Also ist mit &amp;quot;OtherData&amp;quot; dann 0x0078 (dez. 120) verknüpft. &lt;br /&gt;
&lt;br /&gt;
'''Noch eins:''' Wir haben ja gesagt, für den Assembler ist alles letztlich eine Zahl. Wir können daher auch damit rechnen. Wenn wir also die &amp;quot;24&amp;quot; nicht selbst wo hinschreiben wollen, verwenden wir einfach den Ausdruck &lt;br /&gt;
 LDI R10 , Otherdata - CharBuf &lt;br /&gt;
und laden damit das Register 10 mit der Zahl 24 &lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
===Daten im FLASH (Literale)===&lt;br /&gt;
Literale sind Werte, die schon in der Source festgelegt werden können. Das geht im Prinzip ähnlich, nur müssen wir nun auch Datentypen festlegen&lt;br /&gt;
&amp;lt;pre&amp;gt; &lt;br /&gt;
OneByte: 	.db   1             ; ein byte mit dem inhalt 0x01   &lt;br /&gt;
MeinName:       .db   &amp;quot;Sepp Meier&amp;quot;  ; mehrere Bytes mit Text&lt;br /&gt;
OneWord: 	.dw   1,2           ; zwei WORDs (16 Bit) mit dem inhalt 0x0001 u.  0x0002&lt;br /&gt;
....     &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Diese Definitionen können wir auch direkt in den Programmcode reinmischen. Wir müssen aber natürlich schauen, daß der AVR zum Laufzeitpunkt nicht versucht, diese Zeichen als Befehl auszuführen.&lt;br /&gt;
&lt;br /&gt;
===Daten im EEPROM (ERAM)===&lt;br /&gt;
genauso geht es, wenn man für den EEPROM feste Werte vorgeben will:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
.ESEG           ; Das ist ein EEPROM-Segment&lt;br /&gt;
OneByte: 	.db   1             ; ein byte mit dem inhalt 0x01   &lt;br /&gt;
MeinName:       .db   &amp;quot;Sepp Meier&amp;quot;  ; mehrere Bytes mit Text&lt;br /&gt;
OneWord: 	.dw   1,2           ; zwei WORDs (16 Bit) mit dem inhalt 0x0001 u.  0x0002&lt;br /&gt;
....     &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Verzweigungen==&lt;br /&gt;
Es gibt zwei Arten, bedingte Programm-Sprünge zu formulieren:&lt;br /&gt;
* Durch irgendwelche Befehle, meistens durch Vergleichsoperationen, erst die Bits im Statusregister (SREG) zu setzen, und diese Status-Bits abzufragen und je nachdem einen Programmsprung durchzuführen oder nicht. &lt;br /&gt;
* Man kann aber auch abhängig von Datenbits in GPRs und SFRs den Folgebefehl überspringen (Skippen) lassen. Dieser Folgebefehl kann, muß aber nicht, ein Sprung- oder Callbefehl sein. &lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
==Zusammenfassung==&lt;br /&gt;
Da dieser Artikel kein Assembler Tutorial sein kann und soll, soll hier auf die &amp;quot;eigentlichen&amp;quot; Instruktionen nicht eingegangen werden. Ich wollte nur versuchen, die &amp;quot;Denkweise&amp;quot; des Assembler und der AVR-Micros ein wenig näherzubringen und einige ermuntern, doch die ersten Operationen direkt am offenen Herzen des Kontrollers zu wagen. &lt;br /&gt;
&lt;br /&gt;
In manchen Fällen habe ich aber sicher einige Leser endgültig verschreckt.  &lt;br /&gt;
&lt;br /&gt;
==Noch ein Tip==&lt;br /&gt;
Gut abgeschrieben ist am Anfang besser als schlecht ausgedacht. Gerade die verschiedenen Geräte-Initialisierungen (SFR) in den zahlreichen GCC Codeschnipsel können fast direkt abgeschrieben werden (Baudrate, Input/Output, etc), da der C-Compiler das ja auch nicht anders machen kann. &lt;br /&gt;
&lt;br /&gt;
==Autor==&lt;br /&gt;
[[User:PicNick|PicNick]]&lt;br /&gt;
&lt;br /&gt;
==Weblinks==&lt;br /&gt;
[http://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=11488 Ausführlicher Foren-Beitrag zum Thema Assembler-Programmierung] &amp;amp;ndash; Lang aber lehrreich&lt;br /&gt;
==Siehe auch==&lt;br /&gt;
*[[AVR]]&lt;br /&gt;
*[[Sourcevergleich]]&lt;br /&gt;
*[[GNU Assembler]]&lt;br /&gt;
*[[Assembler_Einf%C3%BChrung_f%C3%BCr_Bascom-User|Assembler Einführung für Bascom-User]]&lt;br /&gt;
[[Kategorie:Microcontroller]]&lt;br /&gt;
[[Kategorie:Robotikeinstieg]]&lt;br /&gt;
[[Kategorie:Software]]&lt;br /&gt;
[[Kategorie:Quellcode Assembler AVR]]&lt;/div&gt;</summary>
		<author><name>Heigro</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=Avr-gcc&amp;diff=9750</id>
		<title>Avr-gcc</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=Avr-gcc&amp;diff=9750"/>
				<updated>2006-12-01T07:56:07Z</updated>
		
		<summary type="html">&lt;p&gt;Heigro: Typo&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''avr-gcc''' ist ein freier C-[[Compiler]], mit dem man C-Programme zu ausführbaren Programmen übersetzen kann, die auf [[Microcontroller]]n der [[AVR]]-Familie lauffähig sind. &lt;br /&gt;
An Sprachen versteht avr-gcc sowohl C als auch [[#C%2b%2b|C++]]. &lt;br /&gt;
Neben Standard-C bzw. ANSI-C versteht avr-gcc auch GNU-C, das etwas mehr Möglichkeiten und kleinere Spracherweiterungen bietet.&lt;br /&gt;
&lt;br /&gt;
avr-gcc kann auch dazu verwendet werden, um C/C++ Programme nach Assembler zu übersetzen oder um Bibliotheken zu erstellen, die später in unterschiedlichen Projekten verwendet werden können.&lt;br /&gt;
&lt;br /&gt;
Wie bei allen aus der UNIX-Welt kommenden Programmen ist das Kommando-Interface von avr-gcc die Shell bzw. die Kommandozeile, über die Optionen, Parameter, Einstellungen und die Namen der zu übersetzenden Dateien angegeben werden. &lt;br /&gt;
&lt;br /&gt;
=How to Read=&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel bespricht avr-gcc Version 3.x. Er ist kein C-Tutorial und kein AVR-Handbuch &amp;amp;ndash; das würde den Umfang des Artikels bei weitem sprengen. Es gibt einen Unterartikel, der [[avr-gcc/Interna|Interna von avr-gcc]] zusammenfasst.&lt;br /&gt;
&lt;br /&gt;
Der Artikel ist ein Handbuch zu avr-gcc. Er bespricht zum Beispiel, wie man avr-gcc anwendet und Besonderheiten von avr-gcc-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 avr-gcc compiliert werden kann.&lt;br /&gt;
&lt;br /&gt;
Es gibt ein [[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 avr-gcc ist &amp;amp;ndash; wie für alle Programme, die aus der UNIX-Welt kommen &amp;amp;ndash; die Kommandozeile einer Shell, Console bzw. Eingabeaufforderung. &lt;br /&gt;
&lt;br /&gt;
Im einfachsten Fall sieht ein Aufruf von avr-gcc 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 avr-gcc wurde vom Betriebssystem gefunden und konnte/durfte gestartet werden. Dann gibt avr-gcc 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;
Um eine C-Datei &amp;lt;tt&amp;gt;foo.c&amp;lt;/tt&amp;gt; mir avr-gcc optimiert zu einem lauffähigen elf-Programm &amp;lt;tt&amp;gt;foo.elf&amp;lt;/tt&amp;gt; für einen [[ATmega32]] zu compileren, würde man angeben&lt;br /&gt;
 &amp;gt; avr-gcc -O2 -mmcu=atmega32 foo.c -o foo.elf&lt;br /&gt;
Hat man seine Quellen auf zwei oder mehre Dateien verteilt, geht es analog:&lt;br /&gt;
 &amp;gt; avr-gcc -O2 -mmcu=atmega32 foo.c foo2.c -o foo.elf&lt;br /&gt;
&lt;br /&gt;
Will man nur eine Objekt-Datei erstellen (nur compilieren, nicht linken), dann geht das wie folgt. Das kann günstig sein bei grösseren Projekten, wenn man das Projekt neu erzeugen will, aber nur in einer Quelldatei was geändert hat. Oder wenn das Objekt in einer Bibliothek landen soll.&lt;br /&gt;
 &amp;gt; avr-gcc -O2 -c -mmcu=atmega32 foo.c -o foo.o&lt;br /&gt;
&lt;br /&gt;
Die ausführbare Gesamtdatei &amp;lt;tt&amp;gt;foo_all.elf&amp;lt;/tt&amp;gt; erhält man dann, indem alle Objekte zusammenlinkt:&lt;br /&gt;
 &amp;gt; avr-gcc -mmcu=atmega32 foo.o foo2.o foo3.o -o foo_all.elf&lt;br /&gt;
&lt;br /&gt;
Um die ausführbare Datei in das oft verwendete Intex-HEX-Format umzuwandeln (einmal fürs Programm, einmal für ein Abbild des [[EEPROM]]s) gibt man an:&lt;br /&gt;
 &amp;gt; avr-objcopy -O ihex -j .text -j .data                         foo_all.elf  foo_all.hex&lt;br /&gt;
 &amp;gt; avr-objcopy -O ihex -j .eeprom --change-section-lma .eeprom=0 foo_all.elf  foo_all_eeprom.hex&lt;br /&gt;
&lt;br /&gt;
----&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, avr-gcc per Skript oder [[make]] zu starten&lt;br /&gt;
* avr-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 avr-gcc-Aufruf kann sogar von einem Server-Socket oder einer Web-Application heraus erfolgen, welche ein C-Programm empfängt, es von avr-gcc übersetzen lässt, und das Resultat zurückschickt oder sonst was damit anstellt.&lt;br /&gt;
* Lizenzgründe: eine Umgebung, die avr-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;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Kommandozeilen-Optionen=&lt;br /&gt;
Die Codegenerierung bei avr-gcc 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 und der unterstützten AVR-Derivate&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 [[avr-gcc/Interna#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;-std=c89&amp;lt;br/&amp;gt;-ansi&amp;lt;/tt&amp;gt;: bricht mit einer Fehlermeldung ab, wenn kein ANSI-C (ISO C89) verwendet wurde&lt;br /&gt;
; &amp;lt;tt&amp;gt;-std=c99&amp;lt;/tt&amp;gt;: bricht mit einer Fehlermeldung ab, wenn kein ISO C99 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 (Zielsystem/Controller), für das Code generiert werden soll. Je nach Target muss avr-gcc unterschiedliche Instruktionen verwenden und andere Startup-Dateien (&amp;lt;tt&amp;gt;crtxxx.o&amp;lt;/tt&amp;gt;) einbinden. avr-gcc setzt spezielle Defines, um auch in der Quelle zwischen den Targets unterscheiden zu können, falls das notwendig sein sollte: &lt;br /&gt;
:{| border=&amp;quot;0&amp;quot; cellpadding=&amp;quot;0&amp;quot; cellspacing=&amp;quot;0&amp;quot;&lt;br /&gt;
|&lt;br /&gt;
&amp;lt;pre&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;/pre&amp;gt;&lt;br /&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;
=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;
 void function (size_t num_data)&lt;br /&gt;
 {&lt;br /&gt;
    {{comment|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;
    {{comment|Mach was mit p[0] ... p[num_data-1]}}&lt;br /&gt;
    ...&lt;br /&gt;
 }&lt;br /&gt;
oder mittels eines dynamischen Arrays:&lt;br /&gt;
 void function (size_t num_data)&lt;br /&gt;
 {&lt;br /&gt;
    {{comment|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;
    {{comment|Mach was mit p[0] ... p[num_data-1]}}&lt;br /&gt;
    ...&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=C++=&lt;br /&gt;
&lt;br /&gt;
:''&amp;quot;C++ is a complex language and an evolving one, and its standard definition (the ISO C++ standard) was only recently completed. As a result, your C++ compiler may occasionally surprise you, even when its behavior is correct.&amp;quot;''&lt;br /&gt;
&lt;br /&gt;
Zudem sollte der Einsatz von C++ aus Effizienzgründen 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;
Weiterhin 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 avr-gcc. 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;
 #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;
 #if defined (__cplusplus)&lt;br /&gt;
 extern &amp;quot;C&amp;quot; {&lt;br /&gt;
 #endif {{comment|__cplusplus}}&lt;br /&gt;
 &lt;br /&gt;
 SIGNAL (SIG_NAME)&lt;br /&gt;
 {&lt;br /&gt;
    {{comment|machwas}}&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 INTERRUPT (SIG_NAME)&lt;br /&gt;
 {&lt;br /&gt;
    {{comment|mach was}}&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 #if defined (__cplusplus)&lt;br /&gt;
 }&lt;br /&gt;
 #endif {{comment|__cplusplus}}&lt;br /&gt;
&amp;lt;tt&amp;gt;__cplusplus&amp;lt;/tt&amp;gt; ist ein Standard [[avr-gcc/Interna#Builtin Defines|GCC-Builtin-Define]].&lt;br /&gt;
&lt;br /&gt;
Globale Konstruktoren werden in [[avr-gcc/Interna#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 avr-gcc. Es werden Besonderheiten besprochen, die für avr-gcc zu beachten sind. &lt;br /&gt;
&lt;br /&gt;
Dieser Abschnitt ist ''kein'' [[C-Tutorial|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;
For den Zugriff auf die SFRs gibt es Defines über den Include&lt;br /&gt;
 #include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
Abhängig vom eingestellten Controller werden denn Defines eingebunden, über die auf SFRs wie auf normale Variablen zugegriffen werden kann. Die Namen der Defines sind i.d.R. die gleichen wie im AVR-Manual, also z.b. &amp;lt;tt&amp;gt;SREG&amp;lt;/tt&amp;gt; für das Prozessorstatus-Register SREG:&lt;br /&gt;
 #include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 ...&lt;br /&gt;
   {{ccomment|SREG lesen}}&lt;br /&gt;
   uint8_t sreg = SREG;&lt;br /&gt;
   ...&lt;br /&gt;
   {{ccomment|SREG schreiben}}&lt;br /&gt;
   SREG = sreg;&lt;br /&gt;
&amp;lt;!--  &lt;br /&gt;
Auf SFRs wird generell über deren Adresse zugegriffen:&lt;br /&gt;
 {{ccomment|Liest den Inhalt von SREG an Adresse 0x5f}}&lt;br /&gt;
 unsigned char sreg = *((unsigned char volatile*) 0x5f);&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ß avr-gcc 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;
Die Bezeichner der SFRs sind die gleichen wie im Manual.&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
Für einen Überblick über die eingebundenen Defines und kann ein Blick in den Controller-spezifischen Header hilfreich sein. Dieser befindet sich in&lt;br /&gt;
:&amp;lt;tt&amp;gt; &amp;amp;lt;GCC_HOME&amp;amp;gt;/avr/include/avr/io****.h&amp;lt;/tt&amp;gt;&lt;br /&gt;
z.B. &amp;lt;tt&amp;gt;iom32.h&amp;lt;/tt&amp;gt; für einen [[ATmega32]].&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: avr-gcc 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, wenn Interrupts aktiviert sind. Je nach Programm und welche Aufgaben eine [[ISR]] erledigt, kann dies zu Fehlfunktion führen. In dem Fall müssen diese Code-Stücke atomar gemacht werden, damit sie nicht durch einen [[IRQ]] unterbrochen werden können!&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;
&lt;br /&gt;
Um Bits zu löschen, erzeugt man eine Maske, die an der betreffenden Stelle eine &amp;amp;nbsp;0 hat:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// Ports B_2 als Eingang&lt;br /&gt;
DDRB &amp;amp;= ~(1&amp;amp;lt;&amp;amp;lt;PB2);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&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 Includes und die folgenden Makros.&lt;br /&gt;
&lt;br /&gt;
Bitte beachte auch die Hinweise zu den [[#Inkompatibilität|Inkompatibilität]]en von avr-gcc!&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 avr-gcc 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/interrupt.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 avr-gcc 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;
&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();                     {{ccomment|Interrupts global abschalten}}&lt;br /&gt;
    wdt_enable (WDTO_15MS);    {{ccomment|Watchdog aufziehen auf 15ms}}&lt;br /&gt;
    while (1);                 {{ccomment|warten, bis er zubeisst...}}&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;
 #include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 {{ccomment| status informiert z.B. darüber, ob wir selber den Watchdog ausgelöst haben }}&lt;br /&gt;
 {{ccomment| 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;
     {{ccomment|Wert von MCUSCR merken, möglichst früh im Programm }}&lt;br /&gt;
     unsigned char mcucsr = MCUCSR;&lt;br /&gt;
 &lt;br /&gt;
     {{ccomment|MCUCSR zurücksetzen }}&lt;br /&gt;
     MCUCSR = 0;&lt;br /&gt;
 &lt;br /&gt;
     {{ccomment|Watchdog-Reset }}&lt;br /&gt;
     if (mcuscr &amp;amp; (1 &amp;lt;&amp;lt; WDRF))&lt;br /&gt;
     {&lt;br /&gt;
         {{ccomment|status auswerten }}&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     {{ccomment|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;
     {{ccomment|status auswerten }}&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 ([[avr-gcc/Interna#Sections|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 avr-gcc 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;
&lt;br /&gt;
 void code_init3() __attribute__ ((naked, section (&amp;quot;.init3&amp;quot;)));&lt;br /&gt;
 &lt;br /&gt;
 {{comment|!!! never call this function !!!}}&lt;br /&gt;
 void code_init3 (void)&lt;br /&gt;
 {&lt;br /&gt;
    {{comment|Code}}&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Der Code in den &amp;lt;tt&amp;gt;.init''n''&amp;lt;/tt&amp;gt;-Sections wird sequenziell ausgeführt, daher darf in diese Sections nur der nackte Funktions-Code, ohne Prolog und ohne Epilog (also auch ohne &amp;lt;tt&amp;gt;ret&amp;lt;/tt&amp;gt;-Instruktion!). Da disee nackten Funktionen kein &amp;lt;tt&amp;gt;ret&amp;lt;/tt&amp;gt; haben, dürfen sie nicht explizit aufgerufen werden! Ihr Aufruf erfolgt implizit dadurch, daß ihr Code in einer &amp;lt;tt&amp;gt;init&amp;lt;/tt&amp;gt;-Section steht.&lt;br /&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, avr-gcc 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 in avr-gcc|inline-Assembler]] angezeigt oder die Implementierung in einem eigenen Assembler-Modul, das dazu gelinkt wird. Der erzeugte Code ist im List-File zu überprüfen.&lt;br /&gt;
* Werden mehrere Funktionen in die selbe 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;
Ein Programmbeispiel für Code in einer init-Section ist in &amp;quot;[[Speicherverbrauch bestimmen mit avr-gcc#Dynamischer RAM-Verbrauch|Speicherverbrauch bestimmen mit avr-gcc]]&amp;quot;.&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 avr-gcc 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 sind die Pfade &lt;br /&gt;
 &amp;lt;GCC_HOME&amp;gt;/avr/include                           Standard               (stdio.h, ...)&lt;br /&gt;
 &amp;lt;GCC_HOME&amp;gt;/avr/include/avr                       AVR-spezifisch         (avr/io.h, ...)&lt;br /&gt;
 &amp;lt;GCC_HOME&amp;gt;/lib/gcc/avr/&amp;lt;GCC_VERSION&amp;gt;/include     Standard, compilerabh. (limits.h, ...)&lt;br /&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 den Verzeichnissen stehen Standard-Includes, die benötigt werden, wenn man libc-Funktionen &lt;br /&gt;
oder mathematische Funktionen etc. 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                   Zeichen-Umwandlungs-Makros und ctype Makros&lt;br /&gt;
 errno.h                   Symbolische Namen für Fehlercodes&lt;br /&gt;
 inttypes.h                Definiert [u]intN_t wenn man genau N [un]signed Bits &lt;br /&gt;
                           braucht, ISO C99.&lt;br /&gt;
 math.h                    Mathematische Funktionen: sin, cos, log, gamma, bessel, ...&lt;br /&gt;
 setjmp.h                  libc unterstützt setjmp() und longjmp(), um direkt in eine&lt;br /&gt;
                           andere (nicht-lokale) Funktion zu springen. &lt;br /&gt;
 stdio.h                   Standard I/O-Funktionen (printf, ...).&lt;br /&gt;
 stdlib.h                  Deklariert grundlegende ISO C-Makros und -Funktionen &lt;br /&gt;
                           sowie einige AVR-spezifische Erweiterungen&lt;br /&gt;
 string.h                  Stringoperationen auf NULL-terminierten Strings. (strlen, ...)&lt;br /&gt;
 stdarg.h                  Funktionen mit variabler Argumenanzahl&lt;br /&gt;
 limits.h                  Min- und Max-Werte von Skalaren (UCHAR_MAX, LONG_MIN, ...)&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 die I/O-Header eingebunden, die zum AVR-Modell passen, 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ögerungsschleifen für kurze, exakte Verzögerungen&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;
 &lt;br /&gt;
util/crc16.h          Prüfsumme CRC16&lt;br /&gt;
util/delay.h          Verzögerungsschleifen für kurze, exakte Verzögerungen &lt;br /&gt;
util/parity.h         Parität&lt;br /&gt;
util/twi.h            I2C&lt;br /&gt;
 &lt;br /&gt;
[*]  bei neueren avr-gcc-Versionen in util&lt;br /&gt;
[**] entfällt bei neueren avr-gcc-Versionen. Stattdessen avr/interrupt.h verwenden&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Anwendungs-spezifisch==&lt;br /&gt;
Eigene Header, die nur innerhalb eigener Projekte gebraucht werden, includet man mit&lt;br /&gt;
 #include &amp;quot;...&amp;quot;&lt;br /&gt;
Auch hier darf man Unterverzeichnisse angeben oder ins übergeordnete Verzeichnis:&lt;br /&gt;
 #include &amp;quot;../../mein-zeug.h&amp;quot;&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;
&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;
:''&amp;quot;Unlike most other C compilers, GCC allows you to use -g with -O. The shortcuts taken by optimized code may occasionally produce surprising results: some variables you declared may not exist at all; flow of control may briefly move where you did not expect it; some statements may not be executed because they compute constant results or their values were already at hand; some statements may execute in different places because they were moved out of loops.''&lt;br /&gt;
&lt;br /&gt;
:''Nevertheless it proves possible to debug optimized output. This makes it reasonable to use the optimizer for programs that might have bugs.&amp;quot;''&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;
 #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;
   {{ccomment|String im SRAM mit String im Flash vergleichen}}&lt;br /&gt;
   if (!strcmp_P (str_sram, str_p))&lt;br /&gt;
   {&lt;br /&gt;
       {{ccomment|mach was bei Gleichheit}}&lt;br /&gt;
   }&lt;br /&gt;
 &lt;br /&gt;
   {{ccomment|&amp;quot;foo&amp;quot; wird im RAM angelegt. Ineffizient für konstante Strings!}}  &lt;br /&gt;
   {{ccomment|Beachte, daß damit strcmp (nicht strcmp_P) benutzt werden muss.}}  &lt;br /&gt;
   if (!strcmp (str_sram, &amp;quot;foo&amp;quot;))&lt;br /&gt;
   {&lt;br /&gt;
       {{ccomment|mach was bei Gleichheit}}&lt;br /&gt;
   }&lt;br /&gt;
 &lt;br /&gt;
   {{ccomment|PSTR bewirkt, daß die String-Konstante &amp;quot;foo&amp;quot;}}&lt;br /&gt;
   {{ccomment|im Flash angelegt wird}}&lt;br /&gt;
   if (!strcmp_P (str_sram, PSTR (&amp;quot;foo&amp;quot;))&lt;br /&gt;
   {&lt;br /&gt;
       {{ccomment|mach was bei Gleichheit}}&lt;br /&gt;
   }&lt;br /&gt;
 ...&lt;br /&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;
 #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;
 {{ccomment|Die Kommandostruktur}}&lt;br /&gt;
 typedef struct &lt;br /&gt;
 {&lt;br /&gt;
    int (*func)(int);      {{ccomment|Zeiger auf die auszuführende Funktion}}&lt;br /&gt;
    int arg;               {{ccomment|das Argument, das mitübergeben wird}}&lt;br /&gt;
    char text[1+TEXT_LEN]; {{ccomment|Text, maximal TEXT_LEN Zeichen lang}}&lt;br /&gt;
 } command_t;&lt;br /&gt;
 &lt;br /&gt;
 {{ccomment|Das Array mit den Kommandos.}}&lt;br /&gt;
 {{ccomment|Die funcx sind vom Prototyp (z.B. func1 oben)}}&lt;br /&gt;
 {{ccomment|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;
 {{ccomment|Sucht in commands[] nach text und führt gegebenenfalls}}&lt;br /&gt;
 {{ccomment|die dazugehörige Funktion funcx mit Argument arg aus.}}&lt;br /&gt;
 {{ccomment|Liefert den Rückgabewert von funcx}}&lt;br /&gt;
 {{ccomment|oder -1, falls text nicht gefunden wurde.}}&lt;br /&gt;
 int execute (const char *text)&lt;br /&gt;
 {&lt;br /&gt;
    {{ccomment|Schleifenvariable}}&lt;br /&gt;
    unsigned char i;&lt;br /&gt;
 &lt;br /&gt;
    {{ccomment|Wandert durch das Array mit Kommando-Strukturen}}&lt;br /&gt;
    const command_t * cmd = commands;&lt;br /&gt;
 &lt;br /&gt;
    {{ccomment|sizeof wird von gcc ausgewertet und ist wie eine Konstante,}}&lt;br /&gt;
    {{ccomment|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;
       {{ccomment|Ist das der gesuchte String?}} &lt;br /&gt;
       if (strcmp_P (text, cmd-&amp;gt;text))&lt;br /&gt;
       {&lt;br /&gt;
         {{ccomment|Nein, dann weitersuchen}}&lt;br /&gt;
         cmd++;&lt;br /&gt;
         continue;&lt;br /&gt;
       }&lt;br /&gt;
 &lt;br /&gt;
       {{ccomment|Ja}}&lt;br /&gt;
       int (*func)(int), arg;&lt;br /&gt;
 &lt;br /&gt;
       {{ccomment|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;
       {{ccomment|Funktion ausführen und deren Wert zurückliefern}} &lt;br /&gt;
       return func (arg);&lt;br /&gt;
    }&lt;br /&gt;
 &lt;br /&gt;
    {{ccomment|text ist nicht in commands}}&lt;br /&gt;
    return -1;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Nachteil dabei ist, daß jeder String den maximalen Platz von &amp;lt;tt&amp;gt;TEXT_LEN+1&amp;lt;/tt&amp;gt; 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;
 #include &amp;lt;avr/pgmspace.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 {{ccomment|Die Kommandostruktur}}&lt;br /&gt;
 typedef struct &lt;br /&gt;
 {&lt;br /&gt;
    ...&lt;br /&gt;
    char * text;  {{ccomment|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;
 {{ccomment|Sucht in commands[] nach text und führt gegebenenfalls}}&lt;br /&gt;
 {{ccomment|die dazugehörige Funktion funcx mit Argument arg aus.}}&lt;br /&gt;
 {{ccomment|Liefert den Rückgabewert von funcx}}&lt;br /&gt;
 {{ccomment|oder -1, falls text nicht gefunden wurde.}}&lt;br /&gt;
 int execute (const char *text)&lt;br /&gt;
 {&lt;br /&gt;
    {{ccomment|Schleifenvariable}}&lt;br /&gt;
    unsigned char i;&lt;br /&gt;
 &lt;br /&gt;
    {{ccomment|Wandert durch das Array mit Kommando-Strukturen}}&lt;br /&gt;
    const command_t * cmd = commands;&lt;br /&gt;
 &lt;br /&gt;
    {{ccomment|sizeof wird von gcc ausgewertet und ist wie eine Konstante,}}&lt;br /&gt;
    {{ccomment|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;
       {{ccomment|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;
       {{ccomment|Ist das der gesuchte String?}}        &lt;br /&gt;
       if (strcmp_P (text, text_P))&lt;br /&gt;
       {&lt;br /&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;
&lt;br /&gt;
Oft benötigt wird der Zugriff auf die einzelnen Bytes eines &amp;lt;tt&amp;gt;int&amp;lt;/tt&amp;gt;, also der Zugriff auf die Bytes eines 16-Bit-Wertes:&lt;br /&gt;
&lt;br /&gt;
 typedef union&lt;br /&gt;
 {&lt;br /&gt;
    unsigned char  asByte[2];&lt;br /&gt;
    unsigned short asWord;&lt;br /&gt;
    int            asInt;&lt;br /&gt;
 } data16_t;&lt;br /&gt;
 &lt;br /&gt;
 data16_t data;&lt;br /&gt;
 ...&lt;br /&gt;
    int foo;&lt;br /&gt;
    uint8_t wert;&lt;br /&gt;
 &lt;br /&gt;
    data.asInt = foo;&lt;br /&gt;
    wert = data.asByte[1]; {{ccomment|die oberen 8 Bits von foo}}&lt;br /&gt;
&lt;br /&gt;
Ein komplexeres Beispiel, das noch mehr Datentypen überlagert:&lt;br /&gt;
 typedef ... foo_t;&lt;br /&gt;
 &lt;br /&gt;
 typedef union&lt;br /&gt;
 {&lt;br /&gt;
     unsigned char byte[4];      {{ccomment| Zugriff als Bytes (8 Bit) }}&lt;br /&gt;
     unsigned short word[2];     {{ccomment| Zugriff als Words (16 Bit) }}&lt;br /&gt;
     signed long slong;          {{ccomment| Zugriff als signed long (32 Bit) }}&lt;br /&gt;
 &lt;br /&gt;
     struct {{ccomment| Zugriff auf einzelne Bitgruppen }}&lt;br /&gt;
     {&lt;br /&gt;
         unsigned bit_0_3 : 4;   {{ccomment| 4 Bits (0..3) }}&lt;br /&gt;
         unsigned bit_4_8 : 5;   {{ccomment| 5 Bits (4..8) }}&lt;br /&gt;
         unsigned bit_9_21 : 13; {{ccomment| 13 Bits (9..21) }}&lt;br /&gt;
         unsigned bit_22_31: 10; {{ccomment| 10 Bits (22..31) }}&lt;br /&gt;
     };&lt;br /&gt;
 &lt;br /&gt;
     foo_t foo; {{ccomment| 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.byte[2] = 12;          {{ccomment| setzt byte 2 auf 12 }}&lt;br /&gt;
     data.bit_4_8 = 0x1f;        {{ccomment| setzt bits 4..8 (5 Stück) alle auf 1 }}&lt;br /&gt;
 &lt;br /&gt;
     int anInt = data.foo.anInt; {{ccomment| liest ein Feld von foo (hier ein int) }}&lt;br /&gt;
     ...&lt;br /&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;
&lt;br /&gt;
 {{ccomment| 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;
 {{ccomment| 5 Ziffern (0...65535) und evtl. noch eine führende 0 }}&lt;br /&gt;
 #define DIGITS 6&lt;br /&gt;
 &lt;br /&gt;
 {{ccomment| +1 wegen String-Ende (wird im Startup auf 0 gesetzt) }}&lt;br /&gt;
 char string[DIGITS+1];&lt;br /&gt;
 &lt;br /&gt;
 {{ccomment| Wandelt zahl in Dezimaldarstellung um. }}&lt;br /&gt;
 {{ccomment| Der return-Wert zeigt irgendwo ins string[]-Array. }}&lt;br /&gt;
 {{ccomment| string[] wird verändert. }}&lt;br /&gt;
 char* toString (unsigned short zahl)&lt;br /&gt;
 {&lt;br /&gt;
     {{ccomment| s zeigt auf das Ende von string }}&lt;br /&gt;
     {{ccomment| string wird von hinten nach vorne gefüllt }}&lt;br /&gt;
     char *s = string + DIGITS;&lt;br /&gt;
  &lt;br /&gt;
     {{ccomment| 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;
         {{ccomment| Division mit Rest durch 10 }}&lt;br /&gt;
         {{ccomment| quot: Ergebnis für den nächsten Durchlauf }}&lt;br /&gt;
         {{ccomment| rem: Rest ist die Ziffer im 10er-System }}&lt;br /&gt;
         qrem = udiv (qrem.quot, 10);&lt;br /&gt;
  &lt;br /&gt;
         {{ccomment| 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;
     {{ccomment| Falls eine führende '0' gespeichert wurde: weg damit }}&lt;br /&gt;
     {{ccomment| 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;
&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;amp;lt;= num &amp;amp;lt; 100&amp;lt;/tt&amp;gt; nach [[BCD]]&lt;br /&gt;
&lt;br /&gt;
 typedef struct&lt;br /&gt;
 {&lt;br /&gt;
     unsigned char quot; {{ccomment| Quotient }}&lt;br /&gt;
     unsigned char rem;  {{ccomment| 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;
 {{ccomment| Wandelt num nach BCD um, 0 &amp;lt;&amp;amp;#61; num &amp;lt;&amp;amp;#61; 99 }}&lt;br /&gt;
 {{ccomment| return-Wert ist dann 0x0 &amp;lt;&amp;amp;#61; return &amp;lt;&amp;amp;#61; 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;
&lt;br /&gt;
===Division durch Multiplikation===&lt;br /&gt;
===Vermeiden von float und double===&lt;br /&gt;
&lt;br /&gt;
=Inkompatibilität=&lt;br /&gt;
&lt;br /&gt;
[[GCC]] &amp;amp;ndash; und somit auch avr-gcc &amp;amp;ndash; werden ständig weiter entwickelt. Dies betrifft das Beheben von Fehlern, die Unterstützung neuer Architekturen/Sprachen/Betriebssysteme, Implementierung neuer Optimierungsalgorithmen, Vereinheitlichungen, etc.&lt;br /&gt;
&lt;br /&gt;
Leider führt dies auch zu Inkompatibilitäten verschiedener avr-gcc-Versionen untereinander, und eine C-Quelle, die mit einer Version von avr-gcc fehler- und warnungsfrei übersetzt werden kann, ist mit einer anderen Version möglicherweise nicht compilierbar.&lt;br /&gt;
&lt;br /&gt;
Die avr-gcc Version kann man anzeigen lassen, indem man in einer Shell/Eingabeaufforderung eintippt&lt;br /&gt;
 avr-gcc -v&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;tt&amp;gt;#include &amp;lt;avr/signal.h&amp;gt;&amp;lt;/tt&amp;gt;: In Versionen bis 3.4.4 werden in dieser Header-Datei u.a. die Makros &amp;lt;tt&amp;gt;SIGNAL()&amp;lt;/tt&amp;gt; und &amp;lt;tt&amp;gt;INTERRUPT()&amp;lt;/tt&amp;gt; definiert, die man braucht, wenn man eine C-Funktion als Interrupt-Routine ([[ISR]]) kennzeichnen will. In neueren Versionen ab 3.4.5 sind diese Definitionen in den Header &amp;lt;tt&amp;gt;avr/interrupt.h&amp;lt;/tt&amp;gt; gewandert, wo auch Makros wie &amp;lt;tt&amp;gt;sei()&amp;lt;/tt&amp;gt; und &amp;lt;tt&amp;gt;cli()&amp;lt;/tt&amp;gt; definiert werden. Die Inkludierung von &amp;lt;tt&amp;gt;avr/signal.h&amp;lt;/tt&amp;gt; in den neueren avg-gcc Versionen führt zu einer Warnung, irgendwann vielleicht sogar zu einem Fehler, weil die Datei nicht mehr bei avr-gcc dabei ist und daher nicht mehr gefunden wird.&lt;br /&gt;
: '''Verwendet man bei einer älteren avr-gcc-Version &amp;lt;tt&amp;gt;SIGNAL&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;INTERRUPT&amp;lt;/tt&amp;gt; ohne &amp;lt;tt&amp;gt;avr/signal.h&amp;lt;/tt&amp;gt; zu includen, wird u.U. stillschweigend falscher Code erzeugt.'''&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;tt&amp;gt;#include &amp;lt;util/...h&amp;gt;&amp;lt;/tt&amp;gt;: In &amp;lt;tt&amp;gt;util&amp;lt;/tt&amp;gt; stehen jetzt Header wie &amp;lt;tt&amp;gt;util/parity.h&amp;lt;/tt&amp;gt; oder das vielverwendete &amp;lt;tt&amp;gt;util/delay.h&amp;lt;/tt&amp;gt;, die vormals im Include-Unterverzeichnis &amp;lt;tt&amp;gt;avr&amp;lt;/tt&amp;gt; zu finden waren.&lt;br /&gt;
&lt;br /&gt;
;Interrupt Service Routinen: Auch die API zur Definition von [[ISR]]s hat sich von avr-gcc Version 3.x zur Version 4.x geändert:&lt;br /&gt;
:'''avr-gcc 3.x'''&lt;br /&gt;
::{|&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SIGNAL (SIG_INTERRUPT0)&lt;br /&gt;
{&lt;br /&gt;
    /* Interrupt Code */&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
INTERRUPT (SIG_OVERFLOW0)&lt;br /&gt;
{&lt;br /&gt;
    /* Interrupt Code */&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
:'''avr-gcc 4.x'''&lt;br /&gt;
::{|&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ISR (INT0_vect)&lt;br /&gt;
{&lt;br /&gt;
    /* Interrupt Code */&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void TIMER0_OVF_vect (void) __attribute__((interrupt));&lt;br /&gt;
void TIMER0_OVF_vect (void)&lt;br /&gt;
{&lt;br /&gt;
    /* Interrupt Code */&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;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;
&lt;br /&gt;
:'''Workaround''' (hier für eine ISR):&lt;br /&gt;
:{|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
 #include &amp;lt;stdarg.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;avr/interrupt.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 {{ccomment|The return address}}&lt;br /&gt;
 unsigned short volatile return_addr;&lt;br /&gt;
 &lt;br /&gt;
 {{ccomment|Define our special SIGNAL (INTERRUPT analoguous)}}&lt;br /&gt;
 #define SIGNAL_BRA(signame,var)                                         \&lt;br /&gt;
      void signame (unsigned short var, ...) __attribute__ ((signal));   \&lt;br /&gt;
      void signame (unsigned short var, ...)&lt;br /&gt;
 &lt;br /&gt;
 #define SWAP_BYTES(x) (((x) &amp;gt;&amp;gt; 8) | ((x) &amp;lt;&amp;lt; 8))&lt;br /&gt;
 &lt;br /&gt;
 SIGNAL_BRA (SIG_OUTPUT_COMPARE1A, dummy)&lt;br /&gt;
 {&lt;br /&gt;
    {&lt;br /&gt;
       va_list vlist;&lt;br /&gt;
       va_start (vlist, dummy);&lt;br /&gt;
  &lt;br /&gt;
       {{ccomment|Get the return address from the stack}}&lt;br /&gt;
       dummy = va_arg (vlist, unsigned short);&lt;br /&gt;
 &lt;br /&gt;
       {{ccomment|Convert stack address to code location}}&lt;br /&gt;
       addr = SWAP_BYTES(dummy) &amp;lt;&amp;lt; 1;&lt;br /&gt;
       va_end (vlist);&lt;br /&gt;
    }&lt;br /&gt;
    {{ccomment|ISR Code}}&lt;br /&gt;
 }&lt;br /&gt;
|}&lt;br /&gt;
;gcc 4.x: In der 4er-Version gab es tiefgreifende interne Änderungen im Compiler; er ist noch instabil und kann momentan nicht für den Produktiv-Einsatz empfohlen werden (Stand 02/2006). &lt;br /&gt;
&lt;br /&gt;
:Die Auswirkungen der Optimierungen auf das Zielsystem &amp;lt;tt&amp;gt;avr&amp;lt;/tt&amp;gt; bleibt abzuwarten, dürfte aber nicht wesentlich sein. Die neue 4-er Version wurde u.a. deshalb aufgelegt, um mit dem Intel-Compiler gleichzuziehen &amp;amp;ndash; also im Hinblick auf das Zielsystem &amp;lt;tt&amp;gt;i386&amp;lt;/tt&amp;gt;) gemacht. &lt;br /&gt;
&lt;br /&gt;
:Auch nach dem Release der 4-er Version wird die 3-er Version weiterentwickelt, da erst nach 1-2 Jahren nach Release einer neuer Major-Version ein Umstieg anzuraten ist und auch erst dann getätigt wird (zumindest im professionellen Bereich).&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]]: [[Interrupt|'''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;
* [[C-Tutorial]]&lt;br /&gt;
'''Code-Beispiele'''&lt;br /&gt;
* [[Hallo Welt für AVR (LED blinken)]] - ein erstes Beispiel für avr-gcc&lt;br /&gt;
*[[:Kategorie:Quellcode_C|C-Codebeispiele]]&lt;br /&gt;
* [[Fallstricke bei der C-Programmierung]]&lt;br /&gt;
&lt;br /&gt;
'''Details'''&lt;br /&gt;
* [[Inline-Assembler in avr-gcc|Inline-Assembler]]&lt;br /&gt;
* [[avr-gcc/Interna|Interna von avr-gcc]]&lt;br /&gt;
&lt;br /&gt;
'''Installation (Linux)'''&lt;br /&gt;
* [[avr-gcc und avrdude installieren]]&lt;br /&gt;
'''Sonstiges'''&lt;br /&gt;
* [[WinAVR]]&lt;br /&gt;
* [[Speicherverbrauch bestimmen mit avr-gcc]]&lt;br /&gt;
* [[Compiler]]&lt;br /&gt;
* [[Dev-Cpp IDE]]&lt;br /&gt;
* [[AVR]]&lt;br /&gt;
----&lt;br /&gt;
* [[Sourcevergleich]]&lt;br /&gt;
* [[Codevergleich AVR-Compiler]]&lt;br /&gt;
&lt;br /&gt;
=Weblinks=&lt;br /&gt;
==Dokumentation==&lt;br /&gt;
* [http://gcc.gnu.org/onlinedocs/ GCC online documentation (en)] Offline findest du die Doku für gcc, cpp (Präprozessor) und avr-libc bei [[WinAVR]] in&lt;br /&gt;
:&amp;lt;pre&amp;gt;&amp;lt;GCC_HOME&amp;gt;/doc/gcc/&amp;lt;/pre&amp;gt;&lt;br /&gt;
: bzw.&lt;br /&gt;
:&amp;lt;pre&amp;gt;&amp;lt;GCC_HOME&amp;gt;/doc/avr-libc/&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Online finden sich die Dokumente in&lt;br /&gt;
* [http://gcc.gnu.org/onlinedocs/gcc.pdf gcc.pdf (1900 kByte)] - Dokumentation des C/C++/Java-Compilers GCC (en)&lt;br /&gt;
* [http://gcc.gnu.org/onlinedocs/cpp.pdf cpp.pdf (470 kByte)] - Dokumentation des C-Präprozessors (en)&lt;br /&gt;
* [http://www.nongnu.org/avr-libc/user-manual/modules.html http://www.nongnu.org/avr-libc/user-manual] - Dokumentation zur avr-libc.&lt;br /&gt;
&lt;br /&gt;
== Downloads==&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;
== Tipps, Installation ==&lt;br /&gt;
*[http://www.nongnu.org/avr-libc/user-manual/install_tools.html ''&amp;quot;Installing the GNU Tool Chain&amp;quot;''] Hilfe zum Build und Installation von GCC, binutils, etc unter Linux&lt;br /&gt;
* Im GCC-Handbuch, siehe [[#Dokumentation|Dokumentation]].&lt;br /&gt;
* [http://www.linuxfocus.org/Deutsch/November2004/article352.shtml www.linuxfocus.org (Artikel)] - Tipps zu Build und Installation von avr-gcc, binutils und avr-libc unter Linux&lt;br /&gt;
* [http://users.rcn.com/rneswold/avr/ Rich Neswold: ''A GNU Development Environment for the AVR Microcontroller'']&lt;br /&gt;
* [http://www.mikrocontroller.net/topic/24166 www.mikrocontroller.net (Foren-Beitrag)] - Installation von GCC und Toolchain unter Mac OS X&lt;br /&gt;
* [http://www.roboternetz.de/phpBB2/zeigebeitrag.php?p=125603#125603 www.roboternetz.de (Foren-Beitrag)] ''avrgcc + avrdude installieren''&lt;br /&gt;
&lt;br /&gt;
== Sonstiges ==&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://www.mikrocontroller.net/articles/AVR-GCC-Tutorial avr-gcc-Tutorial auf mikrocontroller.net]&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;
=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>Heigro</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=Hallo_Welt_f%C3%BCr_AVR_(LED_blinken)&amp;diff=9739</id>
		<title>Hallo Welt für AVR (LED blinken)</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=Hallo_Welt_f%C3%BCr_AVR_(LED_blinken)&amp;diff=9739"/>
				<updated>2006-11-28T21:05:19Z</updated>
		
		<summary type="html">&lt;p&gt;Heigro: Typo&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Das erste C-Programm, das man zu sehen bekommt, ist für die meisten das &amp;quot;Hallo Welt&amp;quot;.&lt;br /&gt;
Bei &amp;quot;Hallo Welt&amp;quot; geht es weniger um die Funktionalität an sich, sondern darum zu lernen,&lt;br /&gt;
wie man überhaupt ein Programm übersetzt und einen Compiler verwendet.&lt;br /&gt;
&lt;br /&gt;
Was für den PC das &amp;quot;Hallo Welt&amp;quot;, ist für einen kleinen Microcontroller der &amp;quot;Hallo Blinky&amp;quot;,&lt;br /&gt;
der einfach nur eine [[Diode|Leuchtdiode]] (LED) blinken lässt.&lt;br /&gt;
&lt;br /&gt;
Im Vergleich zu &amp;quot;Hallo Welt&amp;quot; sieht der Blinky viel komplizierter aus, &lt;br /&gt;
aber eigentlich ist er einfacher, dann es werden keine umfangreichen Funktionen oder&lt;br /&gt;
Black-Boxen benutzt wie etwa &amp;lt;tt&amp;gt;printf()&amp;lt;/tt&amp;gt;. &lt;br /&gt;
Ausser dem eingegebenen Quellcode kommt also kein anderer Code zur Ausführung!&lt;br /&gt;
&lt;br /&gt;
{{FarbigerRahmen|&lt;br /&gt;
Bitte beachte auch die Hinweise zu [[avr-gcc#Inkompatibilität|Inkompatibilitäten von avr-gcc]]!&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=Beschreibung=&lt;br /&gt;
&lt;br /&gt;
Eine [[LED]] an Port B1 wird einmal pro Sekunde an bzw. ausgeschaltet. Die LED blinkt also mit einer Frequenz von 1/2 Hz.&lt;br /&gt;
&lt;br /&gt;
Im Programm wird der Wert für das OCR1A-Register aus der Taktfrequenz des&lt;br /&gt;
Controllers (&amp;lt;tt&amp;gt;F_CPU&amp;lt;/tt&amp;gt;) und der Anzahl an Interrupts, die pro Sekunde&lt;br /&gt;
ausgelöst werden sollen (&amp;lt;tt&amp;gt;IRQS_PER_SECOND&amp;lt;/tt&amp;gt;), berechnet.&lt;br /&gt;
&lt;br /&gt;
Standardmässig sind [[AVR|AVRs]] mit dem internen RC-Oszillator mit ca. 1&amp;amp;nbsp;MHz getaktet.&lt;br /&gt;
Daher wird &amp;lt;tt&amp;gt;F_CPU&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;blinky.c&amp;lt;/tt&amp;gt; zu 1000000 definiert:&lt;br /&gt;
 #define F_CPU 1000000&lt;br /&gt;
{{FarbigerRahmen|&lt;br /&gt;
Dieser Wert hat rein informativen Charakter und bewirkt ''nicht'', daß der Controller mit einer anderen Frequenz läuft! Das geht über einen anderen Quarz/Oszillator oder andere Fuse-Einstellungen.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Das Programm ist ausgelegt für eine Taktrate von 1&amp;amp;nbsp;MHz. Wenn dein [[Controller]] mit einem anderen Takt läuft, dann hast du zwei Möglichkeiten:&lt;br /&gt;
* Du lässt das Programm so, wie es ist. Dann blinkt die LED entsprechend schneller bzw. langsamer. Hast du deinen AVR zB mit 16&amp;amp;nbsp;MHz getaktet, dann blinkt die LED mit 8&amp;amp;nbsp;Hz.&lt;br /&gt;
* Du passt die Taktfrequenz in der Quelle oder per Kommandozeile an. Für 8 MHz:&lt;br /&gt;
:&amp;lt;pre&amp;gt; &amp;gt; avr-gcc ... -DF_CPU=8000000&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Quellcode=&lt;br /&gt;
Der Quellcode ist für die Version 3.x von [[avr-gcc]]. 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/2005).&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;
 {{ccomment|Geblinkt wird PortB.1 (push-pull)}}&lt;br /&gt;
 {{ccomment|Eine LED in Reihe mit einem Vorwiderstand zwischen}}&lt;br /&gt;
 {{ccomment|PortB.1 und GND anschliessen.}}&lt;br /&gt;
 #define PAD_LED  1&lt;br /&gt;
 #define PORT_LED PORTB&lt;br /&gt;
 #define DDR_LED  DDRB&lt;br /&gt;
 &lt;br /&gt;
 {{ccomment|Der MCU-Takt. Wird gebraucht, um Timer1 mit den richtigen}}&lt;br /&gt;
 {{ccomment|Werten zu initialisieren. Voreinstellung ist 1MHz.}}&lt;br /&gt;
 {{ccomment|(Werkseinstellung für AVRs mit internem Oszillator).}}&lt;br /&gt;
 {{ccomment|Das Define wird nur gemacht, wenn F_CPU noch nicht definiert wurde.}}&lt;br /&gt;
 {{ccomment|F_CPU kann man so auch per Kommandozeile definieren, z.B. für 8MHz:}}&lt;br /&gt;
 {{ccomment|avr-gcc ... -DF_CPU&amp;amp;#61;8000000}}&lt;br /&gt;
 {{ccomment| &amp;amp;nbsp;}}&lt;br /&gt;
 {{ccomment|! Der Wert von F_CPU hat rein informativen Character für}}&lt;br /&gt;
 {{ccomment|! die korrekte Codeerzeugung im Programm!}}&lt;br /&gt;
 {{ccomment|! Um die Taktrate zu ändern müssen die Fuses des Controllers}}&lt;br /&gt;
 {{ccomment|! und/oder Quarz/Resonator/RC-Glied/Oszillator}}&lt;br /&gt;
 {{ccomment|! angepasst werden!}}&lt;br /&gt;
 #ifndef F_CPU&lt;br /&gt;
 #define F_CPU    1000000&lt;br /&gt;
 #endif&lt;br /&gt;
 &lt;br /&gt;
 {{ccomment|So viele IRQs werden jede Sekunde ausgelöst.}}&lt;br /&gt;
 {{ccomment|Für optimale Genauigkeit muss}}&lt;br /&gt;
 {{ccomment|IRQS_PER_SECOND ein Teiler von F_CPU sein}}&lt;br /&gt;
 {{ccomment|und IRQS_PER_SECOND ein Vielfaches von 100.}}&lt;br /&gt;
 {{ccomment|Ausserdem muss gelten F_CPU / IRQS_PER_SECOND &amp;lt;&amp;amp;#61; 65536}}&lt;br /&gt;
 #define IRQS_PER_SECOND   2000 {{comment|500 µs}}&lt;br /&gt;
 &lt;br /&gt;
 {{ccomment|Anzahl IRQs pro 10 Millisekunden}}&lt;br /&gt;
 #define IRQS_PER_10MS     (IRQS_PER_SECOND / 100)&lt;br /&gt;
 &lt;br /&gt;
 {{ccomment|Gültigkeitsprüfung.}}&lt;br /&gt;
 {{ccomment|Bei ungeeigneten Werten gibt es einen Compilerfehler}}&lt;br /&gt;
 #if (F_CPU/IRQS_PER_SECOND &amp;gt; 65536) || (IRQS_PER_10MS &amp;lt; 1) || (IRQS_PER_10MS &amp;gt; 255)&lt;br /&gt;
 #   error Diese Werte fuer F_CPU und IRQS_PER_SECOND&lt;br /&gt;
 #   error sind ausserhalb des gueltigen Bereichs!&lt;br /&gt;
 #endif&lt;br /&gt;
 &lt;br /&gt;
 {{ccomment|Compiler-Warnung falls die Genauigkeit nicht optimal ist.}}&lt;br /&gt;
 {{ccomment|Wenn das nervt für deine Werte, einfach löschen :-)}}&lt;br /&gt;
 #if (F_CPU % IRQS_PER_SECOND != 0) || (IRQS_PER_SECOND % 100 != 0)&lt;br /&gt;
 #   warning Das Programm arbeitet nicht mit optimaler Genauigkeit.&lt;br /&gt;
 #endif&lt;br /&gt;
 &lt;br /&gt;
 {{ccomment|Prototypen}}&lt;br /&gt;
 void wait_10ms (const uint8_t);&lt;br /&gt;
 void timer1_init();&lt;br /&gt;
 &lt;br /&gt;
 {{ccomment|Zähler-Variable. Wird in der ISR erniedrigt und in wait_10ms benutzt.}}&lt;br /&gt;
 static volatile uint8_t timer_10ms;&lt;br /&gt;
 &lt;br /&gt;
 {{ccomment|//////////////////////////////////////////////////////////////////////}}&lt;br /&gt;
 {{ccomment|Implementierungen der Funktionen}}&lt;br /&gt;
 {{ccomment|//////////////////////////////////////////////////////////////////////}}&lt;br /&gt;
 &lt;br /&gt;
 #if !defined (TCNT1H)&lt;br /&gt;
 #error Dieser Controller hat keinen 16-Bit Timer1!&lt;br /&gt;
 #endif {{ccomment|TCNT1H}}&lt;br /&gt;
 &lt;br /&gt;
 {{ccomment|//////////////////////////////////////////////////////////////////////}}&lt;br /&gt;
 {{ccomment|Timer1 so initialisieren, daß er IRQS_PER_SECOND }}&lt;br /&gt;
 {{ccomment|IRQs pro Sekunde erzeugt.}}&lt;br /&gt;
 void timer1_init()&lt;br /&gt;
 {&lt;br /&gt;
     {{ccomment|Timer1: keine PWM}}&lt;br /&gt;
     TCCR1A = 0;&lt;br /&gt;
 &lt;br /&gt;
     {{ccomment|Timer1 ist Zähler: Clear Timer on Compare Match (CTC, Mode #4)}}&lt;br /&gt;
     {{ccomment|Timer1 läuft mit vollem MCU-Takt: Prescale &amp;amp;#61; 1}}&lt;br /&gt;
 #if defined (CTC1) &amp;amp;&amp;amp; !defined (WGM12)&lt;br /&gt;
    TCCR1B = (1 &amp;lt;&amp;lt; CTC1)  | (1 &amp;lt;&amp;lt; CS10);&lt;br /&gt;
 #elif !defined (CTC1) &amp;amp;&amp;amp; defined (WGM12)&lt;br /&gt;
    TCCR1B = (1 &amp;lt;&amp;lt; WGM12) | (1 &amp;lt;&amp;lt; CS10);&lt;br /&gt;
 #else&lt;br /&gt;
 #error Keine Ahnung, wie Timer1 fuer diesen AVR zu initialisieren ist!&lt;br /&gt;
 #endif&lt;br /&gt;
 &lt;br /&gt;
     {{ccomment|OutputCompare für gewünschte Timer1 Frequenz}}&lt;br /&gt;
     {{ccomment|TCNT1 zählt immer 0...OCR1A, 0...OCR1A, ... }}&lt;br /&gt;
     {{ccomment|Beim überlauf OCR1A -&amp;gt; OCR1A+1 wird TCNT1&amp;amp;#61;0 gesetzt und im nächsten}}&lt;br /&gt;
     {{ccomment|MCU-Takt eine IRQ erzeugt.}}&lt;br /&gt;
     OCR1A = (unsigned short) ((unsigned long) F_CPU / IRQS_PER_SECOND-1);&lt;br /&gt;
 &lt;br /&gt;
     {{ccomment|OutputCompareA-Interrupt für Timer1 aktivieren}}&lt;br /&gt;
 #if defined (TIMSK1)&lt;br /&gt;
     TIMSK1 |= (1 &amp;lt;&amp;lt; OCIE1A);&lt;br /&gt;
 #elif defined (TIMSK)&lt;br /&gt;
     TIMSK  |= (1 &amp;lt;&amp;lt; OCIE1A);&lt;br /&gt;
 #else	 &lt;br /&gt;
 #error Keine Ahnung, wie IRQs fuer diesen AVR zu initialisieren sind!&lt;br /&gt;
 #endif&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 {{ccomment|//////////////////////////////////////////////////////////////////////}}&lt;br /&gt;
 {{ccomment|Wartet etwa t*10 ms. }}&lt;br /&gt;
 {{ccomment|timer_10ms wird alle 10ms in der Timer1-ISR erniedrigt. }}&lt;br /&gt;
 {{ccomment|Weil es bis zum nächsten IRQ nicht länger als 10ms dauert,}}&lt;br /&gt;
 {{ccomment|wartet diese Funktion zwischen (t-1)*10 ms und t*10 ms.}}&lt;br /&gt;
 void wait_10ms (const uint8_t t)&lt;br /&gt;
 {&lt;br /&gt;
     timer_10ms = t;&lt;br /&gt;
     while (timer_10ms);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 {{ccomment|//////////////////////////////////////////////////////////////////////}}&lt;br /&gt;
 {{ccomment|Die Interrupt Service Routine (ISR).}}&lt;br /&gt;
 {{ccomment|In interrupt_num_10ms werden die IRQs gezählt.}}&lt;br /&gt;
 {{ccomment|Sind IRQS_PER_10MS Interrups geschehen, }}&lt;br /&gt;
 {{ccomment|dann sind 10 ms vergangen.}}&lt;br /&gt;
 {{ccomment|timer_10ms wird alle 10 ms um 1 vermindert und bleibt bei 0 stehen.}}&lt;br /&gt;
 SIGNAL (SIG_OUTPUT_COMPARE1A)&lt;br /&gt;
 {&lt;br /&gt;
     static uint8_t interrupt_num_10ms;&lt;br /&gt;
 &lt;br /&gt;
     {{ccomment|interrupt_num_10ms erhöhen und mit Maximalwert vergleichen}}&lt;br /&gt;
     if (++interrupt_num_10ms == IRQS_PER_10MS)&lt;br /&gt;
     {&lt;br /&gt;
         {{ccomment|10 Millisekunden sind vorbei}}&lt;br /&gt;
         {{ccomment|interrupt_num_10ms zurücksetzen}}&lt;br /&gt;
         interrupt_num_10ms = 0;&lt;br /&gt;
 &lt;br /&gt;
         {{ccomment|Alle 10ms wird timer_10ms erniedrigt, falls es nicht schon 0 ist.}}&lt;br /&gt;
         {{ccomment|Wird verwendet in wait_10ms}}&lt;br /&gt;
         if (timer_10ms != 0)&lt;br /&gt;
             timer_10ms--;&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 {{ccomment|//////////////////////////////////////////////////////////////////////}}&lt;br /&gt;
 {{ccomment|Das Hauptprogramm: Startpunkt }}&lt;br /&gt;
 int main()&lt;br /&gt;
 {&lt;br /&gt;
     {{ccomment|LED-Port auf OUT}}&lt;br /&gt;
     DDR_LED  |= (1 &amp;lt;&amp;lt; PAD_LED);&lt;br /&gt;
 &lt;br /&gt;
     {{ccomment|Timer1 initialisieren}}&lt;br /&gt;
     timer1_init();&lt;br /&gt;
 &lt;br /&gt;
     {{ccomment|Interrupts aktivieren}}&lt;br /&gt;
     sei();&lt;br /&gt;
 &lt;br /&gt;
     {{ccomment|Endlosschleife}}&lt;br /&gt;
     {{ccomment|Die LED ist jeweils 1 Sekunde an und 1 Sekunde aus,}}&lt;br /&gt;
     {{ccomment|blinkt also mit einer Frequenz von 0.5 Hz}}&lt;br /&gt;
     while (1)&lt;br /&gt;
     {&lt;br /&gt;
         {{ccomment|LED an}}&lt;br /&gt;
         PORT_LED |= (1 &amp;lt;&amp;lt; PAD_LED);&lt;br /&gt;
 &lt;br /&gt;
         {{ccomment|1 Sekunde warten}}&lt;br /&gt;
         wait_10ms (100);&lt;br /&gt;
 &lt;br /&gt;
         {{ccomment|LED aus}}&lt;br /&gt;
         PORT_LED &amp;amp;= ~(1 &amp;lt;&amp;lt; PAD_LED);&lt;br /&gt;
 &lt;br /&gt;
         {{ccomment|1 Sekunde warten}}&lt;br /&gt;
         wait_10ms (100);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     {{ccomment|main braucht keine return-Anweisung, weil wir nie hier hin kommen}}&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=Von der C-Quelle zum hex-File=&lt;br /&gt;
&lt;br /&gt;
Das Übersetzen über Kommandozeilen-Eingaben erledigt und ''nicht''&lt;br /&gt;
über Werkzeuge wie [[make]], &lt;br /&gt;
das die Zusammenhänge eher verschleiert als erhellt,&lt;br /&gt;
und dessen inkorrekte Anwendung eine häufige Fehlerquelle ist.&lt;br /&gt;
&lt;br /&gt;
Nach Speichern der Quelldatein in ein eigenes Verzeichnis enthält dieses die Datei&lt;br /&gt;
 blinky.c&lt;br /&gt;
&lt;br /&gt;
==Compilieren==&lt;br /&gt;
&lt;br /&gt;
Zunächst wird die C-Dateie übersetzt. &lt;br /&gt;
Der Übersetzungsvorgang wird gesteuert durch Kommandozeilen-Parameter (siehe [[avr-gcc]]).&lt;br /&gt;
Die Option &lt;br /&gt;
;&amp;lt;tt&amp;gt;-c&amp;lt;/tt&amp;gt;: legt fest, daß nur compiliert wird (und nicht gelinkt), &lt;br /&gt;
;&amp;lt;tt&amp;gt;-o name&amp;lt;/tt&amp;gt;: gibt den Name der Ausgabedatei an. Ohne diese Option heisst die Ausgabedatei immer &amp;lt;tt&amp;gt;a.out&amp;lt;/tt&amp;gt;&lt;br /&gt;
;&amp;lt;tt&amp;gt;-mmcu=atmega8&amp;lt;/tt&amp;gt;: legt den Controllertyp fest, in dem Beispiel den [[ATmega8]]&lt;br /&gt;
;&amp;lt;tt&amp;gt;-g&amp;lt;/tt&amp;gt;: erzeugt Debug-Infos und&lt;br /&gt;
;&amp;lt;tt&amp;gt;-Os&amp;lt;/tt&amp;gt;: optimiert auf Codegröße.&lt;br /&gt;
;&amp;lt;tt&amp;gt;-DF_CPU=xxx&amp;lt;/tt&amp;gt;: optional, falls der Controller nicht mit 1 MHz läuft. &amp;lt;tt&amp;gt;xxx&amp;lt;/tt&amp;gt; ist die Taktfrequenz in Hertz.&lt;br /&gt;
 &amp;gt; avr-gcc blinky.c -c -o blinky.o -Os -g -mmcu=atmega8&lt;br /&gt;
Danach ist eine neue Datei entstanden (*.o)&lt;br /&gt;
 blinky.c blinky.o&lt;br /&gt;
&lt;br /&gt;
==Linken==&lt;br /&gt;
Die erzeugte Objek-Datei wird nun zur Ausgabedatei (*.elf) gelinkt:&lt;br /&gt;
 &amp;gt; avr-gcc blinky.o -o blinky.elf -mmcu=atmega8&lt;br /&gt;
erzeugt die ausführbare Datei (*.elf), die noch zusätzliche Informationen wie&lt;br /&gt;
Debug-Infos etc. beinhaltet mit dem Namen &amp;lt;tt&amp;gt;blinky.elf&amp;lt;/tt&amp;gt;:&lt;br /&gt;
 blinky.c blinky.elf blinky.o&lt;br /&gt;
&lt;br /&gt;
==Umwandeln nach hex==&lt;br /&gt;
&lt;br /&gt;
===Code und Daten===&lt;br /&gt;
Viele Progger wollen die zu ladende Datei im Intel-hex-Format (*.hex bzw. *.ihex).&lt;br /&gt;
Dazu gibt man an&lt;br /&gt;
 &amp;gt; avr-objcopy -j .text -j .data -O ihex blinky.elf blinky.hex&lt;br /&gt;
Damit enthält die hex-Datei die Sections &amp;lt;tt&amp;gt;.text&amp;lt;/tt&amp;gt; (Programm) und &amp;lt;tt&amp;gt;.data&amp;lt;/tt&amp;gt; (Daten).&lt;br /&gt;
Das Verzeichnis beinhaltet jetzt&lt;br /&gt;
 blinky.c blinky.elf blinky.hex blinky.o&lt;br /&gt;
&lt;br /&gt;
===EEPROM===&lt;br /&gt;
Ein hex-File, das den Inhalt des EEPROMs wiederspiegelt, erhält man mit&lt;br /&gt;
 &amp;gt; avr-objcopy -j .eeprom --change-section-lma .eeprom=0 -O ihex blinky.elf blinky_eeprom.hex&lt;br /&gt;
Für das Beispiel ist das EEPROM-File &amp;lt;tt&amp;gt;blinky_eeprom.hex&amp;lt;/tt&amp;gt; leer, &lt;br /&gt;
da wir keine Daten ins EEPROM gelegt haben.&lt;br /&gt;
&lt;br /&gt;
==Listfile erstellen==&lt;br /&gt;
&lt;br /&gt;
Falls man ein Listfile haben möchte, dann geht das mit&lt;br /&gt;
 &amp;gt; avr-objdump -h -S -j .text -j .data blinky.elf &amp;gt; blinky.lst&lt;br /&gt;
Das Listfile ist eine Textdatei, die alle Assembler-Befehle auflistet,&lt;br /&gt;
wie sie letztendlich auf den Controller geladen werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;avr-objdump&amp;lt;/tt&amp;gt; gibt seine Ausgabe auf das Terminal aus. &lt;br /&gt;
Diese Ausgabe wird mit '&amp;lt;tt&amp;gt;&amp;amp;gt;&amp;lt;/tt&amp;gt;' in die Datei &amp;lt;tt&amp;gt;blinky.lst&amp;lt;/tt&amp;gt; umgeleitet.&lt;br /&gt;
Hier ein Ausschnitt aus dem Listfile:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
00000072 &amp;lt;wait_10ms&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
// //////////////////////////////////////////////////////////////////////&lt;br /&gt;
// Wartet etwa t*10 ms.&lt;br /&gt;
// timer_10ms wird alle 10ms in der Timer1-ISR erniedrigt.&lt;br /&gt;
// Weil es bis zum nächsten IRQ nicht länger als 10ms dauert,&lt;br /&gt;
// wartet diese Funktion zwischen (t-1)*10 ms und t*10 ms.&lt;br /&gt;
void wait_10ms (const uint8_t t)&lt;br /&gt;
{&lt;br /&gt;
    timer_10ms = t;&lt;br /&gt;
  72:	80 93 61 00 	sts	0x0061, r24&lt;br /&gt;
    while (timer_10ms);&lt;br /&gt;
  76:	80 91 61 00 	lds	r24, 0x0061&lt;br /&gt;
  7a:	88 23       	and	r24, r24&lt;br /&gt;
  7c:	e1 f7       	brne	.-8      	; 0x76 &amp;lt;wait_10ms+0x4&amp;gt;&lt;br /&gt;
  7e:	08 95       	ret&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Links stehen die Adressen, dann die Maschinencodes der Befehle,&lt;br /&gt;
danach die Maschinencodes in Assembler-Darstellung. &lt;br /&gt;
Ganz rechts nach dem Kommentarzeichen '&amp;lt;tt&amp;gt;;&amp;lt;/tt&amp;gt;' stehen die Dezimalcodes von&lt;br /&gt;
Konstanten oder die Zieladressen von Sprüngen, wie bei dem &amp;lt;tt&amp;gt;brne&amp;lt;/tt&amp;gt;-Befehl an Adresse 7c, der gegebenenfalls &lt;br /&gt;
8 Bytes zurückspringt und dann an Adresse 76 landet.&lt;br /&gt;
&lt;br /&gt;
==Mapfile erstellen==&lt;br /&gt;
Ein Mapfile gibt Auskunft darüber, an welcher Adresse Code und Objekte&lt;br /&gt;
landen. Erstellt wird das Mapfile während des Linkens, indem &amp;lt;tt&amp;gt;avr-gcc&amp;lt;/tt&amp;gt;&lt;br /&gt;
ein Option an den Linker weiterreicht, die diesem zum Erstellen eines solchen Files veranlasst:&lt;br /&gt;
 &amp;gt; avr-gcc blinky.o -o blinky.elf ... -Wl,-Map,blinky.map&lt;br /&gt;
Dadurch entsteht das Mapfile &amp;lt;tt&amp;gt;blinky.map&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==Die Größe ermitteln==&lt;br /&gt;
&lt;br /&gt;
Die Größe der erhaltenen Objekte/Files können mit &amp;lt;tt&amp;gt;avr-size&amp;lt;/tt&amp;gt; ausgegeben werden.&lt;br /&gt;
 &amp;gt; avr-size -x blinky.o&lt;br /&gt;
druckt aus:&lt;br /&gt;
   text    data     bss     dec     hex filename&lt;br /&gt;
   0x7c     0x0     0x2     126      7e blinky.o&lt;br /&gt;
Das sind die Größen der einzelnen [[avr-gcc/Interna#Sections|Sections]].&lt;br /&gt;
Für das Flash relevant ist die Größe von &lt;br /&gt;
&amp;lt;tt&amp;gt;.text&amp;lt;/tt&amp;gt; (Code) + &amp;lt;tt&amp;gt;.data&amp;lt;/tt&amp;gt; (initialisierte Daten),&lt;br /&gt;
für das SRAM relevent ist &amp;lt;tt&amp;gt;.data&amp;lt;/tt&amp;gt; (initialisierte Daten) &lt;br /&gt;
+ &amp;lt;tt&amp;gt;.bss&amp;lt;/tt&amp;gt; (null-initialisierte Daten).&lt;br /&gt;
&lt;br /&gt;
Im Flash werden also 126+0=126 Bytes belegt, und im SRAM 0+2=2 Bytes.&lt;br /&gt;
&lt;br /&gt;
Ab binutils 2.16 gibt es für &amp;lt;tt&amp;gt;avr-size&amp;lt;/tt&amp;gt; die Option &amp;lt;tt&amp;gt;-C&amp;lt;/tt&amp;gt;, mit der man eine Zusammenfassung des ganzen Programms ausgeben kann:&lt;br /&gt;
 &amp;gt; avr-size -C --mcu=atmega8 blinky.elf&lt;br /&gt;
druckt aus:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AVR Memory Usage&lt;br /&gt;
----------------&lt;br /&gt;
Device: atmega8&lt;br /&gt;
&lt;br /&gt;
Program:     216 bytes (2.6% Full)&lt;br /&gt;
(.text + .data + .bootloader)&lt;br /&gt;
&lt;br /&gt;
Data:          2 bytes (0.2% Full)&lt;br /&gt;
(.data + .bss + .noinit)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Gesamtgrösse ergibt sich erst aus dem elf-File,&lt;br /&gt;
denn auch die Vektortabelle und der Startup-Code belegen Platz. Hier eine Auflistung der beteiligten Sections:&lt;br /&gt;
 &amp;gt; avr-size -x -A blinky.elf&lt;br /&gt;
druckt aus:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
blinky.elf  :&lt;br /&gt;
section            size       addr&lt;br /&gt;
.text              0xd8        0x0&lt;br /&gt;
.data               0x0   0x800060&lt;br /&gt;
.bss                0x2   0x800060&lt;br /&gt;
.noinit             0x0   0x800062&lt;br /&gt;
.eeprom             0x0   0x810000&lt;br /&gt;
.stab             0x36c        0x0&lt;br /&gt;
.stabstr           0x84        0x0&lt;br /&gt;
.debug_aranges     0x14        0x0&lt;br /&gt;
.debug_pubnames    0x48        0x0&lt;br /&gt;
.debug_info        0xfc        0x0&lt;br /&gt;
.debug_abbrev      0xa2        0x0&lt;br /&gt;
.debug_line       0x101        0x0&lt;br /&gt;
.debug_str         0xa6        0x0&lt;br /&gt;
Total             0x86b&amp;lt;/pre&amp;gt;&lt;br /&gt;
Im Flash werden somit 0xd8+0=216 Bytes belegt, also 90 Bytes mehr als das Object benötigt; davon entfallen z.B. schon 38 Bytes auf die Vektortabelle des [[ATmega8]], &lt;br /&gt;
die 2*19 Bytes groß ist. &lt;br /&gt;
&lt;br /&gt;
Die Größen einzelner Funktionen/Variablen lassen sich anzeigen mit&lt;br /&gt;
 &amp;gt; avr-nm --size-sort -S blinky.elf&lt;br /&gt;
was nach Größe sortiert ausdruckt:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
00800060 00000001 b interrupt_num_10ms.0&lt;br /&gt;
00800061 00000001 b timer_10ms&lt;br /&gt;
00000072 0000000e T wait_10ms&lt;br /&gt;
0000005c 00000016 T timer1_init&lt;br /&gt;
000000bc 0000001c T main&lt;br /&gt;
00000080 0000003c T __vector_6&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= HEX-Dateien zu diesem C-Code =&lt;br /&gt;
Zu dieser C-Datei gibt es HEX-Dateien für einige AVRs. Siehe dazu [[HEX Beispiel-Dateien für AVR]].&lt;br /&gt;
=Spin-off=&lt;br /&gt;
&lt;br /&gt;
Eine [[LED]] blinken zu lassen könnte auch wesentlich einfacher implementert werden,&lt;br /&gt;
also z.B. ohne Funktionsaufrufe oder [[Interrupt]]-Programmierung.&lt;br /&gt;
&lt;br /&gt;
Neben der eigentlichen Aufgabe &amp;quot;LED blinken lassen&amp;quot; kann man an dem Code&lt;br /&gt;
aber noch andere Dinge lernen:&lt;br /&gt;
* Programmierung eines Interrupts&lt;br /&gt;
* Initialisierung von Timer1 als Zähler mit &amp;quot;Clear Timer on Compare Match&amp;quot;&lt;br /&gt;
* Bedingte Codeübersetzung/Controllerunterscheidung mit &amp;lt;tt&amp;gt;#ifdef&amp;lt;/tt&amp;gt; (in &amp;lt;tt&amp;gt;timer1_init&amp;lt;/tt&amp;gt;)&lt;br /&gt;
* Abchecken der Gültigkeit von Defines durch den Präprozessor&lt;br /&gt;
&lt;br /&gt;
=Siehe auch=&lt;br /&gt;
* [[HEX Beispiel-Dateien für AVR]] - Aus diesem Quellcode erzeugte Binärdateien zum Download und Proggen.&lt;br /&gt;
* [[AVR]]&lt;br /&gt;
* [[avr-gcc]]&lt;br /&gt;
* [[Interrupt]]&lt;br /&gt;
* [[:Kategorie:Quellcode C|weitere C-Code Beispiele]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Grundlagen]]&lt;br /&gt;
[[Kategorie:Microcontroller]]&lt;br /&gt;
[[Kategorie:Quellcode C]]&lt;br /&gt;
[[Kategorie:Software]]&lt;br /&gt;
[[Kategorie:Praxis]]&lt;/div&gt;</summary>
		<author><name>Heigro</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=Avr-gcc&amp;diff=9665</id>
		<title>Avr-gcc</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=Avr-gcc&amp;diff=9665"/>
				<updated>2006-11-22T18:56:48Z</updated>
		
		<summary type="html">&lt;p&gt;Heigro: Typo&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''avr-gcc''' ist ein freier C-[[Compiler]], mit dem man C-Programme zu ausführbaren Programmen übersetzen kann, die auf [[Microcontroller]]n der [[AVR]]-Familie lauffähig sind. &lt;br /&gt;
An Sprachen versteht avr-gcc sowohl C als auch [[#C%2b%2b|C++]]. &lt;br /&gt;
Neben Standard-C bzw. ANSI-C versteht avr-gcc auch GNU-C, das etwas mehr Möglichkeiten und kleinere Spracherweiterungen bietet.&lt;br /&gt;
&lt;br /&gt;
avr-gcc kann auch dazu verwendet werden, um C/C++ Programme nach Assembler zu übersetzen oder um Bibliotheken zu erstellen, die später in unterschiedlichen Projekten verwendet werden können.&lt;br /&gt;
&lt;br /&gt;
Wie bei allen aus der UNIX-Welt kommenden Programmen ist das Kommando-Interface von avr-gcc die Shell bzw. die Kommandozeile, über die Optionen, Parameter, Einstellungen und die Namen der zu übersetzenden Dateien angegeben werden. &lt;br /&gt;
&lt;br /&gt;
=How to Read=&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel bespricht avr-gcc Version 3.x. Er ist kein C-Tutorial und kein AVR-Handbuch &amp;amp;ndash; das würde den Umfang des Artikels bei weitem sprengen. Es gibt einen Unterartikel, der [[avr-gcc/Interna|Interna von avr-gcc]] zusammenfasst.&lt;br /&gt;
&lt;br /&gt;
Der Artikel ist ein Handbuch zu avr-gcc. Er bespricht zum Beispiel, wie man avr-gcc anwendet und Besonderheiten von avr-gcc-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 avr-gcc compiliert werden kann.&lt;br /&gt;
&lt;br /&gt;
Es gibt ein [[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 avr-gcc ist &amp;amp;ndash; wie für alle Programme, die aus der UNIX-Welt kommen &amp;amp;ndash; die Kommandozeile einer Shell, Console bzw. Eingabeaufforderung. &lt;br /&gt;
&lt;br /&gt;
Im einfachsten Fall sieht ein Aufruf von avr-gcc 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 avr-gcc wurde vom Betriebssystem gefunden und konnte/durfte gestartet werden. Dann gibt avr-gcc 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;
Um eine C-Datei &amp;lt;tt&amp;gt;foo.c&amp;lt;/tt&amp;gt; mir avr-gcc optimiert zu einem lauffähigen elf-Programm &amp;lt;tt&amp;gt;foo.elf&amp;lt;/tt&amp;gt; für einen [[ATmega32]] zu compileren, würde man angeben&lt;br /&gt;
 &amp;gt; avr-gcc -O2 -mmcu=atmega32 foo.c -o foo.elf&lt;br /&gt;
Hat man seine Quellen auf zwei oder mehre Dateien verteilt, geht es analog:&lt;br /&gt;
 &amp;gt; avr-gcc -O2 -mmcu=atmega32 foo.c foo2.c -o foo.elf&lt;br /&gt;
&lt;br /&gt;
Will man nur eine Objekt-Datei erstellen (nur compilieren, nicht linken), dann geht das wie folgt. Das kann günstig sein bei grösseren Projekten, wenn man das Projekt neu erzeugen will, aber nur in einer Quelldatei was geändert hat. Oder wenn das Objekt in einer Bibliothek landen soll.&lt;br /&gt;
 &amp;gt; avr-gcc -O2 -c -mmcu=atmega32 foo.c -o foo.o&lt;br /&gt;
&lt;br /&gt;
Die ausführbare Gesamtdatei &amp;lt;tt&amp;gt;foo_all.elf&amp;lt;/tt&amp;gt; erhält man dann, indem alle Objekte zusammenlinkt:&lt;br /&gt;
 &amp;gt; avr-gcc -mmcu=atmega32 foo.o foo2.o foo3.o -o foo_all.elf&lt;br /&gt;
&lt;br /&gt;
Um die ausführbare Datei in das oft verwendete Intex-HEX-Format umzuwandeln (einmal fürs Programm, einmal für ein Abbild des [[EEPROM]]s) gibt man an:&lt;br /&gt;
 &amp;gt; avr-objcopy -O ihex -j .text -j .data                         foo_all.elf  foo_all.hex&lt;br /&gt;
 &amp;gt; avr-objcopy -O ihex -j .eeprom --change-section-lma .eeprom=0 foo_all.elf  foo_all_eeprom.hex&lt;br /&gt;
&lt;br /&gt;
----&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, avr-gcc per Skript oder [[make]] zu starten&lt;br /&gt;
* avr-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 avr-gcc-Aufruf kann sogar von einem Server-Socket oder einer Web-Application heraus erfolgen, welche ein C-Programm empfängt, es von avr-gcc übersetzen lässt, und das Resultat zurückschickt oder sonst was damit anstellt.&lt;br /&gt;
* Lizenzgründe: eine Umgebung, die avr-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;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Kommandozeilen-Optionen=&lt;br /&gt;
Die Codegenerierung bei avr-gcc 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 und der unterstützten AVR-Derivate&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 [[avr-gcc/Interna#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;-std=c89&amp;lt;br/&amp;gt;-ansi&amp;lt;/tt&amp;gt;: bricht mit einer Fehlermeldung ab, wenn kein ANSI-C (ISO C89) verwendet wurde&lt;br /&gt;
; &amp;lt;tt&amp;gt;-std=c99&amp;lt;/tt&amp;gt;: bricht mit einer Fehlermeldung ab, wenn kein ISO C99 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 (Zielsystem/Controller), für das Code generiert werden soll. Je nach Target muss avr-gcc unterschiedliche Instruktionen verwendet und andere Startup-Dateien (&amp;lt;tt&amp;gt;crtxxx.o&amp;lt;/tt&amp;gt;) einbinden. avr-gcc setzt spezielle Defines, um auch in der Quelle zwischen den Targets unterscheiden zu können, falls das notwendig sein sollte: &lt;br /&gt;
:{| border=&amp;quot;0&amp;quot; cellpadding=&amp;quot;0&amp;quot; cellspacing=&amp;quot;0&amp;quot;&lt;br /&gt;
|&lt;br /&gt;
&amp;lt;pre&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;/pre&amp;gt;&lt;br /&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;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&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;
 void function (size_t num_data)&lt;br /&gt;
 {&lt;br /&gt;
    {{comment|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;
    {{comment|Mach was mit p[0] ... p[num_data-1]}}&lt;br /&gt;
    ...&lt;br /&gt;
 }&lt;br /&gt;
oder mittels eines dynamischen Arrays:&lt;br /&gt;
 void function (size_t num_data)&lt;br /&gt;
 {&lt;br /&gt;
    {{comment|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;
    {{comment|Mach was mit p[0] ... p[num_data-1]}}&lt;br /&gt;
    ...&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=C++=&lt;br /&gt;
&lt;br /&gt;
:''&amp;quot;C++ is a complex language and an evolving one, and its standard definition (the ISO C++ standard) was only recently completed. As a result, your C++ compiler may occasionally surprise you, even when its behavior is correct.&amp;quot;''&lt;br /&gt;
&lt;br /&gt;
Zudem sollte der Einsatz von C++ aus Effizienzgründen 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;
Weiterhin 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 avr-gcc. 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;
 #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;
 #if defined (__cplusplus)&lt;br /&gt;
 extern &amp;quot;C&amp;quot; {&lt;br /&gt;
 #endif {{comment|__cplusplus}}&lt;br /&gt;
 &lt;br /&gt;
 SIGNAL (SIG_NAME)&lt;br /&gt;
 {&lt;br /&gt;
    {{comment|machwas}}&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 INTERRUPT (SIG_NAME)&lt;br /&gt;
 {&lt;br /&gt;
    {{comment|mach was}}&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 #if defined (__cplusplus)&lt;br /&gt;
 }&lt;br /&gt;
 #endif {{comment|__cplusplus}}&lt;br /&gt;
&amp;lt;tt&amp;gt;__cplusplus&amp;lt;/tt&amp;gt; ist ein Standard [[avr-gcc/Interna#Builtin Defines|GCC-Builtin-Define]].&lt;br /&gt;
&lt;br /&gt;
Globale Konstruktoren werden in [[avr-gcc/Interna#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 avr-gcc. Es werden Besonderheiten besprochen, die für avr-gcc zu beachten sind. &lt;br /&gt;
&lt;br /&gt;
Dieser Abschnitt ist ''kein'' [[C-Tutorial|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;
For den Zugriff auf die SFRs gibt es Defines über den Include&lt;br /&gt;
 #include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
Abhängig vom eingestellten Controller werden denn Defines eingebunden, über die auf SFRs wie auf normale Variablen zugegriffen werden kann. Die Namen der Defines sind i.d.R. die gleichen wie im AVR-Manual, also z.b. &amp;lt;tt&amp;gt;SREG&amp;lt;/tt&amp;gt; für das Prozessorstatus-Register SREG:&lt;br /&gt;
 #include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 ...&lt;br /&gt;
   {{ccomment|SREG lesen}}&lt;br /&gt;
   uint8_t sreg = SREG;&lt;br /&gt;
   ...&lt;br /&gt;
   {{ccomment|SREG schreiben}}&lt;br /&gt;
   SREG = sreg;&lt;br /&gt;
&amp;lt;!--  &lt;br /&gt;
Auf SFRs wird generell über deren Adresse zugegriffen:&lt;br /&gt;
 {{ccomment|Liest den Inhalt von SREG an Adresse 0x5f}}&lt;br /&gt;
 unsigned char sreg = *((unsigned char volatile*) 0x5f);&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ß avr-gcc 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;
Die Bezeichner der SFRs sind die gleichen wie im Manual.&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
Für einen Überblick über die eingebundenen Defines und kann ein Blick in den Controller-spezifischen Header hilfreich sein. Dieser befindet sich in&lt;br /&gt;
:&amp;lt;tt&amp;gt; &amp;amp;lt;GCC_HOME&amp;amp;gt;/avr/include/avr/io****.h&amp;lt;/tt&amp;gt;&lt;br /&gt;
z.B. &amp;lt;tt&amp;gt;iom32.h&amp;lt;/tt&amp;gt; für einen [[ATmega32]].&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: avr-gcc 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, wenn Interrupts aktiviert sind. Je nach Programm und welche Aufgaben eine [[ISR]] erledigt, kann dies zu Fehlfunktion führen. In dem Fall müssen diese Code-Stücke atomar gemacht werden, damit sie nicht durch einen [[IRQ]] unterbrochen werden können!&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;
&lt;br /&gt;
Um Bits zu löschen, erzeugt man eine Maske, die an der betreffenden Stelle eine &amp;amp;nbsp;0 hat:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// Ports B_2 als Eingang&lt;br /&gt;
DDRB &amp;amp;= ~(1&amp;amp;lt;&amp;amp;lt;PB2);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&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 Includes und die folgenden Makros.&lt;br /&gt;
&lt;br /&gt;
Bitte beachte auch die Hinweise zu den [[#Inkompatibilität|Inkompatibilität]]en von avr-gcc!&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 avr-gcc 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/interrupt.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 avr-gcc 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;
&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();                     {{ccomment|Interrupts global abschalten}}&lt;br /&gt;
    wdt_enable (WDTO_15MS);    {{ccomment|Watchdog aufziehen auf 15ms}}&lt;br /&gt;
    while (1);                 {{ccomment|warten, bis er zubeisst...}}&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;
 #include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 {{ccomment| status informiert z.B. darüber, ob wir selber den Watchdog ausgelöst haben }}&lt;br /&gt;
 {{ccomment| 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;
     {{ccomment|Wert von MCUSCR merken, möglichst früh im Programm }}&lt;br /&gt;
     unsigned char mcucsr = MCUCSR;&lt;br /&gt;
 &lt;br /&gt;
     {{ccomment|MCUCSR zurücksetzen }}&lt;br /&gt;
     MCUCSR = 0;&lt;br /&gt;
 &lt;br /&gt;
     {{ccomment|Watchdog-Reset }}&lt;br /&gt;
     if (mcuscr &amp;amp; (1 &amp;lt;&amp;lt; WDRF))&lt;br /&gt;
     {&lt;br /&gt;
         {{ccomment|status auswerten }}&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     {{ccomment|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;
     {{ccomment|status auswerten }}&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 ([[avr-gcc/Interna#Sections|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 avr-gcc 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;
&lt;br /&gt;
 void code_init3() __attribute__ ((naked, section (&amp;quot;.init3&amp;quot;)));&lt;br /&gt;
 &lt;br /&gt;
 {{comment|!!! never call this function !!!}}&lt;br /&gt;
 void code_init3 (void)&lt;br /&gt;
 {&lt;br /&gt;
    {{comment|Code}}&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Der Code in den &amp;lt;tt&amp;gt;.init''n''&amp;lt;/tt&amp;gt;-Sections wird sequenziell ausgeführt, daher darf in diese Sections nur der nackte Funktions-Code, ohne Prolog und ohne Epilog (also auch ohne &amp;lt;tt&amp;gt;ret&amp;lt;/tt&amp;gt;-Instruktion!). Da disee nackten Funktionen kein &amp;lt;tt&amp;gt;ret&amp;lt;/tt&amp;gt; haben, dürfen sie nicht explizit aufgerufen werden! Ihr Aufruf erfolgt implizit dadurch, daß ihr Code in einer &amp;lt;tt&amp;gt;init&amp;lt;/tt&amp;gt;-Section steht.&lt;br /&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, avr-gcc 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 in avr-gcc|inline-Assembler]] angezeigt oder die Implementierung in einem eigenen Assembler-Modul, das dazu gelinkt wird. Der erzeugte Code ist im List-File zu überprüfen.&lt;br /&gt;
* Werden mehrere Funktionen in die selbe 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;
Ein Programmbeispiel für Code in einer init-Section ist in &amp;quot;[[Speicherverbrauch bestimmen mit avr-gcc#Dynamischer RAM-Verbrauch|Speicherverbrauch bestimmen mit avr-gcc]]&amp;quot;.&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 avr-gcc 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 sind die Pfade &lt;br /&gt;
 &amp;lt;GCC_HOME&amp;gt;/avr/include                           Standard               (stdio.h, ...)&lt;br /&gt;
 &amp;lt;GCC_HOME&amp;gt;/avr/include/avr                       AVR-spezifisch         (avr/io.h, ...)&lt;br /&gt;
 &amp;lt;GCC_HOME&amp;gt;/lib/gcc/avr/&amp;lt;GCC_VERSION&amp;gt;/include     Standard, compilerabh. (limits.h, ...)&lt;br /&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 den Verzeichnissen stehen Standard-Includes, die benötigt werden, wenn man libc-Funktionen &lt;br /&gt;
oder mathematische Funktionen etc. 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                   Zeichen-Umwandlungs-Makros und ctype Makros&lt;br /&gt;
 errno.h                   Symbolische Namen für Fehlercodes&lt;br /&gt;
 inttypes.h                Definiert [u]intN_t wenn man genau N [un]signed Bits &lt;br /&gt;
                           braucht, ISO C99.&lt;br /&gt;
 math.h                    Mathematische Funktionen: sin, cos, log, gamma, bessel, ...&lt;br /&gt;
 setjmp.h                  libc unterstützt setjmp() und longjmp(), um direkt in eine&lt;br /&gt;
                           andere (nicht-lokale) Funktion zu springen. &lt;br /&gt;
 stdio.h                   Standard I/O-Funktionen (printf, ...).&lt;br /&gt;
 stdlib.h                  Deklariert grundlegende ISO C-Makros und -Funktionen &lt;br /&gt;
                           sowie einige AVR-spezifische Erweiterungen&lt;br /&gt;
 string.h                  Stringoperationen auf NULL-terminierten Strings. (strlen, ...)&lt;br /&gt;
 stdarg.h                  Funktionen mit variabler Argumenanzahl&lt;br /&gt;
 limits.h                  Min- und Max-Werte von Skalaren (UCHAR_MAX, LONG_MIN, ...)&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 die I/O-Header eingebunden, die zum AVR-Modell passen, 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ögerungsschleifen für kurze, exakte Verzögerungen&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;
 &lt;br /&gt;
util/crc16.h          Prüfsumme CRC16&lt;br /&gt;
util/delay.h          Verzögerungsschleifen für kurze, exakte Verzögerungen &lt;br /&gt;
util/parity.h         Parität&lt;br /&gt;
util/twi.h            I2C&lt;br /&gt;
 &lt;br /&gt;
[*]  bei neueren avr-gcc-Versionen in util&lt;br /&gt;
[**] entfällt bei neueren avr-gcc-Versionen. Stattdessen avr/interrupt.h verwenden&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Anwendungs-spezifisch==&lt;br /&gt;
Eigene Header, die nur innerhalb eigener Projekte gebraucht werden, includet man mit&lt;br /&gt;
 #include &amp;quot;...&amp;quot;&lt;br /&gt;
Auch hier darf man Unterverzeichnisse angeben oder ins übergeordnete Verzeichnis:&lt;br /&gt;
 #include &amp;quot;../../mein-zeug.h&amp;quot;&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;
&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;
:''&amp;quot;Unlike most other C compilers, GCC allows you to use -g with -O. The shortcuts taken by optimized code may occasionally produce surprising results: some variables you declared may not exist at all; flow of control may briefly move where you did not expect it; some statements may not be executed because they compute constant results or their values were already at hand; some statements may execute in different places because they were moved out of loops.''&lt;br /&gt;
&lt;br /&gt;
:''Nevertheless it proves possible to debug optimized output. This makes it reasonable to use the optimizer for programs that might have bugs.&amp;quot;''&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;
 #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;
   {{ccomment|String im SRAM mit String im Flash vergleichen}}&lt;br /&gt;
   if (!strcmp_P (str_sram, str_p))&lt;br /&gt;
   {&lt;br /&gt;
       {{ccomment|mach was bei Gleichheit}}&lt;br /&gt;
   }&lt;br /&gt;
 &lt;br /&gt;
   {{ccomment|&amp;quot;foo&amp;quot; wird im RAM angelegt. Ineffizient für konstante Strings!}}  &lt;br /&gt;
   {{ccomment|Beachte, daß damit strcmp (nicht strcmp_P) benutzt werden muss.}}  &lt;br /&gt;
   if (!strcmp (str_sram, &amp;quot;foo&amp;quot;))&lt;br /&gt;
   {&lt;br /&gt;
       {{ccomment|mach was bei Gleichheit}}&lt;br /&gt;
   }&lt;br /&gt;
 &lt;br /&gt;
   {{ccomment|PSTR bewirkt, daß die String-Konstante &amp;quot;foo&amp;quot;}}&lt;br /&gt;
   {{ccomment|im Flash angelegt wird}}&lt;br /&gt;
   if (!strcmp_P (str_sram, PSTR (&amp;quot;foo&amp;quot;))&lt;br /&gt;
   {&lt;br /&gt;
       {{ccomment|mach was bei Gleichheit}}&lt;br /&gt;
   }&lt;br /&gt;
 ...&lt;br /&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;
 #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;
 {{ccomment|Die Kommandostruktur}}&lt;br /&gt;
 typedef struct &lt;br /&gt;
 {&lt;br /&gt;
    int (*func)(int);      {{ccomment|Zeiger auf die auszuführende Funktion}}&lt;br /&gt;
    int arg;               {{ccomment|das Argument, das mitübergeben wird}}&lt;br /&gt;
    char text[1+TEXT_LEN]; {{ccomment|Text, maximal TEXT_LEN Zeichen lang}}&lt;br /&gt;
 } command_t;&lt;br /&gt;
 &lt;br /&gt;
 {{ccomment|Das Array mit den Kommandos.}}&lt;br /&gt;
 {{ccomment|Die funcx sind vom Prototyp (z.B. func1 oben)}}&lt;br /&gt;
 {{ccomment|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;
 {{ccomment|Sucht in commands[] nach text und führt gegebenenfalls}}&lt;br /&gt;
 {{ccomment|die dazugehörige Funktion funcx mit Argument arg aus.}}&lt;br /&gt;
 {{ccomment|Liefert den Rückgabewert von funcx}}&lt;br /&gt;
 {{ccomment|oder -1, falls text nicht gefunden wurde.}}&lt;br /&gt;
 int execute (const char *text)&lt;br /&gt;
 {&lt;br /&gt;
    {{ccomment|Schleifenvariable}}&lt;br /&gt;
    unsigned char i;&lt;br /&gt;
 &lt;br /&gt;
    {{ccomment|Wandert durch das Array mit Kommando-Strukturen}}&lt;br /&gt;
    const command_t * cmd = commands;&lt;br /&gt;
 &lt;br /&gt;
    {{ccomment|sizeof wird von gcc ausgewertet und ist wie eine Konstante,}}&lt;br /&gt;
    {{ccomment|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;
       {{ccomment|Ist das der gesuchte String?}} &lt;br /&gt;
       if (strcmp_P (text, cmd-&amp;gt;text))&lt;br /&gt;
       {&lt;br /&gt;
         {{ccomment|Nein, dann weitersuchen}}&lt;br /&gt;
         cmd++;&lt;br /&gt;
         continue;&lt;br /&gt;
       }&lt;br /&gt;
 &lt;br /&gt;
       {{ccomment|Ja}}&lt;br /&gt;
       int (*func)(int), arg;&lt;br /&gt;
 &lt;br /&gt;
       {{ccomment|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;
       {{ccomment|Funktion ausführen und deren Wert zurückliefern}} &lt;br /&gt;
       return func (arg);&lt;br /&gt;
    }&lt;br /&gt;
 &lt;br /&gt;
    {{ccomment|text ist nicht in commands}}&lt;br /&gt;
    return -1;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Nachteil dabei ist, daß jeder String den maximalen Platz von &amp;lt;tt&amp;gt;TEXT_LEN+1&amp;lt;/tt&amp;gt; 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;
 #include &amp;lt;avr/pgmspace.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 {{ccomment|Die Kommandostruktur}}&lt;br /&gt;
 typedef struct &lt;br /&gt;
 {&lt;br /&gt;
    ...&lt;br /&gt;
    char * text;  {{ccomment|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;
 {{ccomment|Sucht in commands[] nach text und führt gegebenenfalls}}&lt;br /&gt;
 {{ccomment|die dazugehörige Funktion funcx mit Argument arg aus.}}&lt;br /&gt;
 {{ccomment|Liefert den Rückgabewert von funcx}}&lt;br /&gt;
 {{ccomment|oder -1, falls text nicht gefunden wurde.}}&lt;br /&gt;
 int execute (const char *text)&lt;br /&gt;
 {&lt;br /&gt;
    {{ccomment|Schleifenvariable}}&lt;br /&gt;
    unsigned char i;&lt;br /&gt;
 &lt;br /&gt;
    {{ccomment|Wandert durch das Array mit Kommando-Strukturen}}&lt;br /&gt;
    const command_t * cmd = commands;&lt;br /&gt;
 &lt;br /&gt;
    {{ccomment|sizeof wird von gcc ausgewertet und ist wie eine Konstante,}}&lt;br /&gt;
    {{ccomment|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;
       {{ccomment|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;
       {{ccomment|Ist das der gesuchte String?}}        &lt;br /&gt;
       if (strcmp_P (text, text_P))&lt;br /&gt;
       {&lt;br /&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;
&lt;br /&gt;
Oft benötigt wird der Zugriff auf die einzelnen Bytes eines &amp;lt;tt&amp;gt;int&amp;lt;/tt&amp;gt;, also der Zugriff auf die Bytes eines 16-Bit-Wertes:&lt;br /&gt;
&lt;br /&gt;
 typedef union&lt;br /&gt;
 {&lt;br /&gt;
    unsigned char  asByte[2];&lt;br /&gt;
    unsigned short asWord;&lt;br /&gt;
    int            asInt;&lt;br /&gt;
 } data16_t;&lt;br /&gt;
 &lt;br /&gt;
 data16_t data;&lt;br /&gt;
 ...&lt;br /&gt;
    int foo;&lt;br /&gt;
    uint8_t wert;&lt;br /&gt;
 &lt;br /&gt;
    data.asInt = foo;&lt;br /&gt;
    wert = data.asByte[1]; {{ccomment|die oberen 8 Bits von foo}}&lt;br /&gt;
&lt;br /&gt;
Ein komplexeres Beispiel, das noch mehr Datentypen überlagert:&lt;br /&gt;
 typedef ... foo_t;&lt;br /&gt;
 &lt;br /&gt;
 typedef union&lt;br /&gt;
 {&lt;br /&gt;
     unsigned char byte[4];      {{ccomment| Zugriff als Bytes (8 Bit) }}&lt;br /&gt;
     unsigned short word[2];     {{ccomment| Zugriff als Words (16 Bit) }}&lt;br /&gt;
     signed long slong;          {{ccomment| Zugriff als signed long (32 Bit) }}&lt;br /&gt;
 &lt;br /&gt;
     struct {{ccomment| Zugriff auf einzelne Bitgruppen }}&lt;br /&gt;
     {&lt;br /&gt;
         unsigned bit_0_3 : 4;   {{ccomment| 4 Bits (0..3) }}&lt;br /&gt;
         unsigned bit_4_8 : 5;   {{ccomment| 5 Bits (4..8) }}&lt;br /&gt;
         unsigned bit_9_21 : 13; {{ccomment| 13 Bits (9..21) }}&lt;br /&gt;
         unsigned bit_22_31: 10; {{ccomment| 10 Bits (22..31) }}&lt;br /&gt;
     };&lt;br /&gt;
 &lt;br /&gt;
     foo_t foo; {{ccomment| 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.byte[2] = 12;          {{ccomment| setzt byte 2 auf 12 }}&lt;br /&gt;
     data.bit_4_8 = 0x1f;        {{ccomment| setzt bits 4..8 (5 Stück) alle auf 1 }}&lt;br /&gt;
 &lt;br /&gt;
     int anInt = data.foo.anInt; {{ccomment| liest ein Feld von foo (hier ein int) }}&lt;br /&gt;
     ...&lt;br /&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;
&lt;br /&gt;
 {{ccomment| 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;
 {{ccomment| 5 Ziffern (0...65535) und evtl. noch eine führende 0 }}&lt;br /&gt;
 #define DIGITS 6&lt;br /&gt;
 &lt;br /&gt;
 {{ccomment| +1 wegen String-Ende (wird im Startup auf 0 gesetzt) }}&lt;br /&gt;
 char string[DIGITS+1];&lt;br /&gt;
 &lt;br /&gt;
 {{ccomment| Wandelt zahl in Dezimaldarstellung um. }}&lt;br /&gt;
 {{ccomment| Der return-Wert zeigt irgendwo ins string[]-Array. }}&lt;br /&gt;
 {{ccomment| string[] wird verändert. }}&lt;br /&gt;
 char* toString (unsigned short zahl)&lt;br /&gt;
 {&lt;br /&gt;
     {{ccomment| s zeigt auf das Ende von string }}&lt;br /&gt;
     {{ccomment| string wird von hinten nach vorne gefüllt }}&lt;br /&gt;
     char *s = string + DIGITS;&lt;br /&gt;
  &lt;br /&gt;
     {{ccomment| 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;
         {{ccomment| Division mit Rest durch 10 }}&lt;br /&gt;
         {{ccomment| quot: Ergebnis für den nächsten Durchlauf }}&lt;br /&gt;
         {{ccomment| rem: Rest ist die Ziffer im 10er-System }}&lt;br /&gt;
         qrem = udiv (qrem.quot, 10);&lt;br /&gt;
  &lt;br /&gt;
         {{ccomment| 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;
     {{ccomment| Falls eine führende '0' gespeichert wurde: weg damit }}&lt;br /&gt;
     {{ccomment| 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;
&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;amp;lt;= num &amp;amp;lt; 100&amp;lt;/tt&amp;gt; nach [[BCD]]&lt;br /&gt;
&lt;br /&gt;
 typedef struct&lt;br /&gt;
 {&lt;br /&gt;
     unsigned char quot; {{ccomment| Quotient }}&lt;br /&gt;
     unsigned char rem;  {{ccomment| 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;
 {{ccomment| Wandelt num nach BCD um, 0 &amp;lt;&amp;amp;#61; num &amp;lt;&amp;amp;#61; 99 }}&lt;br /&gt;
 {{ccomment| return-Wert ist dann 0x0 &amp;lt;&amp;amp;#61; return &amp;lt;&amp;amp;#61; 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;
&lt;br /&gt;
===Division durch Multiplikation===&lt;br /&gt;
===Vermeiden von float und double===&lt;br /&gt;
&lt;br /&gt;
=Inkompatibilität=&lt;br /&gt;
&lt;br /&gt;
[[GCC]] &amp;amp;ndash; und somit auch avr-gcc &amp;amp;ndash; werden ständig weiter entwickelt. Dies betrifft das Beheben von Fehlern, die Unterstützung neuer Architekturen/Sprachen/Betriebssysteme, Implementierung neuer Optimierungsalgorithmen, Vereinheitlichungen, etc.&lt;br /&gt;
&lt;br /&gt;
Leider führt dies auch zu Inkompatibilitäten verschiedener avr-gcc-Versionen untereinander, und eine C-Quelle, die mit einer Version von avr-gcc fehler- und warnungsfrei übersetzt werden kann, ist mit einer anderen Version möglicherweise nicht compilierbar.&lt;br /&gt;
&lt;br /&gt;
Die avr-gcc Version kann man anzeigen lassen, indem man in einer Shell/Eingabeaufforderung eintippt&lt;br /&gt;
 avr-gcc -v&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;tt&amp;gt;#include &amp;lt;avr/signal.h&amp;gt;&amp;lt;/tt&amp;gt;: In Versionen bis 3.4.4 werden in dieser Header-Datei u.a. die Makros &amp;lt;tt&amp;gt;SIGNAL()&amp;lt;/tt&amp;gt; und &amp;lt;tt&amp;gt;INTERRUPT()&amp;lt;/tt&amp;gt; definiert, die man braucht, wenn man eine C-Funktion als Interrupt-Routine ([[ISR]]) kennzeichnen will. In neueren Versionen ab 3.4.5 sind diese Definitionen in den Header &amp;lt;tt&amp;gt;avr/interrupt.h&amp;lt;/tt&amp;gt; gewandert, wo auch Makros wie &amp;lt;tt&amp;gt;sei()&amp;lt;/tt&amp;gt; und &amp;lt;tt&amp;gt;cli()&amp;lt;/tt&amp;gt; definiert werden. Die Inkludierung von &amp;lt;tt&amp;gt;avr/signal.h&amp;lt;/tt&amp;gt; in den neueren avg-gcc Versionen führt zu einer Warnung, irgendwann vielleicht sogar zu einem Fehler, weil die Datei nicht mehr bei avr-gcc dabei ist und daher nicht mehr gefunden wird.&lt;br /&gt;
: '''Verwendet man bei einer älteren avr-gcc-Version &amp;lt;tt&amp;gt;SIGNAL&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;INTERRUPT&amp;lt;/tt&amp;gt; ohne &amp;lt;tt&amp;gt;avr/signal.h&amp;lt;/tt&amp;gt; zu includen, wird u.U. stillschweigend falscher Code erzeugt.'''&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;tt&amp;gt;#include &amp;lt;util/...h&amp;gt;&amp;lt;/tt&amp;gt;: In &amp;lt;tt&amp;gt;util&amp;lt;/tt&amp;gt; stehen jetzt Header wie &amp;lt;tt&amp;gt;util/parity.h&amp;lt;/tt&amp;gt; oder das vielverwendete &amp;lt;tt&amp;gt;util/delay.h&amp;lt;/tt&amp;gt;, die vormals im Include-Unterverzeichnis &amp;lt;tt&amp;gt;avr&amp;lt;/tt&amp;gt; zu finden waren.&lt;br /&gt;
&lt;br /&gt;
;Interrupt Service Routinen: Auch die API zur Definition von [[ISR]]s hat sich von avr-gcc Version 3.x zur Version 4.x geändert:&lt;br /&gt;
:'''avr-gcc 3.x'''&lt;br /&gt;
::{|&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SIGNAL (SIG_INTERRUPT0)&lt;br /&gt;
{&lt;br /&gt;
    /* Interrupt Code */&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
INTERRUPT (SIG_OVERFLOW0)&lt;br /&gt;
{&lt;br /&gt;
    /* Interrupt Code */&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
:'''avr-gcc 4.x'''&lt;br /&gt;
::{|&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ISR (INT0_vect)&lt;br /&gt;
{&lt;br /&gt;
    /* Interrupt Code */&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void TIMER0_OVF_vect (void) __attribute__((interrupt));&lt;br /&gt;
void TIMER0_OVF_vect (void)&lt;br /&gt;
{&lt;br /&gt;
    /* Interrupt Code */&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;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;
&lt;br /&gt;
:'''Workaround''' (hier für eine ISR):&lt;br /&gt;
:{|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
 #include &amp;lt;stdarg.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;avr/interrupt.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 {{ccomment|The return address}}&lt;br /&gt;
 unsigned short volatile return_addr;&lt;br /&gt;
 &lt;br /&gt;
 {{ccomment|Define our special SIGNAL (INTERRUPT analoguous)}}&lt;br /&gt;
 #define SIGNAL_BRA(signame,var)                                         \&lt;br /&gt;
      void signame (unsigned short var, ...) __attribute__ ((signal));   \&lt;br /&gt;
      void signame (unsigned short var, ...)&lt;br /&gt;
 &lt;br /&gt;
 #define SWAP_BYTES(x) (((x) &amp;gt;&amp;gt; 8) | ((x) &amp;lt;&amp;lt; 8))&lt;br /&gt;
 &lt;br /&gt;
 SIGNAL_BRA (SIG_OUTPUT_COMPARE1A, dummy)&lt;br /&gt;
 {&lt;br /&gt;
    {&lt;br /&gt;
       va_list vlist;&lt;br /&gt;
       va_start (vlist, dummy);&lt;br /&gt;
  &lt;br /&gt;
       {{ccomment|Get the return address from the stack}}&lt;br /&gt;
       dummy = va_arg (vlist, unsigned short);&lt;br /&gt;
 &lt;br /&gt;
       {{ccomment|Convert stack address to code location}}&lt;br /&gt;
       addr = SWAP_BYTES(dummy) &amp;lt;&amp;lt; 1;&lt;br /&gt;
       va_end (vlist);&lt;br /&gt;
    }&lt;br /&gt;
    {{ccomment|ISR Code}}&lt;br /&gt;
 }&lt;br /&gt;
|}&lt;br /&gt;
;gcc 4.x: In der 4er-Version gab es tiefgreifende interne Änderungen im Compiler; er ist noch instabil und kann momentan nicht für den Produktiv-Einsatz empfohlen werden (Stand 02/2006). &lt;br /&gt;
&lt;br /&gt;
:Die Auswirkungen der Optimierungen auf das Zielsystem &amp;lt;tt&amp;gt;avr&amp;lt;/tt&amp;gt; bleibt abzuwarten, dürfte aber nicht wesentlich sein. Die neue 4-er Version wurde u.a. deshalb aufgelegt, um mit dem Intel-Compiler gleichzuziehen &amp;amp;ndash; also im Hinblick auf das Zielsystem &amp;lt;tt&amp;gt;i386&amp;lt;/tt&amp;gt;) gemacht. &lt;br /&gt;
&lt;br /&gt;
:Auch nach dem Release der 4-er Version wird die 3-er Version weiterentwickelt, da erst nach 1-2 Jahren nach Release einer neuer Major-Version ein Umstieg anzuraten ist und auch erst dann getätigt wird (zumindest im professionellen Bereich).&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]]: [[Interrupt|'''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;
* [[C-Tutorial]]&lt;br /&gt;
'''Code-Beispiele'''&lt;br /&gt;
* [[Hallo Welt für AVR (LED blinken)]] - ein erstes Beispiel für avr-gcc&lt;br /&gt;
*[[:Kategorie:Quellcode_C|C-Codebeispiele]]&lt;br /&gt;
* [[Fallstricke bei der C-Programmierung]]&lt;br /&gt;
&lt;br /&gt;
'''Details'''&lt;br /&gt;
* [[Inline-Assembler in avr-gcc|Inline-Assembler]]&lt;br /&gt;
* [[avr-gcc/Interna|Interna von avr-gcc]]&lt;br /&gt;
&lt;br /&gt;
'''Installation (Linux)'''&lt;br /&gt;
* [[avr-gcc und avrdude installieren]]&lt;br /&gt;
'''Sonstiges'''&lt;br /&gt;
* [[WinAVR]]&lt;br /&gt;
* [[Speicherverbrauch bestimmen mit avr-gcc]]&lt;br /&gt;
* [[Compiler]]&lt;br /&gt;
* [[Dev-Cpp IDE]]&lt;br /&gt;
* [[AVR]]&lt;br /&gt;
----&lt;br /&gt;
* [[Sourcevergleich]]&lt;br /&gt;
* [[Codevergleich AVR-Compiler]]&lt;br /&gt;
&lt;br /&gt;
=Weblinks=&lt;br /&gt;
==Dokumentation==&lt;br /&gt;
* [http://gcc.gnu.org/onlinedocs/ GCC online documentation (en)] Offline findest du die Doku für gcc, cpp (Präprozessor) und avr-libc bei [[WinAVR]] in&lt;br /&gt;
:&amp;lt;pre&amp;gt;&amp;lt;GCC_HOME&amp;gt;/doc/gcc/&amp;lt;/pre&amp;gt;&lt;br /&gt;
: bzw.&lt;br /&gt;
:&amp;lt;pre&amp;gt;&amp;lt;GCC_HOME&amp;gt;/doc/avr-libc/&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Online finden sich die Dokumente in&lt;br /&gt;
* [http://gcc.gnu.org/onlinedocs/gcc.pdf gcc.pdf (1900 kByte)] - Dokumentation des C/C++/Java-Compilers GCC (en)&lt;br /&gt;
* [http://gcc.gnu.org/onlinedocs/cpp.pdf cpp.pdf (470 kByte)] - Dokumentation des C-Präprozessors (en)&lt;br /&gt;
* [http://www.nongnu.org/avr-libc/user-manual/modules.html http://www.nongnu.org/avr-libc/user-manual] - Dokumentation zur avr-libc.&lt;br /&gt;
&lt;br /&gt;
== Downloads==&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;
== Tipps, Installation ==&lt;br /&gt;
*[http://www.nongnu.org/avr-libc/user-manual/install_tools.html ''&amp;quot;Installing the GNU Tool Chain&amp;quot;''] Hilfe zum Build und Installation von GCC, binutils, etc unter Linux&lt;br /&gt;
* Im GCC-Handbuch, siehe [[#Dokumentation|Dokumentation]].&lt;br /&gt;
* [http://www.linuxfocus.org/Deutsch/November2004/article352.shtml www.linuxfocus.org (Artikel)] - Tipps zu Build und Installation von avr-gcc, binutils und avr-libc unter Linux&lt;br /&gt;
* [http://users.rcn.com/rneswold/avr/ Rich Neswold: ''A GNU Development Environment for the AVR Microcontroller'']&lt;br /&gt;
* [http://www.mikrocontroller.net/topic/24166 www.mikrocontroller.net (Foren-Beitrag)] - Installation von GCC und Toolchain unter Mac OS X&lt;br /&gt;
* [http://www.roboternetz.de/phpBB2/zeigebeitrag.php?p=125603#125603 www.roboternetz.de (Foren-Beitrag)] ''avrgcc + avrdude installieren''&lt;br /&gt;
&lt;br /&gt;
== Sonstiges ==&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://www.mikrocontroller.net/articles/AVR-GCC-Tutorial avr-gcc-Tutorial auf mikrocontroller.net]&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;
=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>Heigro</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=AVR_Assembler_Einf%C3%BChrung&amp;diff=9664</id>
		<title>AVR Assembler Einführung</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=AVR_Assembler_Einf%C3%BChrung&amp;diff=9664"/>
				<updated>2006-11-22T10:43:22Z</updated>
		
		<summary type="html">&lt;p&gt;Heigro: Instruction Pointer (IP)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==AVR Assembler Einführung==&lt;br /&gt;
Es gibt mehrere Gründe, sich mit dem AVR-Assembler zu beschäftigen: &lt;br /&gt;
* reines Interesse&lt;br /&gt;
* Man hat eben keinen anderen Compiler, Bascom kostet ja was und GCC-C kann man möglicherweise genausowenig, also warum nicht gleich. &lt;br /&gt;
* Endlich Programmieren ohne Sprach-Restriktionen&lt;br /&gt;
* (theoretisch) sagenhaft schneller und kurzer Code&lt;br /&gt;
&lt;br /&gt;
Dadurch ergeben sich aber auch verschiedene Haupt-Zielgruppen für eine Einführung. Die eine ist in einer oder mehreren anderen Sprachen durchaus versiert, und möchte endlich auch mal richtig in die Tiefen der Hardware steigen. Die andere ist totaler Neueinsteiger und hat gehört, daß man Micro-Controller am besten mit Assembler programmiert.&lt;br /&gt;
&lt;br /&gt;
Es soll hier nur eine Starthilfe zum Einstieg gegeben werden. Viele Details und Varianten werden hier bei weitem nicht erschöpfend behandelt.&lt;br /&gt;
&lt;br /&gt;
==Unterschiede zu anderen Sprachen==&lt;br /&gt;
Man kann Assembler nicht direkt mit anderen Hochsprachen vergleichen. Es ist falsch gesagt Assembler ist viel besser als C, oder C ist viel besser als Assembler.&lt;br /&gt;
Hochsprachen haben generell ihren Vorteil in kürzerer (Programmier-) Zeit viel mehr erreichen zu können. Wärend man in Assembler jedes Detail programmieren muss schreibt man in der Hochsprache was man genau möchte und der Compiler erledigt das dann für einen, indem er den Code dann in Assembler übersetzt.&lt;br /&gt;
Der Vorteil liegt also klar auf der Hand, man spart sich eine Menge (unnötiger) Arbeit in dem man schneller sagen kann was man eigentlich machen möchte. Wie das jetzt genau funktioniert und was man dabei beachten muss übernimmt der Compiler.&lt;br /&gt;
Da gibts dann aber auch schon den ersten Nachteil. Fängt man mit einer Hochsprache an, braucht man sich Hardwaremäßig kaum mit dem µC außeinander setzen und weiß deshalb auch nicht genau drüber bescheit. Funktioniert dann etwas nicht sitzt man auf dem Schlauch.&lt;br /&gt;
Die Compiler werden aber immer besser, so kommen immer seltener Fehler Zustande.&lt;br /&gt;
&lt;br /&gt;
Ein weiterer Nachteil ist eine Glaubens Frage, da man sich kaum mehr mit der Hardware auseinander setzt und nicht wissen muss wie ein µC eigentlich funktioniert geht die &amp;quot;Kultur&amp;quot; verloren. Man lernt gar nicht zu schätzen was das Ding jetzt eigentlich leistet. Die Ansprüche werden immer höher gesetzt und jeder Aussetzer ist umso schlimmer.&lt;br /&gt;
&lt;br /&gt;
Ein extremes Beispiel:&lt;br /&gt;
Ein eisener Geschäftsmann geht nach Spanien und braucht Arbeiter, er schickt einen Gehilfen auf die Suche nach Arbeiter und schickt diese dann aufs Feld arbeiten. Ohne auch nur irgend etwas über deren Kultur zu wissen verlangt er das hart gearbeitet wird.&lt;br /&gt;
Doch schon in der ersten Woche gibt es Probleme, die Arbeiter möchten Mittags eine Pause. &amp;quot;Was, eine 3 Stündige Siesta? Seit ihr verrückt? Die in Japan arbeiten die Mittagszeit ja auch durch! Wie kommt ihr auf die Idee 3 Stunden pause zu machen?&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Vorteile von Assembler sind also das man weiß was der µC genau macht (bzw. für Anfänger &amp;quot;was er tun sollte&amp;quot;).&lt;br /&gt;
Man hat die volle Kontrolle und fast jeder Befehl wird bei einem AVR mit einem Takt ausgeführt.&lt;br /&gt;
Man kann immer noch auf eine andere Hochsprache umsteigen, diese beherscht man dann um so besser.&lt;br /&gt;
&lt;br /&gt;
Einzigster Nachteil, man muss alles genau definieren, so wie es der µC haben möchte und kann nicht direkt auf fertige funktionen zurück greifen.&lt;br /&gt;
Man schaft in der selben Zeit zwar genau so viel Code, der Code macht dann aber weniger als in C.&lt;br /&gt;
&lt;br /&gt;
Bildhaft ist der Unterschied der: Beim Assembler hat man ein weißes Stück Papier (ohne Linien) und ein Alphabet von A-Z. Aus diesen Buchstaben soll man nun erstmal Worte suchen und dann damit einen sinnvollen Text verfassen.  &lt;br /&gt;
&lt;br /&gt;
Bei &amp;quot;höheren&amp;quot; Sprachen ist das Papier zumindest mal liniert, und dazu kriegt man auch ein Wörtebuch und die Grammatik. Teile des Textes sind schon vorgeschrieben und ich muß nurmehr bei den ..... Punkten was einsetzen.   &lt;br /&gt;
&lt;br /&gt;
Anderst kann man auch sagen Hochsprachen sind wie ein Baukasten, man muss nur nach seinen Bedürfnissen sich die Teile zusammen &amp;quot;stecken&amp;quot;, ab und zu fertig man sich auch eigene Teile. Aber das meiste ist vorgefertigt und nach eigenen Bedürfnissen schnell angepasst.&lt;br /&gt;
In Assembler muss man sich alles selber anfertigen, fertige Module gibt es nicht, es sei denn man hat es schon einmal gemacht und zufällig da.&lt;br /&gt;
&lt;br /&gt;
* Daten&lt;br /&gt;
Höherer Sprachen kennen alle möglichen Datentypen in allen möglichen Längen, integer, floating point, Strings. Dadurch sind aber auch gleich die möglichen und zulässigen Operationen schon eingeschränkt. &lt;br /&gt;
&lt;br /&gt;
Beim (AVR) Assembler gibt auch einige Datentypen. Sie unterscheiden sich aber nur durch die Größe, d.h. die Anzahl der Bytes, die sie belegen. Es gibt aber keine Einschränkungen bezüglich der Befehle, die man darauf anwenden kann.&lt;br /&gt;
&lt;br /&gt;
* Vor- und Nachteile&lt;br /&gt;
Wenn man den Assembler mit höheren Sprachen vergleicht, um vielleicht Vor- und Nachteile herausarbeiten zu können, kommt man schnell drauf, daß in jedem Vorteil für eine der Seiten auch schon der Nachteil drinnen steckt. Was ich beim Assembler an Performance heraushole, weil ich z.B. &amp;quot;Goodies&amp;quot; eines Controllers ausnutze, bezahle ich, wenn ich mir einen anderen kaufe und dann das ganze Programm umbauen muß.&lt;br /&gt;
&lt;br /&gt;
==Installation AVR-Studio==&lt;br /&gt;
Die Installation des ATMEL AVR Studios ist herzergreifend einfach. &lt;br /&gt;
* Man bekommt von Atmel das AStudio4b01.exe (oder was halt gerade aktuell ist) , das man einfach startet und schon ist es passiert. &lt;br /&gt;
* Wenn man nun das Käferchen doppelklickt und startet, &lt;br /&gt;
**erzeugt man am besten gleich mal ein neues Project. &lt;br /&gt;
**Man wählt den Pfad des Projects, und &lt;br /&gt;
**Wenn man seinen Brennadapter im Menü nicht findet, wählt man eben den Simulator und verwendet dann halt das PonyProg, oder was man halt hat. &lt;br /&gt;
**avrstudio erzeugt ein leeres Projekt und eine leere Assemblersource, die so heißt wie das Projekt. Das Gewurstel mit der Make-file nimmt uns AvrStudio ab. &lt;br /&gt;
==Struktur eines AVR-Maschinenprogrammes==&lt;br /&gt;
Bei höheren Sprachen wird diese Struktur vom Compiler/Linker erzeugt, beim Assembler muß man sich selbst darum kümmern. &lt;br /&gt;
&lt;br /&gt;
[[Bild:Asm_Flow.jpg]]&lt;br /&gt;
&lt;br /&gt;
Der Controller beginnt mit der Abarbeitung links oben bei der Programmspeicheradresse 0000. Wenn man Interrupts verwenden will, muß man gleich das nächste Bereich (ISR-Vectoren) überspringen (mit &amp;quot;JMP&amp;quot;). Wenn nicht, kann man sich diese Vektoren aber auch wegdenken. &lt;br /&gt;
&lt;br /&gt;
Man landet so oder so bei den Befehlen, die der Initialisierung dienen (Setzen der Startbedingung). Das ist zumindest die Festlegung des Stack-Pointers, sonst kann man keine &amp;quot;CALLS&amp;quot; oder Interrupts durchführen.  &lt;br /&gt;
&lt;br /&gt;
Danach kommt man von oben in die Haupt-Programm-Schleife, die (üblicherweise) immer wieder ohne Ende durchlaufen wird.  &lt;br /&gt;
&lt;br /&gt;
Das &amp;quot;End&amp;quot; ist bei Microcontrollern daher auch kaum wirklich notwendig. Wenn es da ist, ist das eine ewige Wiederholung eines einzigen Befehls.&lt;br /&gt;
&lt;br /&gt;
==Source-Code Muster==&lt;br /&gt;
Das folgende Codebeispiel ist eine reine Basis-Initialisierung ohne irgendeine erkennbare Funktion. Für den Einstieg ist es am besten, das einfach abzuschreiben, wie es ist, und dann an den bezeichnenten Stellen mit eigenen Befehlen nach und nach zu erweitern. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 .NOLIST                    ; List-Output unterdrücken&lt;br /&gt;
 .INCLUDE &amp;lt;m8def.inc&amp;gt;       ; das gibt es für jeden Controllertyp&lt;br /&gt;
 .LIST                      ; List-Output wieder aufdrehen&lt;br /&gt;
 .CSEG                      ; was nun folgt, gehört in den FLASH-Speicher&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 ;------------------------------------------------------&lt;br /&gt;
 ;     Start Adresse 0000&lt;br /&gt;
 ;------------------------------------------------------&lt;br /&gt;
 RESET:&lt;br /&gt;
     jmp INIT           ; springen nach &amp;quot;INIT&amp;quot;&lt;br /&gt;
&lt;br /&gt;
 ;------------------------------------------------------&lt;br /&gt;
 ;     ISR VECTORS&lt;br /&gt;
 ;------------------------------------------------------&lt;br /&gt;
 ;    .....    hier kommen dann die Sprungadressen für die Interrupts rein&lt;br /&gt;
 ;             dazu kommen wir noch&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 .ORG INT_VECTORS_SIZE    ; dadurch haben wir für die Vektoren Platz gelassen&lt;br /&gt;
 INIT:  &lt;br /&gt;
 ;------------------------------------------------------&lt;br /&gt;
 ;     INITIALIZE&lt;br /&gt;
 ;------------------------------------------------------&lt;br /&gt;
     ldi r24,high(RAMEND)     ;Stack Pointer setzen &lt;br /&gt;
     out SPH,r24              ; &amp;quot;RAMEND&amp;quot; ist in m8def.inc (s.o.) festgelegt&lt;br /&gt;
     ldi r24,low(RAMEND)      ; &lt;br /&gt;
     out SPL,r24              ;&lt;br /&gt;
&lt;br /&gt;
 ;------------------------------------------------------&lt;br /&gt;
 ;   eigene Initialisierungen&lt;br /&gt;
 ;------------------------------------------------------&lt;br /&gt;
 ;....&lt;br /&gt;
 ;....&lt;br /&gt;
 ;....&lt;br /&gt;
&lt;br /&gt;
 ;------------------------------------------------------&lt;br /&gt;
 ;   HAUPTSCHLEIFE&lt;br /&gt;
 ;------------------------------------------------------&lt;br /&gt;
 Hauptschleife: &lt;br /&gt;
 ;....   eigene befehle&lt;br /&gt;
 ;....   eigene befehle&lt;br /&gt;
 ;....   eigene befehle&lt;br /&gt;
        rjmp Hauptschleife         ; immer wiederholen &lt;br /&gt;
&lt;br /&gt;
 ;------------------------------------------------------&lt;br /&gt;
 ;   ENDE&lt;br /&gt;
 ;------------------------------------------------------&lt;br /&gt;
 Ende:  &lt;br /&gt;
        rjmp Ende&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===Der Ablauf der Übersetzung===&lt;br /&gt;
Der Assembler ist ja selbst auch nur ein Programm und zu Beginn recht spartanisch ausgestattet: Er hat einen Daten-Buffer zur Verfügung, in den er den Maschinencode hineinschreiben soll, einen Pointer (Zeiger) dazu, damit er immer weiß, wo er grad ist, und eine allgemeine Tabelle, wo er Texte mit Zahlen verknüpfen kann. Alles ist zu Beginn leer bzw. auf NULL. &lt;br /&gt;
Mit diesen Voraussetzungen fängt er an, unseren Source-Text zeilenweise zu lesen. Und in jeder Zeile (die nicht leer ist) erwartet er eine Anweisung, was zu tun ist&lt;br /&gt;
====Assembler Direktiven/Präprozessor====&lt;br /&gt;
Das sind Anweisungen an den Assembler selbst und erzeugen keine Maschinenbefehle. Im obigen Source-Beispiel sind einige enthalten.&lt;br /&gt;
 .NOLIST                    &lt;br /&gt;
Normalerweise schreibt der Assembler ja eine Übersetzungsliste. Nach dieser Anweisung läßt er das bleiben&lt;br /&gt;
 .INCLUDE &amp;lt;m8def.inc&amp;gt;       ; das gibt es für jeden Controllertyp&lt;br /&gt;
sagt ihm, er soll jetzt erstmal die (text) datei &amp;quot;m8def.inc&amp;quot; lesen und genauso behandeln, als wäre diese Datei mit dem Editor hier reinkopiert worden. &lt;br /&gt;
 .LIST&lt;br /&gt;
Ab nun wird wieder alles in der Übersetzungsliste protokolliert. &lt;br /&gt;
 .CSEG&lt;br /&gt;
was danach folgt, bezieht sich auf den FLASH-Programm-Speicher&lt;br /&gt;
&lt;br /&gt;
 Gleich ein Hinweis: Der &amp;quot;AVR Assembler 2&amp;quot; geht dazu über, die C-Syntax für &lt;br /&gt;
 Präprozessoranweisungen zu verwenden. Diese haben dann als Kennzeichen ein &amp;quot;#&amp;quot; vorangestellt.&lt;br /&gt;
&lt;br /&gt;
====Bemerkungen / Kommentare====&lt;br /&gt;
 ;------------------------------------------------------&lt;br /&gt;
Alles, was NACH einem Strichpunkt steht, schreibt er einfach nur in die Übersetzungsliste, sonst macht er nix.&lt;br /&gt;
====Label (Sprungmarke)====&lt;br /&gt;
 RESET:&lt;br /&gt;
Was gleich ganz links in der Zeile beginnt (und mit einem Doppelpunkt abgeschlossen ist) schreibt er einfach in die genannte Tabelle und den momentanen Wert des Instruction Pointers (IP) dazu. Sonst hat das im Moment keine weitere Bedeutung. Natürlich, wenn er den gleichen Text schon mal hatte, gibt es eine Fehlermeldung, denn '''ein Label muss eindeutig sein'''&lt;br /&gt;
&lt;br /&gt;
====Commands====&lt;br /&gt;
     jmp INIT           ; springen nach &amp;quot;INIT&amp;quot;&lt;br /&gt;
Alles, was nicht ganz links steht und auch nix anderes ist, betrachtet der Assembler als &amp;quot;Command&amp;quot;. Normalerweise ist das eben eine AVR-Instruktion aus dem &amp;quot;Instruction Set&amp;quot;. Hier ist das &amp;quot;JMP&amp;quot;, also im Programm einfach woanders weitermachen. Gut, aber wo ? Der Rechner braucht nun unbedingt eine Zahl, denn &amp;quot;INIT&amp;quot; sagt ihm ja nichts. Also sieht er nun in der Tabelle nach, ob er den Text &amp;quot;INIT&amp;quot; schon mal hatte. Hatte er nicht, den zu der Stelle weiter hinten, wo &amp;quot;INIT:&amp;quot; als Sprungmarke steht (s.o) ist er ja noch garnicht gekommen. &lt;br /&gt;
&lt;br /&gt;
Ich kann leider nicht genau sagen, welche Strategie der AVR-Assembler nun anwendet, dazu gibt es keine Doku. Manche Assembler lesen erstmal überhaupt nur den Sourcetext von vorn bis hinten durch, um alle &amp;quot;Sprungmarken&amp;quot; zu sammeln (Pass I) und fangen dann nochmal von vorne an (Pass II), diesmal mit schon gefüllter Tabelle. Andere machen das etwas gefinkelter. Ist uns aber eigentlich egal. &lt;br /&gt;
&lt;br /&gt;
Jedenfalls findet er letztlich den Text &amp;quot;INIT&amp;quot; und daneben steht die Nummer der Speicherstelle, wo wir eben &amp;quot;INIT:&amp;quot; hingeschrieben haben. Und nun schreibt der Assembler also den Maschinencode für &amp;quot;JMP&amp;quot; in den Buffer und dazu die Zahl aus der Tabelle. Das war mal ein Befehl, also addiert er auf seinen Zeiger eins drauf und ist mit diesem Befehl fertig.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====ORG / JMP====&lt;br /&gt;
Das, was für den Controller beim Ablauf dann ein &amp;quot;JMP&amp;quot; ist, ist das &amp;quot;.ORG&amp;quot; für den Compiler. Wenn also bislang der Assembler den FLASH-Speicher von 0 - nn mit Befehlen befüllt hat, macht er durch &lt;br /&gt;
 .ORG INT_VECTORS_SIZE    &lt;br /&gt;
mit der Stelle weiter, die er über die gleiche Tabelle unter &amp;quot;INT_VECTORS_SIZE&amp;quot; gefunden hat. Dieser Tabelleneintrag, genauso wie &amp;quot;RAMEND&amp;quot; an anderer Stelle, entsteht aus der Datei &amp;quot;m8def.inc&amp;quot;. Wie im vorliegenen Fall macht man diese &amp;quot;Assembler-Jumps&amp;quot;, um Speicherstellen freizuhalten.&lt;br /&gt;
&lt;br /&gt;
==Merkwürdiges==&lt;br /&gt;
===Befehlsadressen / Byteadressen ===&lt;br /&gt;
[[Atmel Controller Mega16 und Mega32#Maschinen-Code|Ein Maschinenbefehl besteht aus maximal drei, bit-mäßig verschachtelten Teilen]]. Die meisten Befehle brauchen dafür genau 16 Bit (also zwei Byte), manchmal reicht das nicht, da gehören dann nochmal 16 Bit dazu. Kleiner als 16 Bit ist aber keiner. Aus diesem Grund wäre es natürlich sinnlos, Adressen für Befehle in Bytes auszudrücken, wenn es eh immer Vielfache von 2 sein müssen, das kleinste Bit einer solchen Adresse wäre ja immer null. &lt;br /&gt;
&lt;br /&gt;
 Also adressiert man Commands in &amp;quot;Worten&amp;quot; von 16 - Bit bzw. 2 Bytes&lt;br /&gt;
&lt;br /&gt;
Beim Ablegen eines Labels (Sprungmarke) werden also Wortadressen in der Tabelle angelegt. Solange der Wert auch als Befehls-Adresse verwendet wird (z.B. &amp;quot;JMP ''Label''&amp;quot;), braucht das nicht zu kümmern, denn genauso will es der AVR ja dann auch haben. '''Wenn dort aber Daten stehen''' und wir wollen diese adressieren, müssen wird '''den Wert mal 2 nehmen''' (oder einmal nach links schieben, was dasselbe ist), sonst landen wir im Nirwana.   &lt;br /&gt;
===3 ist nicht gleich 3 ===&lt;br /&gt;
Eine Zahl bedeutet also bei der Maschinensprache unter Umständen ganz was anderes, je nachdem, in welchem Zusammenhang sie verwendet wird. Bei allen Befehlen, die nur für die Register 16 - 31 gehen, steht im Maschinencode für das Register 16 nicht 16 drin, sondern 0. die &amp;quot;16&amp;quot; addiert er dann bei der Befehlsausführung drauf (für den Techniker: er braucht ja nur das Bit 2&amp;lt;sup&amp;gt;4&amp;lt;/sup&amp;gt; hochzuziehen)&lt;br /&gt;
===GPR ist nicht gleich GPR===&lt;br /&gt;
Was auch beim Einstieg leicht irritieren kann ist der Umstand, daß die 32 sogenannten &amp;quot;'''G'''eneral '''P'''urpose '''R'''egister&amp;quot; irgendwie so gar nicht generell und gleich sind. Manche Befehle kann ich mit allen 32 Registern machen, einige nur mit R16-R31, andere von R24 aufwärts und dann sind da noch R26 bis R31, die heissen dann manchmal auch noch X, Y und Z &lt;br /&gt;
===SFR ist gar nicht gleich GPR===&lt;br /&gt;
'''S'''pecial '''F'''unction '''R'''egister sind überhaupt seltsam, die meisten GPR-Befehle gehen da gleich garnicht, dafür gibt es andererseits ein paar Bit-Manipulationen, die gehen wiederum nur mit diesen. Dann gibt es auch Bit-Abfragen, die gehen da wie dort und bewirken auch das Gleiche, aber dafür heissen sie dann anders. &lt;br /&gt;
===Assembler-Befehle===&lt;br /&gt;
Viele dieser Probleme nimmt uns der Assembler ab, viele aber nicht. Dort erscheinen die Instruktionen immer so&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
 | ''' '''&lt;br /&gt;
 | '''CMD'''&lt;br /&gt;
 | '''ARG&amp;lt;sub&amp;gt;1&amp;lt;/sub&amp;gt;'''&lt;br /&gt;
 | '''ARG&amp;lt;sub&amp;gt;2&amp;lt;/sub&amp;gt;'''&lt;br /&gt;
 |}&lt;br /&gt;
wobei die Argumente 1 u. 2 optionell, d.h. bei Bedarf erscheinen. Command ist natürlich immer da.&lt;br /&gt;
Trotz der Hilfe des Assemblers durch &amp;quot;Warnings&amp;quot; und &amp;quot;Errors&amp;quot; ist bei den Argumenten aber immer Vorsicht geboten. Wir haben gehört, daß Arg 1 und Arg 2 im Grunde einfach nur zwei Zahlen sind, die dann zusammen mit dem Command-Code zum Maschinenbefehl werden. Wenn es dem Assembler also auch nur irgendwie gelingt, aus dem, was wir da hinschreiben, Zahlen zu machen die er umwandeln kann, nimmt er sie auch.   &lt;br /&gt;
&lt;br /&gt;
===Zwischenbilianz===&lt;br /&gt;
Einiges dieser sonderbaren Dinge lassen sich leicht erklären, manche schwer, manche mangels Unterlagen darüber garnicht. Deswegen versuch ich es hier auch gleich garnicht. &lt;br /&gt;
&lt;br /&gt;
So oder so sind es Fakten, an die man sich am besten einfach gewöhnt. Das scheint und ist am Anfang sicher schwer, solange man noch mit den Befehlen einzeln kämpft. RISC-Befehle werden aber erst in bestimmten Gruppierungen überhaupt wirklich sinnvoll, und durch diese sich immer wieder wiederholenden Gruppen wird es sehr schnell leichter. &lt;br /&gt;
&lt;br /&gt;
Beim Briefe schreiben denkt man ja auch nicht in Buchstaben, das wäre mühsam, sondern in Worten oder in ganzen Sätzen.  &lt;br /&gt;
&lt;br /&gt;
==Load &amp;amp; Store==&lt;br /&gt;
Die meisten Befehle für den AVR laufen nach dem Load &amp;amp; Store (Laden und Speichern) Prinzip ab. Das heißt, die Daten werden zuerst aus dem SRAM-Speicher (oder den I/O bzw. SFR Registern) in die allgemeinen Register (GPR) geladen, dort verarbeitet, und danach wieder in den SRAM oder die SFR zurückgestellt.  &lt;br /&gt;
&lt;br /&gt;
[[Bild:Asm_cmd.jpg]]&lt;br /&gt;
&lt;br /&gt;
Das ist natürlich eine recht allgemeine Darstellung, aber es hilft, das Instruction Set des AVR schon ein wenig besser zu verstehen. &lt;br /&gt;
&lt;br /&gt;
Es bedeutet, um z.B. ein Byte aus der einen Ecke des SRAM in eine andere zu kopieren, brauchen wir wenigstens 2 Maschineninstruktionen, einmal Load und einmal Store. Und wenn wir was an dem Byte ändern wollen, kommt diese Befehle natürlich dazu. &lt;br /&gt;
&lt;br /&gt;
Es gibt zu (fast) jeder Art &amp;quot;Load&amp;quot;-Befehl ein Äquivalent als &amp;quot;Store&amp;quot;, und zum Finden genügt es meist, statt &amp;quot;L&amp;quot; an der selben Stelle ein &amp;quot;S&amp;quot; zu nehmen. &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  LDS    GPR, adresse  ; lade das Byte von der Adresse in ein GPR  &lt;br /&gt;
  STS    adresse, GPR  ; speichere den Inhalt von GPR in der Adresse&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Wenn es um die I/O Register (SFR) geht:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  IN     GPR, I/O-Register    ; GPR &amp;lt;-----I/O Register &lt;br /&gt;
  OUT    I/O-Register, GPR    ; I/O Register &amp;lt;---- GPR&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Für feste Werte (Literals) gibt es natürlich keine Store-Variante, denn diese Werte stehen ja im FLASH (Programm) Speicher, und da kann man nicht einfach einzelne Bytes verändern.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  LDI    GPR, wert&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Beispiel===&lt;br /&gt;
&lt;br /&gt;
An PORTC haben wir (mit Vorwiderständen) ein paar LED angeschlossen. Und die sollen einfach nur zeigen, welche 0-er und 1-er am PORTB anliegen. &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 ; Eigene Initialisierungen&lt;br /&gt;
  LDI R24, 0            ; der wert &amp;quot;0&amp;quot; ins allgemeine Register R24&lt;br /&gt;
  OUT DDRB, R24         ; das kommt ins Controll-register f. PortB&lt;br /&gt;
                        ; dadurch sind diese PINs als INPUT festgelegt&lt;br /&gt;
  LDI R24, 255          ; der wert &amp;quot;255&amp;quot; = FF ins allgemeine Register R24&lt;br /&gt;
  OUT DDRC, R24         ; das kommt ins Controll-register f. PortC&lt;br /&gt;
                        ; dadurch ist das Port auf OUTPUT gestellt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 ; Eigene Befehle (in der Hauptschleife)&lt;br /&gt;
  IN  R24, PINB         ; die Bits vom PortB ins allgemeine Register R24&lt;br /&gt;
  OUT PORTC, r24        ; schreiben wir nach PortC&lt;br /&gt;
                        ; wo ein 1-er ist, leuchtet nun die LED&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn wir diese Befehle in das Programm-Schema oben einfügen, haben wir also das erste Assemblerprogramm schon geschrieben.&lt;br /&gt;
====Programm-Map====&lt;br /&gt;
Eine interessanter Output, wenn wir dieses Programm mit F7 übersetzen lassen, ist die Map-File. Sie ist ein Abbild der oben genannten &amp;quot;Text &amp;lt;--&amp;gt; Adresse&amp;quot;-Tabelle&lt;br /&gt;
&lt;br /&gt;
(gekürzt)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AVRASM ver. 2.0.28  D:\avr_c\avrstudio\Dokutest\Dokutest.asm Sat Dec 10 11:23:45 2005&lt;br /&gt;
....&lt;br /&gt;
EQU  sram_start   00000060&lt;br /&gt;
EQU  sram_size    00000800&lt;br /&gt;
EQU  ramend       0000085f&lt;br /&gt;
......&lt;br /&gt;
EQU  sph          0000003e&lt;br /&gt;
EQU  spl          0000003d&lt;br /&gt;
EQU  portb        00000018&lt;br /&gt;
EQU  ddrb         00000017&lt;br /&gt;
EQU  pinb         00000016&lt;br /&gt;
EQU  portc        00000015&lt;br /&gt;
EQU  ddrc         00000014&lt;br /&gt;
EQU  pinc         00000013&lt;br /&gt;
EQU  int_vectors_size 0000002a&lt;br /&gt;
CSEG reset        00000000&lt;br /&gt;
CSEG init         0000002a&lt;br /&gt;
CSEG hauptschleife 00000032&lt;br /&gt;
CSEG ende         00000035&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Wir finden darin alle Sprungadressen und alle sonstigen Werte, die wir verwendet haben. Tatsächlich in den Maschinencode eingesetzt werden vom Assembler immer die Zahlen, die daneben stehen&lt;br /&gt;
&lt;br /&gt;
===Pointer-Register===&lt;br /&gt;
In vielen Fällen ist es nicht sinnvoll, für Load &amp;amp; Store explizit jedesmal die Speicheradresse dazuschreiben zu müssen. Es können auch die Pointer Register X, Y und Z verwendet werden. Das sind die Register &lt;br /&gt;
 R26:R27 = X &lt;br /&gt;
 R28:R29 = Y &lt;br /&gt;
 R30:R31 = Z &lt;br /&gt;
Da wir ja oft mehr Speicher haben als 256 Byte, werden immer zwei Register zusammengefaßt und können dadurch die Bereiche 0 - 65535 abdecken (64k). Gut, aber wie kriegen wir so große Zahlen da rein ? Wir haben ja nur einen 8-Bit Processor und nicht 16. &lt;br /&gt;
&lt;br /&gt;
Wir müssen also die Adresse 8-Bit-weise übergeben, aber der Assembler hilft uns ja dabei. &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 LDI   R26, LOW(Adresse)        ; R28 für &amp;quot;Y&amp;quot; u. R30 für &amp;quot;Z&amp;quot;&lt;br /&gt;
 LDI   R27, HIGH(Adresse)       ; R29 für &amp;quot;Y&amp;quot; u. R31 für &amp;quot;Z&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Mit diesem &amp;quot;LOW&amp;quot; und &amp;quot;HIGH&amp;quot; teilt uns der Assembler die Adresse genau in die richtigen 8-Bit Portionen, die wir also so in den &amp;quot;X&amp;quot; Pointer laden können.&lt;br /&gt;
&lt;br /&gt;
Noch eine Hilfe gibt es: Wir können, besser zu merken, auch schreiben:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 LDI   XL, LOW(Adresse)        ; YL für &amp;quot;Y&amp;quot; u. ZL für &amp;quot;Z&amp;quot;&lt;br /&gt;
 LDI   XH, HIGH(Adresse)       ; YH für &amp;quot;Y&amp;quot; u. ZH für &amp;quot;Z&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Also &amp;quot;LOW&amp;quot; für &amp;quot;L&amp;quot; und &amp;quot;HIGH&amp;quot; für &amp;quot;H&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Indirekte Adressierung====&lt;br /&gt;
Mit den Pointer-Register kann man also Indirekte Adressieren(=einmal um die Ecke). Statt:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  LDS    GPR, adresse  ; lade das Byte von der Adresse in ein GPR  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Schreiben wir&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  LDI   XL, LOW(Adresse)&lt;br /&gt;
  LDI   XH, HIGH(Adresse)&lt;br /&gt;
  LD    GPR, X        ; '''Indirekt''': lade das Byte, wo der Pointer X hinzeigt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
beziehungsweise &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  LDI   XL, LOW(Adresse)&lt;br /&gt;
  LDI   XH, HIGH(Adresse)&lt;br /&gt;
  ST    X, GPR        ; '''Indirekt''': speichern, wo der Pointer X hinzeigt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Warum sollte man sowas kompliziertes tun ? Nun, zum Beispiel dann, &lt;br /&gt;
* wenn man an einer Stelle im Programm die Adresse festlegt, aber ganz woanders braucht (Subroutinen) &lt;br /&gt;
* wenn man für mehrere Folge-Befehle die gleiche Adresse wieder braucht&lt;br /&gt;
* wenn man mit der Adresse (als Zahl) rechnen will&lt;br /&gt;
&lt;br /&gt;
====Post-Increment/Pre-Decrement====&lt;br /&gt;
Wenn ich zum Beispiel 4 Byte hintereinander im Speicher auf &amp;quot;0&amp;quot; löschen will&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  LDI   XL, LOW(Adresse)&lt;br /&gt;
  LDI   XH, HIGH(Adresse)&lt;br /&gt;
  LDI   GPR, 0&lt;br /&gt;
  ST    X+, GPR   ;speichern, wo X hinzeigt, und dann 1 auf X addieren&lt;br /&gt;
  ST    X+, GPR   ;das 2.Byte dahinter&lt;br /&gt;
  ST    X+, GPR   ;das 3.Byte dahinter&lt;br /&gt;
  ST    X+, GPR   ;das 4.Byte dahinter&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Durch das automatische Addieren brauche ich nichts weiter zu tun. Als Gegenstück dazu kann man auch jedesmal 1 abziehen lassen, das aber immer '''vorher'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  ST    -X, GPR   ;1 von X abziehen und dann speichern, wo X hinzeigt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
All das gibt's für X, Y und Z. Es geht aber immer nur &lt;br /&gt;
* Load &amp;amp; Store und '''dann''' addieren&lt;br /&gt;
* '''erst''' subtrahieren und '''dann''' Load &amp;amp; Store &lt;br /&gt;
Diese Kombinationen werden einfach am häufigsten gebraucht&lt;br /&gt;
&lt;br /&gt;
====Displacement====&lt;br /&gt;
Für die beiden Pointer Y und Z kann man auch mit Displacement arbeiten&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  LDD   GPR, Y+4   ; wo Y hinzeigt, aber 4 Byte dahinter&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Welches Register ?==&lt;br /&gt;
Bei den Load &amp;amp; Store Befehlen könnten als GPR alle 32 Allgemeinen Register beliebig verwendet werden, um das entsprechende Byte aufzunehmen oder abzugeben. Aber als Zwischenspeicher oder Arbeitsregister ist es am besten, Registern wie r26-&amp;gt;r31, die möglicherweise als Pointer gebraucht werden, eher auszuweichen. &lt;br /&gt;
&lt;br /&gt;
 Wird das Assemblerprogramm durch inline oder libraries in eine Hochsprache &lt;br /&gt;
 eingebunden, muß man bei sich natürlich an die Register-Konventionen dieser&lt;br /&gt;
 Umgebung halten. &lt;br /&gt;
&lt;br /&gt;
 Schreibt man ein &amp;quot;stand-alone&amp;quot; Programm, kann (und sollte) man sich seinen eigenen&lt;br /&gt;
 Konventionen und Regeln schaffen. Das ist das, was der Assembler-Fan so liebt.&lt;br /&gt;
&lt;br /&gt;
==Benutzerdaten==&lt;br /&gt;
Daten wie Variable oder Felder werden üblicherweise im SRAM abgelegt und (s.o) von dort auch geholt. Bei allen Compilern und natürlich auch beim Assembler können zum Programmierzeitpunkt nur die Adressen davon festgelegt werden, aber keine Inhalte. Erst zur Laufzeit des Programmes kommen hier Werte rein. Manche Compiler gaukeln es zwar vor, aber (ein C-Beispiel):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 char  MeinName[] = &amp;quot;Sepp Meier&amp;quot; &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
bewirkt in Wirklichkeit drei Dinge: Im SRAM wird die nächste, noch nicht benutzte Adresse dem Text &amp;quot;MeinName&amp;quot; in der oben genannten Tabelle abgelegt, der String &amp;quot;Sepp Meier&amp;quot; wird im FLASH Programmspeicher bereitgestellt, und es wird eine Transfer-Routine generiert, die beim tatsächlichen Start des fertigen Programmes diesen String in das Feld &amp;quot;MeinName&amp;quot; transferiert. &lt;br /&gt;
&lt;br /&gt;
Im Assembler ist es eben genauso: Wir können durch die Anfangsadressen und einen Namen dazu Felder festlegen, die dann zur Laufzeit benützt werden. Mehr eigentlich nicht. Und erst, wenn wir Befehle schreiben, die diese Daten verwenden, ergibt sich daraus ein Datentyp. Vorher sind das einfach nur Bytes.&lt;br /&gt;
&lt;br /&gt;
Das ist bei Hochsprachen anders: Schon in der Source legen wir durch verschiedene Angaben den Datentyp (char, integer, etc.) fest und daraus entscheidet dann der Compiler, welche Maschinen-Instruktionen er dafür verwenden wird. Wir können das nurmehr eingeschränkt beeinflussen. &lt;br /&gt;
&lt;br /&gt;
===Daten im SRAM===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
.DSEG           ; Das ist eine Datensegment, d.h. es werden SRAM-Adressen festgelegt&lt;br /&gt;
CharBuf: 	.byte 24&lt;br /&gt;
OtherData: 	.byte 4 &lt;br /&gt;
....     &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
'''Anmerkung:''' Standardgemäß beginnt der Assembler mit der kleinsten SRAM Adresse. Bei den meisten AVRs ist das die tatsächliche Byte-Adresse 0x0060 (d.i. 96 dezimal). &lt;br /&gt;
[[Atmel_Controller_Mega16_und_Mega32#Adressen_Mapping|Siehe Adress-Mapping]]&lt;br /&gt;
&lt;br /&gt;
Dadurch, daß wir geschrieben haben &amp;quot;.byte 24&amp;quot; bestimmen wir, daß als nächste Datenadresse automatisch dann 96 + 24 = 120 gilt. Also ist mit &amp;quot;OtherData&amp;quot; dann 0x0078 (dez. 120) verknüpft. &lt;br /&gt;
&lt;br /&gt;
'''Noch eins:''' Wir haben ja gesagt, für den Assembler ist alles letztlich eine Zahl. Wir können daher auch damit rechnen. Wenn wir also die &amp;quot;24&amp;quot; nicht selbst wo hinschreiben wollen, verwenden wir einfach den Ausdruck &lt;br /&gt;
 LDI R10 , Otherdata - CharBuf &lt;br /&gt;
und laden damit das Register 10 mit der Zahl 24 &lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
===Daten im FLASH (Literale)===&lt;br /&gt;
Literale sind Werte, die schon in der Source festgelegt werden können. Das geht im Prinzip ähnlich, nur müssen wir nun auch Datentypen festlegen&lt;br /&gt;
&amp;lt;pre&amp;gt; &lt;br /&gt;
OneByte: 	.db   1             ; ein byte mit dem inhalt 0x01   &lt;br /&gt;
MeinName:       .db   &amp;quot;Sepp Meier&amp;quot;  ; mehrere Bytes mit Text&lt;br /&gt;
OneWord: 	.dw   1,2           ; zwei WORDs (16 Bit) mit dem inhalt 0x0001 u.  0x0002&lt;br /&gt;
....     &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Diese Definitionen können wir auch direkt in den Programmcode reinmischen. Wir müssen aber natürlich schauen, daß der AVR zum Laufzeitpunkt nicht versucht, diese Zeichen als Befehl auszuführen.&lt;br /&gt;
&lt;br /&gt;
===Daten im EEPROM (ERAM)===&lt;br /&gt;
genauso geht es, wenn man für den EEPROM feste Werte vorgeben will:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
.ESEG           ; Das ist ein EEPROM-Segment&lt;br /&gt;
OneByte: 	.db   1             ; ein byte mit dem inhalt 0x01   &lt;br /&gt;
MeinName:       .db   &amp;quot;Sepp Meier&amp;quot;  ; mehrere Bytes mit Text&lt;br /&gt;
OneWord: 	.dw   1,2           ; zwei WORDs (16 Bit) mit dem inhalt 0x0001 u.  0x0002&lt;br /&gt;
....     &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Verzweigungen==&lt;br /&gt;
Es gibt zwei Arten, bedingte Programm-Sprünge zu formulieren:&lt;br /&gt;
* Durch irgendwelche Befehle, meistens durch Vergleichsoperationen, erst die Bits im Statusregister (SREG) zu setzen, und diese Status-Bits abzufragen und je nachdem einen Programmsprung durchzuführen oder nicht. &lt;br /&gt;
* Man kann aber auch abhängig von Datenbits in GPRs und SFRs den Folgebefehl überspringen (Skippen) lassen. Dieser Folgebefehl kann, muß aber nicht, ein Sprung- oder Callbefehl sein. &lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
==Zusammenfassung==&lt;br /&gt;
Da dieser Artikel kein Assembler Tutorial sein kann und soll, soll hier auf die &amp;quot;eigentlichen&amp;quot; Instruktionen nicht eingegangen werden. Ich wollte nur versuchen, die &amp;quot;Denkweise&amp;quot; des Assembler und der AVR-Micros ein wenig näherzubringen und einige ermuntern, doch die ersten Operationen direkt am offenen Herzen des Kontrollers zu wagen. &lt;br /&gt;
&lt;br /&gt;
In manchen Fällen habe ich aber sicher einige Leser endgültig verschreckt.  &lt;br /&gt;
&lt;br /&gt;
==Noch ein Tip==&lt;br /&gt;
Gut abgeschrieben ist am Anfang besser als schlecht ausgedacht. Gerade die verschiedenen Geräte-Initialisierungen (SFR) in den zahlreichen GCC Codeschnipsel können fast direkt abgeschrieben werden (Baudrate, Input/Output, etc), da der C-Compiler das ja auch nicht anders machen kann. &lt;br /&gt;
&lt;br /&gt;
==Autor==&lt;br /&gt;
[[User:PicNick|PicNick]]&lt;br /&gt;
&lt;br /&gt;
==Weblinks==&lt;br /&gt;
[http://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=11488 Ausführlicher Foren-Beitrag zum Thema Assembler-Programmierung] &amp;amp;ndash; Lang aber lehrreich&lt;br /&gt;
==Siehe auch==&lt;br /&gt;
*[[AVR]]&lt;br /&gt;
*[[Sourcevergleich]]&lt;br /&gt;
*[[GNU Assembler]]&lt;br /&gt;
*[[Assembler_Einf%C3%BChrung_f%C3%BCr_Bascom-User|Assembler Einführung für Bascom-User]]&lt;br /&gt;
[[Kategorie:Microcontroller]]&lt;br /&gt;
[[Kategorie:Robotikeinstieg]]&lt;br /&gt;
[[Kategorie:Software]]&lt;br /&gt;
[[Kategorie:Quellcode Assembler AVR]]&lt;/div&gt;</summary>
		<author><name>Heigro</name></author>	</entry>

	</feed>