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

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=Benutzer_Diskussion:Frank&amp;diff=4872</id>
		<title>Benutzer Diskussion:Frank</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=Benutzer_Diskussion:Frank&amp;diff=4872"/>
				<updated>2006-01-05T15:49:49Z</updated>
		
		<summary type="html">&lt;p&gt;Nollsen: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
== Kategorien ==&lt;br /&gt;
&lt;br /&gt;
Hi,&lt;br /&gt;
&lt;br /&gt;
die Kategorie AVR war schon angelegt nur nicht vollständig.&lt;br /&gt;
&lt;br /&gt;
--[[Benutzer:Nollsen|Nollsen]] 16:47, 5. Jan 2006 (CET)&lt;br /&gt;
&lt;br /&gt;
PS: Es gibt einige Kategorien eher zu streichen wären als die AVR Kategorie&lt;/div&gt;</summary>
		<author><name>Nollsen</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=Benutzer_Diskussion:Frank&amp;diff=4871</id>
		<title>Benutzer Diskussion:Frank</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=Benutzer_Diskussion:Frank&amp;diff=4871"/>
				<updated>2006-01-05T15:47:16Z</updated>
		
		<summary type="html">&lt;p&gt;Nollsen: Kategorien&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
&lt;br /&gt;
== Kategorien ==&lt;br /&gt;
&lt;br /&gt;
Hi,&lt;br /&gt;
&lt;br /&gt;
die Kategorie AVR war schon angelegt nur nicht vollständig.&lt;br /&gt;
&lt;br /&gt;
--[[Benutzer:Nollsen|Nollsen]] 16:47, 5. Jan 2006 (CET)&lt;/div&gt;</summary>
		<author><name>Nollsen</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=Diskussion:Leiterplatten_herstellen_-_Toner-Transfer-Methode&amp;diff=4764</id>
		<title>Diskussion:Leiterplatten herstellen - Toner-Transfer-Methode</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=Diskussion:Leiterplatten_herstellen_-_Toner-Transfer-Methode&amp;diff=4764"/>
				<updated>2006-01-03T19:35:04Z</updated>
		
		<summary type="html">&lt;p&gt;Nollsen: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Hallo,&lt;br /&gt;
