<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="de">
	<id>https://www.mikrocontroller.net/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=217.7.89.210</id>
	<title>Mikrocontroller.net - Benutzerbeiträge [de]</title>
	<link rel="self" type="application/atom+xml" href="https://www.mikrocontroller.net/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=217.7.89.210"/>
	<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/articles/Spezial:Beitr%C3%A4ge/217.7.89.210"/>
	<updated>2026-04-09T22:59:04Z</updated>
	<subtitle>Benutzerbeiträge</subtitle>
	<generator>MediaWiki 1.39.7</generator>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=Diskussion:Remote_IRMP&amp;diff=82337</id>
		<title>Diskussion:Remote IRMP</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=Diskussion:Remote_IRMP&amp;diff=82337"/>
		<updated>2014-03-28T11:35:13Z</updated>

		<summary type="html">&lt;p&gt;217.7.89.210: Die Seite wurde neu angelegt: „Interessantes Projekt. Wäre auch auf Basis eines Pollin-NetIO und Ethersex umzusetzen.“&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Interessantes Projekt.&lt;br /&gt;
Wäre auch auf Basis eines Pollin-NetIO und Ethersex umzusetzen.&lt;/div&gt;</summary>
		<author><name>217.7.89.210</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=Remote_IRMP&amp;diff=82336</id>
		<title>Remote IRMP</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=Remote_IRMP&amp;diff=82336"/>
		<updated>2014-03-28T11:32:13Z</updated>

		<summary type="html">&lt;p&gt;217.7.89.210: /* Bootloader-Software */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Von &#039;&#039;&#039;Frank M. ([http://www.mikrocontroller.net/user/show/ukw ukw])&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[Datei:Remote-IRMP-Screenshot1.png|thumb|Frei gestaltbare Tasten zum Senden von IR-Befehlen]]&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel ist eine konkrete Anwendung des [[IRMP]]-Projekts. Wir verschaffen unserem Mikrocontroller nicht nur einen IR-Sender und Empfänger, sondern auch noch einen Netzwerkanschluss. Damit wird es möglich, mit einer Android-App eine anlernbare IR-Fernbedienung zu realisieren. Der Anwender kann dann mehrere Geräte, die irgendwo im Haushalt verteilt sind, über das Handy steuern. Dabei sendet die App über WLAN zuvor gespeicherte [[IRMP]]-Codes an den gewünschten µC. Dieser strahlt dann die Signale über den IR-Sender aus, um damit unsere Geräte aus der Unterhaltungsindustrie zu schalten.&lt;br /&gt;
&lt;br /&gt;
Außerdem ist eine Erweiterung von [[IRMP]] um Funksender geplant, damit zukünftig auch Funksteckdosen bequem vom Handy aus geschaltet werden können.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;DIESER ARTIKEL IST NOCH IN BEARBEITUNG&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Merkmale ==&lt;br /&gt;
&lt;br /&gt;
Folgende Funktionalitäten sind bereits umgesetzt:&lt;br /&gt;
&lt;br /&gt;
* Anbindung des µC an einen Wiznet W5100 Ethernet-Controller&lt;br /&gt;
* Protokollschnittstelle über TCP/IP und UDP&lt;br /&gt;
* Testprogramme der Kommunikation für Unix, Linux und Windows&lt;br /&gt;
* Android-App mit frei konfigurierbaren Bedienertasten/Bildschirmseiten&lt;br /&gt;
* Anlernen von IR-Codes mit Speicherung unter Android&lt;br /&gt;
* Senden der IR-Codes über WLAN an den Remote-IRMP Controller&lt;br /&gt;
&lt;br /&gt;
== Hardware ==&lt;br /&gt;
&lt;br /&gt;
[[Datei:Remote-irmp-schaltung-arduino.png|thumb|Schaltbild des Prototyps als Shield für Arduino Ethernet]]&lt;br /&gt;
&lt;br /&gt;
Der stabil laufende Prototyp wurde mit dem Arduino Ethernet Board realisiert - jedoch ohne die Verwendung der Arduino-Bibliotheken bzw. Arduino-Software. Die Verwendung des fertigen Boards hatte den Vorteil, dass der Lötaufwand sich auf ein Minimum reduziert: Es muss lediglich je ein IR-Sender- und ein Empfänger-Modul angeschlossen werden. Diese Module bestehen lediglich aus ein paar Bauteilen, welche hier auf eine Lochraster-Platine gelötet werden. Die Lochraster-Platine wird dann einfach als Shield auf das Arduino-Board aufgesteckt. Das Schaltbild dazu ist rechts zu sehen.&lt;br /&gt;
&lt;br /&gt;
Dabei ist:&lt;br /&gt;
&lt;br /&gt;
  * 0C0A = PD6 oder in der Arduino-Nomenklatur: Digital Pin 6&lt;br /&gt;
  * PC0 in der Arduino-Schreibweise: Analog Input 0.&lt;br /&gt;
