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

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

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

	</feed>