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

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=Diskussion:Hallo_Welt_f%C3%BCr_AVR_(LED_blinken)&amp;diff=7351</id>
		<title>Diskussion:Hallo Welt für AVR (LED blinken)</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=Diskussion:Hallo_Welt_f%C3%BCr_AVR_(LED_blinken)&amp;diff=7351"/>
				<updated>2006-05-15T12:41:02Z</updated>
		
		<summary type="html">&lt;p&gt;Supernull: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;--[[Benutzer:supernull|supernull]] 14:30, 15. May 2006 (CEST)&lt;br /&gt;
zur verwendung von: signal.h&lt;br /&gt;
&lt;br /&gt;
hab die signal.h anfang april durch den moderneren header interrupt.h ersetzt, da signal.h im aktuellen avr-gcc nur eine warnung:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;quot;This header file is obsolete.  Use &amp;lt;avr/interrupt.h&amp;gt;.&amp;quot;&amp;lt;br&amp;gt;&lt;br /&gt;
fabriziert. nimmt man diese warnung nicht für 100%, dann erzeugt der compiler eine weitere warnung, dass die funktion:&lt;br /&gt;
SIGNAL(...) keinen rückgabewert verwendet, d.h. der interrupt wird in der interrupttable nicht gesetzt. klar, da es das aufgerufene makro nicht gibt und nun als funktionsdefinition gewertet wird. am anfang ihrer karriere stehende compilerbediener verzweifeln sicher zu diesem zeitpunkt am nicht gesetzten interruptvektor. darum bitte nochmal mit aktuellem compiler prüfen! &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Kleiner Verbesserungsvorschlag&lt;br /&gt;
&lt;br /&gt;
Was soll BLINKY heißen? Erst beim lesen merkt man das du Dateiname so gewählt hast. Das verwirrt ein wenig, sinnvoller wäre es wenn man Namen wegläßt sonst denkt man zuerst das sei neuer Compiler oder Linker (Blinky hieß gaub mal ein dBase Compiler). Zudem liegt es auch Nahe ein HelloWorld-Beispiel HelloWorld.c zu nennen. &lt;br /&gt;
&lt;br /&gt;
--[[Benutzer:Frank|Frank]] 16:51, 21. Dez 2005 (CET)&lt;br /&gt;
&lt;br /&gt;
:Wie würdest du es denn nennen? &amp;quot;Hallo Welt&amp;quot; macht ja ne Terminalausgabe, ich kenn solche Programme unter dem Namen &amp;quot;Blinky&amp;quot; resp. &amp;quot;Blinki&amp;quot; --[[Benutzer:SprinterSB|SprinterSB]] 17:04, 21. Dez 2005 (CET)&lt;/div&gt;</summary>
		<author><name>Supernull</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=Hallo_Welt_f%C3%BCr_AVR_(LED_blinken)&amp;diff=6815</id>
		<title>Hallo Welt für AVR (LED blinken)</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=Hallo_Welt_f%C3%BCr_AVR_(LED_blinken)&amp;diff=6815"/>
				<updated>2006-04-11T11:39:44Z</updated>
		
		<summary type="html">&lt;p&gt;Supernull: /* Alles in einer Datei */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Das erste C-Programm, das man zu sehen bekommt, ist für die meisten das &amp;quot;Hallo Welt&amp;quot;.&lt;br /&gt;