&lt;br /&gt;
habe mich auch lange mit der Bügelmethode herumgeschlagen, mein Fazit: Belichten geht 100x besser. &lt;br /&gt;
&lt;br /&gt;
Mfg --[[Benutzer:Nollsen|Nollsen]] 20:35, 3. Jan 2006 (CET)&lt;br /&gt;
&lt;br /&gt;
PS: Werde bei Bedarf Bauanleitungen für Ätzmaschinen etc einbringen&lt;/div&gt;</summary>
		<author><name>Nollsen</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=AT90S2313&amp;diff=4763</id>
		<title>AT90S2313</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=AT90S2313&amp;diff=4763"/>
				<updated>2006-01-03T19:33:02Z</updated>
		
		<summary type="html">&lt;p&gt;Nollsen: /* Weblinks */ Kategorie AVR&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Versorgungspannung:''' &lt;br /&gt;
::AT90S2313-4: 2.7V-6V&lt;br /&gt;
::AT90S2313-10: 4V-6V&lt;br /&gt;
'''Flash-Programm-Speicher:''' 2kByte &amp;lt;br&amp;gt;&lt;br /&gt;
'''EEPROM-Datenspeicher:''' 128Byte &amp;lt;br&amp;gt;&lt;br /&gt;
'''SRAM-Datenspeicher:''' 128 Byte &amp;lt;br&amp;gt;&lt;br /&gt;
'''Taktfrequenz:'''&lt;br /&gt;
::AT90S2313-4: bis 4MHz&lt;br /&gt;
::AT90S2313-10: bis 10MHz&lt;br /&gt;
'''Features:'''&lt;br /&gt;
* Full Duplex UART&lt;br /&gt;
* ein 8-bit Timer&lt;br /&gt;
* ein 16-bit Timer mit PWM, InputCapure, external Clock&lt;br /&gt;
* Analog-Comparator&lt;br /&gt;
* 15 digitale I/O-Ports&lt;br /&gt;
* programmierbarer Watchdog-Timer&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Der AT90S2313 ist heute veraltet. Der Hersteller empfiehlt, für neue Designs den ATTiny2313 zu verwenden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
http://www.roboternetz.de/wiki/uploads/Main/at902313.gif&lt;br /&gt;
&lt;br /&gt;
==Siehe auch==&lt;br /&gt;
* [[Atmel]]&lt;br /&gt;
* [[Avr]]&lt;br /&gt;
&lt;br /&gt;
== Packages==&lt;br /&gt;
* PDIP 20&lt;br /&gt;
* SOIC 20 &lt;br /&gt;
&lt;br /&gt;
==Weblinks==&lt;br /&gt;
* [http://www.atmel.com/dyn/resources/prod_documents/DOC0839.PDF Datenblatt des AT90S2313 (englisches PDF, 92 Seiten, 1.6 MByte)]&lt;br /&gt;
* [http://www.atmel.com/dyn/resources/prod_documents/doc4298.pdf AVR091: Replacing AT90S2313 by ATtiny2313 (englisches PDF, 11 Seiten, 118 kByte)]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:AVR]]&lt;br /&gt;
[[Kategorie:Microcontroller]]&lt;br /&gt;
[[Kategorie:Grundlagen]]&lt;br /&gt;
[[Kategorie:Elektronik]]&lt;/div&gt;</summary>
		<author><name>Nollsen</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=AVR_Assembler_Einf%C3%BChrung&amp;diff=4762</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=4762"/>
				<updated>2006-01-03T19:32:46Z</updated>
		
		<summary type="html">&lt;p&gt;Nollsen: /* Siehe auch */ Kategorie AVR&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;
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;
* 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 Pointers 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;
====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: PicNick&lt;br /&gt;
&lt;br /&gt;
==Siehe auch==&lt;br /&gt;
*[[Avr]]&lt;br /&gt;
*[[Sourcevergleich]]&lt;br /&gt;
[[Kategorie:AVR]]&lt;br /&gt;
[[Kategorie:Robotikeinstieg]]&lt;br /&gt;
[[Kategorie:Software]]&lt;/div&gt;</summary>
		<author><name>Nollsen</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=ATmega128&amp;diff=4761</id>
		<title>ATmega128</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=ATmega128&amp;diff=4761"/>
				<updated>2006-01-03T19:32:43Z</updated>
		
		<summary type="html">&lt;p&gt;Nollsen: /* Siehe auch */ Kategorie AVR&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Sehr leistungsstarker Atmel Controller. Da jedoch derzeit nur als [[SMD]]-Ausführung erhältlich, ist er fr Hobbybastler schwierig zu löten bzw. zu entlöten. Daher ist er noch relativ wenig unter Bastlern verbreitet.&lt;br /&gt;
&lt;br /&gt;
*ATMega AVR 128&lt;br /&gt;
*Gehäuse: TQFP-64&lt;br /&gt;
*MHz: 16&lt;br /&gt;
*Flash: 128&lt;br /&gt;
*EEProm: 4K&lt;br /&gt;
*RAM: 4K&lt;br /&gt;
*I/ O: 53 &lt;br /&gt;
&lt;br /&gt;
http://www.roboternetz.de/wiki/uploads/Main/mega128pinbelegung.gif&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Siehe auch==&lt;br /&gt;
* [[Avr]]&lt;br /&gt;
* [[Atmel]]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:AVR]]&lt;br /&gt;
[[Kategorie:Microcontroller]]&lt;br /&gt;
[[Kategorie:Grundlagen]]&lt;br /&gt;
[[Kategorie:Elektronik]]&lt;/div&gt;</summary>
		<author><name>Nollsen</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=ATmega8&amp;diff=4760</id>
		<title>ATmega8</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=ATmega8&amp;diff=4760"/>
				<updated>2006-01-03T19:32:40Z</updated>
		
		<summary type="html">&lt;p&gt;Nollsen: /* Siehe auch */ Kategorie AVR&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;* ATMega AVR 8-16 PDIP&lt;br /&gt;
* Gehäuse: DIL-28&lt;br /&gt;
* MHz: 16&lt;br /&gt;
* Flash: 8&lt;br /&gt;
* EEProm: 512&lt;br /&gt;
* RAM: 1K&lt;br /&gt;
* I/ O: 23 &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Bild:Pinbelegungmega8.gif|center]]&lt;br /&gt;
&lt;br /&gt;
==Siehe auch==&lt;br /&gt;
* [[Atmel Controller Mega48 Mega88 Mega168]] - Mega8 Pinkompatibel&lt;br /&gt;
* [[Atmel]]&lt;br /&gt;
* [[Avr]]&lt;br /&gt;
* [[AVR-Einstieg leicht gemacht]]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:AVR]]&lt;br /&gt;
[[Kategorie:Microcontroller]]&lt;br /&gt;
[[Kategorie:Grundlagen]]&lt;br /&gt;
[[Kategorie:Elektronik]]&lt;/div&gt;</summary>
		<author><name>Nollsen</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=ATmega16_ATmega32_ATmega644&amp;diff=4759</id>
		<title>ATmega16 ATmega32 ATmega644</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=ATmega16_ATmega32_ATmega644&amp;diff=4759"/>
				<updated>2006-01-03T19:32:38Z</updated>
		
		<summary type="html">&lt;p&gt;Nollsen: /* Siehe auch */ Kategorie AVR&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Merkmale und Pinbelegung ==&lt;br /&gt;
&lt;br /&gt;
*ATMega AVR 16/32&lt;br /&gt;
*Gehäuse: DIL-40&lt;br /&gt;
*MHz: 16&lt;br /&gt;
*Flash: 16/32 kB&lt;br /&gt;
*EEProm: 1 kB&lt;br /&gt;
*RAM: 2 kB&lt;br /&gt;
*I/ O: 32 &lt;br /&gt;
&lt;br /&gt;
[[Bild:Mega1632.gif|center]]&lt;br /&gt;
&lt;br /&gt;
== Einfache Grundschaltung ==&lt;br /&gt;
&lt;br /&gt;
[[Bild:avrtutorial_grundschaltung_mitquarz.gif|center|500px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Weitere Grundschaltungen im Artikel [[AVR-Einstieg leicht gemacht]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
==Internes zum Atmega32==&lt;br /&gt;
&lt;br /&gt;
Wenn man das erste Mal mit solchen komplizierten Geräten wie Micro-Controllern konfrontiert wird, kann es schon sein, daß man vor Ehrfurcht erschaudert. Und auch wenn man von Bits und Bytes durchaus eine Ahnung hat, ist allein schon der Umfang des Datasheets möglicherweise abschreckend. &lt;br /&gt;
Es soll hier versucht werden darzustellen, daß die ganze Sache nun so schlimm auch wieder nicht ist, wenn man sich den Aufbau eines typischen Vertreters der ATMEL Microcontroller etwas näher betrachtet.&lt;br /&gt;
&lt;br /&gt;
===Architektur Überblick===&lt;br /&gt;
&lt;br /&gt;
[[Bild:Avr.jpg]]Quelle:www.atmel.com&lt;br /&gt;
&lt;br /&gt;
Dieses Bild stammt aus dem Datasheet. Das haben wir wohl schon alle mal gesehen, und vermittelt dem Anfänger eigentlich nur, daß in dem Chip offenbar eine Menge Zeugs drinnen ist. Und da die meisten Pfeile in beide Richtungen zeigen, kann man sich auch nicht recht vorstellen, was da eigentlich in welcher Folge abläuft.  &lt;br /&gt;
&lt;br /&gt;
===CPU===&lt;br /&gt;
Das &amp;quot;Herz&amp;quot; des Controllers ist im mittleren Bereich links, das ist die &amp;quot;CPU&amp;quot; (= Zentral-Processor). Von hier aus wird all das Drumherum gesteuert, hier landet das Programm, das wir mit mit irgendeinem Compiler erstellt haben. &lt;br /&gt;
&lt;br /&gt;
[[Bild:Avrcpu.jpg]]Quelle:www.atmel.com&lt;br /&gt;
&lt;br /&gt;
Der Rest von dem ganzen Atmega32 ist die &amp;quot;Peripherie&amp;quot;, das sind eine Reihe von Einzelgeräten, die alle ihre speziellen Funktionen und Aufgaben haben. Da liegen auch hauptsächlich die Unterschiede zwischen den verschiedenen Micro-Controllern, denn ein kleiner (Tiny) hat weniger solche Geräte und braucht dadurch natürlich auch weniger Pins. &lt;br /&gt;
&lt;br /&gt;
Sehr ähnlich, wenn nicht identisch, ist bei allen AVR-Controllern diese CPU aufgebaut, daher ist es zum Verständnis unerlässlich, sich damit näher zu beschäftigen. &lt;br /&gt;
&lt;br /&gt;
====Program Flash====&lt;br /&gt;
Was da so ein kleines Kästchen ist, das ist der Programmspeicher, der beim Atmega32 immerhin 32k groß ist.&lt;br /&gt;
====Program Counter====&lt;br /&gt;
(=Befehlszähler) beinhaltet IMMER die Adresse des nächsten Befehls im Programmspeicher&lt;br /&gt;
====Instruction Register====&lt;br /&gt;
hier landet der Inhalt des Programmspeichers von der Adresse &amp;quot;Befehlszähler&amp;quot; immer zuerst, da ja der AVR erstmal selber gucken muß, was für ein Befehl das wohl ist.&lt;br /&gt;
Jedes Befehlswort beinhaltet (kodiert) drei Dinge: &amp;quot;WAS&amp;quot;, &amp;quot;WOHER&amp;quot; und &amp;quot;WOHIN&amp;quot;. &lt;br /&gt;
Einiges kann direkt im SRAM oder in den Register eine Auswahl treffen, einiges muß weiter zum&lt;br /&gt;
====Instruction Decoder====&lt;br /&gt;
Je nach Befehl müssen Datenrichtungen eingestellt werden, und etliche Schalter bedient werden. (CONTROL-LINES)&lt;br /&gt;
====SRAM====&lt;br /&gt;
Das ist der frei verwendbare Schreib- und Lesespeicher, beim Atmeg32 2k (2048 Byte)&lt;br /&gt;
====Stack Pointer====&lt;br /&gt;
Der &amp;quot;Stapel-Zeiger&amp;quot; kann ausschlißlich den SRAM adressieren. Aber dazu kommen wir noch&lt;br /&gt;
&lt;br /&gt;
====General Purpose Register (GPR)====&lt;br /&gt;
Wie der Name sagt, das sind 32 Bytes für den allgemeinen Gebrauch. Bezeichnet werden sie als R0 (Addresse $0000) bis R31 (Addresse $001F). Die meisten Maschinenbefehle des AVR beziehen sich darauf, wobei einige Unterschiede zwischen R0 - R15 und R16 - R31 gemacht werden. &lt;br /&gt;
R26 bis R31 können auch als Pointer-Register X, Y u. Z mit ein paar Extras verwendet werden. &lt;br /&gt;
[[Bild:Avrgpr.jpg]]Quelle:www.atmel.com&lt;br /&gt;
&lt;br /&gt;
====ALU====&lt;br /&gt;
Arithmetische-Logische-Einheit. Die Register R0 - R31 können ihre Werte da anlegen, die ALU macht dann den eigentlichen Befehl damit. Also Addieren, Subtrahieren, usw.  &lt;br /&gt;
Das Ergebnis landet dann irgendwo in dem gesamten CPU-Bereich, je nachdem, wie eben die Control-Lines vom Decoder eingestellt sind. &lt;br /&gt;
Als Nebenprodukt gibt es aber ein paar Bits, die im &lt;br /&gt;
====STATUS REGISTER====&lt;br /&gt;
landen, wie eben das &amp;quot;ZERO&amp;quot;-Bit, das &amp;quot;CARRY&amp;quot;-Bit usw. &lt;br /&gt;
&lt;br /&gt;
====Adressen Mapping====&lt;br /&gt;
Damit es einfacher ist, Input- und Output-Daten immer ins richtige Kästchen reinzutun oder zu holen, gibt das &amp;quot;Address-Mapping&amp;quot;. Es wird einfach eine fortlaufende Adresse angegeben, aber je nach Werte-Bereich landet man ganz woanders. &lt;br /&gt;
[[Bild:Adrmap.jpg]]&lt;br /&gt;
=====REGISTER=====&lt;br /&gt;
Das sind die bereits oben erwähnten &amp;quot;Allgemeinen Register&amp;quot; (GPR)&lt;br /&gt;
=====I/O=====&lt;br /&gt;
Wenn man hier schreibt oder liest, landet man in Wirklichkeit bei den Kontroll-Schaltern von einem der &amp;quot;Peripheriegeräte&amp;quot;. Da gibt es zum Beispiel Stellen, wenn man da reinschreibt, verändert man irgendeinen PIN aussen am Controller.&lt;br /&gt;
=====SRAM=====&lt;br /&gt;
Der auch schon erwähnte frei verfügbare Schreib-und Lesespeicher&lt;br /&gt;
&lt;br /&gt;
===Maschinen-Code===&lt;br /&gt;
&lt;br /&gt;
====Aufbau====&lt;br /&gt;
Eine Assembler Source-Zeile, schematisch:&lt;br /&gt;
 '''Command   Argument1 , Argument2'''     ; die Argumente sind optionell, je nach Befehl&lt;br /&gt;
&lt;br /&gt;
Jede Instruktion ist (mindestens) 16 Bit (zwei Bytes) breit. Hier ein paar Befehle, die Bits in den Spalten von Bit 15 (MSB)  bis Bit  0 (LSB), links nach rechts&lt;br /&gt;
&lt;br /&gt;
[[Bild:Code1.jpg]]&lt;br /&gt;
&lt;br /&gt;
Der Befehle haben nicht einfach eine Nummer von 0 - 65535, wie man vielleicht erwarten würde, sondern die Befehl-Bits sind mit den Argumenten in recht seltsamer Weise gemischt in diese beiden Bytes hineincodiert.&lt;br /&gt;
Der Grund ist der, daß die Argumente ja mal mehr, mal weniger Platz beanspruchen, das heißt, für den eigentlichen Befehlscode bleiben u.U. recht wenig Bits übrig. &lt;br /&gt;
&lt;br /&gt;
* Die erste Command-Selektion erfolgt mit den Bits A u. B (s.o.): Im obigen Beispiel steht dort immer &amp;quot;10&amp;quot;.&lt;br /&gt;
* Dann ist &amp;quot;C&amp;quot; zu prüfen: &lt;br /&gt;
Steht dort &amp;quot;0&amp;quot;, ist es einer der vier LD/ST Befehle&lt;br /&gt;
Ist dort aber &amp;quot;1&amp;quot;, &lt;br /&gt;
* geht es weiter mit den Bits in den Spalten &amp;quot;D&amp;quot; und &amp;quot;E&amp;quot;  (und so fort)&lt;br /&gt;
&lt;br /&gt;
Die beiden Befehle &amp;quot;JMP&amp;quot; und &amp;quot;CALL&amp;quot; kommen mit den 16 Bits garnicht aus, da wird auch das nächste Wort gelesen, das den restlichen Teil der Zieladresse beinhaltet. (Dadurch brauchen sie auch einen Clock-Cycle mehr)&lt;br /&gt;
&lt;br /&gt;
=====Details=====&lt;br /&gt;
Schauen wir uns noch ein paar Bits genauer an. &lt;br /&gt;
======LD / ST======&lt;br /&gt;
Die Bits A, B u. C dienen zu Identifizierung. Zur weiteren Unterscheidung bleiben noch die beiden anderen farbig unterlegten Bits&lt;br /&gt;
* 2&amp;lt;sup&amp;gt;7&amp;lt;/sup&amp;gt;  ==&amp;gt; LD (SRAM --&amp;gt; Register) oder ST (Register --&amp;gt; SRAM)&lt;br /&gt;
* 2&amp;lt;sup&amp;gt;3&amp;lt;/sup&amp;gt;  ==&amp;gt; Pointer-Register Z  oder  Y&lt;br /&gt;
======IN / OUT======&lt;br /&gt;
Ob IN oder OUT, entscheidet das Bit 2&amp;lt;sup&amp;gt;11&amp;lt;/sup&amp;gt;&lt;br /&gt;
======JMP / CALL======&lt;br /&gt;
Der einzige Unterschied ist der, ob der aktuelle PC (Program-Count) vor dem Sprung auf den Stack gepusht wird oder nicht (2&amp;lt;sup&amp;gt;1&amp;lt;/sup&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
====Mehrere Namen für einen Befehl====&lt;br /&gt;
Bei einer Reihe von Befehlen gibt es mehrere Namen für ein und denselben Maschinenbefehl. &lt;br /&gt;
Ein Beispiel: &lt;br /&gt;
 CLR R1     ; (Setze Register 1 auf  $00 )&lt;br /&gt;
bringt den gleichen Maschinencode wie&lt;br /&gt;
 EOR R1, R1 ; Register 1 =   Register1  &amp;quot;exclusive or&amp;quot; Register1&lt;br /&gt;
&lt;br /&gt;
Besonders im Umfeld des Stausregisters (SREG) kann man fast von einer &amp;quot;Befehlsvermehrung&amp;quot; sprechen. Obwohl es für Setzen, Löschen und Abfragen der Status-Bits entspechenden Maschinencode gibt, tauchen im &amp;quot;Instruction Set&amp;quot; diese Befehle für jedes der Bits einzeln nochmals auf. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
''Artikel: PicNick / ergänzt Frank''&lt;br /&gt;
&lt;br /&gt;
==Siehe auch==&lt;br /&gt;
* [[Atmel]]&lt;br /&gt;
* [[Avr]]&lt;br /&gt;
* [[RN-Control]]&lt;br /&gt;
* [[AVR-Einstieg leicht gemacht]]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:AVR]]&lt;br /&gt;
[[Kategorie:Microcontroller]]&lt;br /&gt;
[[Kategorie:Grundlagen]]&lt;br /&gt;
[[Kategorie:Elektronik]]&lt;br /&gt;
[[Kategorie:Robotikeinstieg]]&lt;/div&gt;</summary>
		<author><name>Nollsen</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=ATmega48_ATmega88_ATmega168_ATmega328&amp;diff=4758</id>
		<title>ATmega48 ATmega88 ATmega168 ATmega328</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=ATmega48_ATmega88_ATmega168_ATmega328&amp;diff=4758"/>
				<updated>2006-01-03T19:32:35Z</updated>
		
		<summary type="html">&lt;p&gt;Nollsen: /* Siehe auch */ Kategorie AVR&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Diese Controllertypen sind bis auf einige spezielle Funktionen pinkompatibel&lt;br /&gt;
&lt;br /&gt;
===Mega8===&lt;br /&gt;
*ATMega AVR 8-16 PDIP&lt;br /&gt;
*Gehäuse: DIL-28&lt;br /&gt;
*MHz: 16&lt;br /&gt;
*Flash: 8&lt;br /&gt;
*EEProm: 512&lt;br /&gt;
*RAM: 1K&lt;br /&gt;
*I/ O: 23 &lt;br /&gt;
*Betriebsspannung: 2.7 - 5.5V &lt;br /&gt;
&lt;br /&gt;
===Mega48===&lt;br /&gt;
*ATMega AVR 48-20 PDIP&lt;br /&gt;
*Gehäuse: DIL-28&lt;br /&gt;
*MHz: 20&lt;br /&gt;
*Flash: 4 kByte&lt;br /&gt;
*EEProm: 256 Byte&lt;br /&gt;
*RAM: 512 Byte&lt;br /&gt;
*I/ O: 23&lt;br /&gt;
*Betriebsspannung: 1.8 - 5.5V &lt;br /&gt;
&lt;br /&gt;
===Mega88===&lt;br /&gt;
*ATMega AVR 88-20 PDIP&lt;br /&gt;
*Gehäuse: DIL-28&lt;br /&gt;
*MHz: 20&lt;br /&gt;
*Flash: 8 kByte&lt;br /&gt;
*EEProm: 512 Byte&lt;br /&gt;
*RAM: 1024 Byte&lt;br /&gt;
*I/ O: 23&lt;br /&gt;
*Betriebsspannung: 1.8 - 5.5V &lt;br /&gt;
&lt;br /&gt;
===Mega168===&lt;br /&gt;
*ATMega AVR 168-20 PDIP&lt;br /&gt;
*Gehäuse: DIL-28&lt;br /&gt;
*MHz: 20&lt;br /&gt;
*Flash: 16 kByte&lt;br /&gt;
*EEProm: 512 Byte&lt;br /&gt;
*RAM: 1 kByte&lt;br /&gt;
*I/ O: 23&lt;br /&gt;
*Betriebsspannung: 1.8 - 5.5V &lt;br /&gt;
&lt;br /&gt;
http://www.roboternetz.de/wiki/uploads/Main/pinbelegungmega8_168.gif&lt;br /&gt;
&lt;br /&gt;
=== Unterschiede zwischen Mega8 und Mega88===&lt;br /&gt;
&lt;br /&gt;
Der Mega88 ist zwar nicht als Ersatz für den Mega8 entwickelt worden. &lt;br /&gt;
Aufgrund der Pin-Kompatibilität läßt er sich aber sehr leicht in bestehenden Schaltungen ersetzen.&lt;br /&gt;
Einige Besonderheiten müssen dabei bei der Programmierung berücksichtigt werden.&lt;br /&gt;
&lt;br /&gt;
Die wichtigsten Verbesserungen des ATmega88 gegenüber dem ATmega8 im Überblick:&lt;br /&gt;
&lt;br /&gt;
*Schnellere Taktfrequenz bis 20MHz&lt;br /&gt;
*Geringerer Energieverbrauch&lt;br /&gt;
*Schnellere EEPROM Schreibzugriffe&lt;br /&gt;
*On-Chip Deggugging möglich mit DebugWire (über den RESET Pin)&lt;br /&gt;
*Pin Change Interrupt auf allen Eingangs Pins&lt;br /&gt;
*10bit Auflösung bei allen Analog/Digital Wandler Kanälen  &lt;br /&gt;
*Timer 0,2 erweitert um PWM und Compare Einheit&lt;br /&gt;
*Ausgabe des Systemtaktes auf einen I/O Pin&lt;br /&gt;
&lt;br /&gt;
=== Unterschiede zwischen Mega48, Mega88 und Mega 168===&lt;br /&gt;
&lt;br /&gt;
Die Unterschiede beschränken sich im wesentlichen auf den internen Speicher:&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
 |&lt;br /&gt;
 |'''ATmega48'''&lt;br /&gt;
 |'''ATmega88'''&lt;br /&gt;
 |'''ATmega168'''&lt;br /&gt;
 |-&lt;br /&gt;
 |FLASH(bytes)&lt;br /&gt;
 |4096&lt;br /&gt;
 |8192&lt;br /&gt;
 |16384&lt;br /&gt;
 |-&lt;br /&gt;
 |EEPROM(bytes)&lt;br /&gt;
 |256&lt;br /&gt;
 |512&lt;br /&gt;
 |512&lt;br /&gt;
 |-&lt;br /&gt;
 |SRAM(bytes)&lt;br /&gt;
 |512&lt;br /&gt;
 |1024&lt;br /&gt;
 |1024&lt;br /&gt;
 |-&lt;br /&gt;
 |Boot Sector Größe(bytes)&lt;br /&gt;
 |n.v&lt;br /&gt;
 |256..2048&lt;br /&gt;
 |256..2048&lt;br /&gt;
 |-&lt;br /&gt;
 |FLASH Page Größe(bytes) &lt;br /&gt;
 |64&lt;br /&gt;
 |64&lt;br /&gt;
 |128&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Siehe auch==&lt;br /&gt;
* [[Atmel]]&lt;br /&gt;
* [[Avr]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:AVR]]&lt;br /&gt;
[[Kategorie:Microcontroller]]&lt;br /&gt;
[[Kategorie:Grundlagen]]&lt;br /&gt;
[[Kategorie:Elektronik]]&lt;/div&gt;</summary>
		<author><name>Nollsen</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=AVR-ISP_Programmierkabel&amp;diff=4757</id>
		<title>AVR-ISP Programmierkabel</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=AVR-ISP_Programmierkabel&amp;diff=4757"/>
				<updated>2006-01-03T19:32:33Z</updated>
		
		<summary type="html">&lt;p&gt;Nollsen: /* Bezugsquellen */ Kategorie AVR&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==ISP-Dongle - Programmieradapter günstig selbst bauen==&lt;br /&gt;
&lt;br /&gt;
Um einen Atmel Controller wie Mega32 etc. (z.B. im RN-Board [[RN-Control]] oder [[RNBFRA-Board]]) oder auch einen anderen Atmel Controller programmieren zu können, benötigt man ein spezielles Anschlusskabel mit ein wenig Elektronik. In der Regel hat sich eine Schaltung bewährt, welche am Druckerport des PCs eingesteckt wird. &lt;br /&gt;
Hier gibt es zwar auch verschiedene einfache Lösungen die nur mit einigen Widerständen oder Dioden aus kommen, von diesen ist aber abzuraten da ein defektes Board oder ein falsch aufgesteckter ISP Stecker dann schnell die Druckerschnittstelle beschädigen kann. &lt;br /&gt;
&lt;br /&gt;
Besser sind Lösungen mit einem Bustreiber.&lt;br /&gt;
&lt;br /&gt;
Eine bewährte Schaltung, ist folgende:&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
http://www.robotikhardware.de/bilder/ispplan.gif&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
Eine solche Schaltung schützt den Druckerport er erlaubt die zuverlässige und schnelle Programmierung der meisten Atmel Controller, wahlweise direkt aus dem Basic Compiler Bascom heraus oder mit dem ebenfalls oft genutztem Übertragungsprogramm Pony.&lt;br /&gt;
&lt;br /&gt;
Besonders günstig und einfach lässt sich die Schaltung mit einer speziell geformten Platine aufbauen. Durch die geformte Platine lassen sich nämlich sowohl Stecker als auch Gehäuse sehr leicht montieren. Zudem sind Fehler beim Aufbau der Schaltung fast unmöglich.&lt;br /&gt;
&lt;br /&gt;
Insgesamt benötigt man nur wenige Bauteile:&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
http://www.robotikhardware.de/bilder/isp/isp1.jpg&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 1 Stück Platine (über www.robotikhardware.de für ca. 5,90 Euro erhältlich) &lt;br /&gt;
 1 Stück Widerstand 100 k&lt;br /&gt;
 1 Stück Kondensator 100 nF&lt;br /&gt;
 1 Stück Diode z.B. 1N4148 oder ähnlich&lt;br /&gt;
 1 Stück IC 74HC244&lt;br /&gt;
 1 Stück 9 pol SUB D-Buchse&lt;br /&gt;
 1 Stück 25 pol SUB D-Stecker&lt;br /&gt;
&lt;br /&gt;
 1 Stück 9 pol SUB D Stecker zum aufpressen auf Flachkabel&lt;br /&gt;
 1 Stück 10pol Wannenstecker zum aufpressen auf Flachkabel&lt;br /&gt;
 1m Flachkabel 9 polig&lt;br /&gt;
 1 Stück Universal Sub D-Gehäuse&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Der 1 Schritt besteht darin das man gleich alle Bauteil in die Platine einsteckt und so biegt, das diese beim umdrehen und einlöten nicht herausfallen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
http://www.robotikhardware.de/bilder/isp/isp2.jpg&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Löten ist eigentlich bei den wenigen Bauteilen keine groß Kunst und sollte von jedem Laien in wenigen 2 Minuten erledigt sein.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
http://www.robotikhardware.de/bilder/isp/isp3.jpg&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nun werden die SUB-D Stecker einfach direkt auf die Platine gesteckt. Und zwar so, das die Platine genau zwischen der oberen und unteren Reihe liegt. Dabei sollte man darauf achten das die Kontakte auf den verzinnten  Lötflächen liegen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
http://www.robotikhardware.de/bilder/isp/isp4.jpg&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Am besten legt man die Platine mit den aufgesteckten Steckern schon einmal in das Gehäuse um die Passgenauigkeit zu überprüfen. Man variiert also gegebenenfalls die Steckerposition um 1 mm falls es noch nicht 100% passt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
http://www.robotikhardware.de/bilder/isp/isp5.jpg&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Großes Bild [[http://www.robotikhardware.de/bilder/isp/isp6.jpg]]&lt;br /&gt;
&lt;br /&gt;
Jetzt kann man die Kontakte einfach verlöten. Dabei sollte man das Lötzinn  etwas neben den Kontakt halten, damit dieses auch darunter fließen kann. Auch das ist in ca. 2 bis 3 Minuten sehr einfach zu erledigen.&lt;br /&gt;
Gelötet sieht das ganze dann so aus:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
http://www.robotikhardware.de/bilder/isp/isp7.jpg&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nun kann man das Gehäuse einfach zusammenstecken. Jetzt benötigen wir aber noch ein Anschlusskabel für das Roboter- bzw. Experimentierboard. Da hie rein 10 poliger Wannenstecker üblich ist, benötigen wir also diesen und ein SUP-D Stecker und etwas Kabel (9 polig). &lt;br /&gt;
&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
http://www.robotikhardware.de/bilder/isp/isp8.jpg&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Besonders einfach lassen sich hier die Stecker nutzen, die man einfach auf das Flachkabel aufpresst. Zuerst wird das Kabel wie auf dem Bild eingelegt und der hintere Teil am Stecker etwas zusamengedrückt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
http://www.robotikhardware.de/bilder/isp/isp9.jpg&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Eigentlich benötigt man nun eine spezielle Zange um den Stecker gleichmäßig zusammenzudrücken, damit es wirklich gerade in die Adern einschneidet. Aber da nur wenige ein solches Werkzeug besitzen, kann man sich zum Beispiel auch mit einem Schraubstock oder dergleichen behelfen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
http://www.robotikhardware.de/bilder/isp/isp10.jpg&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wichtig ist nur das man die Stecker gleichmäßig und langsam zusammendrückt.&lt;br /&gt;
&lt;br /&gt;
Auf der anderen Seite montieren wir nun auf die gleiche Weise den 10 poligen Wannenstecker. Dabei ist darauf zu achten das Pin 1 (der rot markierte Draht am Flachkabel) an der Stelle sitzt, wo ein Pfeil auf dem Stecker erkennbar ist.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
http://www.robotikhardware.de/bilder/isp/isp11.jpg&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Auch diesen Stecker kann man mit einem Schraubstock oder Maschinenschraubstock pressen&lt;br /&gt;
&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
http://www.robotikhardware.de/bilder/isp/isp12.jpg&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das war es schon. Unser perfektes ISP-Kabel ist fertig und sollte so aussehen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
http://www.robotikhardware.de/bilder/isp/isp13.jpg&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
http://www.robotikhardware.de/bilder/isp/ispstecker.jpg&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Siehe auch==&lt;br /&gt;
*[[RN-Definitionen]]&lt;br /&gt;
*[[Avr]]&lt;br /&gt;
&lt;br /&gt;
==Bezugsquellen==&lt;br /&gt;
* Platine Shop http://www.robotikhardware.de&lt;br /&gt;
* Fertiger Dongle http://www.robotikhardware.de&lt;br /&gt;
Bauteile : &lt;br /&gt;
* http://www.reichelt.de&lt;br /&gt;
* http://www.conrad.de&lt;br /&gt;
&lt;br /&gt;
{{Platinenservice|http://www.robotikhardware.de}}&lt;br /&gt;
{{Fertigservice|http://www.robotikhardware.de}}&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:AVR]]&lt;br /&gt;
[[Category:Robotikeinstieg]]&lt;br /&gt;
[[Category:Praxis]]&lt;br /&gt;
[[Category:Elektronik]]&lt;br /&gt;
[[Category:Projekte]]&lt;/div&gt;</summary>
		<author><name>Nollsen</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=Bascom_-_Erstes_Programm_in_den_AVR_Controller_%C3%BCbertragen&amp;diff=4756</id>
		<title>Bascom - Erstes Programm in den AVR Controller übertragen</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=Bascom_-_Erstes_Programm_in_den_AVR_Controller_%C3%BCbertragen&amp;diff=4756"/>
				<updated>2006-01-03T19:32:30Z</updated>
		
		<summary type="html">&lt;p&gt;Nollsen: /* Weblinks */ Kategorie AVR&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Wie ist der Ablauf mit Bascom Basic?==&lt;br /&gt;
Atmel Controller (also auch [[RN-Control]]) lassen in verschiedenen Programmiersprachen programmieren.  Sehr beliebt sind diesbezüglich der Basic Compiler [[Bascom]], der C Compiler GCC und der AVR Studio Assembler. &lt;br /&gt;
&lt;br /&gt;
Der Einstieg wird einem besonders einfach beim [[Bascom]] Compiler gemacht. Nicht nur dass dieser unzählige von Funktion besitzt, nein auch die Entwicklungsumgebung ist sehr umfangreich. Simulator, [[Terminalprogramm]] und Flasher (Übertragungsprogramm) sowie eine ganze Reihe anderer Tools sind bereits integriert. Zudem erzeugt der Compiler überraschend kompakten Maschinencode.&lt;br /&gt;
Es gibt eine kostenlose Demo-Version von [[Bascom]]. Die Einschränkung gegenüber der Vollversion besteht im wesentlichen darin, das nur 4K Code erzeugt werden kann. Dies reicht bereits für viele kleinere Anwendungen aus. Für ca. 90 Euro gibt’s auch eine Vollversion ohne Einschränkung. Fast alle gängigen [[Atmel]]-Controller lassen sich mit Bascom Basic programmieren.&lt;br /&gt;
&lt;br /&gt;
Der Einstieg ist sehr einfach. Nachdem man sich die Demo oder Vollversion besorgt hat, installiert man das Programm über SETUP auf einem Windows-Rechner, dies ist recht unproblematisch.&lt;br /&gt;
Das Programm wird anschließend über das START-Menü aufgerufen.&lt;br /&gt;
&lt;br /&gt;
Bevor ein erstes Programm entwickelt wird, sollte man erst mal einige grundsätzliche Optionen in Bascom einstellen. Zum Programmieren eines Controllers benötigt man ein speziellen Adapter welcher einige Leitungen des Controllers (SPI-Ports und RESET) mit dem PC verbindet. Man spricht hier von einem [[AVR-ISP Programmierkabel|AVR-ISP Programmierkabel]] oder auch [[AVR-ISP Programmierkabel|ISP-Dongel]] genannt, dieser wird oft an den Druckerport des PC  angeschlossen. &lt;br /&gt;
&lt;br /&gt;
Beispiel eines ISP-Programmierkabels (hier [[AVR-ISP Programmierkabel|Bauanleitung]]):&lt;br /&gt;
&lt;br /&gt;
[[Bild:avrtutorial_ispkabel.jpg|center]]&lt;br /&gt;
&lt;br /&gt;
Verwendet man ein solches Kabel, so sollte man in Bascom folgende Optionen einstellen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
http://www.roboternetz.de/bilder/bascom/bascomispoptionen.gif&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Diese Optionen bleiben dauerhaft gespeichert und müssen nicht bei jedem neuen Programm geändert werden.&lt;br /&gt;
&lt;br /&gt;
Nun müssen noch die Output-Optionen in [[Bascom]] festgelegt werden. Bascom ist in der Lage eine ganze Reihe von verschiedenen Dateien zu generieren um später verschiedene Programmiertools und Debugger nutzen zu können. Empfehlenswert ist folgende Grundeinstellung:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
http://www.roboternetz.de/bilder/bascom/bascomoutputoptionen.gif&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Das erste Programm===&lt;br /&gt;
&lt;br /&gt;
Über das Menü File/New kann dann ein neues Fenster für ein erstes Bascom-Programm geöffnet werden.&lt;br /&gt;
Als erstes Einstiegsprogramm könnte ein &amp;quot;Hello World&amp;quot;-Programm so aussehen:&lt;br /&gt;
&lt;br /&gt;
  Print &amp;quot;**** RN-CONTROL sagt Hello World *****&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Dieses Programm würde allerdings kaum funktionieren, außer wenn man unter Optionen den Controllertyp, die genaue Quarzfrequenz und Baudrate des verwendeten Controllers (Controllerboard´s) richtig eingestellt hat.&lt;br /&gt;
&lt;br /&gt;
Es ist allerdings empfehlenswert diese Werte lieber im Programmcode mit festzulegen. Dadurch hat man eine wesentlich bessere Übersicht und kann die Programme auch leichter, ohne zusätzliche Kommentare, an interessierte weitergeben. Eventuell vorhandene Einstellungen im Optionsmenü werden durch die Anweisungen im Code außer Kraft gesetzt.&lt;br /&gt;
Im Falle von dem Microcontrollerboard [[RN-Control]] mit AVR [[ATMega32]] sollte daher jeder Quelltext mit folgenden Zeilen beginnen:&lt;br /&gt;
&lt;br /&gt;
  $regfile = &amp;quot;m32def.dat&amp;quot;&lt;br /&gt;
  $framesize = 32&lt;br /&gt;
  $swstack = 32&lt;br /&gt;
  $hwstack = 32&lt;br /&gt;
  $crystal = 16000000&lt;br /&gt;
  $baud = 9600&lt;br /&gt;
   do&lt;br /&gt;
     Print &amp;quot;**** RN-CONTROL sagt Hello World *****&amp;quot;&lt;br /&gt;
     wait 1&lt;br /&gt;
   loop&lt;br /&gt;
&lt;br /&gt;
Die erste Anweisung $regfile  legt fest für welchen Controllertyp überhaupt Code produziert werden soll. Die Anweisungen    $framesize,  $swstack,  $hwstack sind eigentlich bei dem kleinen Programm nicht notwendig. Sie legen den Platz fest, der für bestimmte Stackbereiche (lokale Variablen / Funktionsparameter) reserviert wird. Man sollte sich jedoch gleich angewöhnen diese Anweisungen in den Code zu schreiben. Das ermitteln der richtigen Werte für die Stackgröße ist etwas aufwendiger, dazu bietet Bascom spezielle Funktionen für den Simulator. In der Regel kommt man aber mit den oberen Werten schon bei den meisten Programmen hin. Im Zweifel sollte man die Werte etwas erhöhen. Je höher die Werte, desto mehr Speicher wird natürlich benötigt. Zu geringe Werte können aber unter Umständen, wenn z.B. viele Subroutinen, Funktionen, Interrupts, lokale Variablen genutzt werden, zu seltsamen schwer auffindbaren Programmfehlern führen. &lt;br /&gt;
Wenn also eine Funktion völlig unsinnige Ergebnisse liefert oder Abstürze erfolgen, dann ist es Zeit den Stack mal zu prüfen.&lt;br /&gt;
&lt;br /&gt;
Die Anweisung $crystal legt die Quarzfrequenz fest. Es ist wichtig dass Bascom weiss mit welcher Quarzfrequenz der Controller arbeitet, ansonsten liefern viele Funktionen falsche Ergebnisse oder funktionieren erst garnicht. Anzumerken ist hier, das [[AVR]] Controller der Mega Serie (wie der [[ATMega32]] in [[RN-Control]]) nach dem Kauf noch gar keinen Quarz sondern den internen Taktgenerator nutzen. Der interne Taktgenerator läuft immer mit 1 Mhz, so dass man bei neuen Controllern eigentlich   $crystal=1000000 angeben müsste. Zumindest solange bis man den Quarz über die sogenannten Fusebits (bestimmte Einstellungen im Controller) aktiviert.&lt;br /&gt;
Da in diesem Beispiel jedoch das Board [[RN-Control]] gleich auf die vollen 16 Mhz umgeschaltet werden soll,  geben wir gleich $crystal = 16000000  an.&lt;br /&gt;
&lt;br /&gt;
Die Anweisung  $baud = 9600 bestimmt die Übertragungsgeschwindigkeit der RS232 Schnittstelle im Controller. 9600 Baud ist ein Wert der sehr oft genutzt wird. Da ein Controller ja kein Bildschirm besitzt, erfolgen alle Ausgaben gewöhnlich über diese RS232  Schnittstelle. Man muss also nur das eingebaute [[Terminalprogramm]] in [[Bascom]] starten und kann dann alle Ausgaben des angeschlossenen Controllers am Bildschirm verfolgen. Dies ist sehr hilfreich bei der Fehlersuche in Programmen, daher gehört neben dem [[AVR-ISP Programmierkabel]] eigentlich auch immer ein RS232-Kabel zur Standard Ausstattung eines Programmierers.&lt;br /&gt;
&lt;br /&gt;
Nachdem nun der Quellcode erstellt wurde muss dieser compiliert (in Maschinencode übersetzt) werden. Dies geschieht durch einen einfachen Klick: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
http://www.roboternetz.de/bilder/bascom/bascomcompilieren550_a.gif&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hat man noch einen Fehler im Quellcode, dann steht nun gewöhnlich im unteren Bereich eine Fehlermeldung, ansonsten dürfte ein Fenster ähnlich wie dieses erscheinen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
http://www.roboternetz.de/bilder/bascom/bascomcompiliermsg_b.gif&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dieser Vorgang dauert oft nur wenige Sekunden, danach ist das Maschinencodeprogramm fertig. Damit es ausgeführt werden kann, muss es natürlich in den Controller übertragen werden. Dazu verbindet man das Controllerboard über ein ISP-Programmierkabel mit dem Druckerport des PC´s. Zudem schaltet man die Betriebsspannung des Baords ein. Nun kann der Bascom Programmiermodus durch einen Klick aktiviert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
http://www.roboternetz.de/bilder/bascom/bascomprgaktivieren550_c.gif&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im Bascom Programmiermodus wird der Maschinencode in Hex-Form angezeigt. In diesem Dialog brauchen wir eigentlich nur die Übertragung zu starten. Dies geschieht wiederum durch einen Klick:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
http://www.roboternetz.de/bilder/bascom/bascomispstart550_d.gif&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Auch die Übertragung dauert nur wenige Sekunden. Wenn alles geklappt hat sollte in der Statuszeile links &amp;quot;OK&amp;quot; stehen. Leider ist die ISP Übertragung manchmal etwas störanfällig so das man einen zweiten oder dritten Versuch braucht. Kommt dies öfters vor, sollte man prüfen ob nicht ein Netzkabel oder eine andere Störquelle das ISP Kabel kreuzt.&lt;br /&gt;
&lt;br /&gt;
Nachdem man das Programm übertragen hat, muss man bei einem neuen Controller noch die sogenannten Fusebit´s umschalten. Unter dem Begriff Fusebit´s versteht man bestimmte Controllereinstellungen die ebenfalls über das ISP-Programmierkabel geändert werden können. Es gibt eine ganze Reihe von Einstellungen die man verändern kann, dies ist bei jedem Controller ein wenig anders. gewöhnlich reicht es jedoch den Quarz zu aktivieren und ein soganannten JTAG-Interface zu deaktivieren. Das JTAG-Interface ist ein spezielles Debugger-Interface um Programmfehler zu finden, es kann jedoch nur genutzt werden wenn man spezielle Zusatzhardware besitzt. Da dies selten der Fall ist kann man diese Port´s auch für andere Zwecke nutzen, daher wird dieses oft deaktiviert.&lt;br /&gt;
Um die Fusebit´s nun zu ändern rufen wir im Programmierdialog die Tafel mit den [[Fusebits]] durch einen klick auf:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
http://www.roboternetz.de/bilder/bascom/bascomfusebitdialog550_e.gif&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Controller muss beim Aufruf dieses Dialoges angeschlossen und mit Strom versorgt werden.&lt;br /&gt;
Nun können wir die [[Fusebits]] an zwei Stellen ändern. Dies geht in [[Bascom]] sehr bequem, da wir in zwei Feldern nur eine andere Auswahl treffen müssen, siehe Bild:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
http://www.roboternetz.de/bilder/bascom/bascomquarz550_f.gif&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Beim Quarz ist es meist die unterste Auswahlmöglichkeit. Die [[Fusebits]] sind also richtig eingestellt wenn es wie auf dem oberen Bild aussieht. Bei dem Board [[RN-Control]] sind diese Einstellungen in der Regel nicht notwendig da diese bereits vor der Auslieferung umgestellt werden.&lt;br /&gt;
Die Fusebits müssen auch nur einmal umgestellt werden. Die Einstellungen  bleiben auch erhalten wenn ein neues Programm eingespielt wird.&lt;br /&gt;
Nicht vergessen dass nach der Änderungen der Fusebit-Auswahl diese auch über den Button &amp;quot;WRITE FS&amp;quot; und &amp;quot;WRITE FSH&amp;quot; in den Controller übertragen werden müssen. &lt;br /&gt;
&lt;br /&gt;
Vorsicht: Vor der Übertragung darauf achten dass die richtigen Quarzeinstellungen gewählt wurden. Man kann den Controller dort nämlich auch auf aktive externe Taktgeneratoren umstellen. Wenn man dies versehentlich tut und keinen echten Taktgenerator hat, dann ist der Controller quasi tot und muss gewechselt werden.&lt;br /&gt;
&lt;br /&gt;
Mit der Programmübertragung wird gleichzeitig auch immer ein RESET ausgeführt und das Programm im Controller gestartet. Wenn Sie nun also das Terminalprogramm in Bascom starten (Parameter 9800 baud, 8 Bit, 1 Stopp Bit), dann wird im Sekundentakt  ''**** RN-CONTROL sagt Hello World *****''  erscheinen.&lt;br /&gt;
&lt;br /&gt;
'''Nun viel Spaß beim Einstieg'''&lt;br /&gt;
&lt;br /&gt;
==Autor==&lt;br /&gt;
* Frank&lt;br /&gt;
&lt;br /&gt;
==Siehe auch==&lt;br /&gt;
*[[Bascom]]&lt;br /&gt;
*[[AVR-ISP Programmierkabel]]&lt;br /&gt;
*[[RN-Board FAQ-Seite]] &lt;br /&gt;
*[[Atmel]]&lt;br /&gt;
*[[RN-Control]]&lt;br /&gt;
*[[AVR-Einstieg leicht gemacht]]&lt;br /&gt;
*[[Buchvorstellungen]]&lt;br /&gt;
&lt;br /&gt;
==Weblinks==&lt;br /&gt;
[http://www.roboternetz.de/phpBB2/viewforum.php?f=32 Bascom-Forum]&lt;br /&gt;
[[Kategorie:AVR]]&lt;br /&gt;
[[Kategorie:Microcontroller]]&lt;br /&gt;
[[Kategorie:Software]]&lt;br /&gt;
[[Kategorie:Grundlagen]]&lt;br /&gt;
[[Kategorie:Praxis]]&lt;br /&gt;
[[Kategorie:Robotikeinstieg]]&lt;/div&gt;</summary>
		<author><name>Nollsen</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=Bascom_Inside&amp;diff=4755</id>
		<title>Bascom Inside</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=Bascom_Inside&amp;diff=4755"/>
				<updated>2006-01-03T19:32:27Z</updated>
		
		<summary type="html">&lt;p&gt;Nollsen: /* Siehe auch */ Kategorie AVR&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Bascom Inside==&lt;br /&gt;
===Stacks &amp;amp; Frame===&lt;br /&gt;
Bascom arbeitet mit drei Bereichen: &lt;br /&gt;
* HW-Stack, &lt;br /&gt;
* Software-Stack und &lt;br /&gt;
* Frame. &lt;br /&gt;
Beschrieben ist das im „HELP“.&lt;br /&gt;
Zusätzlich wird noch das &lt;br /&gt;
* Register r6 für spezielle Flags verwendet (Bit #2 im Register 6 ist das ERR-Bit)&lt;br /&gt;
&lt;br /&gt;
[[Bild:Stack1.jpg]]&lt;br /&gt;
&lt;br /&gt;
====Hw-(Hardware-)Stack====&lt;br /&gt;
Der Hardware-Stack ist sozusagen der &amp;quot;normale&amp;quot; Stack, der von den Controllern durch den Stack-Pointer und entsprechende Befehle unterstützt wird.&lt;br /&gt;
BasCom verwendet ihn natürlich für CALL / RET / RETI / PUSH und POP. &lt;br /&gt;
====Sw-(Software-)Stack====&lt;br /&gt;
Für Pointer auf temporäre Daten und die Parameter für SUB und FUNCTION hat BasCom einen eigenen Stack definiert. Er liegt unterhalb des Hardwarestacks. &lt;br /&gt;
====Frame====&lt;br /&gt;
Für die temporäre Daten selbst wird der Frame-Bereich verwendet&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Definition===&lt;br /&gt;
  $framesize = 32         ' die Größe des Frames &lt;br /&gt;
  $swstack = 32           ' die Größe des Software-stacks&lt;br /&gt;
  $hwstack = 32           ' die Größe des Hardware-Stacks&lt;br /&gt;
&lt;br /&gt;
Die tatsächlich benötigten Größen sind schwer zu errechnen. &lt;br /&gt;
Einige Anhaltspunkte:&lt;br /&gt;
* Bei jedem Interrupt werden schon mal 32 Byte HW-Stack sicher verbraten, nur, um alle Register zu sichern. &lt;br /&gt;
* Jedes &amp;quot;LOCAL&amp;quot; Data verbraucht Frame-Space in seiner Größe + 2 byte auf dem Soft-Stack&lt;br /&gt;
* Jeder Parameter einer &amp;quot;SUB&amp;quot;  braucht 2 Byte SoftStack + die Datengröße,  wenn zusätzlich &amp;quot;byval&amp;quot; angegeben ist. &lt;br /&gt;
* datenkonversionen Zahl --&amp;gt; string brauchen die Stringlänge ( PRINT !) &lt;br /&gt;
&lt;br /&gt;
 Für ein anständiges Programm sind die Default-Werte auf jeden Fall viel zu klein.&lt;br /&gt;
 Im Zweifelsfall so groß wie möglich, besonders der SoftStack.  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Lokale Daten===&lt;br /&gt;
&lt;br /&gt;
Für lokale Daten muß natürlich erstmal ein Platz geschaffen werden. BasCom verwendet dazu das Frame, die Adresse der Daten legt er auf den Software-Stack. &lt;br /&gt;
Alle Datentypen werden gleich behandelt, nur die reservierte Byte-Länge ist relevant.&lt;br /&gt;
BasCom schreibt die erforderliche Länge des Items nach R24 und ruft eine interne Function auf.Diese sichert erst den Frame-Pointer (r4:r5) auf dem Software-Stack, erhöht den Frame-Pointer um den verlangten Wert und kehrt zurück &lt;br /&gt;
&lt;br /&gt;
====reserve space====&lt;br /&gt;
LOCAL  Einbyte AS BYTE&lt;br /&gt;
&lt;br /&gt;
  ....&lt;br /&gt;
 LDI r24,$01 // gewünschte Länge = immediate value&lt;br /&gt;
 CALL AddFrame&lt;br /&gt;
  ....&lt;br /&gt;
&lt;br /&gt;
 AddFrame:&lt;br /&gt;
 ST --Y,r5 // Store &amp;amp; Save Frampointer Hi&lt;br /&gt;
 ST --Y,r4 // Store &amp;amp; Save Frampointer LO&lt;br /&gt;
 ADD r4,r24 // addieren der gewünschten Länge auf den FramePointer&lt;br /&gt;
 CLR r24 &lt;br /&gt;
 ADC r5,r24 // ev. carry - Überlauf&lt;br /&gt;
 RET&lt;br /&gt;
&lt;br /&gt;
Dadurch befindet sich die Adresse des lokalen Datums auf &lt;br /&gt;
&lt;br /&gt;
 Y + 0 // Adresse LSB&lt;br /&gt;
 Y + 1 // Adresse MSB&lt;br /&gt;
&lt;br /&gt;
und steht dort (natürlich nur innerhalb der Function oder Subroutine) zu Verfügung&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====unreserve====&lt;br /&gt;
Vor dem &amp;quot;Return&amp;quot; der Subroutine oder Function muß natürlich alles wiederhergestellt werden&lt;br /&gt;
BasCom hat natürlich mitgezählt, wieviel Platz benötigt wurde, und er weiß auch, wieviele solcher Adressen er auf den Soft-Stack gelegt hat.&lt;br /&gt;
&lt;br /&gt;
 …..&lt;br /&gt;
 ADIW YL,$0002 // Addieren auf den Software Stack Pointer&lt;br /&gt;
 LDI r24,$01   // Subtrahieren vom Frame Pointer (z.b. 1 Byte )&lt;br /&gt;
 CALL SubR4&lt;br /&gt;
 RET           // return Sub or Function&lt;br /&gt;
&lt;br /&gt;
 SubR4:&lt;br /&gt;
 SUB r4,r24&lt;br /&gt;
 CLR r24&lt;br /&gt;
 SBC r5,r24&lt;br /&gt;
 RET&lt;br /&gt;
&lt;br /&gt;
===Call Sub &amp;amp; Function===&lt;br /&gt;
&lt;br /&gt;
Die Parameter an die Funktion / Sub werden über den Softstack übergeben. &lt;br /&gt;
Außer für den eigentlichen CALL der Function / Sub wird der HW-Stack hier nicht verwendet.&lt;br /&gt;
&lt;br /&gt;
Es gibt an sich zwei Übergabe-Varianten: BYVAL und BYREF, es wird aber immer BYREF (Addresse von) verwendet, der Unterschied liegt nur darin, dass bei &lt;br /&gt;
BYVAL die Addresse einer Daten-Kopie statt des Originals übergeben wird. Die Reihenfolge ist von links nach rechts, wobei die Adresse des Ergebnisses (Funktion) &lt;br /&gt;
als erstes auf den Soft-Stack gelegt wird wird. &lt;br /&gt;
&lt;br /&gt;
'''Folgenden Deklarationen führen im Programm zum gleichen Code'''&lt;br /&gt;
 Declare Function MyFunc (byval Op1 as byte, byval Op2 as byte) as byte&lt;br /&gt;
 Declare Sub MySub (byref Result as byte , byval Op1 as byte, byval Op2 as byte) &lt;br /&gt;
&lt;br /&gt;
Die Situation beim Aufruf der Funktion / Sub sieht nun folgendermaßen aus, den HW-Stack nicht berücksichtigend&lt;br /&gt;
&lt;br /&gt;
[[Bild:Stack2.jpg]]&lt;br /&gt;
&lt;br /&gt;
Die Funktion / Sub findet nun (beim Entry)&lt;br /&gt;
&lt;br /&gt;
 OP2 auf Y + 0/1 &lt;br /&gt;
 OP1 auf Y + 2/3 &lt;br /&gt;
 Result auf Y + 4/5 &lt;br /&gt;
&lt;br /&gt;
Verwendet die Funktion / Sub nun selbst den SW-Stack oder das Frame, muß sie das natürlich bei den Y-Offsets berücksichtigen und vor dem Return muß der obige &lt;br /&gt;
Zustand auch wiederhergestellt werden. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Siehe auch==&lt;br /&gt;
* [[Bascom]]&lt;br /&gt;
[[Kategorie:AVR]]&lt;br /&gt;
[[Kategorie:Grundlagen]]&lt;br /&gt;
[[Kategorie:Software]]&lt;/div&gt;</summary>
		<author><name>Nollsen</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=Bascom&amp;diff=4754</id>
		<title>Bascom</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=Bascom&amp;diff=4754"/>
				<updated>2006-01-03T19:32:23Z</updated>
		
		<summary type="html">&lt;p&gt;Nollsen: /* Literatur */ Kategorie AVR&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==AVR Bascom Basic==&lt;br /&gt;
&lt;br /&gt;
Bascom ist eine komplette Basic-Entwicklungsumgebung für die verschiedensten AVR Controller.Er bietet ein ungeheuer großes Leistungsvermögen und besonders anwenderfreundliche Entwicklungsumgebung. &lt;br /&gt;
Eine kostenlose Version, die bis zu 4 KB (das ist schon einiges bei einem Controller) keinerlei Einschränkungen besitzt, findet man auf der Seite des Herstellers &lt;br /&gt;
&lt;br /&gt;
[http://www.mcselec.com/index.php?option=com_docman&amp;amp;task=cat_view&amp;amp;gid=99&amp;amp;Itemid=54 Bascom-Download]&lt;br /&gt;
&lt;br /&gt;
Nach dem Download müssen alle Dateien entpackt und das SETUP-Programm aufgerufen werden. Danach steht ein Basic-Entwicklungssystem zur Verfügung das alles beinhaltet was für die AVR-Programmierung notwendig ist. Zum Beispiel: Editor mit Befehlsvorschlag, Simulator, Terminalprogram, Avr-FuseBit Einstellung, integriertem Assembler, eingebauten Programmer zur Übertragung des Programmcode usw.&lt;br /&gt;
&lt;br /&gt;
Als erstes solltet ihr unter dem Menü Options / Compiler den Zielprozessor angeben. Fast alle gängigen AVR Controller können programmiert werden.&lt;br /&gt;
In diesem Dialog können auch noch viele weitere Einstellungen vorgenommen werden. Eigentlich ist das alles selbsterklärend. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
http://www.shop.robotikhardware.de/shop/catalog/images/artikelbilder/bascom/bascom.gif&lt;br /&gt;
&lt;br /&gt;
==Befehlsübersicht von Bascom==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Decision and structures:&lt;br /&gt;
IF, THEN, ELSE, ELSEIF, END IF, DO, LOOP, WHILE, WEND, UNTIL,&lt;br /&gt;
EXIT DO, EXIT WHILE, FOR, NEXT, TO,  STEP, EXIT FOR,&lt;br /&gt;
ON .. GOTO/GOSUB, SELECT, CASE.&lt;br /&gt;
&lt;br /&gt;
Input and output:&lt;br /&gt;
PRINT, INPUT, INKEY, PRINT, INPUTHEX, LCD, UPPERLINE, LOWERLINE,&lt;br /&gt;
DISPLAY ON/OFF, CURSOR ON/OFF/BLINK/NOBLINK, HOME, LOCATE, &lt;br /&gt;
SHIFTLCD LEFT/RIGHT, SHIFTCURSOR LEFT/RIGHT, CLS, DEFLCDCHAR, WAITKEY,&lt;br /&gt;
INPUTBIN, PRINTBIN,  OPEN, CLOSE, DEBOUNCE, SHIFTIN, SHIFTOUT,&lt;br /&gt;
GETATKBD, SPC, SERIN, SEROUT&lt;br /&gt;
&lt;br /&gt;
Numeric functions:&lt;br /&gt;
AND, OR, XOR, INC, DEC, MOD, NOT, ABS, BCD, LOG, EXP, SQR, SIN,COS,&lt;br /&gt;
TAN,ATN, ATN2, ASIN, ACOS, FIX, ROUND, MOD, SGN, POWER, RAD2DEG,&lt;br /&gt;
DEG2RAD, LOG10, TANH, SINH, COSH.&lt;br /&gt;
&lt;br /&gt;
I2C:&lt;br /&gt;
I2CSTART, I2CSTOP, I2CWBYTE, I2CRBYTE, I2CSEND and I2CRECEIVE.&lt;br /&gt;
&lt;br /&gt;
1WIRE:&lt;br /&gt;
1WWRITE, 1WREAD, 1WRESET, 1WIRECOUNT, 1WSEARCHFIRST, 1WSEARCHNEXT.&lt;br /&gt;
&lt;br /&gt;
SPI:&lt;br /&gt;
SPIINIT, SPIIN, SPIOUT, SPIMOVE.&lt;br /&gt;
&lt;br /&gt;
Interrupt programming:&lt;br /&gt;
ON INT0/INT1/TIMER0/TIMER1/SERIAL, RETURN, ENABLE, DISABLE, &lt;br /&gt;
COUNTERx, CAPTUREx, INTERRUPTS, CONFIG, START, LOAD.&lt;br /&gt;
&lt;br /&gt;
Bit manipulation:&lt;br /&gt;
SET, RESET, ROTATE, SHIFT, BITWAIT, TOGGLE.&lt;br /&gt;
&lt;br /&gt;
Variables:&lt;br /&gt;
DIM, BIT , BYTE , INTEGER , WORD, LONG, SINGLE, DOUBLE, STRING , DEFBIT,&lt;br /&gt;
DEFBYTE, DEFINT, DEFWORD.&lt;br /&gt;
&lt;br /&gt;
Miscellaneous:&lt;br /&gt;
REM, ' , SWAP, END, STOP, CONST, DELAY, WAIT, WAITMS, GOTO, GOSUB, &lt;br /&gt;
POWERDOWN, IDLE, DECLARE, CALL, SUB, END SUB, MAKEDEC, MAKEBCD, &lt;br /&gt;
INP,OUT, ALIAS, DIM , ERASE, DATA, READ, RESTORE, INCR, DECR, PEEK,&lt;br /&gt;
POKE, CPEEK, FUNCTION, READMAGCARD, BIN2GRAY, GRAY2BIN, CRC8, CRC16,&lt;br /&gt;
CHECKSUM.&lt;br /&gt;
&lt;br /&gt;
Compiler directives:&lt;br /&gt;
$INCLUDE, $BAUD and $CRYSTAL,  $SERIALINPUT, $SERIALOUTPUT, $RAMSIZE,&lt;br /&gt;
$RAMSTART,   $DEFAULT XRAM, $ASM-$END ASM, $LCD, $EXTERNAL, $LIB.&lt;br /&gt;
&lt;br /&gt;
String manipulation:&lt;br /&gt;
STRING, SPACE, LEFT, RIGHT, MID, VAL, HEXVAL, LEN, STR, HEX, &lt;br /&gt;
LTRIM, RTRIM, TRIM, LCASE, UCASE, FORMAT, FUSING, INSTR. &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Erläuterung grundlegender Bascom-Funktionen==&lt;br /&gt;
Hier einige kleine Programme welche die grundlegende Funktionen und Syntax zeigen. Es wird immer ein komplettes Programm gezeigt, so das man dieses einfach kopieren und austesten kann. Bascom Programme bestehen in der Regel fast immer nur aus einer Sourcecode-Datei (obwohl es auch anders geht), also nicht wie bei der Programmiersprache C üblich aus mehreren Dateien (Header-Dateien etc.). Auch das macht Bascom besonders Einsteigerfreundlich.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Das berühmte Hello World Programm in Bascom===&lt;br /&gt;
Da bei einem Controllerboard gewöhnlich kein Bildschirm zur Verfügung steht, verbindet man das Board über einfaches RS232 Kabel (nur 3 Drähte sind notwendig) mit dem PC. Ein [[Terminalprogramm]] (Bascom hat bereits eines in der Entwicklungsumgebung integriert) zeigt nun auf dem Bildschirm alle Ausgaben des Boardes (z.B. des Print Befehles) an. Eine Methode die zum Debuggen von Programmen oft genutzt wird. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 $regfile = &amp;quot;m32def.dat&amp;quot; 'Die Anweisung bestimmt Ccntrollertyp, hier AVR Mega 32&lt;br /&gt;
 $framesize = 32         'Stackanweisungen, die eigentlich nur bei größeren Programmen &lt;br /&gt;
 $swstack = 32           'wirklich nötig werden&lt;br /&gt;
 $hwstack = 32&lt;br /&gt;
 $crystal = 16000000     'Die Frequenz des verwendeten Quarzes&lt;br /&gt;
&lt;br /&gt;
 $baud = 9600            'Die Baudrate für RS232 Ausgabe. &lt;br /&gt;
                         'Sie muss auch bei PC Terminalprogramm identisch sein&lt;br /&gt;
  do&lt;br /&gt;
    Print &amp;quot;**** RN-CONTROL sagt Hello World *****&amp;quot;&lt;br /&gt;
    wait 1&lt;br /&gt;
  loop&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Einen I/O Port umschalten===&lt;br /&gt;
Die wohl wichtigste Aufgabe beim Controller ist die Programmierung der Ports. Also  das bestimmen des Ausgangspegels eines Controllerpins. &lt;br /&gt;
Bascom verfügt über zwei Möglichkeiten die Ports zu beeinflussen, die sogenannten High-Level Befehle und die übliche Registerzuweisung wie sie in C üblich ist.&lt;br /&gt;
Zuerst ein Programm mit High-Level Anweisung. Ein [[Pin]] wird als Ausgang definiert und dann fortlaufenden ein und ausgeschaltet. ISt übe rein Wiederstand eine LED an diesem Controllerpin angschlossen (so im Falle von [[RN-Control]]), so ergibt sich ein blinken&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 $regfile = &amp;quot;m32def.dat&amp;quot;  'Die Anweisung bestimmt Controllertyp, hier AVR Mega 32&lt;br /&gt;
 $framesize = 32          'Stackanweisungen, die eigentlich nur bei größeren Programmen &lt;br /&gt;
 $swstack = 32            'wirklich nötig werden&lt;br /&gt;
 $hwstack = 32&lt;br /&gt;
 $crystal = 16000000      'Die Frequenz des verwendeten Quarzes&lt;br /&gt;
&lt;br /&gt;
 $baud = 9600             'Die Baudrate für RS232 Ausgabe. &lt;br /&gt;
                          'Sie muss auch bei PC Terminalprogramm identisch sein&lt;br /&gt;
&lt;br /&gt;
 Config Portc.0 = Output  'Ein Pin wird aus Ausgang konfiguriert PC0 (also Pin0 von Port C)&lt;br /&gt;
&lt;br /&gt;
  do&lt;br /&gt;
     Portc.0 = 1          'Pin wird auf High, also 5V geschaltet&lt;br /&gt;
     Waitms 100&lt;br /&gt;
     Portc.0 = 0          'Pin wird auf Low, also 0V geschaltet&lt;br /&gt;
     Waitms 100&lt;br /&gt;
  loop&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Man kann das ganze noch etwas übersichtlicher gestalten indem man dem Port-[[Pin]] im Programmcode eine andere Bezeichnung gibt, z.B. LED wie in dem folgenden Beispiel. Durch den Alias Befehl wird das ganze Programm wesentlich klarer, so das einige Kommentarzeilen durchaus entfallen könnten. Man sollte sich daher angewöhnen den Alias Befehl auch zu nutzen&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 $regfile = &amp;quot;m32def.dat&amp;quot;  'Die Anweisung bestimmt Controllertyp, hier AVR Mega 32&lt;br /&gt;
 $framesize = 32          'Stackanweisungen, die eigentlich nur bei größeren Programmen &lt;br /&gt;
 $swstack = 32            'wirklich nötig werden&lt;br /&gt;
 $hwstack = 32&lt;br /&gt;
 $crystal = 16000000      'Die Frequenz des verwendeten Quarzes&lt;br /&gt;
&lt;br /&gt;
 $baud = 9600             'Die Baudrate für RS232 Ausgabe. &lt;br /&gt;
                          'Sie muss auch beim PC Terminalprogramm identisch sein&lt;br /&gt;
&lt;br /&gt;
 Config Portc.0 = Output  'Ein Pin wird als Ausgang konfiguriert PC0 (also Pin0 von Port C)&lt;br /&gt;
 Led Alias Portc.0       &lt;br /&gt;
&lt;br /&gt;
  do&lt;br /&gt;
     Led = 1              'Pin wird auf High, also 5V geschaltet&lt;br /&gt;
     Waitms 100&lt;br /&gt;
     Led = 0              'Pin wird auf Low, also 0V geschaltet&lt;br /&gt;
     Waitms 100&lt;br /&gt;
  loop&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Das nachfolgende Beispiel kommt ohne den High-Level Befehl CONFIG aus, indem direkt in das Datenrichtungsregister des Controllers geschrieben wird. In diesem Register steht jedes Bit für den Betriebsmode eines Pins. Die 1 bedeutet der Pin ist auf Ausgang geschaltet, 0 bedeutet Eingang. Diese Schreibweise hat den Nachteil das sie ein wenig unübersichtlicher ist, man kann sehr schnell [[Pin]]´s verwechseln. Vorteil ist allerdings das alle 8 [[Pin]]´s eines Portes gleichzeitig mit einer Zuweisung definiert werden können. Es gibt daher Programmierer die diese Methode bevorzugen, insbesondere wenn Sie auch Controller in C programmieren. Das Ergebnis ist in jedem Fall gleich: ein Blinklicht&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 $regfile = &amp;quot;m32def.dat&amp;quot;  'Die Anweisung bestimmt Controllertyp, hier [[AVR]] Mega 32&lt;br /&gt;
 $framesize = 32          'Stackanweisungen, die eigentlich nur bei größeren Programmen &lt;br /&gt;
 $swstack = 32            'wirklich nötig werden&lt;br /&gt;
 $hwstack = 32&lt;br /&gt;
 $crystal = 16000000      'Die Frequenz des verwendeten Quarzes&lt;br /&gt;
&lt;br /&gt;
 $baud = 9600             'Die Baudrate für RS232 Ausgabe. &lt;br /&gt;
                          'Sie muss auch bei PC Terminalprogramm identisch sein&lt;br /&gt;
&lt;br /&gt;
 DDRC = &amp;amp;b00000001        'Port PC0 wird als Ausgang definiert, man hätte hier auch&lt;br /&gt;
                          'DDRC =1 schreiben können. Man verwendet aber oft die Bitdarstellung&lt;br /&gt;
                          'um alle 8 Bit besser überschauen zu können&lt;br /&gt;
&lt;br /&gt;
  do&lt;br /&gt;
     Portc.0 = 1          'Pin wird auf High, also 5V geschaltet&lt;br /&gt;
     Waitms 100&lt;br /&gt;
     Portc.0 = 0          'Pin wird auf Low, also 0V geschaltet&lt;br /&gt;
     Waitms 100&lt;br /&gt;
  loop&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===I/O-Port als Eingang===&lt;br /&gt;
Im nachfolgenden Beispiel möchten wir ein PIN als Eingang verwenden und den Zustand eines Tasters abfragen. Dazu werden die Pole eines Tastes einmal mit GND (Masse) und einmal mit einem Port PA0 verbunden. Wir hätten auch jeden anderen Port nehmen können, da beim [[Avr]] Controller nahezu alle Pin´s auch auf Eingang geschaltet werden können. Der übersichtlichkeit halber verwenden wir wieder den Config und den Alias Befehl um den Port in Taster umzutaufen.&lt;br /&gt;
Etwas gewöhnungsbedürftig ist in Bascom das man bei der Definition von Eingangsports nicht PORT sondern PIN beim Config-Befehl angibt. Eine weitere Besonderheit dieses Beispiels ist der Befehl ''Porta.0=1'' beim EIngabeport. Dieser Befehl sorgt dafür das im Controller der EIngangsport über einen hohen Widerstand (ca. 100k) mit High (5V) verbunden wird. Dadurch erreicht man, das bei unbelegtem Port, in unserem Fall ungedrückte Taste, immer ein High Signal gelesen wird. Erst wenn der Taster gedrückt wird, wird diese Spannung quasi kurzgeschlossen und so ein LOW angelegt. Das ganze Beispiel bewirkt nun das bei gedrückter Taste die LED leuchtet und beim loslassen wieder aus geht. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 $regfile = &amp;quot;m32def.dat&amp;quot;  'Die Anweisung bestimmt Controllertyp, hier AVR Mega 32&lt;br /&gt;
 $framesize = 32          'Stackanweisungen, die eigentlich nur bei größeren Programmen &lt;br /&gt;
 $swstack = 32            'wirklich nötig werden&lt;br /&gt;
 $hwstack = 32&lt;br /&gt;
 $crystal = 16000000      'Die Frequenz des verwendeten Quarzes&lt;br /&gt;
&lt;br /&gt;
 $baud = 9600             'Die Baudrate für RS232 Ausgabe. &lt;br /&gt;
                          'Sie muss auch bei PC Terminalprogramm identisch sein&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Config Portc.0 = Output  'Ein Pin wird aus Ausgang konfiguriert PC0 (also Pin0 von Port C)&lt;br /&gt;
 Led Alias Portc.0       &lt;br /&gt;
 Config Pina.0 = Input    'Ein Pin (PA0) wird als Eingang definiert&lt;br /&gt;
 Taster Alias Pina.0&lt;br /&gt;
 Porta.0=1                'Interner Pullup Widerstand ein&lt;br /&gt;
 &lt;br /&gt;
  do&lt;br /&gt;
     if taster=0 then&lt;br /&gt;
       Led=1            'Pin wird auf High, also 5V geschaltet&lt;br /&gt;
     else&lt;br /&gt;
       Led = 0          'Pin wird auf Low, also 0V geschaltet&lt;br /&gt;
     endif&lt;br /&gt;
     Waitms 100&lt;br /&gt;
  loop&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Siehe auch==&lt;br /&gt;
* [[Bascom - Erstes Programm in den AVR Controller übertragen]]&lt;br /&gt;
* [[RN-Control]]&lt;br /&gt;
* [[RNBFRA-Board]]&lt;br /&gt;
* [[Avr]]&lt;br /&gt;
* [[RN-Board FAQ-Seite]] mit wichtigen Einstiegstips&lt;br /&gt;
* [[Sourcevergleich]] - GCC und Bascom&lt;br /&gt;
* [[Bascom Inside]]&lt;br /&gt;
&lt;br /&gt;
==Weblinks==&lt;br /&gt;
* [http://www.mcselec.com Niederländischer Hersteller MCSELEC]&lt;br /&gt;
* [http://www.robotikhardware.de Bezugsquelle in Deutschland u.a. Robotikhardware.de] &lt;br /&gt;
* [http://www.roboternetz.de/phpBB2/viewtopic.php?t=1511 Bauanleitungen zu Experimentier- und Roboterboards]&lt;br /&gt;
* [http://www.roboternetz.de/phpBB2/dload.php?action=file&amp;amp;file_id=169 RN-Timer Windows Programm zur Timer-Berechnung]&lt;br /&gt;
&lt;br /&gt;
==Literatur==&lt;br /&gt;
* [[Buchvorstellungen|Programmieren der AVR RISC Mikrocontroller mit BASCOM-AVR; 2. Auflage]]&lt;br /&gt;
* [[Buchvorstellungen|Bascom–AVR, Autor M.Meissner - Beschreibung der Bascom IDE]]&lt;br /&gt;
* [[Buchvorstellungen|AVR-Microcontroller Lehrbuch – Ein tieferer Einstieg in Bascom und AT-MEGA8 und ähnliche AVR-Controller]]&lt;br /&gt;
* [[Buchvorstellungen|BASCOM-AVR Sprachbefehle - Ein umfangreiches Werk welches alle Befehle beschreibt ]]&lt;br /&gt;
* [[Buchvorstellungen|Mega16 Programmierung am Beispiel des RNBFRA-Boards]]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:AVR]]&lt;br /&gt;
[[Kategorie:Microcontroller]]&lt;br /&gt;
[[Kategorie:Software]]&lt;br /&gt;
[[Kategorie:Grundlagen]]&lt;br /&gt;
[[Kategorie:Robotikeinstieg]]&lt;br /&gt;
[[Kategorie:Praxis]]&lt;/div&gt;</summary>
		<author><name>Nollsen</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=RC5-Decoder_f%C3%BCr_ATMega&amp;diff=4753</id>
		<title>RC5-Decoder für ATMega</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=RC5-Decoder_f%C3%BCr_ATMega&amp;diff=4753"/>
				<updated>2006-01-03T19:32:21Z</updated>
		
		<summary type="html">&lt;p&gt;Nollsen: /* Autor */ Kategorie AVR&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Dieser Code imlpementiert einen Interrupt-getriebenen RC5-Empfänger.&lt;br /&gt;
&lt;br /&gt;
Auf eine Flanke an einem externen INT hin werden die nachfolgenden Pulslängen gemessen und in einer Struktur bereitgestellt, falls es sich um RC5-Code handelt und die Empfängeradresse übereinstimmt.&lt;br /&gt;
&lt;br /&gt;
=Abgrenzung=&lt;br /&gt;
&lt;br /&gt;
Nicht alle Fernbedienungen halten sich genau an die RC5-Spezifikation und haben oft einen mehr oder weniger starken Jitter auf dem Signal. In konstanten Zeitabständen auf den Port zu schauen und anhand des gelesenen Wertes das RC5-Signal aufzubauen, funktioniert daher nicht zuverlässig bei allen Fernbedienungen.&lt;br /&gt;
&lt;br /&gt;
Der Ansatz, den diese Implementierung verfolgt, ist aufwändiger und ergibt ein längeres Programm, hat aber dafür nicht den beschriebenen Nachteil.&lt;br /&gt;
&lt;br /&gt;
=Resourcen=&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}} valign=&amp;quot;top&amp;quot;&lt;br /&gt;
 |- bgcolor=&amp;quot;#ccccff&amp;quot;&lt;br /&gt;
! |Resource&lt;br /&gt;
! |Verbrauch (mit &amp;lt;tt&amp;gt;-Os&amp;lt;/tt&amp;gt;)&lt;br /&gt;
 |-&lt;br /&gt;
 |I/O&lt;br /&gt;
 |Timer0, 1 Pin für extern INT&lt;br /&gt;
 |-&lt;br /&gt;
 |Interrupts&lt;br /&gt;
 |Timer0 Overflow, 1 externer IRQ&lt;br /&gt;
 |-&lt;br /&gt;
 |Flash&lt;br /&gt;
 | ~ 0x180&lt;br /&gt;
 |- valign=&amp;quot;top&amp;quot;&lt;br /&gt;
 |SRAM&lt;br /&gt;
 | statisch: 8&amp;lt;br/&amp;gt;Stack: 11&lt;br /&gt;
 |- valign=&amp;quot;top&amp;quot;&lt;br /&gt;
 |Laufzeit,&amp;lt;br/&amp;gt;Erhöhung der IRQ-Latenz&lt;br /&gt;
 | ?, aber statisch abschätzbar&lt;br /&gt;
 |-&lt;br /&gt;
 |externe Hardware&lt;br /&gt;
 |IR-Empfänger wie TSOP17xx, TSOP18xx o.ä.&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
=Schaltplan=&lt;br /&gt;
{| {{Blaueschmaltabelle}}&lt;br /&gt;
 |[[Bild:Tsop-avr-connect.png|Anschluss TSOP17xx an AVR, R1 ca 10k&amp;amp;Omega;]]&lt;br /&gt;
 |-&lt;br /&gt;
 |&amp;lt;div align=&amp;quot;center&amp;quot;&amp;gt;IR-Empfänger vom Typ TSOP17xx an AVR&amp;lt;br&amp;gt;R1 ca 10 k&amp;amp;Omega;&amp;lt;/div&amp;gt;&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
=Interface=&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#define RC5_INT0 0&lt;br /&gt;
#define RC5_INT1 1&lt;br /&gt;
&lt;br /&gt;
#define RC5_ALL 0xff&lt;br /&gt;
&lt;br /&gt;
typedef struct&lt;br /&gt;
{&lt;br /&gt;
	uint8_t code;&lt;br /&gt;
	uint8_t addr;&lt;br /&gt;
	volatile char flip;&lt;br /&gt;
} rc5_t;&lt;br /&gt;
&lt;br /&gt;
extern rc5_t rc5;&lt;br /&gt;
extern void rc5_init (uint8_t addr);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;void rc5_init (uint8_t addr)&amp;lt;/code&amp;gt;: Initialisiert die Hardware für RC5-Empfang. Akzeptiert wird Code, der an Adresse &amp;lt;code&amp;gt;addr&amp;lt;/code&amp;gt; geschickt wird. Falls &amp;lt;code&amp;gt;addr = RC5_ALL&amp;lt;/code&amp;gt; bzw Bit 7 von &amp;lt;code&amp;gt;addr&amp;lt;/code&amp;gt;	gesetzt ist, werden alle Adressen akzeptiert.&lt;br /&gt;
{{FarbigerRahmen|&lt;br /&gt;
Der beteiligte INT-Port wird ''nicht'' auf IN geschaltet und das I-Flag in &amp;lt;code&amp;gt;SREG&amp;lt;/code&amp;gt; (Global Interrupt Enable/Disable-Flag) wird nicht verändert.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;extern rc5_t rc5&amp;lt;/code&amp;gt;: In &amp;lt;code&amp;gt;rc5&amp;lt;/code&amp;gt; wird der empfangene RC5-Code geliefert. Über dieses Objekt wird zudem der RC5-Empfang gesteuert. Wird ein Code mit der gewünschten Adresse ampfangen und ist &amp;lt;code&amp;gt;rc5.flip = -1&amp;lt;/code&amp;gt;, dann wird der Code gespeichert und &amp;lt;code&amp;gt;rc5.flip&amp;lt;/code&amp;gt; gesetzt wie es empfangen wurde. &lt;br /&gt;
Danach wird der Empfänger solange inaktiv, bis der Anwender wieder &amp;lt;code&amp;gt;rc5.flip&amp;lt;/code&amp;gt; auf &amp;lt;code&amp;gt;-1&amp;lt;/code&amp;gt; setzt.&lt;br /&gt;
:;&amp;lt;code&amp;gt;rc5.code&amp;lt;/code&amp;gt;: der empfangene RC5-Code, falls &amp;lt;code&amp;gt;rc5.flip != -1&amp;lt;/code&amp;gt;&lt;br /&gt;
:;&amp;lt;code&amp;gt;rc5.addr&amp;lt;/code&amp;gt;: die Adresse, an die gesendet wurde, falls &amp;lt;code&amp;gt;rc5.flip != -1&amp;lt;/code&amp;gt;&lt;br /&gt;
:;&amp;lt;code&amp;gt;rc5.flip&amp;lt;/code&amp;gt;: das Flip-Bit&lt;br /&gt;
::;&amp;lt;code&amp;gt;rc5.flip = 0&amp;lt;/code&amp;gt;: Code empfangen, RC5-Empfang inaktiv&lt;br /&gt;
::;&amp;lt;code&amp;gt;rc5.flip = 1&amp;lt;/code&amp;gt;: dito&lt;br /&gt;
::;&amp;lt;code&amp;gt;rc5.flip = -1&amp;lt;/code&amp;gt;: RC5-Empfang aktiv, wartet auf nächste Übertragung&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}} &lt;br /&gt;
|- bgcolor=&amp;quot;#ccccff&amp;quot;&lt;br /&gt;
! |Define&lt;br /&gt;
! |default&lt;br /&gt;
! |Werte&lt;br /&gt;
! |Beschreibung&lt;br /&gt;
 |-&lt;br /&gt;
 |&amp;lt;code&amp;gt;RC5_INT&amp;lt;/code&amp;gt;&lt;br /&gt;
 |&amp;lt;code&amp;gt;RC5_INT0&amp;lt;/code&amp;gt;&lt;br /&gt;
 |&amp;lt;code&amp;gt;RC5_INT0&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;RC5_INT1&amp;lt;/code&amp;gt;&lt;br /&gt;
 |Code wird generiert für INT0 resp. INT1, zB gcc-Aufruf mit &amp;lt;code&amp;gt;-DRC5_INT=RC5_INT1&amp;lt;/code&amp;gt; erzeugt Code für INT1&lt;br /&gt;
 |-&lt;br /&gt;
 |&amp;lt;code&amp;gt;RC5_PRESCALE&amp;lt;/code&amp;gt;&lt;br /&gt;
 |&amp;lt;code&amp;gt;1024&amp;lt;/code&amp;gt;&lt;br /&gt;
 |&amp;lt;code&amp;gt;64, 256, 1024&amp;lt;/code&amp;gt;&lt;br /&gt;
 |Legt den Prescaler für Timer0 fest. Standardeinstellung auf 1024, was zu F_CPU=16000000 passt. Für kleinere CPU-Frequenzen muss evtl ein kleinerer PRESCALE gewählt werden; das geht noch nicht automatisch.&lt;br /&gt;
 |-&lt;br /&gt;
 |&amp;lt;code&amp;gt;F_CPU&amp;lt;/code&amp;gt;&lt;br /&gt;
 |&lt;br /&gt;
 |&lt;br /&gt;
 |Gibt die CPU-Frequenz in Hz an&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
=Seiteneffekte=&lt;br /&gt;
&lt;br /&gt;
==SFRs==&lt;br /&gt;
&lt;br /&gt;
Der Code verwendet folgende SFRs und ändert deren Inhalt in den ISRs:&lt;br /&gt;
: '''&amp;lt;code&amp;gt;MCUCR&amp;lt;/code&amp;gt;''': MCU Control Reg&lt;br /&gt;
: '''&amp;lt;code&amp;gt;GICR&amp;lt;/code&amp;gt;''': Global Interrupt Control Reg&lt;br /&gt;
: '''&amp;lt;code&amp;gt;TCNT0&amp;lt;/code&amp;gt;''': Timer0 Counter Reg&lt;br /&gt;
: '''&amp;lt;code&amp;gt;TIMSK&amp;lt;/code&amp;gt;''': Timer Interrupt Mask Reg&lt;br /&gt;
&lt;br /&gt;
{{FarbigerRahmen|&lt;br /&gt;
Falls eines dieser SFRs verändert wird, nachdem RC5-Empfang aktiviert wurde, ''muss'' diese Änderung atomar erfolgen!&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;
#include &amp;lt;avr/interrupt.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
   ...&lt;br /&gt;
   {&lt;br /&gt;
      sreg = SREG;&lt;br /&gt;
      cli();     &lt;br /&gt;
      TIMSK |= ...&lt;br /&gt;
      SREG = sreg;&lt;br /&gt;
   }&lt;br /&gt;
   ...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
==Prescaler==&lt;br /&gt;
&lt;br /&gt;
Timer0 verwendet den Prescaler. Ein Prescaler-Reset sollte aufgrund der langsamen Übertragung bei RC5 unkritisch sein.&lt;br /&gt;
&lt;br /&gt;
=Code=&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
 |'''ANSI-C'''&lt;br /&gt;
 |Nein (C++ Kommentare, anonymous struct)&lt;br /&gt;
 |-&lt;br /&gt;
 |'''Dateien'''&lt;br /&gt;
 | &amp;lt;code&amp;gt;rc5.h&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;rc5.c&amp;lt;/code&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 |'''getestet für'''&lt;br /&gt;
 | ATMega8-16 @ 16MHz, Vcc = 5V&lt;br /&gt;
 |-&lt;br /&gt;
 |'''Portierung'''&lt;br /&gt;
 | ATMegaXX: sollte ohne Anpassung laufen&amp;lt;br&amp;gt;ATTiny, Classic: Anpassungen erforderlich&lt;br /&gt;
 |-&lt;br /&gt;
 |'''Comment-Style'''&lt;br /&gt;
 | &amp;amp;#150;&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
==rc5.c==&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;
#include &amp;lt;avr/signal.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#include &amp;quot;rc5.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
#ifndef RC5_INT&lt;br /&gt;
#define RC5_INT      RC5_INT0&lt;br /&gt;
#endif  // RC5_INT&lt;br /&gt;
&lt;br /&gt;
#ifndef RC5_PRESCALE&lt;br /&gt;
#define RC5_PRESCALE 1024&lt;br /&gt;
#endif  // RC5_PRESCALE&lt;br /&gt;
&lt;br /&gt;
//////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
&lt;br /&gt;
rc5_t rc5;&lt;br /&gt;
&lt;br /&gt;
//////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
&lt;br /&gt;
#ifndef F_CPU&lt;br /&gt;
#error Please define F_CPU&lt;br /&gt;
#endif // !F_CPU&lt;br /&gt;
&lt;br /&gt;
// µs for a whole bit of RC5 (first &amp;amp; second part)&lt;br /&gt;
#define RC5_BIT_US   (64*27)&lt;br /&gt;
&lt;br /&gt;
#define RC5_TICKS \&lt;br /&gt;
	((uint8_t) ((uint32_t) (F_CPU / 1000 * RC5_BIT_US / 1000 / RC5_PRESCALE)))&lt;br /&gt;
	&lt;br /&gt;
#define RC5_DELTA \&lt;br /&gt;
	(RC5_TICKS / 6)&lt;br /&gt;
	&lt;br /&gt;
typedef union &lt;br /&gt;
{&lt;br /&gt;
	uint16_t w;&lt;br /&gt;
	uint8_t b[2];&lt;br /&gt;
	&lt;br /&gt;
	struct&lt;br /&gt;
	{&lt;br /&gt;
		unsigned code:6;&lt;br /&gt;
		unsigned addr:5;&lt;br /&gt;
		unsigned flip:1;&lt;br /&gt;
		unsigned agc:4;&lt;br /&gt;
	} __attribute__ ((packed));&lt;br /&gt;
	&lt;br /&gt;
} code_t;&lt;br /&gt;
&lt;br /&gt;
static code_t code;&lt;br /&gt;
static uint8_t rc5_addr;&lt;br /&gt;
&lt;br /&gt;
// Number of Bits received so far&lt;br /&gt;
// Number of Interrupts occured so far;&lt;br /&gt;
static uint8_t nbits;&lt;br /&gt;
static uint8_t nint;&lt;br /&gt;
&lt;br /&gt;
//////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
	&lt;br /&gt;
void &lt;br /&gt;
rc5_init (uint8_t addr)&lt;br /&gt;
{&lt;br /&gt;
	nint = 0;&lt;br /&gt;
	nbits = 0;&lt;br /&gt;
	rc5.flip = -1;&lt;br /&gt;
	&lt;br /&gt;
	rc5_addr = addr;&lt;br /&gt;
	&lt;br /&gt;
#if (RC5_PRESCALE==1024)&lt;br /&gt;
	TCCR0 = (1 &amp;lt;&amp;lt; CS02) | (1 &amp;lt;&amp;lt; CS00);&lt;br /&gt;
#elif	(RC5_PRESCALE==256)&lt;br /&gt;
	TCCR0 = (1 &amp;lt;&amp;lt; CS02);&lt;br /&gt;
#elif	(RC5_PRESCALE==64)&lt;br /&gt;
	TCCR0 = (1 &amp;lt;&amp;lt; CS01) | (1 &amp;lt;&amp;lt; CS00);&lt;br /&gt;
#else&lt;br /&gt;
#error This RC5_PRESCALE is not supported&lt;br /&gt;
#endif // RC5_PRESCALE&lt;br /&gt;
	&lt;br /&gt;
	// INTx on falling edge&lt;br /&gt;
	// clear pending INTx&lt;br /&gt;
	// enable INTx interrupt&lt;br /&gt;
#if (RC5_INT == RC5_INT0)		&lt;br /&gt;
	MCUCR |=   (1 &amp;lt;&amp;lt; ISC01);&lt;br /&gt;
	MCUCR &amp;amp;= ~ (1 &amp;lt;&amp;lt; ISC00);&lt;br /&gt;
	GIFR = (1 &amp;lt;&amp;lt; INTF0);&lt;br /&gt;
	GICR |= (1 &amp;lt;&amp;lt; INT0);&lt;br /&gt;
#elif (RC5_INT == RC5_INT1)		&lt;br /&gt;
	MCUCR |=   (1 &amp;lt;&amp;lt; ISC11);&lt;br /&gt;
	MCUCR &amp;amp;= ~ (1 &amp;lt;&amp;lt; ISC10);&lt;br /&gt;
	GIFR = (1 &amp;lt;&amp;lt; INTF1);&lt;br /&gt;
	GICR |= (1 &amp;lt;&amp;lt; INT1);&lt;br /&gt;
#else&lt;br /&gt;
#error please define RC5_INT&lt;br /&gt;
#endif // RC5_INT&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
&lt;br /&gt;
SIGNAL (SIG_OVERFLOW0)&lt;br /&gt;
{&lt;br /&gt;
	TIMSK &amp;amp;= ~(1 &amp;lt;&amp;lt; TOIE0);&lt;br /&gt;
	&lt;br /&gt;
	uint8_t _nbits = nbits;&lt;br /&gt;
	code_t _code = code;&lt;br /&gt;
	&lt;br /&gt;
	if (26 == _nbits)&lt;br /&gt;
	{&lt;br /&gt;
		_nbits++;&lt;br /&gt;
		_code.w &amp;lt;&amp;lt;= 1;&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
	if (27 == _nbits &lt;br /&gt;
		&amp;amp;&amp;amp; 3 == _code.agc &lt;br /&gt;
		&amp;amp;&amp;amp; 0 &amp;gt; rc5.flip)&lt;br /&gt;
	{&lt;br /&gt;
		uint8_t _rc5_code;&lt;br /&gt;
		uint8_t _rc5_addr;&lt;br /&gt;
		// we do the bit manipulation stuff by hand, because of code size&lt;br /&gt;
		_rc5_code = _code.b[0] &amp;amp; 0x3f; // 0b00111111 : #0..#5&lt;br /&gt;
		_code.w &amp;lt;&amp;lt;= 2;&lt;br /&gt;
		_rc5_addr = _code.b[1] &amp;amp; 0x1f; // 0b00011111 : #6..#10&lt;br /&gt;
		&lt;br /&gt;
		if (rc5_addr &amp;amp; 0x80&lt;br /&gt;
			|| rc5_addr == _rc5_addr)&lt;br /&gt;
		{&lt;br /&gt;
			rc5.code = _rc5_code;&lt;br /&gt;
			rc5.addr = _rc5_addr;&lt;br /&gt;
			char flip = 0;&lt;br /&gt;
			if (_code.b[1] &amp;amp; 0x20) // 0b00100000 : #11&lt;br /&gt;
				flip = 1;&lt;br /&gt;
			rc5.flip = flip;&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
	nint = 0;&lt;br /&gt;
	nbits = 0;&lt;br /&gt;
	&lt;br /&gt;
	// INTx on falling edge&lt;br /&gt;
	// clear pending INTx&lt;br /&gt;
	// enable INTx interrupt&lt;br /&gt;
#if (RC5_INT == RC5_INT0)		&lt;br /&gt;
	MCUCR |=   (1 &amp;lt;&amp;lt; ISC01);&lt;br /&gt;
	MCUCR &amp;amp;= ~ (1 &amp;lt;&amp;lt; ISC00);&lt;br /&gt;
	GIFR = (1 &amp;lt;&amp;lt; INTF0);&lt;br /&gt;
	GICR |= (1 &amp;lt;&amp;lt; INT0);&lt;br /&gt;
#elif (RC5_INT == RC5_INT1)		&lt;br /&gt;
	MCUCR |=   (1 &amp;lt;&amp;lt; ISC11);&lt;br /&gt;
	MCUCR &amp;amp;= ~ (1 &amp;lt;&amp;lt; ISC10);&lt;br /&gt;
	GIFR = (1 &amp;lt;&amp;lt; INTF1);&lt;br /&gt;
	GICR |= (1 &amp;lt;&amp;lt; INT1);&lt;br /&gt;
#endif&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
&lt;br /&gt;
#if (RC5_INT == RC5_INT0)		&lt;br /&gt;
SIGNAL (SIG_INTERRUPT0)&lt;br /&gt;
#elif (RC5_INT == RC5_INT1)		&lt;br /&gt;
SIGNAL (SIG_INTERRUPT1)&lt;br /&gt;
#endif // RC5_INT&lt;br /&gt;
{&lt;br /&gt;
	code_t _code = code;&lt;br /&gt;
	uint8_t _nint = nint;&lt;br /&gt;
	&lt;br /&gt;
	if (0 == _nint)&lt;br /&gt;
	{&lt;br /&gt;
		// INTx on both edges&lt;br /&gt;
		// clear pending INTx&lt;br /&gt;
#if (RC5_INT == RC5_INT0)		&lt;br /&gt;
		MCUCR &amp;amp;= ~ (1 &amp;lt;&amp;lt; ISC01);&lt;br /&gt;
		MCUCR |=   (1 &amp;lt;&amp;lt; ISC00);&lt;br /&gt;
		GIFR = (1 &amp;lt;&amp;lt; INTF0);&lt;br /&gt;
#elif (RC5_INT == RC5_INT1)		&lt;br /&gt;
		MCUCR &amp;amp;= ~ (1 &amp;lt;&amp;lt; ISC11);&lt;br /&gt;
		MCUCR |=   (1 &amp;lt;&amp;lt; ISC10);&lt;br /&gt;
		GIFR = (1 &amp;lt;&amp;lt; INTF1);&lt;br /&gt;
#endif // RC5_INT&lt;br /&gt;
	&lt;br /&gt;
		TCNT0 = 0;&lt;br /&gt;
		TIFR = (1 &amp;lt;&amp;lt; TOV0);&lt;br /&gt;
		TIMSK |= (1 &amp;lt;&amp;lt; TOIE0);&lt;br /&gt;
		_code.w = 0;&lt;br /&gt;
	}&lt;br /&gt;
	else&lt;br /&gt;
	{&lt;br /&gt;
		uint8_t tcnt0 = TCNT0;&lt;br /&gt;
		&lt;br /&gt;
		TCNT0 = 0;&lt;br /&gt;
		&lt;br /&gt;
		// Number of bits of the just elapsed period;&lt;br /&gt;
		uint8_t n = 1;&lt;br /&gt;
		// Bits received so far&lt;br /&gt;
		uint8_t _nbits = nbits;&lt;br /&gt;
	&lt;br /&gt;
		// is TCNT0 close to RC5_TICKS or RC5_TICKS/2 ?&lt;br /&gt;
		if (tcnt0 &amp;gt; RC5_TICKS + RC5_DELTA)&lt;br /&gt;
			goto invalid;&lt;br /&gt;
		else if (tcnt0 &amp;lt; RC5_TICKS/2 - RC5_DELTA)&lt;br /&gt;
			goto invalid;&lt;br /&gt;
		else if (tcnt0 &amp;gt; RC5_TICKS - RC5_DELTA)&lt;br /&gt;
			n = 2;&lt;br /&gt;
		else if (tcnt0 &amp;gt; RC5_TICKS/2 + RC5_DELTA)&lt;br /&gt;
			goto invalid;&lt;br /&gt;
		&lt;br /&gt;
		//	store the just received 1 or 2 bits&lt;br /&gt;
		do&lt;br /&gt;
		{&lt;br /&gt;
			_nbits++;&lt;br /&gt;
			if (_nbits &amp;amp; 1)&lt;br /&gt;
			{&lt;br /&gt;
				_code.w &amp;lt;&amp;lt;= 1;&lt;br /&gt;
				_code.b[0] |= _nint &amp;amp; 1;&lt;br /&gt;
			}&lt;br /&gt;
		} &lt;br /&gt;
		while (--n);&lt;br /&gt;
		&lt;br /&gt;
		if (0)&lt;br /&gt;
		{&lt;br /&gt;
			invalid:&lt;br /&gt;
			&lt;br /&gt;
			// disable INTx, run into Overflow0&lt;br /&gt;
#if (RC5_INT == RC5_INT0)		&lt;br /&gt;
			GICR &amp;amp;= ~(1 &amp;lt;&amp;lt; INT0);&lt;br /&gt;
#elif (RC5_INT == RC5_INT1)		&lt;br /&gt;
			GICR &amp;amp;= ~(1 &amp;lt;&amp;lt; INT1);&lt;br /&gt;
#endif // RC5_INT			&lt;br /&gt;
&lt;br /&gt;
			_nbits = 0;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		nbits = _nbits;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	code = _code;&lt;br /&gt;
	nint = 1+_nint;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==rc5.h==&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#ifndef _RC5_H_&lt;br /&gt;
#define _RC5_H_&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;inttypes.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#define RC5_INT0 0&lt;br /&gt;
#define RC5_INT1 1&lt;br /&gt;
&lt;br /&gt;
#define RC5_ALL 0xff&lt;br /&gt;
&lt;br /&gt;
typedef struct&lt;br /&gt;
{&lt;br /&gt;
	uint8_t code;&lt;br /&gt;
	uint8_t addr;&lt;br /&gt;
	volatile char flip;&lt;br /&gt;
} rc5_t;&lt;br /&gt;
&lt;br /&gt;
extern rc5_t rc5;&lt;br /&gt;
extern void rc5_init (uint8_t addr);&lt;br /&gt;
&lt;br /&gt;
#endif /* _RC5_H_ */&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Beispiele=&lt;br /&gt;
&lt;br /&gt;
==Initialisierung==&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;
#include &amp;lt;avr/interrupt.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#include &amp;quot;rc5.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
	...&lt;br /&gt;
	// der ensprechende INT-Port muss INPUT sein&lt;br /&gt;
	// RC5 initialisieren, alle Adressen zulassen&lt;br /&gt;
	rc5_init (RC5_ALL);&lt;br /&gt;
&lt;br /&gt;
	// Interrupts zulassen&lt;br /&gt;
	sei();&lt;br /&gt;
	...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Anwendung==&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;
#include &amp;lt;avr/interrupt.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#include &amp;quot;rc5.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
	...&lt;br /&gt;
	// FIXME: eigentlich sollte es nicht nötig sein, das atomar zu machen&lt;br /&gt;
	// Code atomar machen&lt;br /&gt;
	uint8_t sreg = SREG;&lt;br /&gt;
	cli();&lt;br /&gt;
	// Gibt's was Neues?&lt;br /&gt;
	if (-1 == rc5.flip)&lt;br /&gt;
	{&lt;br /&gt;
		// Nein, dann&lt;br /&gt;
		// atomaren Block beenden	&lt;br /&gt;
		SREG = sreg;&lt;br /&gt;
		// ...und zurück (oder sonst was machen)&lt;br /&gt;
		return;&lt;br /&gt;
	}&lt;br /&gt;
	// Ja, dann code merken, und evtl. rc5.addr, falls man die nicht sowieso kennt&lt;br /&gt;
	uint8_t code = rc5.code;&lt;br /&gt;
	// und auf nächstes Zeichen warten&lt;br /&gt;
	rc5.flip = -1;&lt;br /&gt;
	&lt;br /&gt;
	// atomaren Block beenden&lt;br /&gt;
	SREG = sreg;&lt;br /&gt;
	// code (evtl. addr) auswerten&lt;br /&gt;
	...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=WebLinks=&lt;br /&gt;
* [http://www.atmel.com/dyn/resources/prod_documents/DOC1473.PDF AVR410 (Application Note): ''RC5 IR Remote Control Receiver'', pdf (en)]&lt;br /&gt;
&lt;br /&gt;
=Autor=&lt;br /&gt;
&lt;br /&gt;
--[[Benutzer:SprinterSB|SprinterSB]] 18:17, 7. Dez 2005 (CET)&lt;br /&gt;
[[Kategorie:AVR]]&lt;br /&gt;
[[Kategorie:Software]]&lt;br /&gt;
[[Kategorie:Praxis]]&lt;br /&gt;
[[Kategorie:Quellcode C]]&lt;/div&gt;</summary>
		<author><name>Nollsen</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=TWI&amp;diff=4752</id>
		<title>TWI</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=TWI&amp;diff=4752"/>
				<updated>2006-01-03T19:32:19Z</updated>
		
		<summary type="html">&lt;p&gt;Nollsen: /* Siehe auch */ Kategorie AVR&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Two-wire Serial Interface =&lt;br /&gt;
&lt;br /&gt;
Bezeichnung von [[Atmel|Atmel]] für den auf vielen [[AVR|AVR]]'s vorhandenen  [[I2C|I&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;C]].&lt;br /&gt;
&lt;br /&gt;
In diesem Artikel soll nur auf Besonderheiten der [[Atmel]] [[Microcontroller]] eingegangen werden, Einzeilheiten zu [[I2C|I&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;C]] finden sich in den entsprechenden Artikeln.&lt;br /&gt;
&lt;br /&gt;
= Merkmale =&lt;br /&gt;
&lt;br /&gt;
* Master- und Slavemodus&lt;br /&gt;
* Multimaster&lt;br /&gt;
* 7-Bit Adressierung (als Master möglicherweise auch 10-Bit Adressierung)&lt;br /&gt;
* Übertragungsrate von bis zu 400kBit/s&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= TWI verwenden =&lt;br /&gt;
Um TWI mit dem [[AVR]] verwenden zu können sind einige Einstellungen nötig, die hier, in Abhängigkeit der Anwendung, aufgezeigt werden.&lt;br /&gt;
&lt;br /&gt;
== Übertragungsarten ==&lt;br /&gt;
Bei TWI gibt es diese Übertragungsarten&lt;br /&gt;
* Master Transmitter (nur senden)&lt;br /&gt;
* Master Receiver (senden und empfangen)&lt;br /&gt;
* Slave Transmitter (auf abruf senden)&lt;br /&gt;
* Slave Receiver (nur empfangen)&lt;br /&gt;
Abhängig von der Anwendung, kann der [[AVR]] alle Arten der Übertragung im gleichen Programm ausführen.&lt;br /&gt;
&lt;br /&gt;
== Master ==&lt;br /&gt;
Ist der AVR Master, bestimmt er was und wie schnell es auf dem [[I2C|I&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;C]]-Bus zugeht. (Ausnahme: [[Clock_Stretching]] )&lt;br /&gt;
&lt;br /&gt;
Zur Bestimmung der Bus-Geschwindigkeit ist der ''Bit Rate Generator'' zuständig.&lt;br /&gt;
&lt;br /&gt;
=== Bit Rate Generator ===&lt;br /&gt;
Zur Übertragung gibt es die Bitraten ''Standard'', mit bis zu 100kBit/s, und ''FastMode'', mit bis zu 400kBit/s.&lt;br /&gt;
Der Master muss immer den Takt erzeugen, der bei bedarf auf der Leitung SCL angelegt wird.&lt;br /&gt;
Der SCL-Takt ist beim AVR abhängig von der CPU-Frequenz, deshalb ist es von Vorteil (im gegensatz zu RS232), wenn man Frequenzen mit geraden Werten verwendet, zB. 8.0 MHz, da sich der Wert besser teilen lässt um auf 100kHz bzw. 400kHz zu kommen.&lt;br /&gt;
&lt;br /&gt;
Im TWI-Modul des AVR gibt es zwei stellen, an denen man die Teilung der Frequenz einstellen kann.&lt;br /&gt;
* die ''Prescaler Bits'' (TWPS), diese 2 Bits befinden sich im ''TWI Status Register'' (TWSR)&lt;br /&gt;
* für die genauere Einstellung das ''TWI Bit Rate Register'' (TWBR)&lt;br /&gt;
&lt;br /&gt;
'''Formel zur Berechnung der SCL-Frequenz:'''&lt;br /&gt;
&amp;lt;div align=&amp;quot;center&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;\mathrm{SCL{-}Frequenz =  \frac{CPU{-}Frequenz}{16\ +\ 2\ ( TWBR )\ 4 ^ { TWPS } } }&amp;lt;/math&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Da ein AVR zur Zeit max. mit 20MHz getaktet werden kann, ist es nicht nötig den Prescaler zu benutzen, bzw. er wird auf den Teiler 1 gestellt, was keiner Teilung entspricht. Mit diesem Teiler können alle CPU-Frequenzen und TWI-Takte abgedeckt werden.&lt;br /&gt;
&lt;br /&gt;
'''Mögliche Prescaler Werte:'''&lt;br /&gt;
&amp;lt;div align=&amp;quot;center&amp;quot;&amp;gt;&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|'''BitWert'''&lt;br /&gt;
|'''Teiler'''&lt;br /&gt;
|-&lt;br /&gt;
|00&lt;br /&gt;
|1&lt;br /&gt;
|-&lt;br /&gt;
|01&lt;br /&gt;
|4&lt;br /&gt;
|-&lt;br /&gt;
|10&lt;br /&gt;
|16&lt;br /&gt;
|-&lt;br /&gt;
|11&lt;br /&gt;
|64&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
Die Werte von TWBR gehen von theoretisch 0 bis 255. Laut [[Atmel]] soll der Wert aber mind. 10 Betragen, da es sonst zu Problemen bei der Übertragung kommen kann.&lt;br /&gt;
&lt;br /&gt;
'''Beispiel Berechnung'''&lt;br /&gt;
&lt;br /&gt;
Es soll eine SCL-Frequenz von 100kHz erzeugt werden, die CPU-Frequenz beträgt 8.0MHz, der Teiler (Prescaler) ist, wie oben erwähnt, auf 1 (TWPS = 0).&lt;br /&gt;
&lt;br /&gt;
Laut der Formel ergibt das dann:&lt;br /&gt;
&amp;lt;pre&amp;gt;100kHz = 8.0MHz / (16 + 2 * x * 4^0 )    / 1 fällt weg&lt;br /&gt;
100kHz = 8.0MHz / (16 + 2 * x )          / *(16 + 2 * x )&lt;br /&gt;
100kHz * (16 + 2 * x ) = 8000kHz         / kürzen  / : 100&lt;br /&gt;
16 + 2 * x  = 80                         / -16&lt;br /&gt;
2 * x  = 64                              / :2&lt;br /&gt;
x = 32&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
'''Ergebnis:''' Der Wert für TWBR muss 32 sein, damit die SCL-Frequenz 100kHz, bei 8.0MHz CPU-Frequenz, ergibt.&lt;br /&gt;
&lt;br /&gt;
'''Es Ergibt sich somit Folgende Formel zum Berechnen von TWBR:'''&lt;br /&gt;
&amp;lt;div align=&amp;quot;center&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;\mathrm{TWBR = \frac{ \frac {CPU{-}Frequenz}{SCL{-}Frequenz} - 16}{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Kommt ein Wert kleiner 10 heraus, sollte eine höhere CPU-Frequenz gewählt werden. Wird eine krumme CPU-Frequenz verwendet was kein Ganzzahliges Ergebnis zur folge hat, kann man mit der 1. Formel überprüfen ob der Wert auf- oder Abgerundet wird. Auf der sicheren Seite ist man, wenn der Wert aufgerundet wird, das entspricht einer grösseren Teilung, also eine geringfügig kleinere Bitrate und liegt deshalb im Standard.&lt;br /&gt;
&lt;br /&gt;
= Quellen =&lt;br /&gt;
Atmel Datenblätter&lt;br /&gt;
&lt;br /&gt;
= Siehe auch =&lt;br /&gt;
* [[I2C|I&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;C]]&lt;br /&gt;
* [[RS232]]&lt;br /&gt;
* [[RS485]]&lt;br /&gt;
* [[RN-Slave ID Übersicht]]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:AVR]]&lt;br /&gt;
[[Kategorie:Abkürzung]]&lt;br /&gt;
[[Kategorie:Grundlagen]]&lt;br /&gt;
[[Kategorie:Microcontroller]]&lt;br /&gt;
[[Kategorie:Elektronik]]&lt;br /&gt;
[[Kategorie:Praxis]]&lt;/div&gt;</summary>
		<author><name>Nollsen</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=WinAVR&amp;diff=4751</id>
		<title>WinAVR</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=WinAVR&amp;diff=4751"/>
				<updated>2006-01-03T19:32:15Z</updated>
		
		<summary type="html">&lt;p&gt;Nollsen: /* Weblinks */ Kategorie AVR&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;WinAVR ist Paket für die C-Programmierung von [[AVR]]-Controllern. genauer gesagt ist es eine Portierung des beliebten Open Source Compilers [[avr-gcc]]. &lt;br /&gt;
Das Paket beinhaltet neben dem GCC-Compiler (Cross Compiler) noch Linker, Editor, Standard Libarys und viele kleinere Tools. Die Installation erfolgt jedoch unter Windows bequem über ein einziges SETUP-Programm. Der Vorteil dieses Paketes ist also die einfache Installation. &lt;br /&gt;
&lt;br /&gt;
Vorhandene Tools in WinAVR:&lt;br /&gt;
&lt;br /&gt;
* [[Avr-gcc]] - der C Compiler &lt;br /&gt;
* avr-libc  - Libary mit Standard Funktionen&lt;br /&gt;
* Mfile - Tool zum Erstellen von Makefiles &lt;br /&gt;
* AVR Insight - Debugger &lt;br /&gt;
* Programmers Notepad - Editor mit Syntax Highlightning &lt;br /&gt;
* avrdude - Übertragungssoftware für Programmcode (verschiedene ISP Programmer)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Siehe auch==&lt;br /&gt;
* [[C-Tutorial]]&lt;br /&gt;
* [[Avr-gcc]]&lt;br /&gt;
* [[Sourcevergleich]]&lt;br /&gt;
* [[Avr]]&lt;br /&gt;
* [[Atmel]]&lt;br /&gt;
* [[Compiler]]&lt;br /&gt;
&lt;br /&gt;
==Weblinks==&lt;br /&gt;
* [http://sourceforge.net/projects/winavr/ aktuellste Version über sourceforge.net]&lt;br /&gt;
[[Kategorie:AVR]]&lt;br /&gt;
[[Kategorie:Microcontroller]]&lt;br /&gt;
[[Kategorie:Robotikeinstieg]]&lt;/div&gt;</summary>
		<author><name>Nollsen</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=Avr-gcc&amp;diff=4750</id>
		<title>Avr-gcc</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=Avr-gcc&amp;diff=4750"/>
				<updated>2006-01-03T19:29:08Z</updated>
		
		<summary type="html">&lt;p&gt;Nollsen: /* Autor */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Die GNU Compiler Collection (GCC) unterstützt das Zielsystem (Target) [[Avr|AVR]] für die Sprachen C und C++. GCC ist ein sehr leistungsfähiger [[Compiler]], und er kann als die wichtigste freie Software überhaupt bezeichnet werden. Immerhin sind das freie [[Betriebssystem]] &amp;lt;tt&amp;gt;Linux&amp;lt;/tt&amp;gt; und viele andere Programme &amp;amp;#150; auch gcc und die Toolchains selbst &amp;amp;#150; mit gcc generiert. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
Im Gegensatz zu [[Bascom]] ist &amp;lt;tt&amp;gt;avr-gcc&amp;lt;/tt&amp;gt; ein reiner Compiler, bringt also keine umfangreiche Bibliothek an Funktionalitäten mit. Jedoch finden sich einige low-level Funktionen zum Lesen aus dem [[Flash]] oder Lesen/Schreiben des [[EEPROM|EEPROMs]] etc. in der &amp;lt;tt&amp;gt;avr-libc&amp;lt;/tt&amp;gt;. &lt;br /&gt;
--&amp;gt;&lt;br /&gt;
=How to Read=&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel bespricht &amp;lt;tt&amp;gt;avr-gcc&amp;lt;/tt&amp;gt;. Er ist kein Tutorial und kein AVR-Handbuch &amp;amp;#150; das würde den Umfang des Artikels bei weitem sprengen.&lt;br /&gt;
&lt;br /&gt;
Der Artikel ist ein Handbuch zu &amp;lt;tt&amp;gt;avr-gcc&amp;lt;/tt&amp;gt;. Er bespricht zum Beispiel, wie man &amp;lt;tt&amp;gt;avr-gcc&amp;lt;/tt&amp;gt; anwendet und&lt;br /&gt;
Besonderheiten von &amp;lt;tt&amp;gt;avr-gcc&amp;lt;/tt&amp;gt;-C,&lt;br /&gt;
die nicht zum Sprachumfang von C gehören.&lt;br /&gt;
Dazu zählen die Definition von Interrupt Service Routinen (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 (Blinky)|Blinky]]&amp;quot;,&lt;br /&gt;
das nur eine [[LED]] blinkt und zeigt, &lt;br /&gt;
wie ein kleines Projekt mit &amp;lt;tt&amp;gt;avr-gcc&amp;lt;/tt&amp;gt; compiliert werden kann.&lt;br /&gt;
&lt;br /&gt;
=Benutzer-Schnittstelle=&lt;br /&gt;
&lt;br /&gt;
Die Benutzer-Schnittstelle von GCC ist die Kommandozeile einer Shell, Console bzw. Eingabeaufforderung. &lt;br /&gt;
&lt;br /&gt;
Im einfachsten Fall sieht ein Aufruf von &amp;lt;tt&amp;gt;avr-gcc&amp;lt;/tt&amp;gt; also so aus:&lt;br /&gt;
 &amp;gt; avr-gcc&lt;br /&gt;
Dabei das '&amp;lt;tt&amp;gt;&amp;gt;&amp;lt;/tt&amp;gt;' nicht mittippen, und ein ENTER am Ende der Zeile drücken.&lt;br /&gt;
Die Antwort bei korrekter Installation ist dann&lt;br /&gt;
 avr-gcc: no input files&lt;br /&gt;
Was bedeutet: das Programm &amp;lt;tt&amp;gt;avr-gcc&amp;lt;/tt&amp;gt; wurde vom Betriebssystem gefunden und konnte/durfte gestartet werden. Dann gibt &amp;lt;tt&amp;gt;avr-gcc&amp;lt;/tt&amp;gt; eine Fehlermeldung aus und beendet die Ausführung, weil er keine Eingabedatei(en) bekommen hat &amp;amp;#150; was ja auch stimmt. Soweit ist also alles in Butter.&lt;br /&gt;
&lt;br /&gt;
GCC war immer Kommandozeilen-orientiert und wird es auch immer bleiben, denn das hat gute Gründe:&lt;br /&gt;
* ein Compiler ist ein Compiler (und keine grafische Bedienschnittstelle)&lt;br /&gt;
* die Plattformabhängigkeit wird auf ein Minimum reduziert&lt;br /&gt;
* es gibt die Möglichkeit, GCC per Skript oder [[make]] zu starten&lt;br /&gt;
* GCC kann durchaus in eine Umgebung integriert werden: in einen Editor oder in eine GUI wie neuere Versionen von AVR-Studio, etc. Der GCC-Aufruf kann sogar von einem Server-Socket oder einer Web-Application heraus erfolgen, welche ein C-Programm empfängt, es von GCC übersetzen lässt, und das Resultat zurückschickt oder sonst was damit anstellt.&lt;br /&gt;
* Lizenzgründe: eine Umgebung, die GCC integriert, kann durchaus proprietär oder nicht quelloffen sein und muss nicht der [[Freie Software|GPL]] unterliegen.&lt;br /&gt;
&lt;br /&gt;
=Allgemeine Charakteristika von avr-gcc=&lt;br /&gt;
&lt;br /&gt;
;Groß- und Kleinschreibung: C unterscheidet generell zwischen Groß- und Kleinschreibung, sowohl bei Variablen- und Funktionsnamen, bei Sprungmarken als auch bei Makros, und je nach Betriebssystem auch bei Pfad- und Dateinamen/Dateierweiterungen.&lt;br /&gt;
&lt;br /&gt;
;Größe des Typs int: Der Standard-Typ &amp;lt;tt&amp;gt;int&amp;lt;/tt&amp;gt; ist 16 Bit groß&lt;br /&gt;
&lt;br /&gt;
;Größe von Pointern: Ein Pointer (Zeiger) ist 16 Bit groß&lt;br /&gt;
&lt;br /&gt;
;Endianess: &amp;lt;tt&amp;gt;avr-gcc&amp;lt;/tt&amp;gt; implementiert Datentypen als little-endian, d.h. bei Datentypen, die mehrere Bytes groß sind, wird das niederwertigste Byte an der niedrigsten Adresse gespeichert. Dies gilt auch für Adressen und deren Ablage auf dem [[Stack]] sowie die Ablage von Werten, die mehrere Register belegen.&lt;br /&gt;
&lt;br /&gt;
==Binäre Konstanten==&lt;br /&gt;
Einige Versionen von &amp;lt;tt&amp;gt;avr-gcc&amp;lt;/tt&amp;gt; ermöglichen die Verwendung binärer Konstanten für 8-Bit-Werte:&lt;br /&gt;
&amp;lt;pre&amp;gt;unsigned char value = 0b00000010;&amp;lt;/pre&amp;gt;&lt;br /&gt;
Davon sollte man absehen, denn zum einen hat man schnell eine 0 zu wenig oder zu viel getippselt, es ist kein Standard-C und man hat die leserlichere Alternative&lt;br /&gt;
&amp;lt;pre&amp;gt;unsigned char value = (1&amp;lt;&amp;lt;1);&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Registerverwendung==&lt;br /&gt;
;R0: ein temporäres Register, in dem man rumwutzen darf&lt;br /&gt;
;R1: enthält immer den Wert 0&lt;br /&gt;
;R2 &amp;amp;#150; R17, R28, R29: allgemeine Register, die durch einen Funktionsaufruf nicht verändert bzw wieder auf den ursprünglichen Wert restauriert werden&lt;br /&gt;
;R18 &amp;amp;#150; R27, R30, R31: können durch Funktionsaufrufe verändert werden&lt;br /&gt;
; R28 &amp;amp;#150; R29 (Y-Reg): enthält den Framepointer, sofern benötigt&lt;br /&gt;
&lt;br /&gt;
=Ablauf der Codegenerierung=&lt;br /&gt;
&lt;br /&gt;
Die Code-Erzeugung durch avr-gcc geschieht in mehreren, voneinander unabhängigen Schritten. Diese  Schritte sind für den Anwender nicht immer erkennbar, und es auch nicht unbedingt notwendig, sie zu kennen. Für ein besseres Verständnis der Code-Generierung und zur Einordnung von Fehlermeldungen ist eine Kenntnis aber hilfreich.&lt;br /&gt;
&lt;br /&gt;
==Übersichts-Grafik==&lt;br /&gt;
&lt;br /&gt;
[[Bild:Avr-gcc-1.png|Zusammenspiel zwischen avr-gcc und binutils]]&lt;br /&gt;
&lt;br /&gt;
==Schritte der Codegenerierung==&lt;br /&gt;
&lt;br /&gt;
Ohne die Angabe spezieller Optionen werden die Zwischenformate nur als temporäre Dateien angelegt und nach Beenden des gcc-Laufs wieder gelöscht. Dadurch fällt die Aufgliederung in Unterschritte nicht auf. In diesem Falle müssen Assembler und Linker/Locator auch nicht extra aufgerufen werden, sondern die Aufrufe erfolgen durch gcc. Ausnahme ist &amp;lt;tt&amp;gt;avr-objcopy&amp;lt;/tt&amp;gt;, welches immer aufgerufen werden muss, wenn man z.B. eine HEX-Datei haben möchte.&lt;br /&gt;
&lt;br /&gt;
;Precompileren: Alle Preprozessor-Direktiven werden aufgelöst. Dazu gehören Direktiven wie&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;quot;meinzeug.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
#define MAKRONAME ERSATZTEXT&lt;br /&gt;
&lt;br /&gt;
#if !defined(__AVR__)&lt;br /&gt;
#error einen Fehler ausgeben und abbrechen&lt;br /&gt;
#else&lt;br /&gt;
/* Alles klar, wir koennen loslegen mit C-Code fuer AVR */&lt;br /&gt;
#endif &lt;br /&gt;
&lt;br /&gt;
MAKRONAME&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Precompilieren besteht also nur aus reinem Textersatz: Auflösen von Makros, kopieren von anderen Dateien in die Quelle, etc. &lt;br /&gt;
&lt;br /&gt;
;Compilieren: In diesem Schritt geschieht der eigentliche Compilier-Vorgang: &amp;lt;tt&amp;gt;avr-gcc&amp;lt;/tt&amp;gt; übersetzt die reine, precompilierte C-Quelle (*.i): Die Quelle wird auf Syntax-Fehler geprüft, es werden Optimierungen gemacht, und das übersetzte C-Programm als Assembler-Datei in (*.s) gespeichert.&lt;br /&gt;
&lt;br /&gt;
;Assemblieren: Der Assembler (&amp;lt;tt&amp;gt;avr-as&amp;lt;/tt&amp;gt;) übersetzt den Assembler-Code (*.s) in das  AVR-eigene Objektformat elf32-avr (*.o). Das Objekt enthält schon Maschinen-Code. Zusätzlich gibt es aber noch Lücken, die erst später gefüllt werden und Debug-Informationen und ganz viel anderes Zeug.&lt;br /&gt;
&lt;br /&gt;
;Linken und Lokatieren: Der Linker (&amp;lt;tt&amp;gt;avr-ld&amp;lt;/tt&amp;gt;) bindet die angegebenen Objekte (*.o) zusammen und löst externe Referenzen auf. Der Linker entscheidet anhand der Beschreibung im Linker-Script, in welchen Speicheradressen und Sektionen die Daten landen: er ''lokatiert'' (von location, locate (en)). Module aus Bibliotheken (*.a) werden hinzugebunden (z.B. &amp;lt;tt&amp;gt;printf&amp;lt;/tt&amp;gt;) und die elf32-avr Ausgabedatei (üblicherweise *.elf) erzeugt.&lt;br /&gt;
&lt;br /&gt;
;Umwandeln ins gewünschte Objekt-Format: Linker und Assembler erzeugen ihre Ausgabe im Objektformat elf32-avr. Wird ein anderes Objektformat wie Intel-HEX (*.hex), binary (*.bin) oder srec (*.srec) benötigt, kann &amp;lt;tt&amp;gt;avr-objcopy&amp;lt;/tt&amp;gt; dazu verwendet werden, um diese zu erstellen. Der Inhalt einzelner Sections kann gezielt umkopiert oder ausgeblendet werden, so daß Dateien erstellt werden können, die nur den Inhalt des Flashs (Section &amp;lt;tt&amp;gt;.text&amp;lt;/tt&amp;gt;) oder des EEPROMs (Section &amp;lt;tt&amp;gt;.eeprom&amp;lt;/tt&amp;gt;) repräsentieren. Durch das Umwandeln in ein anderes Objektformat gehen üblicherweise Informationen wie Debug-Informationen verloren.&lt;br /&gt;
&lt;br /&gt;
=Kommandozeilen-Optionen=&lt;br /&gt;
Die Codegenerierung bei &amp;lt;tt&amp;gt;avr-gcc&amp;lt;/tt&amp;gt; wird über Kommandozeilen-Optionen gesteuert. Diese legen fest, für welchen Controller Code zu erzeugen ist, wie stark optimiert wird, ob Debug-Informationen erzeugt werden, etc. Die Optionen teilen sich in zwei Gruppen: Optionen, die für alle GCC-Ports verfürgbar sind und maschinenspezifische Optionen, die nur für AVR verfügbar sind.&lt;br /&gt;
&lt;br /&gt;
Aus der Masse an GCC-Optionen kann hier nur ein kleiner Auszug der wichtigsten und am häufigsten verwendeten Optionen vorgestellt werden. Eine Auflistung aller GCC-Optionen mit Kurzbeschreibung umfasst knapp 1000 Zeilen &amp;amp;#150; ohne undokumentierte Optionen, versteht sich.&lt;br /&gt;
&lt;br /&gt;
==Allgemeine Optionen für GCC==&lt;br /&gt;
; &amp;lt;tt&amp;gt;--help&amp;lt;/tt&amp;gt;: Anzeige der wichtigsten Optionen&lt;br /&gt;
; &amp;lt;tt&amp;gt;--help -v&amp;lt;/tt&amp;gt;: Überschüttet einen mit Optionen&lt;br /&gt;
; &amp;lt;tt&amp;gt;--target-help&amp;lt;/tt&amp;gt;: Anzeige der wichtigsten maschinenspezifischen Optionen&lt;br /&gt;
; &amp;lt;tt&amp;gt;-O0&amp;lt;/tt&amp;gt;: keine Optimierung&lt;br /&gt;
; &amp;lt;tt&amp;gt;-O1&amp;lt;/tt&amp;gt;: Optimierung&lt;br /&gt;
; &amp;lt;tt&amp;gt;-Os&amp;lt;/tt&amp;gt;: optimiert für Code-Größe&lt;br /&gt;
; &amp;lt;tt&amp;gt;-O2&amp;lt;/tt&amp;gt;: stärkere Optimierung für bessere Laufzeit&lt;br /&gt;
; &amp;lt;tt&amp;gt;-g&amp;lt;/tt&amp;gt;: erzeugt Debug-Informationen&lt;br /&gt;
; &amp;lt;tt&amp;gt;-c&amp;lt;/tt&amp;gt;: (pre)compilert und assembliert nur bis zum Objekt (*.o), kein [[Linker|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 (*.i) erzeugen, kein Compilieren, kein Assemblieren, kein Linken&lt;br /&gt;
; &amp;lt;tt&amp;gt;-o&amp;lt;/tt&amp;gt; &amp;amp;lt;filename&amp;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;/tt&amp;gt;&amp;amp;lt;path&amp;amp;gt;: Angabe eines weiteren Include-Pfads, in dem Dateien mit &amp;lt;tt&amp;gt;#include &amp;amp;lt;...&amp;amp;gt;&amp;lt;/tt&amp;gt; gesucht werden&lt;br /&gt;
; &amp;lt;tt&amp;gt;-E -dM &amp;lt;/tt&amp;gt; &amp;amp;lt;filename&amp;amp;gt;:Anzeige aller Defines&lt;br /&gt;
; &amp;lt;tt&amp;gt;-D&amp;lt;/tt&amp;gt;&amp;amp;lt;name&amp;amp;gt;:Definiert [[Makro]] &amp;lt;tt&amp;gt;&amp;amp;lt;name&amp;amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
; &amp;lt;tt&amp;gt;-D&amp;lt;/tt&amp;gt;&amp;amp;lt;name&amp;amp;gt;=&amp;amp;lt;wert&amp;amp;gt;:Definiert Makro &amp;lt;tt&amp;gt;&amp;amp;lt;name&amp;amp;gt;&amp;lt;/tt&amp;gt; zu &amp;lt;tt&amp;gt;&amp;amp;lt;wert&amp;amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
; &amp;lt;tt&amp;gt;-U&amp;lt;/tt&amp;gt;&amp;amp;lt;name&amp;amp;gt;:Undefiniert Makro &amp;lt;tt&amp;gt;&amp;amp;lt;name&amp;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 (*.i, *.s) werden nicht gelöscht. Teilweise fehlerhaft zusammen mit &amp;lt;tt&amp;gt;-c&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;tt&amp;gt;-Wa,&amp;lt;/tt&amp;gt;&amp;amp;lt;options&amp;amp;gt;: übergibt Komma-getrennte Liste &amp;lt;tt&amp;gt;&amp;amp;lt;options&amp;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;-Wp,&amp;lt;/tt&amp;gt;&amp;amp;lt;options&amp;amp;gt;:  übergibt Komma-getrennte Liste &amp;lt;tt&amp;gt;&amp;amp;lt;options&amp;amp;gt;&amp;lt;/tt&amp;gt; an den Preprozessor&lt;br /&gt;
; &amp;lt;tt&amp;gt;-Wl,&amp;lt;/tt&amp;gt;&amp;amp;lt;options&amp;amp;gt;:  übergibt Komma-getrennte Liste &amp;lt;tt&amp;gt;&amp;amp;lt;options&amp;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;-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 bedonders pedantisch mit Code um&lt;br /&gt;
; &amp;lt;tt&amp;gt;-ansi&amp;lt;/tt&amp;gt;: bricht mit einer Fehlermeldung ab, wenn kein ANSI-C verwendet wurde&lt;br /&gt;
; &amp;lt;tt&amp;gt;-ffreestanding&amp;lt;/tt&amp;gt;: Das erzeugte Programm läuft nicht in einer Umgebung wie einer Shell. Der Prototyp von &amp;lt;tt&amp;gt;main&amp;lt;/tt&amp;gt; ist&lt;br /&gt;
:&amp;lt;tt&amp;gt;&lt;br /&gt;
 void main (void);&lt;br /&gt;
&amp;lt;/tt&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;
;&amp;lt;tt&amp;gt;-mmcu=xxx&amp;lt;/tt&amp;gt;: Festlegen des Targets, für das Code generiert werden soll. Je nach Target werden unterschiedliche Instruktionen verwendet und andere Startup-Dateien (&amp;lt;tt&amp;gt;crtxxx.o&amp;lt;/tt&amp;gt;) eingebunden. Spezielle Defines werden gesetzt, um in der Quelle zwischen den Targets unterscheiden zu können: &lt;br /&gt;
:&amp;lt;tt&amp;gt;&lt;br /&gt;
 #ifdef __AVR_AT90S2313__&lt;br /&gt;
 /* Code fuer AT90S2313 */&lt;br /&gt;
 #elif defined (__AVR_ATmega8__) || defined (__AVR_ATmega32__)&lt;br /&gt;
 /* Code fuer Mega8 und Mega32 */ &lt;br /&gt;
 #else&lt;br /&gt;
 #error Das ist noch nicht implementiert für diesen Controller!&lt;br /&gt;
 #endif&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zwar gibt es für alle AVR-Derivate die &amp;lt;tt&amp;gt;avr/io.h&amp;lt;/tt&amp;gt;, aber die AVR-Familien unterscheiden sich in ihrer Hardware; z.B. darin, wie 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;
=Builtin Defines=&lt;br /&gt;
&lt;br /&gt;
Zur bedingten Codeerzeugung und zur Erkennung, welcher Compiler sich an der Quelle zu schaffen macht, sind folgende Defines hilfreich&lt;br /&gt;
&lt;br /&gt;
==GCC==&lt;br /&gt;
;&amp;lt;tt&amp;gt;__GNUC__&amp;lt;/tt&amp;gt;: X wenn GCC-Version X.Y.Z&lt;br /&gt;
;&amp;lt;tt&amp;gt;__GNUC_MINOR__&amp;lt;/tt&amp;gt;: Y wenn GCC-Version X.Y.Z&lt;br /&gt;
;&amp;lt;tt&amp;gt;__GNUC_PATCHLEVEL__&amp;lt;/tt&amp;gt;: Z wenn GCC-Version X.Y.Z&lt;br /&gt;
;&amp;lt;tt&amp;gt;__VERSION__&amp;lt;/tt&amp;gt;: &amp;quot;X.Y.Z&amp;quot; wenn GCC-Version X.Y.Z&lt;br /&gt;
;&amp;lt;tt&amp;gt;__GXX_ABI_VERSION&amp;lt;/tt&amp;gt;: Version der ABI (Application Binary Interface)&lt;br /&gt;
;&amp;lt;tt&amp;gt;__OPTIMIZE__&amp;lt;/tt&amp;gt;: Optimierung ist aktiviert&lt;br /&gt;
;&amp;lt;tt&amp;gt;__NO_INLINE__&amp;lt;/tt&amp;gt;: Ohne Schalter &amp;lt;tt&amp;gt;-finline&amp;lt;/tt&amp;gt; resp. &amp;lt;tt&amp;gt;-finline-all-functions&amp;lt;/tt&amp;gt; etc.&lt;br /&gt;
;&amp;lt;tt&amp;gt;__ASSEMBLER__&amp;lt;/tt&amp;gt;: GCC betrachtet die Eingabe als Assembler-Code und compiliert nicht. Weiterleitung an den Assembler.&lt;br /&gt;
&lt;br /&gt;
==avr-gcc==&lt;br /&gt;
;&amp;lt;tt&amp;gt;__AVR&amp;lt;/tt&amp;gt;: Definiert für Target avr, d.h. &amp;lt;tt&amp;gt;avr-gcc&amp;lt;/tt&amp;gt; ist am Werk&lt;br /&gt;
;&amp;lt;tt&amp;gt;__AVR__&amp;lt;/tt&amp;gt;: dito&lt;br /&gt;
;&amp;lt;tt&amp;gt;__AVR_ARCH__&amp;lt;/tt&amp;gt;: codiert den AVR-Kern, für den Code erzeugt wird (Classic, Mega, ...). &lt;br /&gt;
;&amp;lt;tt&amp;gt;__AVR_XXXX__&amp;lt;/tt&amp;gt;: Gesetzt, wenn &amp;lt;tt&amp;gt;-mmcu=xxxx&amp;lt;/tt&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Siehe auch: [[Avr-gcc#Maschinenspezifische_Optionen_f.C3.BCr_avr-gcc|Maschinenspezifische Optionen]]&lt;br /&gt;
&lt;br /&gt;
=Sections=&lt;br /&gt;
&lt;br /&gt;
Sections sind mit Fächern vergleichbar, in die Daten, Code, Debug-Informationen usw. einsortiert werden. Zur Section &amp;lt;tt&amp;gt;.text&amp;lt;/tt&amp;gt; gehört z.B. der ausführbare Code, welcher letztendlich im Flash landet. Wo genau das ist, braucht man nicht zu wissen und es spielt auch keine Rolle, wo eine bestimmte Funktion landet.&lt;br /&gt;
&lt;br /&gt;
Für 'normalen' Code und 'normale' Daten braucht man sich nicht um die Sections zu kümmern, sie werden von &amp;lt;tt&amp;gt;avr-gcc&amp;lt;/tt&amp;gt; automatisch richtig zugeordnet. Für spezielle Anwendungen kann es aber notwendig sein, die Ablage in eine andere Section zu machen; etwa wenn man Daten im EEPROM lesen/schreiben will. Wie das genau gemacht wird, steht im Abschnitt &amp;quot;[[avr-gcc#Attribute|Attribute]]&amp;quot; und es gibt ein Beispiele in den Abschnitten &lt;br /&gt;
&amp;quot;[[avr-gcc#SRAM, Flash, EEPROM: Datenablage am Beispiel Strings|Datenablage am Beispiel Strings]]&amp;quot; und &amp;quot;[[avr-gcc#Zufall|Zufall]]&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|- bgcolor=&amp;quot;#ccccff&amp;quot;&lt;br /&gt;
! |Section&lt;br /&gt;
! |Ablage&lt;br /&gt;
! |Betrifft&lt;br /&gt;
! |Beschreibung&lt;br /&gt;
 |-&lt;br /&gt;
 |&amp;lt;tt&amp;gt;.text&amp;lt;/tt&amp;gt;&lt;br /&gt;
 |Flash&lt;br /&gt;
 |Code&lt;br /&gt;
 |normaler Programm-Code&lt;br /&gt;
 |-&lt;br /&gt;
 |&amp;lt;tt&amp;gt;.data&amp;lt;/tt&amp;gt;&lt;br /&gt;
 |SRAM&lt;br /&gt;
 |Daten&lt;br /&gt;
 |wird vom Startup-Code initialisiert, u.a. aus &amp;lt;tt&amp;gt;.progmem&amp;lt;/tt&amp;gt;&lt;br /&gt;
 |- &lt;br /&gt;
 |&amp;lt;tt&amp;gt;.bss&amp;lt;/tt&amp;gt;&lt;br /&gt;
 |SRAM&lt;br /&gt;
 |Daten&lt;br /&gt;
 |wird vom Startup-Code zu 0 initialisiert&lt;br /&gt;
 |- &lt;br /&gt;
 |colspan=&amp;quot;4&amp;quot; bgcolor=&amp;quot;#bbbbff&amp;quot;|&lt;br /&gt;
 |-&lt;br /&gt;
 |&amp;lt;tt&amp;gt;.progmem&amp;lt;/tt&amp;gt;&lt;br /&gt;
 |Flash&lt;br /&gt;
 |Daten&lt;br /&gt;
 |wird vom Startup-Code nach &amp;lt;tt&amp;gt;.data&amp;lt;/tt&amp;gt; kopiert&lt;br /&gt;
 |-&lt;br /&gt;
 |&amp;lt;tt&amp;gt;.eeprom&amp;lt;/tt&amp;gt;&lt;br /&gt;
 |EEPROM&lt;br /&gt;
 |Daten&lt;br /&gt;
 |Daten im EEPROM&lt;br /&gt;
 |-&lt;br /&gt;
 |&amp;lt;tt&amp;gt;.noinit&amp;lt;/tt&amp;gt;&lt;br /&gt;
 |SRAM&lt;br /&gt;
 |Daten&lt;br /&gt;
 |wird nicht initialisiert&lt;br /&gt;
 |- &lt;br /&gt;
 |colspan=&amp;quot;4&amp;quot; bgcolor=&amp;quot;#bbbbff&amp;quot;|&lt;br /&gt;
 |-&lt;br /&gt;
 |&amp;lt;tt&amp;gt;.init''n''&amp;lt;/tt&amp;gt;&lt;br /&gt;
 |Flash&lt;br /&gt;
 |Code&lt;br /&gt;
 |wird vor &amp;lt;tt&amp;gt;main&amp;lt;/tt&amp;gt; ausgeführt, ''n'' = 0...9&lt;br /&gt;
 |-&lt;br /&gt;
 |&amp;lt;tt&amp;gt;.fini''n''&amp;lt;/tt&amp;gt;&lt;br /&gt;
 |Flash&lt;br /&gt;
 |Code&lt;br /&gt;
 |wird nach &amp;lt;tt&amp;gt;main&amp;lt;/tt&amp;gt; ausgeführt, ''n'' = 9...0&lt;br /&gt;
 |-&lt;br /&gt;
 |&amp;lt;tt&amp;gt;.vectors&amp;lt;/tt&amp;gt;&lt;br /&gt;
 |Flash&lt;br /&gt;
 |Code&lt;br /&gt;
 |Vektor-Tabelle: Tabelle mit Sprüngen zur jeweiligen ISR&lt;br /&gt;
 |-&lt;br /&gt;
 |&amp;lt;tt&amp;gt;.bootloader&amp;lt;/tt&amp;gt;&lt;br /&gt;
 |Flash&lt;br /&gt;
 |Code&lt;br /&gt;
 |für den Bootloader&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
Der Anfang einer Section kann auch dem Linker mitgegeben werden, etwa wenn wie üblich &amp;lt;tt&amp;gt;avr-gcc&amp;lt;/tt&amp;gt; als Treiber für den Linker verwendet wird:&lt;br /&gt;
 avr-gcc ...  -Wl,--section-start=.eeprom=0x810001&lt;br /&gt;
Damit beginnt Section &amp;lt;tt&amp;gt;.eeprom&amp;lt;/tt&amp;gt; nicht an der (virtuellen) Adresse &amp;lt;tt&amp;gt;0x810000&amp;lt;/tt&amp;gt;, &lt;br /&gt;
sondern ein Byte später. &lt;br /&gt;
Manche AVRs haben einen Silicon-Bug, der bei Verwendung der EEPROM-Adresse 0 zu Fehlern führt. &lt;br /&gt;
Mit der obigen Linker-Option wird diese Adresse nicht mehr verwendet.&lt;br /&gt;
&lt;br /&gt;
=Attribute=&lt;br /&gt;
&lt;br /&gt;
Mit Attributen kann man die Codeerzeugung beeinflussen. Es gibt verschiedene Attribute, die auf Daten, Typen, und/oder Funktionen anwendbar sind.&lt;br /&gt;
&lt;br /&gt;
'''Syntax:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
__attribute__ ((&amp;amp;lt;name&amp;amp;gt;))&lt;br /&gt;
__attribute__ ((&amp;amp;lt;name1&amp;amp;gt;, &amp;amp;lt;name2&amp;amp;gt;, ...))&lt;br /&gt;
__attribute__ ((&amp;amp;lt;name&amp;amp;gt; (&amp;amp;quot;&amp;amp;lt;wert&amp;amp;gt;&amp;amp;quot;)))&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Nützliche Attribute von GCC==&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|+ '''Tabelle: Attribute von GCC''' (Auszug)&lt;br /&gt;
|- {{Hintergrund1}}&lt;br /&gt;
! |Attribut ||Funktionen ||Daten ||Typen ||Beschreibung&lt;br /&gt;
 |-&lt;br /&gt;
 | &amp;lt;tt&amp;gt;section (&amp;quot;&amp;amp;lt;name&amp;amp;gt;&amp;quot;)&amp;lt;/tt&amp;gt;&lt;br /&gt;