&lt;br /&gt;
Die für den Prototyp entwickelte Software funktioniert aber auch mit einem WIZnet WIZ812MJ-Modul, welches man zum Beispiel bei [http://www.watterott.com/de/WIZnet-WIZ812MJ-Ethernet-Modul Watterott] erstehen kann. Dieses Modul wird dann auf eine eigens zu entwickelnde Platine aufgesteckt.&lt;br /&gt;
&lt;br /&gt;
Die dafür notwendige Hauptplatine als endgültige Version mit ATmega, Infrarot-Sender/Empfänger und Funksteckdosen-Sendermodul ist noch nicht ganz fertig - dazu später mehr. Der Prototyp mit dem Arduino Ethernet Board ist aber durchaus jetzt schon einsatzfähig.&lt;br /&gt;
&lt;br /&gt;
== Protokoll ==&lt;br /&gt;
&lt;br /&gt;
[[Datei:Remote-IRMP-Screenshot3.png|thumb|Beispiel für einen DVD-Player]]&lt;br /&gt;
&lt;br /&gt;
Das Kommunikationsprotokoll für die Remote-IRMP-Satelliten wurde bewusst einfach gehalten. Dabei kann sowohl TCP/IP als auch UDP verwendet werden.&lt;br /&gt;
&lt;br /&gt;
=== Senden eines IRMP-Codes ===&lt;br /&gt;
&lt;br /&gt;
In diesem Fall sind 7 Bytes zu übertragen:&lt;br /&gt;
&lt;br /&gt;
* Byte 1: &#039;S&#039; als Kommmando &amp;quot;Send&amp;quot;&lt;br /&gt;
* Byte 2: [[IRMP]]-Protokollnummer&lt;br /&gt;
* Byte 3: Upper Byte der [[IRMP]]-Adresse&lt;br /&gt;
* Byte 4: Lower Byte der [[IRMP]]-Adresse&lt;br /&gt;
* Byte 5: Upper Byte des [[IRMP]]-Kommandos&lt;br /&gt;
* Byte 6: Lower Byte des [[IRMP]]-Kommandos&lt;br /&gt;
* Byte 7: [[IRMP]]-Flag&lt;br /&gt;
&lt;br /&gt;
Antwort:&lt;br /&gt;
&lt;br /&gt;
* Byte 1: &#039;S&#039;&lt;br /&gt;
* Byte 2: &#039;+&#039; im Erfolgsfall&lt;br /&gt;
&lt;br /&gt;
oder:&lt;br /&gt;
&lt;br /&gt;
* Byte 1: &#039;S&#039;&lt;br /&gt;
* Byte 2: &#039;-&#039; als Fehlercode, wenn das Protokoll unbekannt ist.&lt;br /&gt;
&lt;br /&gt;
=== Empfangen eines IRMP-Codes (Anlernen) ===&lt;br /&gt;
&lt;br /&gt;
Es wird lediglich 1 Byte gesandt:&lt;br /&gt;
&lt;br /&gt;
* Byte 1: &#039;R&#039; als Kommmando &amp;quot;Receive&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Wenn man als Anwender innerhalb von 5 Sekunden nun eine Fernbedienung betätigt, wird der angelernte Code als Antwort zurückgeschickt, nämlich:&lt;br /&gt;
&lt;br /&gt;
* Byte 1: &#039;R&#039; als Bestätigung&lt;br /&gt;
* Byte 2: &#039;+&#039; als Erfolgscode&lt;br /&gt;
* Byte 3: [[IRMP]]-Protokollnummer&lt;br /&gt;
* Byte 4: Upper Byte der [[IRMP]]-Adresse&lt;br /&gt;
* Byte 5: Lower Byte der [[IRMP]]-Adresse&lt;br /&gt;
* Byte 6: Upper Byte des [[IRMP]]-Kommandos&lt;br /&gt;
* Byte 7: Lower Byte des [[IRMP]]-Kommandos&lt;br /&gt;
* Byte 8: [[IRMP]]-Flag&lt;br /&gt;
&lt;br /&gt;
Sollte keine Fernbedienungstaste betätigt oder das verwendete IR-Protokoll von IRMP nicht verstanden werden, werden als Antwort auch 8 Bytes zurückgesandt, aber:&lt;br /&gt;
&lt;br /&gt;
* Byte 1: &#039;R&#039; als Bestätigung&lt;br /&gt;
* Byte 2: &#039;-&#039; als Fehlercode&lt;br /&gt;
* Byte 3-8: 0x00&lt;br /&gt;
&lt;br /&gt;
=== Weitere Netzwerkbefehle ===&lt;br /&gt;
&lt;br /&gt;
[[Datei:Remote-IRMP-Screenshot4.png|thumb|Bis zu 8 Remote-IRMP Server sind ansprechbar]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Außerdem wurde noch ein Kommando eingebaut, um die Kommunikation über IP selbst zu testen:&lt;br /&gt;
&lt;br /&gt;
* Byte 1: &#039;P&#039; als &amp;quot;Ping&amp;quot;-Kommando&lt;br /&gt;
&lt;br /&gt;
Antwort:&lt;br /&gt;
&lt;br /&gt;
* Byte 1: &#039;P&#039; als Bestätigung&lt;br /&gt;
* Byte 2: &#039;+&#039; als Erfolgscode&lt;br /&gt;
&lt;br /&gt;
Es gibt noch ein weiteres Kommando - dieses jedoch nur für TCP/IP, nicht für UDP:&lt;br /&gt;
&lt;br /&gt;
* Byte 1: &#039;B&#039; als Bootloader-Sprungkommando&lt;br /&gt;
&lt;br /&gt;
Es kommt keine Antwort zurück, sondern der ATmega328 springt dann direkt in den Ethernet-Bootloader, damit man ein Update flashen kann, ohne extra die RESET-Taste drücken zu müssen. Siehe dazu auch das Kapitel [http://www.mikrocontroller.net/articles/Remote_IRMP#Bootloader_-_Flashen_.C3.BCbers_Netzwerk Bootloader - Flashen übers Netzwerk].&lt;br /&gt;
&lt;br /&gt;
== IRMP-Software mit LAN-Anbindung ==&lt;br /&gt;
&lt;br /&gt;
Der Source-Code lässt sich einfach für AVR-µCs übersetzen, indem man unter Windows die Projekt-Datei irmp.aps in das AVR Studio 4 lädt. Jedoch sollte der avr-gcc schon ein neuerer sein, als ursprünglich mal 2010 mit dem AVR Studio 4 ausgeliefert wurde. Ich persönlich nutze avr-gcc 4.7.2.&lt;br /&gt;
&lt;br /&gt;
Bei neueren Entwicklungsumgebungen bzw. Linux ist es auch kein Problem, ein eigenes Projekt bzw. Makefile zu erstellen. Folgende Sources müssen dafür ins Projekt übernommen werden:&lt;br /&gt;
&lt;br /&gt;
* ipserver.c - das main-Modul&lt;br /&gt;
* irmp.c - der IR-Multiprotokoll-Decoder&lt;br /&gt;
* irsnd.c - der IR-Encoder&lt;br /&gt;
* w5100.c - der Wiznet W5100 Treiber&lt;br /&gt;
&lt;br /&gt;
Zum Projekt gehören dann noch folgende Includes:&lt;br /&gt;
&lt;br /&gt;
* irmp.h&lt;br /&gt;
* irmpconfig.h&lt;br /&gt;
* irmpextlog.h&lt;br /&gt;
* irmpprotocols.h&lt;br /&gt;
* irmpsystem.h&lt;br /&gt;
* irsnd.h&lt;br /&gt;
* irsndconfig.h&lt;br /&gt;
* w5100.h&lt;br /&gt;
* w5100config.h&lt;br /&gt;
&lt;br /&gt;
Zusatzlich zu den Standard-Compiler-Optionen (Prozessor-Typ etc.) sollten dem Projekt für alle C-Dateien folgende Optionen hinzugefügt werden:&lt;br /&gt;
&lt;br /&gt;
  -DF_CPU=16000000UL&lt;br /&gt;
  -Os&lt;br /&gt;
  -flto&lt;br /&gt;
  -ffunction-sections&lt;br /&gt;
  -fdata-sections&lt;br /&gt;
&lt;br /&gt;
Als Linker-Optionen:&lt;br /&gt;
&lt;br /&gt;
  -Os&lt;br /&gt;
  -flto&lt;br /&gt;
  -ffunction-sections&lt;br /&gt;
  -fdata-sections&lt;br /&gt;
  -Wl,--gc-sections&lt;br /&gt;
&lt;br /&gt;
=== Fuses ===&lt;br /&gt;
Wichtig sind auch die Fuses. Wenn das Arduino Ethernet Board verwendet wird, muss auf jeden Fall der standardmäßig installierte Bootloader deaktiviert werden. Aber auch für eine eigene Platine müssen die Fuses angepasst werden, nämlich auf:&lt;br /&gt;
&lt;br /&gt;
* lfuse: 0xFF&lt;br /&gt;
* hfuse: 0xD1&lt;br /&gt;
* efuse: 0xFD&lt;br /&gt;
&lt;br /&gt;
Nur wenn der eigene IP-Bootloader auch verwendet werden soll, ist die hfuse nochmals zu ändern. Das ist dann im [http://www.mikrocontroller.net/articles/Remote_IRMP#Bootloader_-_Flashen_.C3.BCbers_Netzwerk Bootloader-Kapitel] weiter unten nachzulesen.&lt;br /&gt;
&lt;br /&gt;
=== Konfiguration ===&lt;br /&gt;
&lt;br /&gt;
[[Datei:Remote-IRMP-Screenshot5.png|thumb|Konfiguration und Test eines Remote-IRMP Servers]]&lt;br /&gt;
&lt;br /&gt;
Es können etliche Parameter angepasst werden. Hier die wichtigsten Einstellungen:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ipserver.c&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define DEBUG                       1&lt;br /&gt;
&lt;br /&gt;
#define MAC_ADDRESS                 {0x90,0xA2,0xDA,0x00,0xF4,0x65}         // mac address&lt;br /&gt;
#define IP_ADDRESS                  {192,168,10,233}                        // ip address&lt;br /&gt;
#define IP_NETMASK                  {255,255,255,0}                         // netmask&lt;br /&gt;
#define IP_GATEWAY                  {192,168,10,1}                          // gateway address&lt;br /&gt;
&lt;br /&gt;
#define DBG_PORT                    10000                                   // debug tcp listen port&lt;br /&gt;
#define TCP_PORT                    10001                                   // normal tcp listen port&lt;br /&gt;
#define UDP_PORT                    10001                                   // udp port&lt;br /&gt;
&lt;br /&gt;
#define LED_DDR                     DDRB&lt;br /&gt;
#define LED_PORT                    PORTB&lt;br /&gt;
#define LED_BIT                     PB1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Als MAC-Adresse (MAC_ADDRESS) wählt man beim Arduino Ethernet Board am besten die aufgeklebte MAC-Adresse. Dann kann es nicht zu Konflikten kommen. Die IP-Adresse (IP_ADDRESS) sollte an das lokale Netzwerk angepasst werden. Ebenso die Netzwerkmaske (IP_NETMASK), wenn sie im lokalen Netz abweicht. Die Angabe eines Gateways (IP_GATEWAY) ist nicht unbedingt notwendig, wenn die IRMP-Server nur im lokalen Netz erreichbar sein sollen. In diesem Fall kann {0,0,0,0} angegeben werden.&lt;br /&gt;
&lt;br /&gt;
Normalerweise horchen die IRMP-Server auf dem TCP- und UDP-Port 10001. Wenn gewünscht, können die Ports sowohl für TCP (TCP_PORT) als auch für UDP (UDP_PORT) geändert werden. Sie können auch verschieden sein. Normalerweise ist aber eine Änderung nicht notwendig.&lt;br /&gt;
&lt;br /&gt;
Bleibt noch der Debug-Port (DBG_PORT). Nur wenn die Präprozessor-Konstante DEBUG auf 1 steht, spielt dieser eine Rolle. Dann protokolliert der IRMP-Server nämlich alle eingehenden IRMP-Befehle, wenn man eine telnet-Session für die konfigurierte IP-Adresse und den Debug-Port öffnet. Unter Windows eignet sich dafür hervorragend PuTTY, welches man aus dem Internet herunterladen kann. Bei unixoiden Systemen ist telnet sowieso verfügbar - meist schon standardmäßig installiert.&lt;br /&gt;
&lt;br /&gt;
Wird Debugging nicht gewünscht, kann man DEBUG auf 0 setzen und der Wert des DBG_PORTs wird irrelevant.&lt;br /&gt;
&lt;br /&gt;
Außerdem gibt es noch die Definitionen für eine am ATmega angeschlossene LED (Konstanten LED_xxx). Hier werden dann ausgesandte IR-Signale parallel auf der LED visualisiert. Außerdem leuchtet diese LED, solange man einen IR-Code anlernt.&lt;br /&gt;
&lt;br /&gt;
Die obigen Werte dafür entsprechen der bereits vorhandenen LED auf dem Arduino-Board. Sie können natürlich für andere Hardware (z.B. eigene Platine mit WIZ812MJ-Modul) angepasst werden. Besser: Man wählt beim Entwurf einer eigenen Hauptplatine einfach denselben Port.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;w5100config.h&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define CHIP_SELECT_AVAILABLE       0            // set to 1 if CS will be controlled by other pin than SS of the µC &lt;br /&gt;
#define CHIP_RESET_AVAILABLE        0            // set to 1 if RESET can be controlled by µC&lt;br /&gt;
&lt;br /&gt;
#if CHIP_SELECT_AVAILABLE == 1                   // if CS can be controlled , enter port/pin of µC&lt;br /&gt;
#  define CS_DDR                    DDRD&lt;br /&gt;
#  define CS_PORT                   PORTD&lt;br /&gt;
#  define CS_BIT                    4&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
#if CHIP_RESET_AVAILABLE == 1                    // if RESET can be controlled by µC, enter port/pin of µC&lt;br /&gt;
#  define RESET_DDR                 DDRD&lt;br /&gt;
#  define RESET_PORT                PORTD&lt;br /&gt;
#  define RESET_BIT                 5&lt;br /&gt;
#endif&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die obigen Konstanten beschreiben, wie der W5100-Controller an den ATmega angebunden ist.&lt;br /&gt;
&lt;br /&gt;
Ist CS (Chip-Select) des W5100 &#039;&#039;&#039;nicht&#039;&#039;&#039; an SS des ATmegas angeschlossen, muss CHIP_SELECT_AVAILABE auf 1 gesetzt werden und mittels CS_xxx-Konstanten der für CS verwendete Port-Pin des ATmegas angegeben werden, damit der ATmega software-mäßig den Ethernet-Controller aktiovieren kann. Beim Arduino Ethernet Board ist CS mit SS fest verbunden, so dass CHIP_SELECT_AVAILABLE auf 0 stehen bleibt und die CS_xxx-Konstanten nicht weiter beachtet werden.&lt;br /&gt;
&lt;br /&gt;
Muss der W5100-Controller explizit über den RESET-Pin softwaremäßig zurückgesetzt werden, dann sollte dies über den ATmega geschehen. In diesem Fall setzt man CHIP_RESET_AVAILABLE auf 1 und definiert weiter unten den Portpin (RESET_xxx), an welchem ATmega-Portpin der RESET-Pin des W51000 angeschlossen ist. Beim Arduino Ethernet Board hängt der W5100 an einer eigenen Hardware-Reset-Schaltung, so dass CHIP_SELEVT_AVAILABLE auf 0 stehen bleiben kann und damit die RESET_xxx-Konstanten irrelevant werden.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;irmpconfig.h&#039;&#039;&#039; und &#039;&#039;&#039;irsndconfig.h&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Die Konstanten in den IRMP-Konfigurationsdateien sind ausführlich im [[IRMP]]-Artikel erklärt. Daher wird hier darauf verzichtet. Im wesentlichen wird hier definiert, welche Pins am ATmega für den IR-Empfänger und für den IR-Sender verwendet werden. Ausserdem kann man hier die IR-Protokolle auswählen, die IRMP/IRSND mit einbinden soll. Insgsamt sind 36 Protokolle wählbar. Die häufigsten 6 Protokolle sind bereits aktiviert.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Erster Start&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Der erste Start mit dem Arduino Ethernet Board kann durchaus auch ohne selbstgebautes &amp;quot;Shield&amp;quot; auf Lochrasterplatine gewagt werden. Hierzu wird die vom Compiler erzeugte Hex-Datei über den 6-poligen ISP-Stecker des Boards eingespielt. [http://www.mikrocontroller.net/articles/Remote_IRMP#Fuses Fuses] nicht vergessen! Anschließend sollte man vom PC aus das Modul per ping-Befehl ansprechen können. Wenn das funktioniert, ist man schon fast am Ziel. Nun sollte man das Board von der Stromversorgung trennen und die Platine mit IR-Empfänger und Sender als Shield aufstecken. Nach Neustart kann man nun entweder direkt die Funktionen mit der [http://www.mikrocontroller.net/articles/Remote_IRMP#Android-Software Android-App] testen oder erstmal mit einem [http://www.mikrocontroller.net/articles/Remote_IRMP#Andere_Betriebssysteme_als_Clients PC-Testprogramm], siehe weiter unten.&lt;br /&gt;
&lt;br /&gt;
Ganz Mutige lassen das aber mit dem Programmieren der Remote-IRMP-Software über den ISP, sondern installieren direkt den [http://www.mikrocontroller.net/articles/Remote_IRMP#Bootloader_-_Flashen_.C3.BCbers_Netzwerk Bootloader], siehe weiter [http://www.mikrocontroller.net/articles/Remote_IRMP#Bootloader_-_Flashen_.C3.BCbers_Netzwerk unten]. Anschließend kann man beliebig oft die IRMP-Software oder Updates davon direkt übers Netzwerk installieren.&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
Weitere Beschreibung der AVR-Software folgt in den nächsten Tagen.&lt;br /&gt;
&lt;br /&gt;
== Bootloader - Flashen übers Netzwerk ==&lt;br /&gt;
&lt;br /&gt;
Wenn man schon einen netzwerkfähigen ATmega hat, dann möchte man Updates auch über das angesteckte Netzwerkkabel einspielen. Dafür wurde ein Bootloader entwickelt, welcher mit 1,6 KB Größe leicht in den oberen Flash-Bereich des ATmega328 passt. Das eigentliche Flash-Programm sendet dann per TCP/IP die Daten an den Bootloader. Das Flash-Programm ist für Unix, Linux und Windows verfügbar.&lt;br /&gt;
&lt;br /&gt;
=== Bootloader-Kommunikationsprotokoll ===&lt;br /&gt;
&lt;br /&gt;
* Bootloader (BL) horcht auf TCP/Port 22222 und wartet für 3 Sekunden auf das Zeichen &#039;$&#039; (1 Byte)&lt;br /&gt;
* Falls dieses eintrifft, antwortet BL ebenfalls mit dem &#039;$&#039;-Zeichen (1 Byte), anderenfalls hier Ende&lt;br /&gt;
* BL sendet die µC-spezifische &amp;quot;Page-Size&amp;quot; des Flashs zum Programmieren an den PC (1 Byte)&lt;br /&gt;
* PC sendet erste Page-Nummer des zu schreibenden Programms (2 Bytes, LSB, i.d.R. 0x00 0x00)&lt;br /&gt;
* PC sendet die Anzahl der zu übertragenden Pages (2 Bytes, LSB)&lt;br /&gt;
* PC sendet die Daten für eine Page - gefolgt von einem Prüfsummen-Byte&lt;br /&gt;
* BL antwortet mit &#039;1&#039;, wenn das Prüfsummen-Byte passt, anderenfalls mit &#039;0&#039; und bricht ab&lt;br /&gt;
* Weiter gehts mit der nächsten Page, also 2 Schritte höher...&lt;br /&gt;
&lt;br /&gt;
=== Bootloader-Software ===&lt;br /&gt;
&lt;br /&gt;
Der Source-Code lässt sich einfach für AVR-µCs übersetzen, indem man unter Windows die Projekt-Datei ipbootloader.aps in das AVR Studio 4 lädt. Der avr-gcc muss jedoch neuer sein als der, welcher ursprünglich im Jahre 2010 mit dem AVR Studio 4 ausgeliefert wurde. Empfehlung: avr-gcc 4.7.2 oder neuer.&lt;br /&gt;
&lt;br /&gt;
Bei neueren AVR-Entwicklungsumgebungen bzw. Linux ist es auch kein Problem, ein eigenes Projekt bzw. Makefile zu erstellen. Folgende Sources müssen dafür ins Projekt übernommen werden:&lt;br /&gt;
&lt;br /&gt;
* ipbootloader.c - der Bootloader&lt;br /&gt;
* w5100.c - der Wiznet W5100 Treiber&lt;br /&gt;
&lt;br /&gt;
Zum Projekt gehören dann noch folgende Includes:&lt;br /&gt;
&lt;br /&gt;
* w5100.h&lt;br /&gt;
* w5100config.h&lt;br /&gt;
&lt;br /&gt;
Zusatzlich zu den Standard-Compiler-Optionen (Prozessor-Typ etc.) müssen dem Projekt für alle C-Dateien folgende Optionen hinzugefügt werden:&lt;br /&gt;
&lt;br /&gt;
  -DF_CPU=16000000UL&lt;br /&gt;
  -Os&lt;br /&gt;
  -flto&lt;br /&gt;
  -ffunction-sections&lt;br /&gt;
  -fdata-sections&lt;br /&gt;
&lt;br /&gt;
Als Linker-Optionen:&lt;br /&gt;
&lt;br /&gt;
  -Os&lt;br /&gt;
  -flto&lt;br /&gt;
  -ffunction-sections&lt;br /&gt;
  -fdata-sections&lt;br /&gt;
  -Wl,--gc-sections&lt;br /&gt;
  -Wl,--section-start=.text=0x7800&lt;br /&gt;
&lt;br /&gt;
Mit der letzten Linker-Option wird das Programm derart übersetzt, dass es ab Adresse 0x7800 lauffähig ist. Damit liegt es in den letzten 2KB des ATmega328-Flash-Speichers. Beim Übersetzen ist dringendst darauf zu achten, dass das Compilat eine &amp;quot;Program Size&amp;quot; von ca. 1,6KB hat. Wird es größer als 2KB, dann sind offensichtlich die obigen Compiler- und Linker-Optionen nicht korrekt eingetragen und das Programm ist als Bootloader unbrauchbar.&lt;br /&gt;
&lt;br /&gt;
=== Konfiguration des Bootloaders ===&lt;br /&gt;
&lt;br /&gt;
Hier gelten im wesentlichen dieselben Konfigurationsparameter für w5100config.h wie [http://www.mikrocontroller.net/articles/Remote_IRMP#Konfiguration oben]. Wichtig ist die Anpassung der IP-Adresse, siehe dafür ipbootloader.c:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define MAC_ADDRESS     {0x90,0xA2,0xDA,0x00,0xF4,0x65}             // mac address&lt;br /&gt;
#define IP_ADDRESS      {192,168,10,233}                            // ip address&lt;br /&gt;
#define IP_NETMASK      {255,255,255,0}                             // netmask&lt;br /&gt;
#define IP_GATEWAY      {192,168,10,1}                              // gateway address&lt;br /&gt;
&lt;br /&gt;
#define TCP_PORT        22222                                       // listen port&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Fuses für den Bootloader ===&lt;br /&gt;
&lt;br /&gt;
Die Fuses sind in diesem Fall auf folgende Werte zu ändern:&lt;br /&gt;
&lt;br /&gt;
* lfuse: 0xFF&lt;br /&gt;
* hfuse: 0xD2&lt;br /&gt;
* efuse: 0xFD&lt;br /&gt;
&lt;br /&gt;
Damit werden die letzten 2KB im Flash für den Bootloader reserviert. Dieser kann dann über den ISP-Stecker installiert werden. Updates der Remote-IRMP-Software können anschließend bequem über das Netzwerk eingespielt werden. Der Anschluss eines ISP-Programmers ist dann nicht mehr notwendig.&lt;br /&gt;
&lt;br /&gt;
=== Flashprogramm ===&lt;br /&gt;
&lt;br /&gt;
Das Flashprogramm ist unter Unix, Linux und Windows verfügbar. Als Executable für Windows benutzt man einfach ipflash.exe, unter unixoiden System kompiliert man sich das Programm selbst mit:&lt;br /&gt;
&lt;br /&gt;
  cc -O ipflash.c -o ipflash&lt;br /&gt;
&lt;br /&gt;
Der Aufruf ist dann allgemein:&lt;br /&gt;
&lt;br /&gt;
  ipflash [-b ipserver-tcp-port] ip-address tcp-port hex-file&lt;br /&gt;
&lt;br /&gt;
oder konkret für die Windows-Eingabeaufforderung:&lt;br /&gt;
&lt;br /&gt;
  ipflash.exe 192.168.10.233 22222 ipserver.hex&lt;br /&gt;
&lt;br /&gt;
bzw. linux:&lt;br /&gt;
&lt;br /&gt;
  ./ipflash 192.168.10.233 22222 ipserver.hex&lt;br /&gt;
&lt;br /&gt;
Wichtig ist dabei, kurz vorher den RESET-Button auf dem Board zu drücken und dann innerhalb von 3 Sekunden das Flash-Programm zu starten.&lt;br /&gt;
&lt;br /&gt;
Ist einmal das ipserver-Programm installiert, kann man sich das Drücken des RESET-Buttons zukünftig auch sparen. Dann kann das Flash-Programm den ATmega auch über das Netzwerk resetten. Hierbei ist zusätzlich der TCP-Port des ipserver-Programms anzugeben, also:&lt;br /&gt;
&lt;br /&gt;
  ipflash.exe -b 10001 192.168.10.233 22222 ipserver.hex&lt;br /&gt;
&lt;br /&gt;
bzw.&lt;br /&gt;
&lt;br /&gt;
  ./ipflash -b 10001 192.168.10.233 22222 ipserver.hex&lt;br /&gt;
&lt;br /&gt;
In diesem Fall schickt das Flash-Programm zunächst den Boot-Befehl auf Port 10001, wartet dann ein paar Sekunden und führt dann erst den eigentlichen Flash-Prozess aus. So kann man dann bequem vom Arbeitsplatz aus alle IRMP-Netzwerkserver im Haushalt aktualisieren, ohne direkt &amp;quot;vor Ort&amp;quot; zu sein.&lt;br /&gt;
&lt;br /&gt;
== Android-Software ==&lt;br /&gt;
&lt;br /&gt;
[[Datei:Remote-IRMP-Screenshot2.png|thumb|Anlernen eines IR-Befehls]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Merkmale:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Ansteuerung von mehreren im Haushalt verteilten IRMP-Satelliten&lt;br /&gt;
* Erstellung von mehreren Bildschirmseiten&lt;br /&gt;
* Frei definierbares Tastenfeld pro Bildschirmseite&lt;br /&gt;
* Anlernen von IR-Codes&lt;br /&gt;
* Senden von IR-Codes&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Weitere Planung:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Erweiterung um Graphiksymbole für die Tasten&lt;br /&gt;
* Makros, um mehrere nachfolgende Befehle über eine Taste zu senden&lt;br /&gt;
* Anlernen von Funksteckdosen-Fernbedienungen&lt;br /&gt;
&lt;br /&gt;
Hier folgt die Beschreibung der Android Software in den nächsten Tagen.&lt;br /&gt;
&lt;br /&gt;
== Andere Betriebssysteme als Clients ==&lt;br /&gt;
&lt;br /&gt;
Es ist auch möglich, für andere Betriebssysteme einen Remote-IRMP-Client zu entwickeln. Ein entsprechendes C-Programm inkl. Quelltext, welches IRMP-Codes an einen IRMP-Satelliten schickt bzw. die angelernten Codes empfängt, habe ich beigefügt. Der C-Quelltext ist unter Unix, Linux und Windows compilierbar. Dieses Tesprogramm ist als Vorlage für ambitionierte Anwender gedacht, die selbst ein eigenes PC-Projekt für Remote-IRMP realisieren möchten.&lt;br /&gt;
&lt;br /&gt;
Als Executable für Windows kann man auch einfach ipclient.exe benutzen, unter Unix bzw. Linux kompiliert man das Programm selbst mit:&lt;br /&gt;
&lt;br /&gt;
    cc -O ipclient.c -o ipclient&lt;br /&gt;
&lt;br /&gt;
=== Aufruf des Testprogramms ===&lt;br /&gt;
&lt;br /&gt;
Der Aufruf ist dann allgemein:&lt;br /&gt;
&lt;br /&gt;
IR-Code senden über UDP:&lt;br /&gt;
&lt;br /&gt;
    ipclient udpsend ipaddress tcp-port ir-protocol ir-addr-in-hex ir-command-in-hex flag-in-hex&lt;br /&gt;
&lt;br /&gt;
IR-Code senden über TCP:&lt;br /&gt;
&lt;br /&gt;
    ipclient send ipaddress tcp-port ir-protocol ir-addr-in-hex ir-command-in-hex flag-in-hex&lt;br /&gt;
&lt;br /&gt;
IR-Code empfangen über UDP:&lt;br /&gt;
&lt;br /&gt;
    ipclient udprec ipaddress tcp-port&lt;br /&gt;
&lt;br /&gt;
IR-Code empfangen über TCP:&lt;br /&gt;
&lt;br /&gt;
    ipclient rec ipaddress tcp-port&lt;br /&gt;
&lt;br /&gt;
=== Beispiel: Senden eines IRMP-Codes ===&lt;br /&gt;
&lt;br /&gt;
IR-Code senden über UDP, z.B. NEC-Protokoll (Nr. 2), Adresse 0xFF00, Kommando: 0x0020, Flag: 0x00&lt;br /&gt;
&lt;br /&gt;
Der Aufruf ist dann in der Windows-Eingabeaufforderung:&lt;br /&gt;
&lt;br /&gt;
    ipclient.exe udpsend 192.168.10.233 10001 2 FF00 0020 0&lt;br /&gt;
&lt;br /&gt;
bzw. unter Linux:&lt;br /&gt;
&lt;br /&gt;
    ./ipclient udpsend 192.168.10.233 10001 2 FF00 0020 0&lt;br /&gt;
&lt;br /&gt;
Wichtig ist dabei, dass die Protokollnummer in dezimal, alle anderen IR-Parameter in hexadezimal angegeben werden. Eine Liste der IR-Protokollnummern findet man hier: [http://www.mikrocontroller.net/svnbrowser/irmp/irmpprotocols.h?view=markup irmpprotocols.h]&lt;br /&gt;
&lt;br /&gt;
=== Beispiel: Empfangen eines IRMP-Codes ===&lt;br /&gt;
&lt;br /&gt;
Man kann natürlich auch IR-Telegramme empfangen, z.B. über TCP mit dem folgenden Befehl:&lt;br /&gt;
&lt;br /&gt;
Windows-Eingabeaufforderung:&lt;br /&gt;
&lt;br /&gt;
    ipclient.exe rec 192.168.10.233 10001&lt;br /&gt;
&lt;br /&gt;
Linux:&lt;br /&gt;
&lt;br /&gt;
    ./ipclient rec 192.168.10.233 10001&lt;br /&gt;
&lt;br /&gt;
Sendet man nun innerhalb von 5 Sekunden mit irgendeiner Fernbedienung ein Signal an den IR-Empfänger, wird dieses dann als IRMP-Code (Protokoll, Adresse, Kommando, Flag) auf dem PC ausgegeben.&lt;br /&gt;
&lt;br /&gt;
== Downloads ==&lt;br /&gt;
&lt;br /&gt;
Hier folgen die Download-Links... später ;-)&lt;br /&gt;
&lt;br /&gt;
== Siehe auch ==&lt;br /&gt;
&lt;br /&gt;
* Diskussion zu diesem Projekt: Link später.&lt;br /&gt;
* [[IRMP]]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Infrarot]]&lt;br /&gt;
[[Kategorie:AVR-Projekte]]&lt;/div&gt;</summary>
		<author><name>217.7.89.210</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=AVR-Tutorial:_Timer&amp;diff=82102</id>
		<title>AVR-Tutorial: Timer</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=AVR-Tutorial:_Timer&amp;diff=82102"/>
		<updated>2014-03-19T06:38:44Z</updated>

		<summary type="html">&lt;p&gt;217.7.89.210: Vandalismus&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Timer sind eines der Hauptarbeitspferde in unserem Mikrocontroller. Mit ihrer Hilfe ist es möglich, in regelmäßigen Zeitabständen Aktionen zu veranlassen. Aber Timer können noch mehr!&lt;br /&gt;
* Timer können mit einem externen Pin hochgezählt werden&lt;br /&gt;
* Es gibt Möglichkeiten, bei bestimmten Zählerständen einen Interrupt auslösen zu lassen&lt;br /&gt;
* Timer können aber auch völlig selbstständig Signale an einem Ausgabepin erzeugen&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
Aber der Reihe nach und kurz zur Erinnerung: Die Beispiele passen zu einem ATmega8 und ggf. einer Reihe anderer AVR, können bei einigen Typen aber abweichen. &lt;br /&gt;
&lt;br /&gt;
==Was ist ein Timer?==&lt;br /&gt;
&lt;br /&gt;
Ein Timer ist im Grunde nichts anderes als ein bestimmtes Register im Mikrocontroller, das hardwaregesteuert fortlaufend um 1 erhöht (oder erniedrigt) wird (statt &amp;lt;i&amp;gt;um 1 erhöhen&amp;lt;/i&amp;gt; sagt man auch &#039;&#039;&#039;inkrementieren&#039;&#039;&#039;, und das Gegenstück, &#039;&#039;&#039;dekrementieren&#039;&#039;&#039;, bedeutet &amp;lt;i&amp;gt;um 1 verringern&amp;lt;/i&amp;gt;). Anstatt also Befehle im Programm vorzusehen, die regelmäßig ausgeführt werden und ein Register inkrementieren, erledigt dies der Mikrocontroller ganz von alleine. Dazu ist es möglich, den Timer mit dem Systemtakt zu verbinden und so die Genauigkeit des Quarzes auszunutzen, um ein Register regelmäßig und vor allen Dingen unabhängig vom restlichen Programmfluss (!) hochzählen zu lassen.&lt;br /&gt;
&lt;br /&gt;
Davon alleine hätte man aber noch keinen großen Gewinn. Nützlich wird das Ganze erst dann, wenn man bei bestimmten Zählerständen eine Aktion ausführen lassen kann. Einer der &#039;bestimmten Zählerstände&#039; ist zum Beispiel der &#039;&#039;&#039;Overflow&#039;&#039;&#039;. Das Zählregister eines Timers kann natürlich nicht beliebig lange inkrementiert werden – z. B. ist der höchste Zählerstand, den ein 8-Bit-Timer erreichen kann, 2&amp;lt;sup&amp;gt;8&amp;lt;/sup&amp;gt; – 1 = 255. Beim nächsten Inkrementierschritt tritt ein Überlauf (engl. Overflow) auf, der den Timerstand wieder zu 0 werden lässt. Und hier liegt der springende Punkt. Wir können uns nämlich an diesen Overflow &amp;quot;anhängen&amp;quot; und den Controller so konfigurieren, dass beim Auftreten des Timer-Overflows ein Interrupt ausgelöst wird.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Kann auch alles nochmal nachgelesen werden im Datenblatt von Atmel zu einigen ATMega Datenblättern http://www.atmel.com/Images/doc8161.pdf&lt;br /&gt;
&lt;br /&gt;
==Der Vorteiler (Prescaler)==&lt;br /&gt;
&lt;br /&gt;
Wenn also der Quarzoszillator mit 4 MHz schwingt, dann würde auch der Timer 4 Millionen mal in der Sekunde erhöht werden. Da der Timer jedes Mal von 0 bis 255 zählt, bevor ein Overflow auftritt, heißt das auch, dass in einer Sekunde 4000000 / 256 = 15625 Overflows vorkommen. Ganz schön schnell! Nur: Oft ist das nicht sinnvoll. Um diese Raten zu verzögern, gibt es den Vorteiler, oder auf Englisch, Prescaler. Er kann z.B. auf die Werte 1, 8, 64, 256 oder 1024 eingestellt werden, je nach Timer (Bitte Datenblatt konsultieren!). Seine Aufgabe ist es, den Systemtakt um den angegebenen Faktor zu teilen. Steht der Vorteiler also auf 1024, so wird nur bei jedem 1024-ten Impuls vom Systemtakt das Timerregister um 1 erhöht. Entsprechend weniger häufig kommen dann natürlich die Overflows. Der Systemtakt sei wieder 4000000. Dann wird der Timer in 1 Sekunde 4000000 / 1024 = 3906.25 mal erhöht. Da der Timer wieder jedesmal bis 255 zählen muss bis ein Overflow auftritt, bedeutet dies, dass in 1 Sekunde 3906.25 / 256 = 15.25 Overflows auftreten.&lt;br /&gt;
&lt;br /&gt;
Systemtakt: 4Mhz&lt;br /&gt;
&lt;br /&gt;
  Vorteiler    Overflows/Sekunde      Zeit zwischen&lt;br /&gt;
                                      2 Overflows [s]&lt;br /&gt;
&lt;br /&gt;
      1            15625                0.000064&lt;br /&gt;
      8             1953.125            0.000512&lt;br /&gt;
     64              244.1406           0.004096&lt;br /&gt;
    256               61.0351           0.016384&lt;br /&gt;
   1024               15.2587           0.065536&lt;br /&gt;
&lt;br /&gt;
Die Zeit zwischen 2 Overflows lässt sich sehr leicht berechnen:&lt;br /&gt;
&amp;lt;math&amp;gt;t=\frac{2^\text{Bit des Timers} \cdot \text{Vorteiler}}{\text{Systemtakt in Hz}} \text{s}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==Erste Tests==&lt;br /&gt;
&lt;br /&gt;
Ein Programm, das einen Timer Overflow in Aktion zeigt, könnte z.&amp;amp;nbsp;B. so aussehen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;avrasm&amp;quot;&amp;gt; &lt;br /&gt;
.include &amp;quot;m8def.inc&amp;quot;&lt;br /&gt;
&lt;br /&gt;
.def temp = r16&lt;br /&gt;
.def leds = r17&lt;br /&gt;
&lt;br /&gt;
.org 0x0000&lt;br /&gt;
        rjmp    main                  ; Reset Handler&lt;br /&gt;
.org OVF0addr&lt;br /&gt;
        rjmp    timer0_overflow       ; Timer Overflow Handler&lt;br /&gt;
&lt;br /&gt;
main:&lt;br /&gt;
        ; Stackpointer initialisieren&lt;br /&gt;
        ldi     temp, HIGH(RAMEND)&lt;br /&gt;
        out     SPH, temp&lt;br /&gt;
        ldi     temp, LOW(RAMEND)     &lt;br /&gt;
        out     SPL, temp&lt;br /&gt;
	&lt;br /&gt;
        ldi     temp, 0xFF            ; Port B auf Ausgang&lt;br /&gt;
        out     DDRB, temp&lt;br /&gt;
&lt;br /&gt;
        ldi     leds, 0xFF&lt;br /&gt;
&lt;br /&gt;
        ldi     temp, (1&amp;lt;&amp;lt;CS00)       ; CS00 setzen: Teiler 1&lt;br /&gt;
        out     TCCR0, temp&lt;br /&gt;
&lt;br /&gt;
        ldi     temp, (1&amp;lt;&amp;lt;TOIE0)      ; TOIE0: Interrupt bei Timer Overflow&lt;br /&gt;
        out     TIMSK, temp&lt;br /&gt;
&lt;br /&gt;
        sei&lt;br /&gt;
&lt;br /&gt;
loop:   rjmp    loop&lt;br /&gt;
&lt;br /&gt;
timer0_overflow:                      ; Timer 0 Overflow Handler&lt;br /&gt;
        out     PORTB, leds&lt;br /&gt;
        com     leds&lt;br /&gt;
        reti&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Programm beginnt mit der [[AVR-Tutorial:_Interrupts|Interrupt-Vektoren-Tabelle]]. Dort ist an der Adresse &amp;lt;i&amp;gt;OVF0Addr&amp;lt;/i&amp;gt; ein Sprung zur Marke &amp;lt;i&amp;gt;timer0_overflow&amp;lt;/i&amp;gt; eingetragen. Wenn also ein Overflow Interrupt vom Timer 0 auftritt, so wird dieser Interrupt durch den &#039;&#039;&#039;rjmp&#039;&#039;&#039; weitergeleitet an die Stelle &amp;lt;i&amp;gt;timer0_overflow&amp;lt;/i&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Das Hauptprogramm beginnt ganz normal mit der Belegung des Stackpointers. Danach wird der Port B auf Ausgang geschaltet, wir wollen hier wieder die LED anschliessen.&lt;br /&gt;
&lt;br /&gt;
Durch Beschreiben von TCCR0 mit dem Bitmuster 0b00000001, hier ausgedrückt durch (1&amp;lt;&amp;lt;CS00), wird der Vorteiler auf 1 gesetzt. Für die ersten Versuche empfiehlt es sich, das Programm mit dem AVR-Studio zunächst zu simulieren. Würden wir einen größeren Vorteiler benutzen, so müsste man ziemlich oft mittels F11 einen simulierten Schritt ausführen, um eine Änderung im Timerregister zu erreichen.&lt;br /&gt;
&lt;br /&gt;
Die nächsten Anweisungen setzen im TIMSK Register das TOIE0 Bit. Sinn der Sache ist es, dem Timer zu erlauben, bei Erreichen eines Overflow einen Interrupt auszulösen.&lt;br /&gt;
&lt;br /&gt;
Zum Schluss noch die Interrupts generell mittels &#039;&#039;&#039;sei&#039;&#039;&#039; freigeben. Dieser Schritt ist obligatorisch. Im Mikrocontroller können viele Quellen einen Interrupt auslösen. Daraus folgt: Für jede mögliche Quelle muss festgelegt werden, ob sie einen Interrupt erzeugen darf oder nicht. Die Oberhoheit hat aber das globale Interrupt Flag. Mit ihm können alle Interrupts, egal von welcher Quelle sie kommen, unterdrückt werden.&lt;br /&gt;
&lt;br /&gt;
Damit ist die Initialisierung beendet und das Hauptprogramm kann sich schlafen legen. Die &#039;&#039;&#039;loop: rjmp loop&#039;&#039;&#039; Schleife macht genau dieses.&lt;br /&gt;
&lt;br /&gt;
Tritt nun ein Overflow am Timer auf, so wird über den Umweg über die Interrupt Vektor Tabelle der Programmteil &amp;lt;i&amp;gt;timer0_overflow&amp;lt;/i&amp;gt; angesprungen. Dieser gibt einfach nur den Inhalt des Registers leds am Port B aus. Danach wird das leds Register mit einer &#039;&#039;&#039;com&#039;&#039;&#039; Operation negiert, so dass aus allen 0 Bits eine 1 wird und umgekehrt. Die Overflow Behandlung ist damit beendet und mittels &#039;&#039;&#039;reti&#039;&#039;&#039; wird der Interrupt Handler wieder verlassen.&lt;br /&gt;
&lt;br /&gt;
==Simulation im AVR-Studio==&lt;br /&gt;
&lt;br /&gt;
Es lohnt sich, den ganzen Vorgang im AVR-Studio simulieren zu lassen. Dazu am besten in der linken I/O View Ansicht die Einträge für PORTB und TIMER_COUNTER_0 öffnen. Wird mittels F11 durch das Programm gegangen, so sieht man, dass ab dem Moment, ab dem der Vorteiler auf 1 gesetzt wird, der Timer 0 im TCNT0 Register zu zählen anfängt. Mit jedem Druck auf F11 erhöht sich der Zählerstand. Irgendwann ist dann die Endlosschleife loop erreicht. Drücken Sie weiterhin F11 und beobachten sie, wie TCNT0 immer höher zählt, bis der Overflow erreicht wird. In dem Moment, in dem der Overflow erreicht wird, wird der Interrupt ausgelöst. Mit dem nächsten F11 landen sie in der Interrupt Vektor Tabelle und von dort geht es weiter zu timer_0_overflow. Weitere Tastendrücke von F11 erledigen dann die Ausgabe auf den Port B, das Invertieren des Registers r17 und der Interrupt ist damit behandelt. Nach dem &#039;&#039;&#039;reti&#039;&#039;&#039; macht der Microcontroller genau an der Stelle weiter, an der er vom Interrupt unterbrochen wurde. Und der Timer 0 hat in der Zwischenzeit weitergezählt! Nach exakt weiteren 256 Schritten, vom Auftreten des ersten Overflows an gerechnet, wird der nächste Overflow ausgelöst.&lt;br /&gt;
&lt;br /&gt;
==Wie schnell schaltet denn jetzt der Port?==&lt;br /&gt;
&lt;br /&gt;
Eine berechtigte Frage. Dazu müssen wir etwas rechnen. Keine Angst, es ist nicht schwer, und wer das Prinzip bisher verstanden hat, der sollte keine Schwierigkeiten haben, die Berechnung nachzuvollziehen.&lt;br /&gt;
&lt;br /&gt;
Der Quarzoszillator schwingt mit 4 MHz. Das heißt, in 1 Sekunde werden 4000000 Taktzyklen generiert. Durch die Wahl des Vorteilers von 1 bedeutet das auch, dass der Timer 4000000 mal in der Sekunde erhöht wird. Von einem Overflow zum nächsten muss der Timer 256 Zählvorgänge ausführen. Also werden in 1 Sekunde 4000000 / 256 = 15625 Overflows generiert. Bei jedem Overflow schalten wir die LEDs jeweils in den anderen Zustand. D.h die LEDs blinken mit einer Frequenz von 7812.5 Hz. Das ist zuviel als dass wir es noch sehen könnten.&lt;br /&gt;
&lt;br /&gt;
Was können wir also tun, um diese Blinkfrequenz zu verringern? Im Moment ist unsere einzige Einflussgröße der Vorteiler. Wie sieht die Rechnung aus, wenn wir einen Vorteiler von 1024 wählen?&lt;br /&gt;
&lt;br /&gt;
Wiederrum: Der Systemtakt sei 4 Mhz. Durch den Vorteiler von 1024 werden daraus 4000000 / 1024 = 3906.25 Pulse pro Sekunde für den Timer. Der zählt wiederum 256 Zustände von einem Overflow zum nächsten. 3906.25 / 256 = 15.2587. Und wiederum: Im Overflow werden die LEDs ja abwechselnd ein und ausgeschaltet, also dividieren wir noch durch 2: 15.2587 / 2 = 7.629. Also knapp 7 Hz. Diese Frequenz müsste man schon mit freiem Auge sehen. Die LEDs werden ziemlich schnell vor sich hin blinken.&lt;br /&gt;
&lt;br /&gt;
Reicht diese Verzögerung noch immer nicht, dann haben wir 2 Möglichkeiten:&lt;br /&gt;
* Entweder wir benutzen einen anderen Timer. Timer 1 beispielsweise ist ein 16 Bit Timer. Der Timer zählt also nicht von 0 bis 255 sondern von 0 bis 65535. Bei entsprechender Umarbeitung des Programms und einem Vorteiler von 1024 bedeutet das, dass die LEDs einen Ein/Aus Zyklus in 33 Sekunden absolvieren.&lt;br /&gt;
* Oder wir schalten die LEDs nicht bei jedem Timer Overflow um. Man könnte zum Beispiel in einem Register bis 7 zählen und nur dann, wenn dieses Register 7 erreicht hat, wird&lt;br /&gt;
** das Register wieder auf 0 gesetzt und&lt;br /&gt;
** die LEDs umgeschaltet.&lt;br /&gt;
&lt;br /&gt;
==Timer 0==&lt;br /&gt;
&lt;br /&gt;
Timer 0 ist ein 8 Bit Timer.&lt;br /&gt;
&lt;br /&gt;
* Overflow Interrupt&lt;br /&gt;
&lt;br /&gt;
===TCCR0===&lt;br /&gt;
====TCCR - Timer/Counter Control Register====&lt;br /&gt;
{{Byte |TCCR0 |      |      |      |      |      | CS02 | CS01 | CS00 }}&lt;br /&gt;
&lt;br /&gt;
====CS02/CS00 - Clock Select====&lt;br /&gt;
&lt;br /&gt;
{| {{Tabelle}}&lt;br /&gt;
|-  style=&amp;quot;background-color:#ffddcc&amp;quot;&lt;br /&gt;
! CS02 || CS01 || CS00 || Bedeutung&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
||keine (Der Timer ist angehalten)&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
||Vorteiler: 1&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
||Vorteiler: 8&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
||Vorteiler: 64&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
||Vorteiler: 256&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
||Vorteiler: 1024&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
||Vorteiler: Externer Takt vom Pin T0, fallende Flanke&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
||Vorteiler: Externer Takt vom Pin T0, steigende Flanke&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===TIMSK===&lt;br /&gt;
&lt;br /&gt;
{{Byte|TIMSK|      |      |      |      |      |      |      | TOIE0 }}&lt;br /&gt;
&lt;br /&gt;
====TOIE0 - Timer 0 Overflow Interrupt Enable====&lt;br /&gt;
Ist dieses Bit gesetzt, so wird beim Auftreten eines Overflows am Timer ein Interrupt ausgelöst.&lt;br /&gt;
&lt;br /&gt;
Anstatt der Schreibweise&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;avrasm&amp;quot;&amp;gt; &lt;br /&gt;
        ldi     temp, 0b00000001      ; TOIE0: Interrupt bei Timer Overflow&lt;br /&gt;
        out     TIMSK, temp&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
ist es besser, die Schreibweise&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;avrasm&amp;quot;&amp;gt; &lt;br /&gt;
        ldi     temp, 1 &amp;lt;&amp;lt; TOIE0&lt;br /&gt;
        out     TIMSK, temp&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
zu wählen, da hier unmittelbar aus dem Ladekommando hervorgeht, welche Bedeutung das gesetzte Bit hat. Die vorher inkludierte m8def.inc definiert dazu alles Notwendige.&lt;br /&gt;
&lt;br /&gt;
==Timer 1==&lt;br /&gt;
&lt;br /&gt;
Timer 1 ist ein 16 Bit Timer&lt;br /&gt;
&lt;br /&gt;
* Overflow Interrupt&lt;br /&gt;
* Clear Timer on Compare Match&lt;br /&gt;
* Input Capture&lt;br /&gt;
* 2 Compare Einheiten&lt;br /&gt;
* div. PWM Modi&lt;br /&gt;
&lt;br /&gt;
===TCCR1B===&lt;br /&gt;
&lt;br /&gt;
{{Byte|TCCR1B| ICNC1| ICES1|      | WGM13| WGM12| CS12 | CS11 | CS10 }}&lt;br /&gt;
&lt;br /&gt;
====CS12/CS10 - Clock Select====&lt;br /&gt;
&lt;br /&gt;
{| {{Tabelle}}&lt;br /&gt;
|-  style=&amp;quot;background-color:#ffddcc&amp;quot;&lt;br /&gt;
! CS12 || CS11 || CS10 || Bedeutung&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
||keine (Der Timer ist angehalten)&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
||Vorteiler: 1&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
||Vorteiler: 8&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
||Vorteiler: 64&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
||Vorteiler: 256&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
||Vorteiler: 1024&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
||Vorteiler: Externer Takt vom Pin T1, fallende Flanke&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
||Vorteiler: Externer Takt vom Pin T1, steigende Flanke&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====ICES1 - Input Capture Edge Select====&lt;br /&gt;
&lt;br /&gt;
====ICNC1 - Input Capture Noise Canceler====&lt;br /&gt;
&lt;br /&gt;
===TCCR1A===&lt;br /&gt;
&lt;br /&gt;
{{Byte|TCCR1A|COM1A1|COM1A0|COM1B1|COM1B0|FOC1A |FOC1B |WGM11 |WGM10 }}&lt;br /&gt;
&lt;br /&gt;
===OCR1A===&lt;br /&gt;
&lt;br /&gt;
{{Byte||&amp;amp;nbsp;|||||||}}&lt;br /&gt;
&lt;br /&gt;
{{Byte||&amp;amp;nbsp;|||||||}}&lt;br /&gt;
&lt;br /&gt;
===OCR1B===&lt;br /&gt;
{{Byte||&amp;amp;nbsp;|||||||}}&lt;br /&gt;
&lt;br /&gt;
{{Byte||&amp;amp;nbsp;|||||||}}&lt;br /&gt;
&lt;br /&gt;
===ICR1===&lt;br /&gt;
{{Byte||&amp;amp;nbsp;|||||||}}&lt;br /&gt;
&lt;br /&gt;
{{Byte||&amp;amp;nbsp;|||||||}}&lt;br /&gt;
&lt;br /&gt;
===TIMSK1===&lt;br /&gt;
{{Byte|TIMSK|      |      |TICIE1|OCIE1A|OCIE1B|     |      |TOIE1}}&lt;br /&gt;
&lt;br /&gt;
====TICIE1 - Timer 1 Input Capture Interrupt Enable====&lt;br /&gt;
====OCIE1A - Timer 1 Output Compare A Match Interrupt Enable====&lt;br /&gt;
&lt;br /&gt;
====OCIE1B - Timer 1 Output Compare B Match Interrupt Enable====&lt;br /&gt;
&lt;br /&gt;
====TOIE1 - Timer 1 Overflow Interrupt Enable====&lt;br /&gt;
&lt;br /&gt;
==Timer 2==&lt;br /&gt;
Timer 2 ist ein 8 Bit Timer.&lt;br /&gt;
&lt;br /&gt;
* Overflow Interrupt&lt;br /&gt;
* Compare Match Interrupt&lt;br /&gt;
* Clear Timer on Compare Match&lt;br /&gt;
* Phasen korrekte PWM&lt;br /&gt;
&lt;br /&gt;
===TCCR2===&lt;br /&gt;
&lt;br /&gt;
{{Byte|TCCR2| FOC2 | WGM20| COM21| COM20| WGM21| CS22 | CS21 | CS20 }}&lt;br /&gt;
&lt;br /&gt;
====CS22/CS20 - Clock Select====&lt;br /&gt;
&lt;br /&gt;
{| {{Tabelle}}&lt;br /&gt;
|-  style=&amp;quot;background-color:#ffddcc&amp;quot;&lt;br /&gt;
! CS22 || CS21 || CS20 || Bedeutung&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
||keine (Der Timer ist angehalten)&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
||Vorteiler: 1&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
||Vorteiler: 8&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
||Vorteiler: 32&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
||Vorteiler: 64&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
||Vorteiler: 128&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
||Vorteiler: 256&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
||Vorteiler: 1024&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===OCR2===&lt;br /&gt;
&lt;br /&gt;
{{Byte||&amp;amp;nbsp;|||||||}}&lt;br /&gt;
&lt;br /&gt;
===TIMSK2===&lt;br /&gt;
{{Byte|TIMSK| OCIE2| TOIE2|      |      |      |      |      |      }}&lt;br /&gt;
&lt;br /&gt;
====OCIE2 - Timer 2 Output Compare Interrupt Enable====&lt;br /&gt;
====TOIE2   Timer 2 Overflow Interrupt Enable====&lt;br /&gt;
&lt;br /&gt;
==Was geht noch mit einem Timer?==&lt;br /&gt;
&lt;br /&gt;
Timer sind sehr universelle Microcontroller Bestandteile. Für weitergehende Studien ist es daher unerlässlich, das entsprechende Datenblatt des Microcontrollers zu studieren. Oft ist es z.&amp;amp;nbsp;B. möglich, dass der Timer bei erreichen von bestimmten Zählerständen einen Ausgabepin von sich aus ein-/aus-/umschaltet. Er erledigt dann das, was wir oben noch mit einem Interrupt gemacht haben, eigenständig komplett in Hardware. Bei einigen Timern ist es möglich, damit eine [[PWM]] (Pulsweiten-Modulation) aufzubauen.&lt;br /&gt;
&lt;br /&gt;
Ein paar der Timermodule lassen sich auch als Counter verwenden. Damit kann man z.&amp;amp;nbsp;B. die Anzahl externer Ereignisse wie Schaltvorgänge eines Inkrementalgebers bestimmen.&lt;br /&gt;
&lt;br /&gt;
Andere bieten die Möglichkeit, über einen externen Uhrenquarz getaktet zu werden (Anwendung z.&amp;amp;nbsp;B. eine &amp;quot;Echtzeituhr&amp;quot; oder als &amp;quot;Weckfunktion&amp;quot; aus einem Standby/Powerdownmodus).&lt;br /&gt;
&lt;br /&gt;
Durch geschickte Umprogrammierung in Echtzeit, lässt sich mit einem Timer eine [[PLL]] aufbauen, die sich fortwährend auf einen Eingangstakt synchronisiert. Damit wird vermieden, dass der Controller ein Signal ständig abpollen muss, sondern das Signale wird per Timer-Interrupt verarbeitet. Massgeblich ist die Messung der aktuellen- und Schätzung der kommenden Flanke mithilfe eines einstellbaren [[Taktteiler]]-verhältnisses.&lt;br /&gt;
&lt;br /&gt;
== Weblinks ==&lt;br /&gt;
* [http://www.uni-koblenz.de/~physik/informatik/MCU/Timer.pdf Timer/Counter und PWM beim ATMega16 Mikrocontroller] Proseminar von Marcel Jakobs, September 2006 (PDF)&lt;br /&gt;
* [http://frank.circleofcurrent.com/cache/avrtimercalc.htm AVR Timer Calculator]&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
{{Navigation_zurückhochvor|&lt;br /&gt;
zurücktext=Speicher|&lt;br /&gt;
zurücklink=AVR-Tutorial: Speicher|&lt;br /&gt;
hochtext=Inhaltsverzeichnis|&lt;br /&gt;
hochlink=AVR-Tutorial|&lt;br /&gt;
vortext=Uhr|&lt;br /&gt;
vorlink=AVR-Tutorial: Uhr}}&lt;br /&gt;
&lt;br /&gt;
[[Category:AVR-Tutorial|Timer]]&lt;br /&gt;
[[Category:Timer und Uhren]]&lt;/div&gt;</summary>
		<author><name>217.7.89.210</name></author>
	</entry>
</feed>