Bei &amp;quot;Hallo Welt&amp;quot; geht es weniger um die Funktionalität an sich, sondern darum zu lernen,&lt;br /&gt;
wie man überhaupt ein Programm übersetzt und einen Compiler verwendet.&lt;br /&gt;
&lt;br /&gt;
Was für den PC das &amp;quot;Hallo Welt&amp;quot;, ist für einen kleinen Microcontroller der &amp;quot;Hallo Blinky&amp;quot;,&lt;br /&gt;
der einfach nur eine [[Diode|Leuchtdiode]] (LED) blinken lässt.&lt;br /&gt;
&lt;br /&gt;
Im Vergleich zu &amp;quot;Hallo Welt&amp;quot; sieht der Blinky viel komplizierter aus, &lt;br /&gt;
aber eigentlich ist er einfacher, dann es werden keine umfangreichen Funktionen oder&lt;br /&gt;
Black-Boxen benutzt wie etwa &amp;lt;tt&amp;gt;printf()&amp;lt;/tt&amp;gt;. &lt;br /&gt;
Ausser dem eingegebenen Quellcode kommt also kein andere Code zur Ausführung!&lt;br /&gt;
&lt;br /&gt;
=Beschreibung=&lt;br /&gt;
&lt;br /&gt;
Eine LED an Port B1 wird einmal pro Sekunde an bzw. ausgeschaltet. Die LED blinkt also mit einer Frequenz von 1/2 Hz.&lt;br /&gt;
&lt;br /&gt;
Dazu wird Timer1 so initialisiert, daß er 1000 Interrupts pro Sekunde auslöst. In jedem 1000. Timer1-Interrupt wird dann die LED geschaltet.&lt;br /&gt;
&lt;br /&gt;
=Von der C-Quelle zum hex-File=&lt;br /&gt;
&lt;br /&gt;
Das Beispiel besteht ganz bewusst aus zwei getrennten &lt;br /&gt;
Quelldateien (Modulen) um zu zeigen, &lt;br /&gt;
wie man Code auf mehrere Dateien aufteilen kann um die Übersichtlichkeit&lt;br /&gt;
bei grösseren Projekten zu wahren. &lt;br /&gt;
Eine etwas einfachere Struktur hat die Datei im Abschnitt &amp;quot;[[Hallo Welt für AVR (Blinky)#Alles in einer Datei|Alles in einer Datei]]&amp;quot;, das den Blinky in einer einzigen Datei implementiert.&lt;br /&gt;
&lt;br /&gt;
Ausserdem wird das Übersetzen über Kommandozeilen-Eingaben erledigt und ''nicht''&lt;br /&gt;
über Werkzeuge wie [[make]], &lt;br /&gt;
das die Zusammenhänge eher verschleiert als erhellt,&lt;br /&gt;
und dessen inkorrekte Anwendung eine häufige Fehlerquelle ist.&lt;br /&gt;
&lt;br /&gt;
Nach Speichern der Quelldatein in ein eigenes Verzeichnis enthält dieses die Dateien&lt;br /&gt;
 blinky.c timer1.c timer1.h&lt;br /&gt;
&lt;br /&gt;
==Compilieren==&lt;br /&gt;
&lt;br /&gt;
Zunächst werden die C-Dateien übersetzt. &lt;br /&gt;
Der Übersetzungsvorgang wird gesteuert durch Kommandozeilen-Parameter (siehe [[avr-gcc]]).&lt;br /&gt;
Die Option &lt;br /&gt;
;&amp;lt;tt&amp;gt;-c&amp;lt;/tt&amp;gt;: legt fest, daß nur compiliert wird (und nicht gelinkt), &lt;br /&gt;
;&amp;lt;tt&amp;gt;-o name&amp;lt;/tt&amp;gt;: gibt den Name der Ausgabedatei an. Ohne diese Option heisst die Ausgabedatei immer &amp;lt;tt&amp;gt;a.out&amp;lt;/tt&amp;gt;&lt;br /&gt;
;&amp;lt;tt&amp;gt;-mmcu=atmega8&amp;lt;/tt&amp;gt;: legt den Controllertyp fest, in dem Beispiel den [[ATmega8]]&lt;br /&gt;
;&amp;lt;tt&amp;gt;-g&amp;lt;/tt&amp;gt;: erzeugt Debug-Infos und&lt;br /&gt;
;&amp;lt;tt&amp;gt;-Os&amp;lt;/tt&amp;gt;: optimiert auf Codegröße.&lt;br /&gt;
 &amp;gt; avr-gcc blinky.c -c -o blinky.o -Os -g -mmcu=atmega8&lt;br /&gt;
 &amp;gt; avr-gcc timer1.c -c -o timer1.o -Os -g -mmcu=atmega8&lt;br /&gt;
Danach sind zwei neue Dateien entstanden (*.o)&lt;br /&gt;
 blinky.c blinky.o timer1.c timer1.h timer1.o&lt;br /&gt;
&lt;br /&gt;
In der Quelle wird der Wert für das OCR1A-Register aus der Taktfrequenz des&lt;br /&gt;
Controllers (&amp;lt;tt&amp;gt;F_CPU&amp;lt;/tt&amp;gt;) und der Anzahl an Interrupts, die pro Sekunde&lt;br /&gt;
ausgelöst werden sollen (&amp;lt;tt&amp;gt;INTERRUPTS_PER_SECOND&amp;lt;/tt&amp;gt;), berechnet.&lt;br /&gt;
&lt;br /&gt;
Standardmässig sind [[AVR|AVRs]] mit dem internen RC-Oszillator mit ca. 1&amp;amp;nbsp;MHz getaktet.&lt;br /&gt;
Daher wird &amp;lt;tt&amp;gt;F_CPU&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;timer1.c&amp;lt;/tt&amp;gt; zu 1000000 definiert:&lt;br /&gt;
 #ifndef F_CPU&lt;br /&gt;
 #define F_CPU 1000000&lt;br /&gt;
 #endif /* F_CPU */&lt;br /&gt;
{{FarbigerRahmen|&lt;br /&gt;
Dieser Wert hat rein informativen Charakter und bewirkt ''nicht'', daß der Controller mit einer anderen Frequenz läuft! Das geht über einen anderen Quarz/Oszillator oder andere Fuse-Einstellungen.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Hat man den AVR mit einem anderen Takt laufen, dann gibt man diesen einfach in der&lt;br /&gt;
Kommandozeile an, z.B. für 8&amp;amp;nbsp;MHz:&lt;br /&gt;
 &amp;gt; avr-gcc ... -DF_CPU=8000000&lt;br /&gt;
&lt;br /&gt;
Analog kann man mit &amp;lt;tt&amp;gt;INTERRUPTS_PER_SECOND&amp;lt;/tt&amp;gt; verfahren, das auf 1000 gesetzt ist,&lt;br /&gt;
und auch mit der Option &amp;lt;tt&amp;gt;-D&amp;lt;/tt&amp;gt; überschrieben werden kann.&lt;br /&gt;
&lt;br /&gt;
==Linken==&lt;br /&gt;
Die beiden erzeugten Objekte werden nun zusammengebunden, um die Ausgabedatei (*.elf) zu erhalten:&lt;br /&gt;
 &amp;gt; avr-gcc blinky.o timer1.o -o blinky.elf -mmcu=atmega8&lt;br /&gt;
erzeugt die ausführbare Datei (*.elf), die noch zusätzliche Informationen wie&lt;br /&gt;
Debug-Infos etc. beinhaltet mit dem Namen &amp;lt;tt&amp;gt;blinky.elf&amp;lt;/tt&amp;gt;:&lt;br /&gt;
 blinky.c blinky.elf blinky.o timer1.c timer1.h timer1.o&lt;br /&gt;
&lt;br /&gt;
==Umwandeln nach hex==&lt;br /&gt;
&lt;br /&gt;
===Code und Daten===&lt;br /&gt;
Viele Progger wollen die zu ladende Datei im Intel-hex-Format (*.hex bzw. *.ihex).&lt;br /&gt;
Dazu gibt man an&lt;br /&gt;
 &amp;gt; avr-objcopy -j .text -j .data -O ihex blinky.elf blinky.hex&lt;br /&gt;
Damit enthält die hex-Datei die Sections &amp;lt;tt&amp;gt;.text&amp;lt;/tt&amp;gt; (Programm) und &amp;lt;tt&amp;gt;.data&amp;lt;/tt&amp;gt; (Daten).&lt;br /&gt;
Das Verzeichnis beinhaltet jetzt&lt;br /&gt;
 blinky.c blinky.elf blinky.hex blinky.o timer1.c timer1.h timer1.o&lt;br /&gt;
&lt;br /&gt;
===EEPROM===&lt;br /&gt;
Ein hex-File, das den Inhalt des EEPROMs wiederspiegelt, erhält man mit&lt;br /&gt;
 &amp;gt; avr-objcopy -j .eeprom --change-section-lma .eeprom=0 -O ihex blinky.elf blinky_eeprom.hex&lt;br /&gt;
Für das Beispiel ist das EEPROM-File &amp;lt;tt&amp;gt;blinky_eeprom.hex&amp;lt;/tt&amp;gt; leer, &lt;br /&gt;
da wir keine Daten ins EEPROM gelegt haben.&lt;br /&gt;
&lt;br /&gt;
==Listfile erstellen==&lt;br /&gt;
&lt;br /&gt;
Falls man ein Listfile haben möchte, dann geht das mit&lt;br /&gt;
 &amp;gt; avr-objdump -h -S -j .text -j .data blinky.elf &amp;gt; blinky.lst&lt;br /&gt;
Das Listfile ist eine Textdatei, die alle Assembler-Befehle auflistet,&lt;br /&gt;
wie sie letztendlich auf den Controller geladen werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;avr-objdump&amp;lt;/tt&amp;gt; gibt seine Ausgabe auf das Terminal aus. &lt;br /&gt;
Diese Ausgabe wird mit '&amp;lt;tt&amp;gt;&amp;amp;gt;&amp;lt;/tt&amp;gt;' in die Datei &amp;lt;tt&amp;gt;blinky.lst&amp;lt;/tt&amp;gt; umgeleitet.&lt;br /&gt;
Hier ein Ausschnitt aus dem Listfile:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
0000005c &amp;lt;job_timer1&amp;gt;:&lt;br /&gt;
    uint16_t count;&lt;br /&gt;
&lt;br /&gt;
    /* irq_count um 1 erhöhen und              */&lt;br /&gt;
    /* gegebenenfalls die LED blinken */&lt;br /&gt;
    count = 1+irq_count;&lt;br /&gt;
  5c:   20 91 60 00     lds     r18, 0x0060&lt;br /&gt;
  60:   30 91 61 00     lds     r19, 0x0061&lt;br /&gt;
  64:   2f 5f           subi    r18, 0xFF       ; 255&lt;br /&gt;
  66:   3f 4f           sbci    r19, 0xFF       ; 255&lt;br /&gt;
&lt;br /&gt;
    if (count &amp;gt;= INTERRUPTS_PER_SECOND)&lt;br /&gt;
  68:   83 e0           ldi     r24, 0x03       ; 3&lt;br /&gt;
  6a:   28 3e           cpi     r18, 0xE8       ; 232&lt;br /&gt;
  6c:   38 07           cpc     r19, r24&lt;br /&gt;
  6e:   30 f0           brcs    .+12            ; 0x7c&lt;br /&gt;
    {&lt;br /&gt;
        count = 0;&lt;br /&gt;
  70:   20 e0           ldi     r18, 0x00       ; 0&lt;br /&gt;
  72:   30 e0           ldi     r19, 0x00       ; 0&lt;br /&gt;
        PORT_LED ^= (1 &amp;lt;&amp;lt; PAD_LED);&lt;br /&gt;
  74:   88 b3           in      r24, 0x18       ; 24&lt;br /&gt;
  76:   92 e0           ldi     r25, 0x02       ; 2&lt;br /&gt;
  78:   89 27           eor     r24, r25&lt;br /&gt;
  7a:   88 bb           out     0x18, r24       ; 24&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    irq_count = count;&lt;br /&gt;
  7c:   30 93 61 00     sts     0x0061, r19&lt;br /&gt;
  80:   20 93 60 00     sts     0x0060, r18&lt;br /&gt;
  84:   08 95           ret&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Links stehen die Adressen, dann die Maschinencodes der Befehle,&lt;br /&gt;
danach die Maschinencodes in Assembler-Darstellung. &lt;br /&gt;
Ganz rechts nach dem Kommentarzeichen '&amp;lt;tt&amp;gt;;&amp;lt;/tt&amp;gt;' stehen die Dezimalcodes von&lt;br /&gt;
Konstanten (z.B. 24 für die 0x18 an Adresse 74) oder die Zieladressen von&lt;br /&gt;
Sprüngen, wie bei dem &amp;lt;tt&amp;gt;brcs&amp;lt;/tt&amp;gt;-Befehl an Adresse 6e, der gegebenenfalls &lt;br /&gt;
12 Bytes überspringt und dann an Adresse 7c landet.&lt;br /&gt;
&lt;br /&gt;
==Mapfile erstellen==&lt;br /&gt;
Ein Mapfile gibt Auskunft darüber, an welcher Adresse Code und Objekte&lt;br /&gt;
landen. Erstellt wird das Mapfile während des Linkens, indem &amp;lt;tt&amp;gt;avr-gcc&amp;lt;/tt&amp;gt;&lt;br /&gt;
ein Option an den Linker weiterreicht, die diesem zum Erstellen eines solchen Files veranlasst:&lt;br /&gt;
 &amp;gt; avr-gcc blinky.o timer1.o -o blinky.elf ... -Wl,-Map,blinky.map&lt;br /&gt;
Dadurch entsteht das Mapfile &amp;lt;tt&amp;gt;blinky.map&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==Die Größe ermitteln==&lt;br /&gt;
&lt;br /&gt;
Die Größe der erhaltenen Objekte/Files können mit &amp;lt;tt&amp;gt;avr-size&amp;lt;/tt&amp;gt; ausgegeben werden.&lt;br /&gt;
 &amp;gt; avr-size -x blinky.o timer1.o&lt;br /&gt;
druckt aus:&lt;br /&gt;
   text    data     bss     dec     hex filename&lt;br /&gt;
   0x42     0x0     0x2      68      44 blinky.o&lt;br /&gt;
   0x70     0x0     0x2     114      72 timer1.o&lt;br /&gt;
Das sind die Größen der einzelnen [[avr-gcc#Sections|Sections]].&lt;br /&gt;
Für das Flash relevant ist die Größe von &lt;br /&gt;
&amp;lt;tt&amp;gt;.text&amp;lt;/tt&amp;gt; (Code) + &amp;lt;tt&amp;gt;.data&amp;lt;/tt&amp;gt; (initialisierte Daten),&lt;br /&gt;
für das SRAM relevent ist &amp;lt;tt&amp;gt;.data&amp;lt;/tt&amp;gt; (initialisierte Daten) &lt;br /&gt;
+ &amp;lt;tt&amp;gt;.bss&amp;lt;/tt&amp;gt; (null-initialisierte Daten).&lt;br /&gt;
&lt;br /&gt;
Im Flash werden also 114+68+0+0=182 Bytes belegt, und im SRAM 0+0+2+2=4 Bytes.&lt;br /&gt;
&lt;br /&gt;
Die Gesamtgrösse ergibt sich jedoch erst aus dem elf-File,&lt;br /&gt;
denn auch die Vektortabelle und der Startup-Code belegen Platz:&lt;br /&gt;
 &amp;gt; avr-size -x -A blinky.elf&lt;br /&gt;
druckt aus:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
blinky.elf  :&lt;br /&gt;
section     size       addr&lt;br /&gt;
.text      0x110        0x0&lt;br /&gt;
.data        0x0   0x800060&lt;br /&gt;
.bss         0x4   0x800060&lt;br /&gt;
.noinit      0x0   0x800064&lt;br /&gt;
.eeprom      0x0   0x810000&lt;br /&gt;
.stab      0x798        0x0&lt;br /&gt;
.stabstr   0x6b0        0x0&lt;br /&gt;
Total      0xf5c&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Im Flash werden somit 0x110+0=272 Bytes belegt, also 90 Bytes mehr als die Objekte benötigen; davon entfallen z.B. schon 38 Bytes auf die Vektortabelle des [[ATmega8]], &lt;br /&gt;
die 2*19 Bytes groß ist. &lt;br /&gt;
&lt;br /&gt;
Die Größen einzelner Funktionen lassen sich anzeigen mit&lt;br /&gt;
 &amp;gt; avr-nm --size-sort -S blinky.elf&lt;br /&gt;
was nach Größe sortiert ausdruckt:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
00800060 00000002 b irq_count&lt;br /&gt;
00800062 00000002 b timer1a_job&lt;br /&gt;
00000086 00000018 T main&lt;br /&gt;
0000009e 00000022 T timer1_init&lt;br /&gt;
0000005c 0000002a t job_timer1&lt;br /&gt;
000000c0 0000004e T SIG_OUTPUT_COMPARE_1A&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Quellcode=&lt;br /&gt;
Der Quellcode ist für die Version 3.x von [[avr-gcc]]. In der 4er-Version gab es tiefgreifende interne Änderungen im Compiler; er ist noch instabil und kann momentan noch nicht für den Produktiv-Einsatz empfohlen werden (Stand 02/2005).&lt;br /&gt;
&lt;br /&gt;
==blinky.c==&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;timer1.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
/* PortB.1 blinkt jede Sekunde                */&lt;br /&gt;
/* also mit einer Frequenz von 1/2 Hz         */&lt;br /&gt;
#define DDR_LED DDRB&lt;br /&gt;
#define PORT_LED PORTB&lt;br /&gt;
#define PAD_LED 1&lt;br /&gt;
&lt;br /&gt;
static void ioinit();&lt;br /&gt;
static void job_timer1();&lt;br /&gt;
&lt;br /&gt;
/* Zählt in jedem aufgetretenem IRQ eins hoch */&lt;br /&gt;
static volatile uint16_t irq_count = 0;&lt;br /&gt;
&lt;br /&gt;
/* Diese Funktion ist ein 'Callback'          */&lt;br /&gt;
/* Sie wird an timer1_init() übergeben        */&lt;br /&gt;
/* und von dort aus aufgerufen, und zwar      */&lt;br /&gt;
/* INTERRUPTS_PER_SECOND mal pro Sekunde.     */&lt;br /&gt;
/* Sie wird also auf IRQ-Ebene ausgeführt     */&lt;br /&gt;
void job_timer1()&lt;br /&gt;
{&lt;br /&gt;
    uint16_t count;&lt;br /&gt;
&lt;br /&gt;
    /* irq_count um 1 erhöhen und              */&lt;br /&gt;
    /* gegebenenfalls die LED blinken */&lt;br /&gt;
    count = 1+irq_count;&lt;br /&gt;
&lt;br /&gt;
    if (count &amp;gt;= INTERRUPTS_PER_SECOND)&lt;br /&gt;
    {&lt;br /&gt;
        count = 0;&lt;br /&gt;
        PORT_LED ^= (1 &amp;lt;&amp;lt; PAD_LED);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    irq_count = count;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void ioinit()&lt;br /&gt;
{&lt;br /&gt;
    /* Port als Ausgang */&lt;br /&gt;
    DDR_LED |= (1 &amp;lt;&amp;lt; PAD_LED);&lt;br /&gt;
    &lt;br /&gt;
    /* Initialisiert Timer1, um jede Sekunde              */&lt;br /&gt;
    /* INTERRUPTS_PER_SECOND mal die Funktion job_timer1  */&lt;br /&gt;
    /* aufzurufen */&lt;br /&gt;
    timer1_init (job_timer1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int main (void)&lt;br /&gt;
{&lt;br /&gt;
    /* Peripherie initialisieren */&lt;br /&gt;
    ioinit();&lt;br /&gt;
&lt;br /&gt;
    /* Interrupts aktivieren     */&lt;br /&gt;
    sei();&lt;br /&gt;
&lt;br /&gt;
    /* Nach main landen wir in exit(),                    */&lt;br /&gt;
    /* das nur aus einer Endlosschleife besteht (avr-gcc) */&lt;br /&gt;
    /* Der Interrupt lässt die LED weiterhin              */&lt;br /&gt;
    /* im Sekundentakt blinken                            */&lt;br /&gt;
    return 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==timer1.h==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#ifndef _TIMER1_H_&lt;br /&gt;
#define _TIMER1_H_&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;inttypes.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#ifndef INTERRUPTS_PER_SECOND&lt;br /&gt;
#define INTERRUPTS_PER_SECOND				1000&lt;br /&gt;
#endif /* INTERRUPTS_PER_SECOND */&lt;br /&gt;
&lt;br /&gt;
extern void timer1_init (void (*) (void));&lt;br /&gt;
&lt;br /&gt;
#endif /* _TIMER1_H_ */&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==timer1.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/interrupt.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#include &amp;quot;timer1.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
#ifndef F_CPU&lt;br /&gt;
#define F_CPU 1000000&lt;br /&gt;
#endif /* F_CPU */&lt;br /&gt;
&lt;br /&gt;
/* Test von F_CPU und INTERRUPTS_PER_SECOND */&lt;br /&gt;
/* auf Gültigkeitsbereich                   */&lt;br /&gt;
#if (F_CPU / INTERRUPTS_PER_SECOND -1 &amp;lt; 0) \&lt;br /&gt;
    || (F_CPU / INTERRUPTS_PER_SECOND -1 &amp;gt;= 0x10000)&lt;br /&gt;
#error Werte für F_CPU bzw. INTERRUPTS_PER_SECOND ungeeignet&lt;br /&gt;
#error evtl. muss der Prescaler verwendet werden&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
/* Callback-Funktion */&lt;br /&gt;
static void (*timer1a_job) (void);&lt;br /&gt;
&lt;br /&gt;
void timer1_init (void (*job) (void))&lt;br /&gt;
{&lt;br /&gt;
    timer1a_job = job;&lt;br /&gt;
&lt;br /&gt;
#if defined (__AVR_AT90S2313__)&lt;br /&gt;
    /* AVR Classic:                     */&lt;br /&gt;
    /* Timer1 läuft mit vollem Takt     */&lt;br /&gt;
    /* CTC: Clear Timer on CompareMatch */&lt;br /&gt;
    /* Timer1 ist Zähler                */&lt;br /&gt;
    TCCR1A = 0;&lt;br /&gt;
    TCCR1B = (1 &amp;lt;&amp;lt; CS10) | (1 &amp;lt;&amp;lt; CTC1);&lt;br /&gt;
#elif defined (__AVR_ARCH__) &amp;amp;&amp;amp; ((__AVR_ARCH__==4) || (__AVR_ARCH__==5))&lt;br /&gt;
    /* AVR Mega:                                 */&lt;br /&gt;
    /* Mode #4 für Timer1 (ATmega8 Manual S. 97) */&lt;br /&gt;
    /* und voller MCU Takt (Prescale=1)          */&lt;br /&gt;
    TCCR1A = 0;&lt;br /&gt;
    TCCR1B = (1 &amp;lt;&amp;lt; WGM12) | (1 &amp;lt;&amp;lt; CS10);&lt;br /&gt;
#else&lt;br /&gt;
#error Dont know how to setup timer1&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
    /* OutputCompare1A Register setzen        */&lt;br /&gt;
    OCR1A = (uint16_t) ((uint32_t) F_CPU / INTERRUPTS_PER_SECOND -1);&lt;br /&gt;
&lt;br /&gt;
    /* evtl. gesetztes OC1A-Flag zurücksetzen */&lt;br /&gt;
    TIFR = (1 &amp;lt;&amp;lt; OCF1A);&lt;br /&gt;
&lt;br /&gt;
    /* OutputCompare1A Interrupt aktivieren   */&lt;br /&gt;
    TIMSK |= (1 &amp;lt;&amp;lt; OCIE1A);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* Die Interrupt Service Routine ruft lediglich */&lt;br /&gt;
/* timer1a_job auf (callback)                   */&lt;br /&gt;
SIGNAL(SIG_OUTPUT_COMPARE1A)&lt;br /&gt;
{&lt;br /&gt;
    timer1a_job();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Alles in einer Datei ==&lt;br /&gt;
&lt;br /&gt;
In der folgenden Quelldatei sind alle Routinen in etwas vereinfachter Form zusammengefasst. &lt;br /&gt;
Zum Übersetzen gibt man an (hier für [[ATmega32]]):&lt;br /&gt;
 &amp;gt; avr-gcc blinky-all.c -o blinky-all.elf -mmcu=atmega32 -g -Os&lt;br /&gt;
oder, falls man die Ausgabe im Intel HEX-Format haben möchte:&lt;br /&gt;
 &amp;gt; avr-gcc blinky-all.c -o blinky-all.hex -mmcu=atmega32 -g -Os -Wl,--oformat=ihex&lt;br /&gt;
Möchte man &amp;lt;tt&amp;gt;F_CPU&amp;lt;/tt&amp;gt; oder &amp;lt;tt&amp;gt;INTERRUPTS_PER_SECOND&amp;lt;/tt&amp;gt; ändern, dann muss das bei diesem Beispiel direkt in der Quelle angepasst werden. &amp;lt;tt&amp;gt;F_CPU&amp;lt;/tt&amp;gt; hat wie immer nur rein informativen Charakter, um zu wissen, wie schnell der AVR läuft. Eingestellt wird die Taktfrequenz über die [[AVR#Die Fusebits|Fuse-Bits]] bzw. Wahl eines entsprechenden Quarzes/Oszillators/Resonators/RC-Glieds.&lt;br /&gt;
&lt;br /&gt;
'''Quelle''' (&amp;lt;tt&amp;gt;blinky-all.c&amp;lt;/tt&amp;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;
// PortB.1 blinkt jede Sekunde&lt;br /&gt;
// also mit einer Frequenz von 1/2 Hz&lt;br /&gt;
#define DDR_LED  DDRB&lt;br /&gt;
#define PORT_LED PORTB&lt;br /&gt;
#define PAD_LED  1&lt;br /&gt;
&lt;br /&gt;
// Werte zur Berechnung der Interrupt-Rate bei AVR-Fuses,&lt;br /&gt;
// die auf 1MHz eingestellt sind (Werkseinstellung für internen RC-Oszillator) &lt;br /&gt;
#define F_CPU                 1000000&lt;br /&gt;
&lt;br /&gt;
// 1000 Interrupts pro Sekunde&lt;br /&gt;
#define INTERRUPTS_PER_SECOND 1000&lt;br /&gt;
&lt;br /&gt;
// Prototypen der Funktionen&lt;br /&gt;
void ioinit();&lt;br /&gt;
&lt;br /&gt;
// Wird durch jeden IRQ eins hochgezählt&lt;br /&gt;
static volatile uint16_t irq_count = 0;&lt;br /&gt;
&lt;br /&gt;
// Wert für das OutputCompare-Register (OCR1A)&lt;br /&gt;
#define OCR_VAL          (F_CPU / INTERRUPTS_PER_SECOND -1)&lt;br /&gt;
&lt;br /&gt;
// Initialisierung der Hardware&lt;br /&gt;
void ioinit()&lt;br /&gt;
{&lt;br /&gt;
    // Port als Ausgang&lt;br /&gt;
    DDR_LED |= (1 &amp;lt;&amp;lt; PAD_LED);&lt;br /&gt;
    &lt;br /&gt;
    // Initialisiert Timer1, um jede Sekunde 1000 IRQs auszulösen&lt;br /&gt;
    // ATmega: Mode #4 für Timer1 und voller MCU-Takt (Prescale=1)&lt;br /&gt;
    TCCR1A = 0;&lt;br /&gt;
    TCCR1B = (1 &amp;lt;&amp;lt; WGM12) | (1 &amp;lt;&amp;lt; CS10);&lt;br /&gt;
&lt;br /&gt;
    // OutputCompare1A Register setzen&lt;br /&gt;
    OCR1A = (uint16_t) ((uint32_t) OCR_VAL);&lt;br /&gt;
&lt;br /&gt;
    // OutputCompare1A Interrupt aktivieren&lt;br /&gt;
    TIMSK |= (1 &amp;lt;&amp;lt; OCIE1A);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Das Hauptprogramm (Einsprungpunkt)&lt;br /&gt;
int main()&lt;br /&gt;
{&lt;br /&gt;
    // Peripherie initialisieren&lt;br /&gt;
    ioinit();&lt;br /&gt;
&lt;br /&gt;
    // Interrupts aktivieren&lt;br /&gt;
    sei();&lt;br /&gt;
&lt;br /&gt;
    // Eine Endlosschleife.  &lt;br /&gt;
    // Der Interrupt lässt die LED weiterhin blinken&lt;br /&gt;
    while (1)&lt;br /&gt;
    {}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Die Interrupt Service Routine (ISR) wird INTERRUPTS_PER_SECOND mal &lt;br /&gt;
// pro Sekunde ausgeführt. irq_count zählt die Aufrufe und blinkt die LED&lt;br /&gt;
// wenn 1 Sekunde vergangen ist.&lt;br /&gt;
SIGNAL(SIG_OUTPUT_COMPARE1A)&lt;br /&gt;
{&lt;br /&gt;
    uint16_t count;&lt;br /&gt;
&lt;br /&gt;
    // irq_count um 1 erhöhen und&lt;br /&gt;
    count = 1+irq_count;&lt;br /&gt;
&lt;br /&gt;
    // alle 1000 IRQs die LED blinken&lt;br /&gt;
    if (count &amp;gt;= INTERRUPTS_PER_SECOND)&lt;br /&gt;
    {&lt;br /&gt;
        count = 0;&lt;br /&gt;
        PORT_LED ^= (1 &amp;lt;&amp;lt; PAD_LED);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    irq_count = count;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für klassische AVRs wie [[AT90S2313]] muss die Initialisierung etwas abgeändert werden, weil sich Bit-Bezeichner unterscheiden:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// AVR Classic:&lt;br /&gt;
// Timer1 läuft mit vollem Takt&lt;br /&gt;
// CTC: Clear Timer on CompareMatch&lt;br /&gt;
// Timer1 ist Zähler&lt;br /&gt;
    TCCR1A = 0;&lt;br /&gt;
    TCCR1B = (1 &amp;lt;&amp;lt; CS10) | (1 &amp;lt;&amp;lt; CTC1);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
Wenn man will, alnn man den Code bzw. die Werte noch einem kleinen Gültikeitstest unterziehen.&lt;br /&gt;
// Test von F_CPU und INTERRUPTS_PER_SECOND auf Gültigkeit&lt;br /&gt;
#if (OCR_VAL &amp;lt; 0) || (OCR_VAL &amp;gt;= 0x10000)&lt;br /&gt;
#error Werte für F_CPU bzw. INTERRUPTS_PER_SECOND ungeeignet&lt;br /&gt;
#endif // test OCR_VAL&lt;br /&gt;
&lt;br /&gt;
#ifndef TCNT1&lt;br /&gt;
#error Dieser Controller hat keinen Timer1&lt;br /&gt;
#endif // TCNT1&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Spin-off=&lt;br /&gt;
&lt;br /&gt;
Eine LED blinken zu lassen könnte auch wesentlich einfacher implementert werden,&lt;br /&gt;
also z.B. ohne Funktionsaufrufe oder Interrupt-Programmierung.&lt;br /&gt;
&lt;br /&gt;
Neben der eigentlichen Aufgabe &amp;quot;LED blinken lassen&amp;quot; kann man an dem Code&lt;br /&gt;
aber noch andere Dinge lernen:&lt;br /&gt;
* Programmierung eines Interrupts&lt;br /&gt;
* Initialisierung von Timer1 als Zähler mit &amp;quot;Clear Timer on Compare Match&amp;quot;&lt;br /&gt;
* Bedingte Codeübersetzung/Controllerunterscheidung mit &amp;lt;tt&amp;gt;#ifdef&amp;lt;/tt&amp;gt; (in &amp;lt;tt&amp;gt;timer1_init&amp;lt;/tt&amp;gt;)&lt;br /&gt;
* Abchecken der Güligkeit von Defines durch den Präprozessor&lt;br /&gt;
* Übergabe eines Funktionszeigers, um später eine Funktion indirekt aufzurufen&lt;br /&gt;
* Zusammenlinken mehrerer Module&lt;br /&gt;
&lt;br /&gt;
=Siehe auch=&lt;br /&gt;
* [[AVR]]&lt;br /&gt;
* [[avr-gcc]]&lt;br /&gt;
* [[Interrupt]]&lt;br /&gt;
* [[:Kategorie:Quellcode C|weitere C-Code Beispiele]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Grundlagen]]&lt;br /&gt;
[[Kategorie:Microcontroller]]&lt;br /&gt;
[[Kategorie:Quellcode C]]&lt;br /&gt;
[[Kategorie:Software]]&lt;br /&gt;
[[Kategorie:Praxis]]&lt;/div&gt;</summary>
		<author><name>Supernull</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=Hallo_Welt_f%C3%BCr_AVR_(LED_blinken)&amp;diff=6814</id>
		<title>Hallo Welt für AVR (LED blinken)</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=Hallo_Welt_f%C3%BCr_AVR_(LED_blinken)&amp;diff=6814"/>
				<updated>2006-04-11T11:38:02Z</updated>
		
		<summary type="html">&lt;p&gt;Supernull: /* timer1.c */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Das erste C-Programm, das man zu sehen bekommt, ist für die meisten das &amp;quot;Hallo Welt&amp;quot;.&lt;br /&gt;
Bei &amp;quot;Hallo Welt&amp;quot; geht es weniger um die Funktionalität an sich, sondern darum zu lernen,&lt;br /&gt;
wie man überhaupt ein Programm übersetzt und einen Compiler verwendet.&lt;br /&gt;
&lt;br /&gt;
Was für den PC das &amp;quot;Hallo Welt&amp;quot;, ist für einen kleinen Microcontroller der &amp;quot;Hallo Blinky&amp;quot;,&lt;br /&gt;
der einfach nur eine [[Diode|Leuchtdiode]] (LED) blinken lässt.&lt;br /&gt;
&lt;br /&gt;
Im Vergleich zu &amp;quot;Hallo Welt&amp;quot; sieht der Blinky viel komplizierter aus, &lt;br /&gt;
aber eigentlich ist er einfacher, dann es werden keine umfangreichen Funktionen oder&lt;br /&gt;
Black-Boxen benutzt wie etwa &amp;lt;tt&amp;gt;printf()&amp;lt;/tt&amp;gt;. &lt;br /&gt;
Ausser dem eingegebenen Quellcode kommt also kein andere Code zur Ausführung!&lt;br /&gt;
&lt;br /&gt;
=Beschreibung=&lt;br /&gt;
&lt;br /&gt;
Eine LED an Port B1 wird einmal pro Sekunde an bzw. ausgeschaltet. Die LED blinkt also mit einer Frequenz von 1/2 Hz.&lt;br /&gt;
&lt;br /&gt;
Dazu wird Timer1 so initialisiert, daß er 1000 Interrupts pro Sekunde auslöst. In jedem 1000. Timer1-Interrupt wird dann die LED geschaltet.&lt;br /&gt;
&lt;br /&gt;
=Von der C-Quelle zum hex-File=&lt;br /&gt;
&lt;br /&gt;
Das Beispiel besteht ganz bewusst aus zwei getrennten &lt;br /&gt;
Quelldateien (Modulen) um zu zeigen, &lt;br /&gt;
wie man Code auf mehrere Dateien aufteilen kann um die Übersichtlichkeit&lt;br /&gt;
bei grösseren Projekten zu wahren. &lt;br /&gt;
Eine etwas einfachere Struktur hat die Datei im Abschnitt &amp;quot;[[Hallo Welt für AVR (Blinky)#Alles in einer Datei|Alles in einer Datei]]&amp;quot;, das den Blinky in einer einzigen Datei implementiert.&lt;br /&gt;
&lt;br /&gt;
Ausserdem wird das Übersetzen über Kommandozeilen-Eingaben erledigt und ''nicht''&lt;br /&gt;
über Werkzeuge wie [[make]], &lt;br /&gt;
das die Zusammenhänge eher verschleiert als erhellt,&lt;br /&gt;
und dessen inkorrekte Anwendung eine häufige Fehlerquelle ist.&lt;br /&gt;
&lt;br /&gt;
Nach Speichern der Quelldatein in ein eigenes Verzeichnis enthält dieses die Dateien&lt;br /&gt;
 blinky.c timer1.c timer1.h&lt;br /&gt;
&lt;br /&gt;
==Compilieren==&lt;br /&gt;
&lt;br /&gt;
Zunächst werden die C-Dateien übersetzt. &lt;br /&gt;
Der Übersetzungsvorgang wird gesteuert durch Kommandozeilen-Parameter (siehe [[avr-gcc]]).&lt;br /&gt;
Die Option &lt;br /&gt;
;&amp;lt;tt&amp;gt;-c&amp;lt;/tt&amp;gt;: legt fest, daß nur compiliert wird (und nicht gelinkt), &lt;br /&gt;
;&amp;lt;tt&amp;gt;-o name&amp;lt;/tt&amp;gt;: gibt den Name der Ausgabedatei an. Ohne diese Option heisst die Ausgabedatei immer &amp;lt;tt&amp;gt;a.out&amp;lt;/tt&amp;gt;&lt;br /&gt;
;&amp;lt;tt&amp;gt;-mmcu=atmega8&amp;lt;/tt&amp;gt;: legt den Controllertyp fest, in dem Beispiel den [[ATmega8]]&lt;br /&gt;
;&amp;lt;tt&amp;gt;-g&amp;lt;/tt&amp;gt;: erzeugt Debug-Infos und&lt;br /&gt;
;&amp;lt;tt&amp;gt;-Os&amp;lt;/tt&amp;gt;: optimiert auf Codegröße.&lt;br /&gt;
 &amp;gt; avr-gcc blinky.c -c -o blinky.o -Os -g -mmcu=atmega8&lt;br /&gt;
 &amp;gt; avr-gcc timer1.c -c -o timer1.o -Os -g -mmcu=atmega8&lt;br /&gt;
Danach sind zwei neue Dateien entstanden (*.o)&lt;br /&gt;
 blinky.c blinky.o timer1.c timer1.h timer1.o&lt;br /&gt;
&lt;br /&gt;
In der Quelle wird der Wert für das OCR1A-Register aus der Taktfrequenz des&lt;br /&gt;
Controllers (&amp;lt;tt&amp;gt;F_CPU&amp;lt;/tt&amp;gt;) und der Anzahl an Interrupts, die pro Sekunde&lt;br /&gt;
ausgelöst werden sollen (&amp;lt;tt&amp;gt;INTERRUPTS_PER_SECOND&amp;lt;/tt&amp;gt;), berechnet.&lt;br /&gt;
&lt;br /&gt;
Standardmässig sind [[AVR|AVRs]] mit dem internen RC-Oszillator mit ca. 1&amp;amp;nbsp;MHz getaktet.&lt;br /&gt;
Daher wird &amp;lt;tt&amp;gt;F_CPU&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;timer1.c&amp;lt;/tt&amp;gt; zu 1000000 definiert:&lt;br /&gt;
 #ifndef F_CPU&lt;br /&gt;
 #define F_CPU 1000000&lt;br /&gt;
 #endif /* F_CPU */&lt;br /&gt;
{{FarbigerRahmen|&lt;br /&gt;
Dieser Wert hat rein informativen Charakter und bewirkt ''nicht'', daß der Controller mit einer anderen Frequenz läuft! Das geht über einen anderen Quarz/Oszillator oder andere Fuse-Einstellungen.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Hat man den AVR mit einem anderen Takt laufen, dann gibt man diesen einfach in der&lt;br /&gt;
Kommandozeile an, z.B. für 8&amp;amp;nbsp;MHz:&lt;br /&gt;
 &amp;gt; avr-gcc ... -DF_CPU=8000000&lt;br /&gt;
&lt;br /&gt;
Analog kann man mit &amp;lt;tt&amp;gt;INTERRUPTS_PER_SECOND&amp;lt;/tt&amp;gt; verfahren, das auf 1000 gesetzt ist,&lt;br /&gt;
und auch mit der Option &amp;lt;tt&amp;gt;-D&amp;lt;/tt&amp;gt; überschrieben werden kann.&lt;br /&gt;
&lt;br /&gt;
==Linken==&lt;br /&gt;
Die beiden erzeugten Objekte werden nun zusammengebunden, um die Ausgabedatei (*.elf) zu erhalten:&lt;br /&gt;
 &amp;gt; avr-gcc blinky.o timer1.o -o blinky.elf -mmcu=atmega8&lt;br /&gt;
erzeugt die ausführbare Datei (*.elf), die noch zusätzliche Informationen wie&lt;br /&gt;
Debug-Infos etc. beinhaltet mit dem Namen &amp;lt;tt&amp;gt;blinky.elf&amp;lt;/tt&amp;gt;:&lt;br /&gt;
 blinky.c blinky.elf blinky.o timer1.c timer1.h timer1.o&lt;br /&gt;
&lt;br /&gt;
==Umwandeln nach hex==&lt;br /&gt;
&lt;br /&gt;
===Code und Daten===&lt;br /&gt;
Viele Progger wollen die zu ladende Datei im Intel-hex-Format (*.hex bzw. *.ihex).&lt;br /&gt;
Dazu gibt man an&lt;br /&gt;
 &amp;gt; avr-objcopy -j .text -j .data -O ihex blinky.elf blinky.hex&lt;br /&gt;
Damit enthält die hex-Datei die Sections &amp;lt;tt&amp;gt;.text&amp;lt;/tt&amp;gt; (Programm) und &amp;lt;tt&amp;gt;.data&amp;lt;/tt&amp;gt; (Daten).&lt;br /&gt;
Das Verzeichnis beinhaltet jetzt&lt;br /&gt;
 blinky.c blinky.elf blinky.hex blinky.o timer1.c timer1.h timer1.o&lt;br /&gt;
&lt;br /&gt;
===EEPROM===&lt;br /&gt;
Ein hex-File, das den Inhalt des EEPROMs wiederspiegelt, erhält man mit&lt;br /&gt;
 &amp;gt; avr-objcopy -j .eeprom --change-section-lma .eeprom=0 -O ihex blinky.elf blinky_eeprom.hex&lt;br /&gt;
Für das Beispiel ist das EEPROM-File &amp;lt;tt&amp;gt;blinky_eeprom.hex&amp;lt;/tt&amp;gt; leer, &lt;br /&gt;
da wir keine Daten ins EEPROM gelegt haben.&lt;br /&gt;
&lt;br /&gt;
==Listfile erstellen==&lt;br /&gt;
&lt;br /&gt;
Falls man ein Listfile haben möchte, dann geht das mit&lt;br /&gt;
 &amp;gt; avr-objdump -h -S -j .text -j .data blinky.elf &amp;gt; blinky.lst&lt;br /&gt;
Das Listfile ist eine Textdatei, die alle Assembler-Befehle auflistet,&lt;br /&gt;
wie sie letztendlich auf den Controller geladen werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;avr-objdump&amp;lt;/tt&amp;gt; gibt seine Ausgabe auf das Terminal aus. &lt;br /&gt;
Diese Ausgabe wird mit '&amp;lt;tt&amp;gt;&amp;amp;gt;&amp;lt;/tt&amp;gt;' in die Datei &amp;lt;tt&amp;gt;blinky.lst&amp;lt;/tt&amp;gt; umgeleitet.&lt;br /&gt;
Hier ein Ausschnitt aus dem Listfile:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
0000005c &amp;lt;job_timer1&amp;gt;:&lt;br /&gt;
    uint16_t count;&lt;br /&gt;
&lt;br /&gt;
    /* irq_count um 1 erhöhen und              */&lt;br /&gt;
    /* gegebenenfalls die LED blinken */&lt;br /&gt;
    count = 1+irq_count;&lt;br /&gt;
  5c:   20 91 60 00     lds     r18, 0x0060&lt;br /&gt;
  60:   30 91 61 00     lds     r19, 0x0061&lt;br /&gt;
  64:   2f 5f           subi    r18, 0xFF       ; 255&lt;br /&gt;
  66:   3f 4f           sbci    r19, 0xFF       ; 255&lt;br /&gt;
&lt;br /&gt;
    if (count &amp;gt;= INTERRUPTS_PER_SECOND)&lt;br /&gt;
  68:   83 e0           ldi     r24, 0x03       ; 3&lt;br /&gt;
  6a:   28 3e           cpi     r18, 0xE8       ; 232&lt;br /&gt;
  6c:   38 07           cpc     r19, r24&lt;br /&gt;
  6e:   30 f0           brcs    .+12            ; 0x7c&lt;br /&gt;
    {&lt;br /&gt;
        count = 0;&lt;br /&gt;
  70:   20 e0           ldi     r18, 0x00       ; 0&lt;br /&gt;
  72:   30 e0           ldi     r19, 0x00       ; 0&lt;br /&gt;
        PORT_LED ^= (1 &amp;lt;&amp;lt; PAD_LED);&lt;br /&gt;
  74:   88 b3           in      r24, 0x18       ; 24&lt;br /&gt;
  76:   92 e0           ldi     r25, 0x02       ; 2&lt;br /&gt;
  78:   89 27           eor     r24, r25&lt;br /&gt;
  7a:   88 bb           out     0x18, r24       ; 24&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    irq_count = count;&lt;br /&gt;
  7c:   30 93 61 00     sts     0x0061, r19&lt;br /&gt;
  80:   20 93 60 00     sts     0x0060, r18&lt;br /&gt;
  84:   08 95           ret&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Links stehen die Adressen, dann die Maschinencodes der Befehle,&lt;br /&gt;
danach die Maschinencodes in Assembler-Darstellung. &lt;br /&gt;
Ganz rechts nach dem Kommentarzeichen '&amp;lt;tt&amp;gt;;&amp;lt;/tt&amp;gt;' stehen die Dezimalcodes von&lt;br /&gt;
Konstanten (z.B. 24 für die 0x18 an Adresse 74) oder die Zieladressen von&lt;br /&gt;
Sprüngen, wie bei dem &amp;lt;tt&amp;gt;brcs&amp;lt;/tt&amp;gt;-Befehl an Adresse 6e, der gegebenenfalls &lt;br /&gt;
12 Bytes überspringt und dann an Adresse 7c landet.&lt;br /&gt;
&lt;br /&gt;
==Mapfile erstellen==&lt;br /&gt;
Ein Mapfile gibt Auskunft darüber, an welcher Adresse Code und Objekte&lt;br /&gt;
landen. Erstellt wird das Mapfile während des Linkens, indem &amp;lt;tt&amp;gt;avr-gcc&amp;lt;/tt&amp;gt;&lt;br /&gt;
ein Option an den Linker weiterreicht, die diesem zum Erstellen eines solchen Files veranlasst:&lt;br /&gt;
 &amp;gt; avr-gcc blinky.o timer1.o -o blinky.elf ... -Wl,-Map,blinky.map&lt;br /&gt;
Dadurch entsteht das Mapfile &amp;lt;tt&amp;gt;blinky.map&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==Die Größe ermitteln==&lt;br /&gt;
&lt;br /&gt;
Die Größe der erhaltenen Objekte/Files können mit &amp;lt;tt&amp;gt;avr-size&amp;lt;/tt&amp;gt; ausgegeben werden.&lt;br /&gt;
 &amp;gt; avr-size -x blinky.o timer1.o&lt;br /&gt;
druckt aus:&lt;br /&gt;
   text    data     bss     dec     hex filename&lt;br /&gt;
   0x42     0x0     0x2      68      44 blinky.o&lt;br /&gt;
   0x70     0x0     0x2     114      72 timer1.o&lt;br /&gt;
Das sind die Größen der einzelnen [[avr-gcc#Sections|Sections]].&lt;br /&gt;
Für das Flash relevant ist die Größe von &lt;br /&gt;
&amp;lt;tt&amp;gt;.text&amp;lt;/tt&amp;gt; (Code) + &amp;lt;tt&amp;gt;.data&amp;lt;/tt&amp;gt; (initialisierte Daten),&lt;br /&gt;
für das SRAM relevent ist &amp;lt;tt&amp;gt;.data&amp;lt;/tt&amp;gt; (initialisierte Daten) &lt;br /&gt;
+ &amp;lt;tt&amp;gt;.bss&amp;lt;/tt&amp;gt; (null-initialisierte Daten).&lt;br /&gt;
&lt;br /&gt;
Im Flash werden also 114+68+0+0=182 Bytes belegt, und im SRAM 0+0+2+2=4 Bytes.&lt;br /&gt;
&lt;br /&gt;
Die Gesamtgrösse ergibt sich jedoch erst aus dem elf-File,&lt;br /&gt;
denn auch die Vektortabelle und der Startup-Code belegen Platz:&lt;br /&gt;
 &amp;gt; avr-size -x -A blinky.elf&lt;br /&gt;
druckt aus:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
blinky.elf  :&lt;br /&gt;
section     size       addr&lt;br /&gt;
.text      0x110        0x0&lt;br /&gt;
.data        0x0   0x800060&lt;br /&gt;
.bss         0x4   0x800060&lt;br /&gt;
.noinit      0x0   0x800064&lt;br /&gt;
.eeprom      0x0   0x810000&lt;br /&gt;
.stab      0x798        0x0&lt;br /&gt;
.stabstr   0x6b0        0x0&lt;br /&gt;
Total      0xf5c&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Im Flash werden somit 0x110+0=272 Bytes belegt, also 90 Bytes mehr als die Objekte benötigen; davon entfallen z.B. schon 38 Bytes auf die Vektortabelle des [[ATmega8]], &lt;br /&gt;
die 2*19 Bytes groß ist. &lt;br /&gt;
&lt;br /&gt;
Die Größen einzelner Funktionen lassen sich anzeigen mit&lt;br /&gt;
 &amp;gt; avr-nm --size-sort -S blinky.elf&lt;br /&gt;
was nach Größe sortiert ausdruckt:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
00800060 00000002 b irq_count&lt;br /&gt;
00800062 00000002 b timer1a_job&lt;br /&gt;
00000086 00000018 T main&lt;br /&gt;
0000009e 00000022 T timer1_init&lt;br /&gt;
0000005c 0000002a t job_timer1&lt;br /&gt;
000000c0 0000004e T SIG_OUTPUT_COMPARE_1A&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Quellcode=&lt;br /&gt;
Der Quellcode ist für die Version 3.x von [[avr-gcc]]. In der 4er-Version gab es tiefgreifende interne Änderungen im Compiler; er ist noch instabil und kann momentan noch nicht für den Produktiv-Einsatz empfohlen werden (Stand 02/2005).&lt;br /&gt;
&lt;br /&gt;
==blinky.c==&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;timer1.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
/* PortB.1 blinkt jede Sekunde                */&lt;br /&gt;
/* also mit einer Frequenz von 1/2 Hz         */&lt;br /&gt;
#define DDR_LED DDRB&lt;br /&gt;
#define PORT_LED PORTB&lt;br /&gt;
#define PAD_LED 1&lt;br /&gt;
&lt;br /&gt;
static void ioinit();&lt;br /&gt;
static void job_timer1();&lt;br /&gt;
&lt;br /&gt;
/* Zählt in jedem aufgetretenem IRQ eins hoch */&lt;br /&gt;
static volatile uint16_t irq_count = 0;&lt;br /&gt;
&lt;br /&gt;
/* Diese Funktion ist ein 'Callback'          */&lt;br /&gt;
/* Sie wird an timer1_init() übergeben        */&lt;br /&gt;
/* und von dort aus aufgerufen, und zwar      */&lt;br /&gt;
/* INTERRUPTS_PER_SECOND mal pro Sekunde.     */&lt;br /&gt;
/* Sie wird also auf IRQ-Ebene ausgeführt     */&lt;br /&gt;
void job_timer1()&lt;br /&gt;
{&lt;br /&gt;
    uint16_t count;&lt;br /&gt;
&lt;br /&gt;
    /* irq_count um 1 erhöhen und              */&lt;br /&gt;
    /* gegebenenfalls die LED blinken */&lt;br /&gt;
    count = 1+irq_count;&lt;br /&gt;
&lt;br /&gt;
    if (count &amp;gt;= INTERRUPTS_PER_SECOND)&lt;br /&gt;
    {&lt;br /&gt;
        count = 0;&lt;br /&gt;
        PORT_LED ^= (1 &amp;lt;&amp;lt; PAD_LED);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    irq_count = count;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void ioinit()&lt;br /&gt;
{&lt;br /&gt;
    /* Port als Ausgang */&lt;br /&gt;
    DDR_LED |= (1 &amp;lt;&amp;lt; PAD_LED);&lt;br /&gt;
    &lt;br /&gt;
    /* Initialisiert Timer1, um jede Sekunde              */&lt;br /&gt;
    /* INTERRUPTS_PER_SECOND mal die Funktion job_timer1  */&lt;br /&gt;
    /* aufzurufen */&lt;br /&gt;
    timer1_init (job_timer1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int main (void)&lt;br /&gt;
{&lt;br /&gt;
    /* Peripherie initialisieren */&lt;br /&gt;
    ioinit();&lt;br /&gt;
&lt;br /&gt;
    /* Interrupts aktivieren     */&lt;br /&gt;
    sei();&lt;br /&gt;
&lt;br /&gt;
    /* Nach main landen wir in exit(),                    */&lt;br /&gt;
    /* das nur aus einer Endlosschleife besteht (avr-gcc) */&lt;br /&gt;
    /* Der Interrupt lässt die LED weiterhin              */&lt;br /&gt;
    /* im Sekundentakt blinken                            */&lt;br /&gt;
    return 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==timer1.h==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#ifndef _TIMER1_H_&lt;br /&gt;
#define _TIMER1_H_&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;inttypes.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#ifndef INTERRUPTS_PER_SECOND&lt;br /&gt;
#define INTERRUPTS_PER_SECOND				1000&lt;br /&gt;
#endif /* INTERRUPTS_PER_SECOND */&lt;br /&gt;
&lt;br /&gt;
extern void timer1_init (void (*) (void));&lt;br /&gt;
&lt;br /&gt;
#endif /* _TIMER1_H_ */&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==timer1.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/interrupt.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#include &amp;quot;timer1.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
#ifndef F_CPU&lt;br /&gt;
#define F_CPU 1000000&lt;br /&gt;
#endif /* F_CPU */&lt;br /&gt;
&lt;br /&gt;
/* Test von F_CPU und INTERRUPTS_PER_SECOND */&lt;br /&gt;
/* auf Gültigkeitsbereich                   */&lt;br /&gt;
#if (F_CPU / INTERRUPTS_PER_SECOND -1 &amp;lt; 0) \&lt;br /&gt;
    || (F_CPU / INTERRUPTS_PER_SECOND -1 &amp;gt;= 0x10000)&lt;br /&gt;
#error Werte für F_CPU bzw. INTERRUPTS_PER_SECOND ungeeignet&lt;br /&gt;
#error evtl. muss der Prescaler verwendet werden&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
/* Callback-Funktion */&lt;br /&gt;
static void (*timer1a_job) (void);&lt;br /&gt;
&lt;br /&gt;
void timer1_init (void (*job) (void))&lt;br /&gt;
{&lt;br /&gt;
    timer1a_job = job;&lt;br /&gt;
&lt;br /&gt;
#if defined (__AVR_AT90S2313__)&lt;br /&gt;
    /* AVR Classic:                     */&lt;br /&gt;
    /* Timer1 läuft mit vollem Takt     */&lt;br /&gt;
    /* CTC: Clear Timer on CompareMatch */&lt;br /&gt;
    /* Timer1 ist Zähler                */&lt;br /&gt;
    TCCR1A = 0;&lt;br /&gt;
    TCCR1B = (1 &amp;lt;&amp;lt; CS10) | (1 &amp;lt;&amp;lt; CTC1);&lt;br /&gt;
#elif defined (__AVR_ARCH__) &amp;amp;&amp;amp; ((__AVR_ARCH__==4) || (__AVR_ARCH__==5))&lt;br /&gt;
    /* AVR Mega:                                 */&lt;br /&gt;
    /* Mode #4 für Timer1 (ATmega8 Manual S. 97) */&lt;br /&gt;
    /* und voller MCU Takt (Prescale=1)          */&lt;br /&gt;
    TCCR1A = 0;&lt;br /&gt;
    TCCR1B = (1 &amp;lt;&amp;lt; WGM12) | (1 &amp;lt;&amp;lt; CS10);&lt;br /&gt;
#else&lt;br /&gt;
#error Dont know how to setup timer1&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
    /* OutputCompare1A Register setzen        */&lt;br /&gt;
    OCR1A = (uint16_t) ((uint32_t) F_CPU / INTERRUPTS_PER_SECOND -1);&lt;br /&gt;
&lt;br /&gt;
    /* evtl. gesetztes OC1A-Flag zurücksetzen */&lt;br /&gt;
    TIFR = (1 &amp;lt;&amp;lt; OCF1A);&lt;br /&gt;
&lt;br /&gt;
    /* OutputCompare1A Interrupt aktivieren   */&lt;br /&gt;
    TIMSK |= (1 &amp;lt;&amp;lt; OCIE1A);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* Die Interrupt Service Routine ruft lediglich */&lt;br /&gt;
/* timer1a_job auf (callback)                   */&lt;br /&gt;
SIGNAL(SIG_OUTPUT_COMPARE1A)&lt;br /&gt;
{&lt;br /&gt;
    timer1a_job();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Alles in einer Datei ==&lt;br /&gt;
&lt;br /&gt;
In der folgenden Quelldatei sind alle Routinen in etwas vereinfachter Form zusammengefasst. &lt;br /&gt;
Zum Übersetzen gibt man an (hier für [[ATmega32]]):&lt;br /&gt;
 &amp;gt; avr-gcc blinky-all.c -o blinky-all.elf -mmcu=atmega32 -g -Os&lt;br /&gt;
oder, falls man die Ausgabe im Intel HEX-Format haben möchte:&lt;br /&gt;
 &amp;gt; avr-gcc blinky-all.c -o blinky-all.hex -mmcu=atmega32 -g -Os -Wl,--oformat=ihex&lt;br /&gt;
Möchte man &amp;lt;tt&amp;gt;F_CPU&amp;lt;/tt&amp;gt; oder &amp;lt;tt&amp;gt;INTERRUPTS_PER_SECOND&amp;lt;/tt&amp;gt; ändern, dann muss das bei diesem Beispiel direkt in der Quelle angepasst werden. &amp;lt;tt&amp;gt;F_CPU&amp;lt;/tt&amp;gt; hat wie immer nur rein informativen Charakter, um zu wissen, wie schnell der AVR läuft. Eingestellt wird die Taktfrequenz über die [[AVR#Die Fusebits|Fuse-Bits]] bzw. Wahl eines entsprechenden Quarzes/Oszillators/Resonators/RC-Glieds.&lt;br /&gt;
&lt;br /&gt;
'''Quelle''' (&amp;lt;tt&amp;gt;blinky-all.c&amp;lt;/tt&amp;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;
#include &amp;lt;avr/signal.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
// PortB.1 blinkt jede Sekunde&lt;br /&gt;
// also mit einer Frequenz von 1/2 Hz&lt;br /&gt;
#define DDR_LED  DDRB&lt;br /&gt;
#define PORT_LED PORTB&lt;br /&gt;
#define PAD_LED  1&lt;br /&gt;
&lt;br /&gt;
// Werte zur Berechnung der Interrupt-Rate bei AVR-Fuses,&lt;br /&gt;
// die auf 1MHz eingestellt sind (Werkseinstellung für internen RC-Oszillator) &lt;br /&gt;
#define F_CPU                 1000000&lt;br /&gt;
&lt;br /&gt;
// 1000 Interrupts pro Sekunde&lt;br /&gt;
#define INTERRUPTS_PER_SECOND 1000&lt;br /&gt;
&lt;br /&gt;
// Prototypen der Funktionen&lt;br /&gt;
void ioinit();&lt;br /&gt;
&lt;br /&gt;
// Wird durch jeden IRQ eins hochgezählt&lt;br /&gt;
static volatile uint16_t irq_count = 0;&lt;br /&gt;
&lt;br /&gt;
// Wert für das OutputCompare-Register (OCR1A)&lt;br /&gt;
#define OCR_VAL          (F_CPU / INTERRUPTS_PER_SECOND -1)&lt;br /&gt;
&lt;br /&gt;
// Initialisierung der Hardware&lt;br /&gt;
void ioinit()&lt;br /&gt;
{&lt;br /&gt;
    // Port als Ausgang&lt;br /&gt;
    DDR_LED |= (1 &amp;lt;&amp;lt; PAD_LED);&lt;br /&gt;
    &lt;br /&gt;
    // Initialisiert Timer1, um jede Sekunde 1000 IRQs auszulösen&lt;br /&gt;
    // ATmega: Mode #4 für Timer1 und voller MCU-Takt (Prescale=1)&lt;br /&gt;
    TCCR1A = 0;&lt;br /&gt;
    TCCR1B = (1 &amp;lt;&amp;lt; WGM12) | (1 &amp;lt;&amp;lt; CS10);&lt;br /&gt;
&lt;br /&gt;
    // OutputCompare1A Register setzen&lt;br /&gt;
    OCR1A = (uint16_t) ((uint32_t) OCR_VAL);&lt;br /&gt;
&lt;br /&gt;
    // OutputCompare1A Interrupt aktivieren&lt;br /&gt;
    TIMSK |= (1 &amp;lt;&amp;lt; OCIE1A);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Das Hauptprogramm (Einsprungpunkt)&lt;br /&gt;
int main()&lt;br /&gt;
{&lt;br /&gt;
    // Peripherie initialisieren&lt;br /&gt;
    ioinit();&lt;br /&gt;
&lt;br /&gt;
    // Interrupts aktivieren&lt;br /&gt;
    sei();&lt;br /&gt;
&lt;br /&gt;
    // Eine Endlosschleife.  &lt;br /&gt;
    // Der Interrupt lässt die LED weiterhin blinken&lt;br /&gt;
    while (1)&lt;br /&gt;
    {}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Die Interrupt Service Routine (ISR) wird INTERRUPTS_PER_SECOND mal &lt;br /&gt;
// pro Sekunde ausgeführt. irq_count zählt die Aufrufe und blinkt die LED&lt;br /&gt;
// wenn 1 Sekunde vergangen ist.&lt;br /&gt;
SIGNAL(SIG_OUTPUT_COMPARE_1A)&lt;br /&gt;
{&lt;br /&gt;
    uint16_t count;&lt;br /&gt;
&lt;br /&gt;
    // irq_count um 1 erhöhen und&lt;br /&gt;
    count = 1+irq_count;&lt;br /&gt;
&lt;br /&gt;
    // alle 1000 IRQs die LED blinken&lt;br /&gt;
    if (count &amp;gt;= INTERRUPTS_PER_SECOND)&lt;br /&gt;
    {&lt;br /&gt;
        count = 0;&lt;br /&gt;
        PORT_LED ^= (1 &amp;lt;&amp;lt; PAD_LED);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    irq_count = count;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für klassische AVRs wie [[AT90S2313]] muss die Initialisierung etwas abgeändert werden, weil sich Bit-Bezeichner unterscheiden:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// AVR Classic:&lt;br /&gt;
// Timer1 läuft mit vollem Takt&lt;br /&gt;
// CTC: Clear Timer on CompareMatch&lt;br /&gt;
// Timer1 ist Zähler&lt;br /&gt;
    TCCR1A = 0;&lt;br /&gt;
    TCCR1B = (1 &amp;lt;&amp;lt; CS10) | (1 &amp;lt;&amp;lt; CTC1);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
Wenn man will, alnn man den Code bzw. die Werte noch einem kleinen Gültikeitstest unterziehen.&lt;br /&gt;
// Test von F_CPU und INTERRUPTS_PER_SECOND auf Gültigkeit&lt;br /&gt;
#if (OCR_VAL &amp;lt; 0) || (OCR_VAL &amp;gt;= 0x10000)&lt;br /&gt;
#error Werte für F_CPU bzw. INTERRUPTS_PER_SECOND ungeeignet&lt;br /&gt;
#endif // test OCR_VAL&lt;br /&gt;
&lt;br /&gt;
#ifndef TCNT1&lt;br /&gt;
#error Dieser Controller hat keinen Timer1&lt;br /&gt;
#endif // TCNT1&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Spin-off=&lt;br /&gt;
&lt;br /&gt;
Eine LED blinken zu lassen könnte auch wesentlich einfacher implementert werden,&lt;br /&gt;
also z.B. ohne Funktionsaufrufe oder Interrupt-Programmierung.&lt;br /&gt;
&lt;br /&gt;
Neben der eigentlichen Aufgabe &amp;quot;LED blinken lassen&amp;quot; kann man an dem Code&lt;br /&gt;
aber noch andere Dinge lernen:&lt;br /&gt;
* Programmierung eines Interrupts&lt;br /&gt;
* Initialisierung von Timer1 als Zähler mit &amp;quot;Clear Timer on Compare Match&amp;quot;&lt;br /&gt;
* Bedingte Codeübersetzung/Controllerunterscheidung mit &amp;lt;tt&amp;gt;#ifdef&amp;lt;/tt&amp;gt; (in &amp;lt;tt&amp;gt;timer1_init&amp;lt;/tt&amp;gt;)&lt;br /&gt;
* Abchecken der Güligkeit von Defines durch den Präprozessor&lt;br /&gt;
* Übergabe eines Funktionszeigers, um später eine Funktion indirekt aufzurufen&lt;br /&gt;
* Zusammenlinken mehrerer Module&lt;br /&gt;
&lt;br /&gt;
=Siehe auch=&lt;br /&gt;
* [[AVR]]&lt;br /&gt;
* [[avr-gcc]]&lt;br /&gt;
* [[Interrupt]]&lt;br /&gt;
* [[:Kategorie:Quellcode C|weitere C-Code Beispiele]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Grundlagen]]&lt;br /&gt;
[[Kategorie:Microcontroller]]&lt;br /&gt;
[[Kategorie:Quellcode C]]&lt;br /&gt;
[[Kategorie:Software]]&lt;br /&gt;
[[Kategorie:Praxis]]&lt;/div&gt;</summary>
		<author><name>Supernull</name></author>	</entry>

	</feed>