!| (x) || (x) || (x)&lt;br /&gt;
 | Lokatiert nach Section &amp;lt;tt&amp;gt;&amp;amp;lt;name&amp;amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 | &amp;lt;tt&amp;gt;noreturn&amp;lt;/tt&amp;gt;&lt;br /&gt;
!| x ||  ||&lt;br /&gt;
 | Die Funktion wird nie zurückkehren&lt;br /&gt;
 |-&lt;br /&gt;
 |&amp;lt;tt&amp;gt;inline&amp;lt;/tt&amp;gt;&lt;br /&gt;
!| x  || ||&lt;br /&gt;
 |Funktion wird geinlinet falls möglich&lt;br /&gt;
 |-&lt;br /&gt;
 |&amp;lt;tt&amp;gt;noinline&amp;lt;/tt&amp;gt;&lt;br /&gt;
!|x  ||  ||&lt;br /&gt;
 |Funktion wird keinesfalls geinlinet&lt;br /&gt;
 |-&lt;br /&gt;
 |&amp;lt;tt&amp;gt;packed&amp;lt;/tt&amp;gt;&lt;br /&gt;
!| || x || x&lt;br /&gt;
 |Datenablage in Strukturen erfolgt dicht, also ohne eventuelle Füllbytes&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
==Attribute von avr-gcc==&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|+ '''Tabelle: Attribute von &amp;lt;tt&amp;gt;avr-gcc&amp;lt;/tt&amp;gt;'''&lt;br /&gt;
|- {{Hintergrund1}}&lt;br /&gt;
! |Attribut ||Funktionen ||Daten ||Typen ||Beschreibung &lt;br /&gt;
|-&lt;br /&gt;
 | &amp;lt;tt&amp;gt;progmem&amp;lt;/tt&amp;gt;&lt;br /&gt;
!| x || x || x&lt;br /&gt;
 | Lokatiert ins Flash&lt;br /&gt;
 |-&lt;br /&gt;
 | &amp;lt;tt&amp;gt;naked&amp;lt;/tt&amp;gt;&lt;br /&gt;
!| x || || &lt;br /&gt;
 |Funktion wird ohne Prolog/Epilog erzeugt&lt;br /&gt;
 |-&lt;br /&gt;
 |&amp;lt;tt&amp;gt;interrupt&amp;lt;/tt&amp;gt;&lt;br /&gt;
!| x || ||&lt;br /&gt;
 |Hier nur wegen der Vollständigkeit erwähnt&lt;br /&gt;
 |-&lt;br /&gt;
 |&amp;lt;tt&amp;gt;signal&amp;lt;/tt&amp;gt;&lt;br /&gt;
!| x ||  ||&lt;br /&gt;
 |Hier nur wegen der Vollständigkeit erwähnt&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
'''Beispiele:'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#define EEPROM __attribute__ ((section (&amp;quot;.eeprom&amp;quot;)))&lt;br /&gt;
&lt;br /&gt;
const char EE_HALLO_WELT[] EEPROM = &amp;quot;Hallo Welt&amp;quot;;&lt;br /&gt;
const int EE_wert EEPROM = 0x1234;&lt;br /&gt;
&lt;br /&gt;
void __attribute__ ((noinline))&lt;br /&gt;
foo()&lt;br /&gt;
{&lt;br /&gt;
   /* Code */&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Dynamische Speicherallokierung=&lt;br /&gt;
&lt;br /&gt;
&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;
Eine resourcen-schonendere Möglichkeit, zur Laufzeit an Speicher zu kommen, &lt;br /&gt;
bietet &amp;lt;tt&amp;gt;__builtin_alloca&amp;lt;/tt&amp;gt;. &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;
Den so erhaltenen Speicher braucht man nicht freizugeben, das geschieht beim Verlassen der Funktion&lt;br /&gt;
in deren Epilog. &lt;br /&gt;
&lt;br /&gt;
Von der Verwendung ist der mittels &amp;lt;tt&amp;gt;__builtin_alloca&amp;lt;/tt&amp;gt; erhaltene Speicher&lt;br /&gt;
also wie eine lokale Variable, mitsamt den bekannten Regeln für den Gültigkeitsbereich.&lt;br /&gt;
&lt;br /&gt;
{{FarbigerRahmen|&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;
Das Programm/der Algorithmus muss daher beim Beschreiten dieses Wegs darauf angepasst werden.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Verwendung:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
void function (size_t num_data)&lt;br /&gt;
{&lt;br /&gt;
   // data_t hat man irgendwo selber definiert, oder es ist ein elementarer Typ&lt;br /&gt;
   data_t * const p = (data_t * const) __builtin_alloca (num_data * sizeof (data_t));&lt;br /&gt;
&lt;br /&gt;
   // Mach was mit p[0] ... p[num_bytes-1]&lt;br /&gt;
   ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Code-Beispiele=&lt;br /&gt;
Dieser Abschnitt enthält Code-Schnippsel für &amp;lt;tt&amp;gt;avr-gcc&amp;lt;/tt&amp;gt;. Es werden Besonderheiten besprochen, die für &amp;lt;tt&amp;gt;avr-gcc&amp;lt;/tt&amp;gt; zu beachten sind. &lt;br /&gt;
&lt;br /&gt;
Dieser Abschnitt ist ''kein'' Tutorial zur C-Programmierung und ''keine'' Einführung in die Programmiersprache C im allgemeinen. Dafür sei auf einschlägige Tutorials/Bücher verwiesen.&lt;br /&gt;
&lt;br /&gt;
==Zugriff auf Special Function Registers (SFRs)==&lt;br /&gt;
&lt;br /&gt;
===Zugiff auf Bytes und Worte===&lt;br /&gt;
Auf SFRs wird generell über deren Adresse zugegriffen:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   // Liest den Inhalt von SREG an Adresse 0x5f&lt;br /&gt;
   unsigned char sreg = *((unsigned char volatile*) 0x5f);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Das bedeutet in etwa: &amp;quot;Lies ein flüchtiges (&amp;lt;tt&amp;gt;volatile&amp;lt;/tt&amp;gt;) Byte (&amp;lt;tt&amp;gt;unsigned char&amp;lt;/tt&amp;gt;) von Adresse &amp;lt;tt&amp;gt;0x5f&amp;lt;/tt&amp;gt;&amp;quot;. Der Speicherinhalt von SFRs ist flüchtig, denn er kann sich ändern, ohne daß &amp;lt;tt&amp;gt;avr-gcc&amp;lt;/tt&amp;gt; dies mitbekommt. Daher muss bei jedem C-Zugriff auf ein SFR dieses wirklich gelesen/geschrieben werden, was der Qualifier &amp;lt;tt&amp;gt;volatile&amp;lt;/tt&amp;gt; sicherstellt. Ansonst geht der Compiler u.U. davon aus, daß der Inhalt bekannt ist und verwendet einen alten, in einem GPR befindlichen Wert.&lt;br /&gt;
&lt;br /&gt;
Um lesbaren, weniger fehleranfälligen und unter AVRs halbwegs portierbaren Code zu erhalten, gibt es Makrodefinitionen im Conroller-spezifischen Header &amp;lt;tt&amp;gt;ioxxxx.h&amp;lt;/tt&amp;gt;, der neben anderen Dingen mit &amp;lt;tt&amp;gt;avr/io.h&amp;lt;/tt&amp;gt; includet wird:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
   // SREG lesen&lt;br /&gt;
   uint8_t sreg = SREG;&lt;br /&gt;
   ...&lt;br /&gt;
   /// SREG schreiben&lt;br /&gt;
   SREG = sreg;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Die Bezeichner der SFRs sind die gleichen wie im Manual. Evtl verschafft ein Blick in den Header Klarheit. Dieser befinden sich in&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt; &amp;amp;lt;AVR_INSTALL_DIR&amp;amp;gt;/avr/include/avr/io****.h&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dieser Zugriff geht auch für 16-Bit Register wie &amp;lt;tt&amp;gt;TCNT1&amp;lt;/tt&amp;gt;, für die eine bestimmte Reihenfolge für den Zugriff auf Low- und High-Teil eingehalten werden muss: &amp;lt;tt&amp;gt;avr-gcc&amp;lt;/tt&amp;gt; generiert die Zugriffe in der richtigen Reihenfolge.&lt;br /&gt;
  uint16_t tcnt1 = TCNT1;&lt;br /&gt;
&lt;br /&gt;
{{FarbigerRahmen|&lt;br /&gt;
Zu beachten ist, daß dieser Zugriff nicht atomar erfolgt. Das Lesen/Schreiben mehrbytiger Werte muss vom Compiler in mehrere Byte-Zugriffe zerlegt werden. Zwischen diesen Zugriffen kann ein Interrupt auftreten, was zu fehlerhaften Resultaten führen kann. Entsprechende Codestücke müssen daher atomar gehalten werden!&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
===Zugriff auf einzelne Bits===&lt;br /&gt;
Zugriff auf Bits geht wie gewohnt mit den Bitoperationen &lt;br /&gt;
&amp;lt;tt&amp;gt;&amp;amp;amp;&amp;lt;/tt&amp;gt; (and),&lt;br /&gt;
&amp;lt;tt&amp;gt;|&amp;lt;/tt&amp;gt; (or),&lt;br /&gt;
&amp;lt;tt&amp;gt;^&amp;lt;/tt&amp;gt; (xor) und&lt;br /&gt;
&amp;lt;tt&amp;gt;~&amp;lt;/tt&amp;gt; (not)&lt;br /&gt;
&lt;br /&gt;
Wieder gibt es Defines in den AVR-Headern, mit denen man Masken für den Zugriff erhalten kann, etwa:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/* GIMSK / GICR */&lt;br /&gt;
#define INT1    7&lt;br /&gt;
#define INT0    6&lt;br /&gt;
#define IVSEL   1&lt;br /&gt;
#define IVCE    0&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Masken ergeben sich durch Schieben von &amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt; an die richtige Position:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// Ports B_0 und B_1 als Ausgang&lt;br /&gt;
DDRB |= (1&amp;amp;lt;&amp;amp;lt;PB0) | (1&amp;amp;lt;&amp;amp;lt;PB1);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
erzeugt&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
87 b3           in      r24, 0x17&lt;br /&gt;
83 60           ori     r24, 0x03&lt;br /&gt;
87 bb           out     0x17, r24&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Etwas anders sieht der Code aus, wenn die Bits einzeln gesetzt werden und das Register im bitadressierbaren Bereich liegt (SRAM &amp;lt;tt&amp;gt;0x20&amp;lt;/tt&amp;gt; bis &amp;lt;tt&amp;gt;0x3f&amp;lt;/tt&amp;gt; resp. I/O &amp;lt;tt&amp;gt;0x0&amp;lt;/tt&amp;gt; bis &amp;lt;tt&amp;gt;0x1f&amp;lt;/tt&amp;gt;):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// Ports B_0 und B_1 als Ausgang&lt;br /&gt;
DDRB |= (1&amp;amp;lt;&amp;amp;lt;PB0);&lt;br /&gt;
DDRB |= (1&amp;amp;lt;&amp;amp;lt;PB1);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
erzeugt&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
b8 9a           sbi     0x17, 0&lt;br /&gt;
b9 9a           sbi     0x17, 1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
{{FarbigerRahmen| &lt;br /&gt;
Auch hier ist zu beachten, daß es Probleme geben kann, wenn nicht atomarer Code erzeugt wird, weil der AVR-Befehlssatz nicht mehr hergibt:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// toggle PORT B_0: wechseln 0 &amp;amp;lt;--&amp;amp;gt; 1 &lt;br /&gt;
PORTB ^= (1&amp;amp;lt;&amp;amp;lt;PB0);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
ergibt&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
88 b3           in      r24, 0x18&lt;br /&gt;
; Wenn hier ein Interrupt auftritt, in dessen ISR PORTB verändert wird,&lt;br /&gt;
; dann wird die Änderung durch die letzte Instruktion wieder überschrieben!&lt;br /&gt;
91 e0           ldi     r25, 0x01&lt;br /&gt;
; dito&lt;br /&gt;
89 27           eor     r24, r25&lt;br /&gt;
; dito&lt;br /&gt;
88 bb           out     0x18, r24&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
}} &amp;lt;!-- /FarbigerRahmen --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Interrupts==&lt;br /&gt;
&lt;br /&gt;
Um zu kennzeichnen, daß es sich bei einer Funktion um eine Interrupt Sevice Routine (ISR) handelt, gibt es spezielle Attribute. Diese brauchen nicht explizit hingeschrieben zu werden, ebensowenig wie die genaue Nummer des Interrupt Requests (IRQ). Dafür gibt es die Includes und die Makros:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/signal.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
SIGNAL (SIG_OUTPUT_COMPARE1A)&lt;br /&gt;
{&lt;br /&gt;
   /* ISR-Code */&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
INTERRUPT (SIG_OUTPUT_COMPARE1B)&lt;br /&gt;
{&lt;br /&gt;
   /* ISR-Code */&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dadurch wird die Funktion mit dem richtigen Prolog/Epilog erzeugt, und es wird ein Eintrag in die Interrupt-Vektortabelle gemacht &amp;amp;#150; bei obigem Beispiel also zwei Einträge.&lt;br /&gt;
&lt;br /&gt;
{{FarbigerRahmen|&lt;br /&gt;
Die Schreibweise des Signal-Names muss genau die sein wie im Header, das schliesst auch Leerzeichen ein! Nicht alle GCC-Versionen bringen Fehler/Warnung, wenn die Schreibweise nicht stimmt.&lt;br /&gt;
 SIGNAL (SIG_OUTPUT_COMPARE1A )  // !!! Macht NICHT das, was man will (Blank am Ende)!!!&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;tt&amp;gt;SIGNAL&amp;lt;/tt&amp;gt;: Mit Ausführung einer ISR deaktiviert die AVR-Hardware die Interrupts, so daß die ISR nicht durch andere Interrupt-Anforderungen unterbrochen wird. Beim Verlassen der ISR werden Interrupts wieder aktiviert.&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.&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 Name 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;
&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;
&lt;br /&gt;
===default Interrupt===&lt;br /&gt;
&lt;br /&gt;
Für nicht implementierte Interrupts macht &amp;lt;tt&amp;gt;avr-gcc&amp;lt;/tt&amp;gt; in die Vektortabelle einen Eintrag,&lt;br /&gt;
der zu &amp;lt;tt&amp;gt;__bad_interrupt&amp;lt;/tt&amp;gt; (definiert im Startup-Code &amp;lt;tt&amp;gt;crt*.o&amp;lt;/tt&amp;gt;) springt&lt;br /&gt;
und von dort aus weiter zu Adresse&amp;amp;nbsp;0. &lt;br /&gt;
Dadurch läuft der AVR wieder von neuem los, wenn ein Interrupt auftritt, &lt;br /&gt;
zu dem man keine ISR definiert hat &lt;br /&gt;
&amp;amp;#150; allerdings ohne die Hardware zurück zu setzen wie bei einem echten Reset.&lt;br /&gt;
&lt;br /&gt;
Möchte man diesen Fall abfangen, dann geht das über eine globale Funktion &lt;br /&gt;
namens &amp;lt;tt&amp;gt;__vector_default&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/signal.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
SIGNAL (__vector_default)&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Damit wird von &amp;lt;tt&amp;gt;__bad_interrupt&amp;lt;/tt&amp;gt; aus nicht nach Adresse&amp;amp;nbsp;0 gesprungen,&lt;br /&gt;
sondern weiter zu &amp;lt;tt&amp;gt;__vector_default&amp;lt;/tt&amp;gt;, welches durch &amp;lt;tt&amp;gt;SIGNAL&amp;lt;/tt&amp;gt; oder&lt;br /&gt;
&amp;lt;tt&amp;gt;INTERRUPT&amp;lt;/tt&amp;gt; den üblichen ISR-Prolog/Epilog bekommt.&lt;br /&gt;
&lt;br /&gt;
Wenn man komplett eigenes Zeug machen will, dann macht man eine nackte Funktion,&lt;br /&gt;
die z.B. eine Meldung ausgibt, in einer Endlosschleife landet, oder über den [[Watchdog]]&lt;br /&gt;
einen richtigen Reset auslöst. Falls &amp;lt;tt&amp;gt;__vector_default&amp;lt;/tt&amp;gt; zurückkehren soll,&lt;br /&gt;
dann ist darauf zu achten, daß man dies mit &amp;lt;tt&amp;gt;reti&amp;lt;/tt&amp;gt; (return from interrupt) tut&lt;br /&gt;
und evtl. verwendete Register und den Status (&amp;lt;tt&amp;gt;SREG&amp;lt;/tt&amp;gt;) sichert:&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;
   __asm__ __volatile (&lt;br /&gt;
      &amp;quot;; mach was&amp;quot;  &amp;quot;\n\t&amp;quot;&lt;br /&gt;
      &amp;quot;; mach was&amp;quot;  &amp;quot;\n\t&amp;quot;&lt;br /&gt;
      &amp;quot;reti&amp;quot;&lt;br /&gt;
      );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===ISR mit eigenem Prolog/Epilog===&lt;br /&gt;
Genauso implementiert man auch eine kleine ISR mit minimalem Overhead.&lt;br /&gt;
Mit &amp;lt;tt&amp;gt;naked&amp;lt;/tt&amp;gt; befreit man die Routine vom Standard-Prolog/Epilog und &lt;br /&gt;
kümmert sich selbst darum:&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;
   __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;
==SRAM, Flash, EEPROM: Datenablage am Beispiel Strings==&lt;br /&gt;
Die Programmiersprache C kennt selber keine Strings; das einzige, was C bekannt ist, ist der Datentyp &amp;lt;tt&amp;gt;char&amp;lt;/tt&amp;gt;, der ein einzelnes Zeichen repräsentiert. &lt;br /&gt;
===Darstellung in C===&lt;br /&gt;
Ein String im Sinne von C ist ein Array von Charactern bzw. ein Zeiger auf den Anfang des Arrays. Die einzelnen Zeichen folgen im Speicher direkt aufeinander und werden in aufsteigenden Adressen gespeichert. Am String-Ende folgt als Abschluss der Character &amp;lt;tt&amp;gt;'\0'&amp;lt;/tt&amp;gt;, um das Ende zu kennzeichnen. Dies ist besonders bei der Berechnung des Speicherplatzes für Strings zu berücksichtigen, denn für die 0 muss auch Platz reserviert werden.&lt;br /&gt;
&lt;br /&gt;
===Bestimmen der Stringlänge===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 /* Bestimmt die Laenge des Strings ohne die abschliessende '\0' zu zaehlen&lt;br /&gt;
 unsigned int strlength (const char *str)&lt;br /&gt;
 {&lt;br /&gt;
   unsigned int len = 0;&lt;br /&gt;
   &lt;br /&gt;
   while (*str++)&lt;br /&gt;
      len++;&lt;br /&gt;
   &lt;br /&gt;
   return len;&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Stringlänge kann auch mit der Standard-Funktion &amp;lt;tt&amp;gt;strlen&amp;lt;/tt&amp;gt; bestimmt werden, deren Prototyp sich in &amp;lt;tt&amp;gt;string.h&amp;lt;/tt&amp;gt; befindet:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
 size_t strlen (const char*);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===String im Flash belassen===&lt;br /&gt;
Oftmals werden Strings nur zu Ausgabezwecken verwendet und nicht verändert. Verwendet man Sequenzen der Gestalt&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 char *str1 = &amp;quot;Hallo Welt!&amp;quot;;&lt;br /&gt;
 char str2[] = &amp;quot;Hallo Welt!&amp;quot;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
dann werden die Strings im SRAM abgelegt. Im Startup-Code werden die Strings vom Flash ins SRAM kopiert und belegen daher sowohl Platz im SRAM als auch im Flash. Wird ein String nicht verändert, braucht er nicht ins SRAM kopiert zu werden. Das spart Platz im knapp bemessenen SRAM. Allerdings muss anders auf den String zugegriffen werden, denn wegen der Harvard-Architektur des AVR-Kerns kann &amp;lt;tt&amp;gt;avr-gcc&amp;lt;/tt&amp;gt; anhand der Adresse nicht unterscheiden, ob diese ins SRAM, ins Flash oder ins EEPROM zeigt.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 #include &amp;lt;avr/pgmspace.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 const prog_char str3[] = &amp;quot;Hallo Welt!&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 unsigned int strlen_P (const prog_char *str)&lt;br /&gt;
 {&lt;br /&gt;
    unsigned int len = 0;&lt;br /&gt;
 &lt;br /&gt;
    while (1)&lt;br /&gt;
    {&lt;br /&gt;
       char c = (char) pgm_read_byte (str);&lt;br /&gt;
       if ('\0' == c)&lt;br /&gt;
          return len;&lt;br /&gt;
       len++;&lt;br /&gt;
       str++; &lt;br /&gt;
    }&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void foo()&lt;br /&gt;
 {&lt;br /&gt;
    unsigned int len;&lt;br /&gt;
    len = strlen_P (str3);&lt;br /&gt;
    len = strlen_P (PSTR(&amp;quot;String im Flash&amp;quot;));&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===String ins EEPROM legen===&lt;br /&gt;
Dies geht nach dem gleichen Muster, nach dem Strings ins Flash gelegt werden. Der Zugriff wird vergleichsweise langsam, denn der EEPROM ist langsamer als SRAM bzw. Flash.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 #include &amp;lt;avr/eeprom.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 const char str4[] __attribute__ ((section(&amp;quot;.eeprom&amp;quot;))) = &amp;quot;Hallo Welt!&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 unsigned int strlen_EE (const char *str)&lt;br /&gt;
 {&lt;br /&gt;
    unsigned int len = 0;&lt;br /&gt;
 &lt;br /&gt;
    while (1)&lt;br /&gt;
    {&lt;br /&gt;
       char c = (char) eeprom_read_byte (str);&lt;br /&gt;
       if ('\0' == c)&lt;br /&gt;
          return len;&lt;br /&gt;
       len++;&lt;br /&gt;
       str++; &lt;br /&gt;
    }&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Reset auslösen==&lt;br /&gt;
Falls ein Reset per Software ausgelöst werden soll, denn 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 RESET. So kann man z.B. via [[UART]] ein RESET-Kommando schicken. Allerdings lässt sich der Watchdog nur minimal auf 15ms einstellen:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/wdt.h&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/interrupt.h&amp;gt;&lt;br /&gt;
...   &lt;br /&gt;
   cli();                     // Interrupts global abschalten&lt;br /&gt;
   wdt_enable (WDTO_15MS);    // Watchdog aufziehen auf 15ms&lt;br /&gt;
   while (1);                 // warten, bis er zubeisst...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Zufall==&lt;br /&gt;
&amp;quot;Echte&amp;quot; Zufallszahlen zu generieren ist leider nicht möglich, hierzu muss man externe Hardware wie einen [[Rauschgenerator]] verwenden. Funktionen  wie &amp;lt;tt&amp;gt;rand&amp;lt;/tt&amp;gt; und &amp;lt;tt&amp;gt;random&amp;lt;/tt&amp;gt; basieren auf algebraischen Verfahren, die eine gute Verteilung der gelieferten Werte haben. Werden diese Funktionen mit dem selben Startwert (seed) initialisiert, liefern sie auch immer die gleiche Folge. In diesem Sinne sind die Werte nicht zufällig sondern nur scheinbar zufällig und &amp;quot;wüst umherhüpfend&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Um einen zufälligen Startwert zu erhalten, kann man den uninitialisierten Inhalt des SRAM verwenden, das nach dem power-up keinen definierten Zustand hat.&lt;br /&gt;
&lt;br /&gt;
===Startwert (seed) besorgen===&lt;br /&gt;
Am einfachsten geht dies, indem man eine Variable in die Sektion &amp;lt;tt&amp;gt;.noinit&amp;lt;/tt&amp;gt; lokatiert und den Wert liest:&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
 unsigned long seed __attribute__ ((section (&amp;quot;.noinit&amp;quot;)));&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Etwas bessere Resultate erhält man, wenn man den ganzen Inhalt des nicht verwendeten SRAMs zur Bildung der seed heranzieht. Das Symbol &amp;lt;tt&amp;gt;__heap_start&amp;lt;/tt&amp;gt; wird übrigens im standard Linker-Script definiert, &amp;lt;tt&amp;gt;RAMEND&amp;lt;/tt&amp;gt; ist ein Makro aus &amp;lt;tt&amp;gt;ioxxxx.h&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
Das Beispiel interpretiert den SRAM-Inhalt als &amp;lt;tt&amp;gt;unsigned short&amp;lt;/tt&amp;gt; Werte und berechnet die seed, indem die einzelnen Werte mit exor &amp;amp;quot;überlagert&amp;amp;quot; werden.&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;
 unsigned short get_seed()&lt;br /&gt;
 {&lt;br /&gt;
    unsigned short seed = 0;&lt;br /&gt;
    unsigned short *p = (unsigned short*) (RAMEND+1);&lt;br /&gt;
    extern unsigned short __heap_start;&lt;br /&gt;
    &lt;br /&gt;
    while (p &amp;gt;= &amp;amp;__heap_start + 1)&lt;br /&gt;
       seed ^= * (--p);&lt;br /&gt;
    &lt;br /&gt;
    return seed;&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Pseudozufall in der avr-libc===&lt;br /&gt;
In der &amp;lt;tt&amp;gt;avr-libc&amp;lt;/tt&amp;gt; finden sich Funktionen, um Pseudo-Zufallszahlen zu erhalten bzw. um Startwerte für die Algorithmen zu setzen:&lt;br /&gt;
&lt;br /&gt;
 #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Prototypen und Defines:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 #define RAND MAX 0x7FFF&lt;br /&gt;
 &lt;br /&gt;
 int rand (void);&lt;br /&gt;
 void srand (unsigned int seed);&lt;br /&gt;
 &lt;br /&gt;
 long random (void);&lt;br /&gt;
 void srandom (unsigned long seed);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Frühe Codeausführung vor main()==&lt;br /&gt;
&lt;br /&gt;
Mitunter ist es notwendig, Code unmittelbar nach dem Reset auszuführen, noch bevor man in &amp;lt;tt&amp;gt;main()&amp;lt;/tt&amp;gt; mit der eigentlichen Programmausführung beginnt. Das kann zB zur Bedienung eines [[Watchdog]]-Timers erforderlich sein.&lt;br /&gt;
&lt;br /&gt;
Nach einen Reset und vor Aufruf von &amp;lt;tt&amp;gt;main&amp;lt;/tt&amp;gt; werden Initialisierungen ausgeführt wie&lt;br /&gt;
* setzen des Stackpointers&lt;br /&gt;
* Vorbelegung globaler Datenobjekte: Daten ohne Initializer werden zu 0 initialisert (Section &amp;lt;tt&amp;gt;.bss&amp;lt;/tt&amp;gt;). Für Daten mit Initializer (Section &amp;lt;tt&amp;gt;.data&amp;lt;/tt&amp;gt;) werden die Werte aus dem Flash ins SRAM kopiert.&lt;br /&gt;
* Initialisierung von Registern wie R1, in dem bei &amp;lt;tt&amp;gt;avr-gcc&amp;lt;/tt&amp;gt; immer die Konstante 0 gehalten wird.&lt;br /&gt;
&lt;br /&gt;
Im Linker-Script werden Sections von &amp;lt;tt&amp;gt;.init0&amp;lt;/tt&amp;gt; bis &amp;lt;tt&amp;gt;.init9&amp;lt;/tt&amp;gt; definiert, die nacheinander abgearbeitet werden. Erst danach wird &amp;lt;tt&amp;gt;main&amp;lt;/tt&amp;gt; betreten. Um Code früh auszuführen, legt man die Funktion in eine dieser Sections:&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
 /* !!! never call this function !!! */&lt;br /&gt;
 void __attribute__ ((naked, section (&amp;quot;.init3&amp;quot;)))&lt;br /&gt;
 code_init3 (void)&lt;br /&gt;
 {&lt;br /&gt;
     /* Code */&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
Zu beachten ist dabei&lt;br /&gt;
* Eine so definierte Funktion darf keinesfalls aufgerufen werden!&lt;br /&gt;
* Zuweisungen wie &amp;lt;tt&amp;gt;i=0;&amp;lt;/tt&amp;gt; ergeben vor &amp;lt;tt&amp;gt;.init3&amp;lt;/tt&amp;gt; inkorrekten Code, da vor Ende von &amp;lt;tt&amp;gt;.init2&amp;lt;/tt&amp;gt; Register R1 noch nicht mit 0 besetzt ist, &amp;lt;tt&amp;gt;avr-gcc&amp;lt;/tt&amp;gt; aber davon ausgeht, daß es eben diesen Wert enthält.&lt;br /&gt;
* Lokale Variablen müssen in Registern liegen, denn vor Ende von &amp;lt;tt&amp;gt;.init2&amp;lt;/tt&amp;gt; ist der Stackpointer noch nicht initialisiert. Zudem ist die Funktion &amp;lt;tt&amp;gt;naked&amp;lt;/tt&amp;gt;, hat also insbesondere keinen Prolog, der den Framepointer (Y-Register) setzen könnte, falls er benötigt wird. &lt;br /&gt;
* Gegebenenfalls ist daher die Verwendung von inline-Assembler angezeigt oder die Implementierung in einem eigenen Assembler-Modul, das dazu gelinkt wird. Der erzeugte Code ist im List-File zu überfrüfen.&lt;br /&gt;
* Werden mehrere Funktionen in die gleiche init-Section gelegt, ist die Reihenfolge ihrer Ausführung nicht spezifiziert und i.a. nicht die gleiche wie in der Quelle.&lt;br /&gt;
Unbenutzte init-Sections haben die Nummern 0, 1, 3 und 5 bis 8. Die verbleibenden werden vom Startup-Code verwendet:&lt;br /&gt;
;&amp;lt;tt&amp;gt;.init2&amp;lt;/tt&amp;gt;: Initialisieren von R1 mit 0 und setzen des Stackpointers&lt;br /&gt;
;&amp;lt;tt&amp;gt;.init4&amp;lt;/tt&amp;gt;: Kopieren der Daten vom Flash ins SRAM (&amp;lt;tt&amp;gt;.data&amp;lt;/tt&amp;gt;) und löschen von &amp;lt;tt&amp;gt;.bss&amp;lt;/tt&amp;gt;&lt;br /&gt;
;&amp;lt;tt&amp;gt;.init6&amp;lt;/tt&amp;gt;: C++ Konstruktoren&lt;br /&gt;
;&amp;lt;tt&amp;gt;.init9&amp;lt;/tt&amp;gt;: Sprung zu &amp;lt;tt&amp;gt;main&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Includes=&lt;br /&gt;
&lt;br /&gt;
Die mit&lt;br /&gt;
 #include &amp;lt;...&amp;gt;&lt;br /&gt;
angegebenen Includes werden von &amp;lt;tt&amp;gt;avr-gcc&amp;lt;/tt&amp;gt; in den &lt;br /&gt;
mit der Option '&amp;lt;tt&amp;gt;-I&amp;lt;/tt&amp;gt;' anegegenen Pfaden gesucht. &lt;br /&gt;
Dem Compiler bekannt ist der Pfad &amp;lt;tt&amp;gt;&amp;lt;GCC_HOME&amp;gt;/avr/include&amp;lt;/tt&amp;gt;.&lt;br /&gt;
Gibt man z.B. an &lt;br /&gt;
 #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
dann wird automatisch in diesem Verzeichnis nach &amp;lt;tt&amp;gt;stdio.h&amp;lt;/tt&amp;gt; gesucht.&lt;br /&gt;
In dem Verzeichnis stehen Standard-Includes die benötigt werden, wenn man libc-Funktionen &lt;br /&gt;
oder mathematische Funktionen verwendet. &lt;br /&gt;
AVR-spezifische Dinge stehen im Unterverzeichnis &amp;lt;tt&amp;gt;avr&amp;lt;/tt&amp;gt;, etwa:&lt;br /&gt;
 #include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Standard==&lt;br /&gt;
&lt;br /&gt;
 ctype.h                   character conversion macros and ctype macros&lt;br /&gt;
 errno.h                   provides symbolic names for various error codes&lt;br /&gt;
 inttypes.h                Use [u]intN_t if you need exactly N bits.&lt;br /&gt;
                           These typedefs are mandated by the C99 standard.&lt;br /&gt;
 math.h                    mathematical functions&lt;br /&gt;
 setjmp.h                  The C library provides the setjmp() and longjmp() functions&lt;br /&gt;
                           to jump directly to another (non-local) function. &lt;br /&gt;
 stdio.h                   Standard IO facilities&lt;br /&gt;
 stdlib.h                  Declares some basic C macros and functions as defined by&lt;br /&gt;
                           the ISO standard, plus some AVR-specific extensions&lt;br /&gt;
 string.h                  perform string operations on NULL terminated strings&lt;br /&gt;
&lt;br /&gt;
==AVR-spezifisch==&lt;br /&gt;
&lt;br /&gt;
Die AVR-spezifischen Includes finden sich wie gesagt im Unterverzeichnis &amp;lt;tt&amp;gt;avr&amp;lt;/tt&amp;gt;.&lt;br /&gt;
Die meisten dort befindlichen Header wird man nie direkt durch Angabe im C-File erhalten,&lt;br /&gt;
sondern durch Angabe von&lt;br /&gt;
 #include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
Dadurch werden z.B. genau der I/O-Header eingebunden, der zum AVR-Modell passt, also&lt;br /&gt;
&amp;lt;tt&amp;gt;avr/iom8.h&amp;lt;/tt&amp;gt; für ATMega8, &lt;br /&gt;
&amp;lt;tt&amp;gt;avr/iotn2313&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;', für ATMega &amp;lt;tt&amp;gt;avr/iom*.h&amp;lt;/tt&amp;gt;' &lt;br /&gt;
und für ATTiny '&amp;lt;tt&amp;gt;avr/iotn*.h&amp;lt;/tt&amp;gt;'.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
avr/boot.h            Bootloader Support&lt;br /&gt;
avr/crc16.h           Prüfsumme CRC16&lt;br /&gt;
avr/delay.h           Verzögerungsschleife - loops for small accurate delays&lt;br /&gt;
avr/eeprom.h          EEPROM-Routinen&lt;br /&gt;
avr/ina90.h           Kompatibilität mit IAR-AVR-Compiler&lt;br /&gt;
avr/interrupt.h       sei(), cli(), ...&lt;br /&gt;
avr/io.h              --&amp;gt; inttypes.h, io*.h&lt;br /&gt;
avr/io*.h             SFRs, SIG_****, SPM_PAGESIZE, RAMEND, XRAMEND, E2END, FLASHEND&lt;br /&gt;
avr/parity.h          Parität&lt;br /&gt;
avr/pgmspace.h        Zugriff aufs Flash: Byte lesen, PROGMEM, prog_char, prog_uint8_t, ...&lt;br /&gt;
avr/portpins.h        Makros für Port-Pins&lt;br /&gt;
avr/signal.h          Makros SIGNAL() und INTERRUPT(), ...&lt;br /&gt;
avr/sleep.h           Power-Safe&lt;br /&gt;
avr/twi.h             I2C&lt;br /&gt;
avr/wdt.h             Watchdog&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Optimierungen, Tipps &amp;amp; Tricks=&lt;br /&gt;
&lt;br /&gt;
Beim Programmieren in C möchte man sich möglichst wenig mit der Codeerzeugung selbst auseinandersetzen. Man verwendet ja gerade deshalb einen Compiler und programmiert nicht in Assembler, weil man sich nicht um Register-Belegungen o.ä. kümmern will, sondern nur um die zu lösende Aufgabe.&lt;br /&gt;
GCC erzeugt zwar recht guten Code, aber er ist nicht perfekt. Gerade auf Systemen wie AVR mit nur sehr begrenzten Resourcen muss man daher dem Compiler hilfreich zur Seite stehen, wenn man noch dichteren/schnelleren Code erhalten möchte.&lt;br /&gt;
&lt;br /&gt;
Um das Ergebnis zu beurteilen, hilft ein Blick ins Listfile. &lt;br /&gt;
Siehe dazu auch die Abschnitte &lt;br /&gt;
&amp;quot;[[Hallo Welt für AVR (Blinky)#Listfile erstellen|Listfile erstellen]]&amp;quot; &lt;br /&gt;
und&lt;br /&gt;
&amp;quot;[[Hallo Welt für AVR (Blinky)#Die Größe ermitteln|Die Größe ermitteln]]&amp;quot; &lt;br /&gt;
im [[Hallo Welt für AVR (Blinky)|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 ist das Compiler-Builtin &amp;lt;tt&amp;gt;__builtin_alloca&amp;lt;/tt&amp;gt; eine effiziente Alternative, 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 Ausgabezwechen 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 die im Flash liegen zuzugreifen, tragen die Suffix &amp;lt;tt&amp;gt;_P&amp;lt;/tt&amp;gt;, wie z.B. &amp;lt;tt&amp;gt;strcmp_P&amp;lt;/tt&amp;gt; mit dem Prototyp&lt;br /&gt;
 extern int *strcmp_P (char *, const prog_char *)&lt;br /&gt;
Die Implementierungen befinden sich in der &amp;lt;tt&amp;gt;avr-libc&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''Anwendung:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/pgmspace.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
const prog_char str_p[]     = &amp;quot;Ein String im Flash&amp;quot;;&lt;br /&gt;
const char str2_p[] PROGMEM = &amp;quot;Noch ein String im Flash&amp;quot;;&lt;br /&gt;
...&lt;br /&gt;
   // String im SRAM mit String im Flash vergleichen&lt;br /&gt;
   if (!strcmp_P (str_sram, str_p))&lt;br /&gt;
   {&lt;br /&gt;
       // mach was bei Gleichheit&lt;br /&gt;
   }&lt;br /&gt;
...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==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;
===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;
Hier ein Beispiel, daß Division mit Rest für &amp;lt;tt&amp;gt;unsigned short&amp;lt;/tt&amp;gt; verwendet, um eine 16-Bit-Zahl in Dezimaldarstellung zu wandeln:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// Struktur definieren und Funktion bekannt machen&lt;br /&gt;
typedef struct&lt;br /&gt;
{&lt;br /&gt;
	unsigned short quot;&lt;br /&gt;
	unsigned short rem;&lt;br /&gt;
} udiv_t;&lt;br /&gt;
&lt;br /&gt;
extern udiv_t __udivmodhi4 (unsigned short, unsigned short);&lt;br /&gt;
&lt;br /&gt;
#define udiv __udivmodhi4&lt;br /&gt;
&lt;br /&gt;
// 5 Ziffern und evtl. noch eine führende 0&lt;br /&gt;
#define DIGITS 6&lt;br /&gt;
&lt;br /&gt;
// +1 wegen String-Ende (wird im Startup auf 0 gesetzt)&lt;br /&gt;
char string[DIGITS+1];&lt;br /&gt;
&lt;br /&gt;
// Wandelt zahl in Dezimaldarstellung um.&lt;br /&gt;
// Der return-Wert zeigt irgendwo ins string[]-Array.&lt;br /&gt;
// string[] wird verändert.&lt;br /&gt;
char* toString (unsigned short zahl)&lt;br /&gt;
{&lt;br /&gt;
	// s zeigt auf das Ende von string&lt;br /&gt;
	// string wird von hinten nach vorne gefüllt&lt;br /&gt;
	char *s = string + DIGITS;&lt;br /&gt;
	&lt;br /&gt;
	// qrem enthält Quotient (quot) und Rest (rem) der Divisionen&lt;br /&gt;
	udiv_t qrem = {.quot = zahl};                  &lt;br /&gt;
&lt;br /&gt;
	do&lt;br /&gt;
	{&lt;br /&gt;
		// Division mit Rest durch 10&lt;br /&gt;
		// quot: Ergebnis für den nächsten Durchlauf&lt;br /&gt;
		// rem:  Rest ist die Ziffer im 10er-System&lt;br /&gt;
		qrem = udiv (qrem.quot, 10);&lt;br /&gt;
		&lt;br /&gt;
		// Ziffer in Zeichen wandeln und speichern&lt;br /&gt;
		*(--s) = '0' + qrem.rem;&lt;br /&gt;
	}	&lt;br /&gt;
	while (0 != qrem.quot);&lt;br /&gt;
	&lt;br /&gt;
	// Falls eine führende '0' gespeichert wurde: weg damit&lt;br /&gt;
	// ausser zahl war selbst schon 0&lt;br /&gt;
	if (*s == '0' &amp;amp;&amp;amp; *(s+1) != '\0')&lt;br /&gt;
		s++;&lt;br /&gt;
&lt;br /&gt;
	return s;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Falls man eine Division und/oder Rest für 8-Bit braucht, dann geht für &amp;lt;tt&amp;gt;unsigned&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
typedef struct&lt;br /&gt;
{&lt;br /&gt;
	unsigned char quot;&lt;br /&gt;
	unsigned char rem;&lt;br /&gt;
} udiv8_t;&lt;br /&gt;
&lt;br /&gt;
extern udiv8_t __udivmodqi4 (unsigned char, unsigned char);&lt;br /&gt;
&lt;br /&gt;
#define udiv8 __udivmodqi4&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Division durch Multiplikation===&lt;br /&gt;
===Vermeiden von float und double===&lt;br /&gt;
=Dateien (WinAVR)=&lt;br /&gt;
&lt;br /&gt;
WinAVR bringt wesentlich mehr mit als nur &amp;lt;tt&amp;gt;avr-gcc&amp;lt;/tt&amp;gt;:&lt;br /&gt;
* Binutils (Assembler (&amp;lt;tt&amp;gt;avr-as&amp;lt;/tt&amp;gt;), Linker (&amp;lt;tt&amp;gt;avr-ld&amp;lt;/tt&amp;gt;), Tools (&amp;lt;tt&amp;gt;avr-size&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;avr-objdump&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;avr-objcopy&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;avr-nm&amp;lt;/tt&amp;gt;, ...))&lt;br /&gt;
* Debugger (&amp;lt;tt&amp;gt;avr-gdb&amp;lt;/tt&amp;gt; mit Oberfläche &amp;lt;tt&amp;gt;insight&amp;lt;/tt&amp;gt;)&lt;br /&gt;
* Bibliothek &amp;lt;tt&amp;gt;avr-libc&amp;lt;/tt&amp;gt; inclusive Dokumentation&lt;br /&gt;
* Progger &amp;lt;tt&amp;gt;avrdude&amp;lt;/tt&amp;gt;&lt;br /&gt;
* Progger &amp;lt;tt&amp;gt;uisp&amp;lt;/tt&amp;gt;&lt;br /&gt;
* AVR-Simlator (simulavr), &lt;br /&gt;
* Programmers Notepad (kleiner Editor)&lt;br /&gt;
* Demo-Projekte&lt;br /&gt;
* viele Linux-Tools wie &amp;lt;tt&amp;gt;make&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;grep&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;sed&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;tar&amp;lt;/tt&amp;gt;, etc.&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
'''Verzeichnisbaum''' (Auszug):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
.                               avr-gcc Installations-Verzeichnis&lt;br /&gt;
./avr/include                   Standard Includes &lt;br /&gt;
./avr/include/avr               Includes AVR-spezifisch &lt;br /&gt;
./avr/lib                       Startup-Code, Libs (avr2)&lt;br /&gt;
./avr/lib/avr3                            &amp;quot;        (avr3)&lt;br /&gt;
./avr/lib/avr4                            &amp;quot;        (avr4)&lt;br /&gt;
./avr/lib/avr5                            &amp;quot;        (avr5)&lt;br /&gt;
./avr/lib/ldscripts             Linker-Skripte&lt;br /&gt;
./bin                           Programme (avr-gcc.exe, giveio.sys, ...&lt;br /&gt;
./doc                           Doku (HTML + pdf)   &lt;br /&gt;
./doc/avr-libc                     avr-libc &lt;br /&gt;
./doc/avrdude-xxx                  avrdude&lt;br /&gt;
./doc/simulavr-xxx                 simulavr      &lt;br /&gt;
./doc/uisp-xxx                     uisp&lt;br /&gt;
./examples                      Beispiel-Projekte&lt;br /&gt;
./examples/demo                    PWM mit AT90S2313&lt;br /&gt;
./examples/twitest                 I2C mit ATMega&lt;br /&gt;
./info                          info pages&lt;br /&gt;
./man                           man pages&lt;br /&gt;
./mfile                         mfile&lt;br /&gt;
./pn                            Programmers Notepad&lt;br /&gt;
./utils/bin                     bzip2, diff, gawk, grep, make, sed, tar, ...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Fallstricke und häufige Fehler=&lt;br /&gt;
&lt;br /&gt;
==Tippfehler==&lt;br /&gt;
&lt;br /&gt;
Tippfehler können immer passieren. Besonders fies ist es, wenn der Tippfehler nicht zu einer Warnung oder zu einer Fehlermeldung führt, weil der entstandene Code korrekter C-Code ist.&lt;br /&gt;
&lt;br /&gt;
===Ein &amp;lt;tt&amp;gt;;&amp;lt;/tt&amp;gt; zu viel===&lt;br /&gt;
Ein reflexartig eingetippter oder nach Ändeungen stehen gebliebener &amp;lt;tt&amp;gt;;&amp;lt;/tt&amp;gt; hat schon so manches &lt;br /&gt;
Programm ausgeknockt:&lt;br /&gt;
 if (a == 0);&lt;br /&gt;
 {&lt;br /&gt;
    /* mach was */&lt;br /&gt;
 }&lt;br /&gt;
Wenn &amp;lt;tt&amp;gt;a == 0&amp;lt;/tt&amp;gt; ist, dann wird &amp;lt;tt&amp;gt;;&amp;lt;/tt&amp;gt; ausgeführt (also im Endeffekt garnichts). Danach kommt der Block, der im &amp;lt;tt&amp;gt;if&amp;lt;/tt&amp;gt; stehen sollte. Der wird immer ausgeführt, denn er gehört nicht mehr zum &amp;lt;tt&amp;gt;if&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Zuweisung statt Vergleich===&lt;br /&gt;
 if (a = 0)&lt;br /&gt;
 {&lt;br /&gt;
    /* mach was */&lt;br /&gt;
 }&lt;br /&gt;
Zuerst wird &amp;lt;tt&amp;gt;a = 0&amp;lt;/tt&amp;gt; gesetzt und dann überprüft, ob die &amp;lt;tt&amp;gt;if&amp;lt;/tt&amp;gt;-Bedingung erfullt ist. Der Wert ist aber immer &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;, was ''nicht erfüllt'' bedeutet. Der nachfolgende Block wird nie betreten.&lt;br /&gt;
&lt;br /&gt;
Abhilfe schafft, sich angewohnen zu schreiben&lt;br /&gt;
 if (0 == a)&lt;br /&gt;
Wenn man dann eine Zuweisung eintippt, gibt's einen Fehler.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Signal/Interrupt-Name vertippt oder Leerzeichen zu viel===&lt;br /&gt;
&lt;br /&gt;
 SIGNAL (SIG_OVEFRLOW0)&lt;br /&gt;
 {&lt;br /&gt;
    /* mach was */&lt;br /&gt;
 }&lt;br /&gt;
Nicht alle Compiler-Versionen meckern da. Der ISR-Code wird nicht in die Interrupt-Tabelle eingetragen. Kommt es zum Interrupt, dann landet man in RESET.&lt;br /&gt;
&lt;br /&gt;
==Nicht-atomarer Code==&lt;br /&gt;
Verwendet man in einem Programm IRQs (Interrupts) und ändert in der ISR (Service Routine) ein Datum (Variable, SFR, ...), dann wird diese Änderung möglicherweise überschrieben, wenn die IRQ zu einem ungünstigen Zeitpunkt auftritt. &lt;br /&gt;
Ein Beispiel, das zeigt, was passieren kann, findet sich im Abschnitt &amp;quot;[[avr-gcc#Zugriff auf einzelne Bits|Zugriff auf einzelne Bits]]&amp;quot;. Ein weiteres Beispiel ist das Lesen, Schreiben oder Testen einer mehrbytigen Variable:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
int volatile i;&lt;br /&gt;
   ...&lt;br /&gt;
   if (0 == i)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Weil &amp;lt;tt&amp;gt;i&amp;lt;/tt&amp;gt; länger als 1 Byte ist, kann es nicht in einem Befehl gelesen werden;&lt;br /&gt;
daher kann während des Lesens eine IRQ auftreten, in deren ISR der Wert von &amp;lt;tt&amp;gt;i&amp;lt;/tt&amp;gt;&lt;br /&gt;
verändert wird. Der obige Code könnte etwa so assembliert werden:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   ; i wird vom SRAM in das Registerpaar r24:r25 geladen&lt;br /&gt;
   ; low-Teil laden&lt;br /&gt;
   lds r24,i&lt;br /&gt;
   ; high-Teil laden&lt;br /&gt;
   ; wenn hier eine IRQ zuschlägt, in der i verändert wird, ist der Registerinhalt korrupt&lt;br /&gt;
   lds r25,(i)+1&lt;br /&gt;
   or r24,r25&lt;br /&gt;
   brne ...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Natürlich können auch komplexere Datenstrukturen von diesem Phänomen betroffen sein.&lt;br /&gt;
Besonders unangenehm an dieser Klasse von Fehlern ist, daß sie nur sporadisch auftauchen&lt;br /&gt;
und man sie daher selbst mit einem guten Debugger sehr schlecht orten kann, da die zugehörige&lt;br /&gt;
Codestelle fast immer korrekt abgearbeitet wird.&lt;br /&gt;
&lt;br /&gt;
Entweder man macht den ganzen betroffenen Block ununterbrechbar (atomar):&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;
   unsigned char sreg = SREG;&lt;br /&gt;
&lt;br /&gt;
   cli();&lt;br /&gt;
   if (0 == i)&lt;br /&gt;
   {&lt;br /&gt;
      i = 1;&lt;br /&gt;
      SREG = sreg;&lt;br /&gt;
   }&lt;br /&gt;
   else&lt;br /&gt;
   {&lt;br /&gt;
      SREG = sreg;&lt;br /&gt;
      return;&lt;br /&gt;
   }&lt;br /&gt;
   ...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
oder je nach Programmstruktur sichert man den Wert, z.B. in eine lokale Variable.&lt;br /&gt;
&lt;br /&gt;
==Mangelnde C-Kenntnis==&lt;br /&gt;
&lt;br /&gt;
===Warnung ignoriert===&lt;br /&gt;
&lt;br /&gt;
::&amp;quot;''Wieso soll das Probleme machen? Das ist doch nur eine Warnung!''&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Warnungen zur Compile-Zeit werden gerne zu Fehlern zur Laufzeit. Letztere sind deutlich schwerer zu finden, als angewarnten Code zu korrigieren.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
void foo (long*);&lt;br /&gt;
&lt;br /&gt;
void bar (int *p)&lt;br /&gt;
{&lt;br /&gt;
    foo (p+1); &lt;br /&gt;
    // Was soll das sein?!&lt;br /&gt;
    // ((long*) p) + 1       oder  &lt;br /&gt;
    // (long*) (p + 1)&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;gt; avr-gcc -c -o prog.o prog.c&lt;br /&gt;
&lt;br /&gt;
prog.c: In function `bar':&lt;br /&gt;
prog.c:5: warning: passing arg 1 of `foo' from incompatible pointer type&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Array-Index===&lt;br /&gt;
&lt;br /&gt;
Informatiker am Bahnhof:&lt;br /&gt;
:''&amp;quot;0, 1, 2, ... Wo ist mein dritter Koffer?!&amp;quot;''&lt;br /&gt;
Gleiches gilt für Arrays:&lt;br /&gt;
 #define NUM 10;&lt;br /&gt;
 int a[NUM]; // für die N Werte a[0] ... a[N-1]&lt;br /&gt;
Ein Zugriff auf &amp;lt;tt&amp;gt;a[N]&amp;lt;/tt&amp;gt; greift igrdendwo hin. &lt;br /&gt;
Wahlweise liest man Schrott oder überschreibt andere Daten, die in der Nähe liegen, und&lt;br /&gt;
plötzlich seltsame Werte enthalten.&lt;br /&gt;
&lt;br /&gt;
===Bitweise vs. Logische Operatoren===&lt;br /&gt;
&lt;br /&gt;
Die Operatoren AND, OR und NOT gibt es in C in zwei Ausprägungen&lt;br /&gt;
;bitweise: Die Operatoren &amp;lt;tt&amp;gt;^&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;|&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;&amp;amp;&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;~&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;|=&amp;lt;/tt&amp;gt;,  &amp;lt;tt&amp;gt;^=&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;&amp;amp;=&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;|=&amp;lt;/tt&amp;gt; operieren bitweise. Der entsprechende Operator wird also auf alle Bits des Wertes parallel angewandt und das Ergebnis für ein Bit ist unabhängig vom Inhalt der anderen Bits.&lt;br /&gt;
;logisch:  Die Operatoren &amp;lt;tt&amp;gt;||&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;&amp;amp;&amp;amp;&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;!&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;&amp;amp;&amp;amp;=&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;||=&amp;lt;/tt&amp;gt; operieren auf dem ganzen (int) Wert und berücksichtigen nur, ob der Wert 0 (false) oder ungleich 0 (true) ist.&lt;br /&gt;
Dementsprechend liefert &amp;lt;tt&amp;gt;&amp;amp;&amp;amp;&amp;lt;/tt&amp;gt; i.d.R. ein anderes Ergebnis als &amp;lt;tt&amp;gt;&amp;amp;&amp;lt;/tt&amp;gt;:&lt;br /&gt;
 if (a &amp;amp;&amp;amp; b) // erfüllt, wenn a!=0 und b!=0 &lt;br /&gt;
 if (a &amp;amp; b)  // erfüllt, wenn in a und b an der gleichen Stelle ein Bit gesetzt ist&lt;br /&gt;
Ein Verwechseln bzw. unkorrektes Einsetzen der Operatoren gibt also ein falsches Programm.&lt;br /&gt;
&lt;br /&gt;
===TRUE ist nicht 1===&lt;br /&gt;
&lt;br /&gt;
Da C die Begriffe TRUE und FALSE eigentlich nicht kennt, wurde schon öfter beobachtet, daß folgendes definiert wurde: &lt;br /&gt;
 #define TRUE 1&lt;br /&gt;
 #define FALSE 0&lt;br /&gt;
solange man damit nur Schalter setzt und abfragt, ist dagegen nichts zu sagen. &lt;br /&gt;
 a = TRUE; b = FALSE;&lt;br /&gt;
 if ( (a == TRUE) &amp;amp;&amp;amp; (b == FALSE)) {..&amp;quot;this is true&amp;quot;..} &lt;br /&gt;
wenn man aber dann schreibt&lt;br /&gt;
 if ( (a &amp;amp; b) == TRUE)  {..&amp;quot;this is true&amp;quot;..}&lt;br /&gt;
kann man einen herbe Enttäuschung erleben. Man müßte für ein richtiges Ergebnis schreiben&lt;br /&gt;
 if ( (a &amp;amp; b) != FALSE)  {..&amp;quot;this is true&amp;quot;..}&lt;br /&gt;
Damit ist aber eine gute Lesbarkeit endgültig dahin.&lt;br /&gt;
&lt;br /&gt;
Besser sind Definition wie&lt;br /&gt;
 #define FALSE (0!=0)&lt;br /&gt;
 #define TRUE  (0==0)&lt;br /&gt;
denn damit gilt einerseits, daß für alle boolschen Werte einschliesslich dieser Konstanten der&lt;br /&gt;
Zusammenhang &amp;lt;tt&amp;gt;x = !!x&amp;lt;/tt&amp;gt; besteht. &lt;br /&gt;
Mit der allerersten Definition hat man das unerwünschte Ergebnis &amp;lt;tt&amp;gt;TRUE != !FALSE&amp;lt;/tt&amp;gt;.&lt;br /&gt;
Andererseits kann man direkt gegen diese Konstanden vergleichen:&lt;br /&gt;
 a = (x &amp;lt; y);&lt;br /&gt;
 ...&lt;br /&gt;
 if (a == TRUE) // oder die 'klassische' Variante: if (a)&lt;br /&gt;
&lt;br /&gt;
===Ein , anstatt . in Konstante===&lt;br /&gt;
&lt;br /&gt;
In C sowie im angloamerikanischen Sprachraum werden Dezimalbrüche mit einem &amp;lt;tt&amp;gt;.&amp;lt;/tt&amp;gt; (Punkt) geschrieben und nicht wie im Deutschen mit einem &amp;lt;tt&amp;gt;,&amp;lt;/tt&amp;gt; (Komma): &lt;br /&gt;
 float pi;&lt;br /&gt;
 pi = 3,14;         // *AUTSCH* soll wohl heissen 3.14&lt;br /&gt;
Die zweite Zeile besteht aus zwei durch ein Komma getrennten Anweisungen, so daß das ganze&lt;br /&gt;
etwa gleichbedeutend ist mit&lt;br /&gt;
 float pi;&lt;br /&gt;
 pi = 3;&lt;br /&gt;
 14;&lt;br /&gt;
Jedenfalls ist es korrekter C-Code!&lt;br /&gt;
Die &amp;lt;tt&amp;gt;14;&amp;lt;/tt&amp;gt; ist ein Ausdruck, der nicht weiter gebraucht wird und daher wegfällt, da&lt;br /&gt;
er im Gegensatz zu einer void-Funktion keine Wirkung hat.&lt;br /&gt;
Man rechnet also mit dem Wert&amp;amp;nbsp;3 für &amp;lt;math&amp;gt;\pi&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Das falsche Komma hat auch schon so manchen ebay-Freak aufs Kreuz gelegt...&lt;br /&gt;
&lt;br /&gt;
===Führende 0 in Konstanten===&lt;br /&gt;
&lt;br /&gt;
In C kennzeichnet eine führende 0 bei einer Zahlenkonstante, &lt;br /&gt;
daß die Zahl oktal dargestellt ist. Somit ist 010 nicht gleich 10.&lt;br /&gt;
 if (a == 030) // ist a gleich 24?&lt;br /&gt;
&lt;br /&gt;
==Warteschleife==&lt;br /&gt;
&lt;br /&gt;
Siehe dazu auch [[Warteschleife]].&lt;br /&gt;
&lt;br /&gt;
=Abkürzungen und Bezeichnungen=&lt;br /&gt;
; GCC: GNU Compiler Collection&lt;br /&gt;
; gcc: GNU C-Compiler&lt;br /&gt;
; GPR: '''G'''eneral '''P'''urpose '''R'''egister&lt;br /&gt;
; ISR: '''I'''nterrupt '''S'''ervice '''R'''outine&lt;br /&gt;
; IRQ: '''I'''nterrupt '''R'''e'''q'''uest&lt;br /&gt;
; Prolog/Epilog: Code am Anfang/Ende jeder Funktionen/ISR, der dazu dient, verwendete Register zu sichern, den Stack-Frame für lokale [[Variable|Variablen]] anzulegen (falls benötigt), Stackpointer zu setzen, zurück zu springen (&amp;lt;tt&amp;gt;ret&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;reti&amp;lt;/tt&amp;gt;), etc.&lt;br /&gt;
; SFR: '''S'''pecial '''F'''unction '''R'''egister&lt;br /&gt;
; Target: Zielsystem, in unserem Falle avr&lt;br /&gt;
&lt;br /&gt;
=Siehe auch=&lt;br /&gt;
*[[Avr]]&lt;br /&gt;
*[[Atmel]]&lt;br /&gt;
*[[Compiler]]&lt;br /&gt;
*[[Sourcevergleich]]&lt;br /&gt;
* [[WinAVR]]&lt;br /&gt;
*[[Hallo Welt für AVR (Blinky)]] - ein erstes Beispiel für avr-gcc&lt;br /&gt;
*[[:Kategorie:Quellcode_C|C-Codebeispiele]]&lt;br /&gt;
&lt;br /&gt;
=Weblinks=&lt;br /&gt;
* [http://gcc.gnu.org/ Offizielle Homepage von GCC (en)]&lt;br /&gt;
* [http://de.wikipedia.org/wiki/GNU_Compiler_Collection GCC in der deutschen Wikipedia]&lt;br /&gt;
* [http://sourceforge.net/projects/winavr/ WinAVR-Projekt bei sourceforge.net (en)]&lt;br /&gt;
* [http://cdk4avr.sourceforge.net/ avr-gcc und toolchain als Linux-Paket bei sourceforge.net (en)]&lt;br /&gt;
* [http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial avr-gcc-Tutorial auf mikrocontroller.net]&lt;br /&gt;
* [http://www.linuxfocus.org/Deutsch/November2004/article352.shtml Tipps zu Build und Installation von avr-gcc, binutils und avr-libc unter Linux bei linuxfocus.org]&lt;br /&gt;
* [http://www.avrfreaks.net/AVRGCC/ avr-gcc bei avrfreaks.net (en)]&lt;br /&gt;
* [http://savannah.nongnu.org/projects/avr-libc/ Nützliche GCC Runtime-Libary]&lt;br /&gt;
&lt;br /&gt;
=ToDo=&lt;br /&gt;
* inline asm&lt;br /&gt;
* optimizing&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;
[[Kategorie:AVR]]&lt;br /&gt;
[[Kategorie:Grundlagen]]&lt;br /&gt;
[[Kategorie:Microcontroller]]&lt;br /&gt;
[[Kategorie:Praxis]]&lt;br /&gt;
[[Kategorie:Software]]&lt;/div&gt;</summary>
		<author><name>Nollsen</name></author>	</entry>

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

	</feed>