<?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=Thymythos</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=Thymythos"/>
	<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/articles/Spezial:Beitr%C3%A4ge/Thymythos"/>
	<updated>2026-05-18T06:36:24Z</updated>
	<subtitle>Benutzerbeiträge</subtitle>
	<generator>MediaWiki 1.43.8</generator>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=Linksammlung&amp;diff=40297</id>
		<title>Linksammlung</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=Linksammlung&amp;diff=40297"/>
		<updated>2009-10-31T10:55:19Z</updated>

		<summary type="html">&lt;p&gt;Thymythos: Siemens S55/C60&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Auf dieser Seite werden Links zu anderen interessanten Mikrocontroller- und Elektronikseiten gesammelt.&lt;br /&gt;
&#039;&#039;&#039;&lt;br /&gt;
Die alte Linkseite findet man [http://www.mikrocontroller.net/en/links hier].&lt;br /&gt;
&lt;br /&gt;
Hinzufügen von Links:&lt;br /&gt;
# [http://www.mikrocontroller.net/wikisoftware/index.php?title=Linksammlung&amp;amp;action=edit Bearbeiten] anklicken&lt;br /&gt;
# Link unter der entsprechenden Kategorie eintragen&lt;br /&gt;
# &amp;quot;Artikel speichern&amp;quot; klicken&lt;br /&gt;
&lt;br /&gt;
== Suchen &amp;amp; Finden ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Verkauf einem hungrigen Mann einen Fisch und du hast ein Geschäft gemacht, bring ihm das Angeln bei und du hast einen Kunden verloren! (asmo)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [http://www.supplyframe.com/ SupplyFrame] - Datasheet and Electronic Spec Search Engine&lt;br /&gt;
* [http://www.globalspec.com/ GlobalSpec] - The Engineering Search Engine&lt;br /&gt;
* [http://www.alldatasheet.com/ alldatasheet] - Datasheet Search&lt;br /&gt;
* [http://www.datasheetarchive.com/ datasheetarchive] - Datasheet Search&lt;br /&gt;
* [http://www.msarnoff.org/chipdb/ ChipDB] - Pinouts von gängigen µCs.&lt;br /&gt;
&lt;br /&gt;
== [[AVR]] ==&lt;br /&gt;
&lt;br /&gt;
=== Herstellerseiten ===&lt;br /&gt;
&lt;br /&gt;
* [http://www.atmel.com/products/avr/ Atmel.com] Herstellerseiten&lt;br /&gt;
* [http://www.atmel.com/dyn/general/updates.asp Atmel.com updates] Liste der letzten Änderungen in Datenblättern und Beispielcode auf ATMEL.com (nicht nur für AVRs)&lt;br /&gt;
* [http://www.filmetrics.com  Filmetrics Inc.] (Filmetrics manufactures affordable thin-film measurement instruments capable of measuring thin films from 3nm to 0.5mm in thickness.)&lt;br /&gt;
&lt;br /&gt;
=== Information (Foren, Mailinglisten, Linksammlungen) ===&lt;br /&gt;
* [http://progforum.com Batronix Elektronik Forum] Gut besuchtes Forum für allgemeine Elektronik, Mikrocontroller und Programmierung&lt;br /&gt;
* [http://www.avrfreaks.net/ AVR Freaks] AVR Forum, Samples, Tutorials, User-Projekte, GCC für AVR (Registrierung empfohlen)&lt;br /&gt;
* [http://avr-asm.tripod.com Atmel AVR ASM Site]&lt;br /&gt;
* [http://www.mikrocontroller.net Mikrocontroller.net] - AVR Tutorials, Examples, LINKS, Forum (D)&lt;br /&gt;
* [http://www.openavr.org/ Openavr.org] &amp;quot;central repository of information for the various open source tools available for the development of software for Atmel&#039;s AVR family of 8-bit RISC microcontrollers&amp;quot;&lt;br /&gt;
* [http://www.omegav.ntnu.no/avr/resources.php3 Omega V&#039;s AVR Resource List]&lt;br /&gt;
* [http://www.omegav.ntnu.no/avr/newresources.php3 Omega V&#039;s AVR NEW Resource List]&lt;br /&gt;
* [http://www.ipass.net/hammill/newavr.htm Atmel AVR Embedded Microcontroller Resources]&lt;br /&gt;
* [http://members.tripod.com/Stelios_Cellar/AVR/AVR%20Info.html Stelios Cellar Atmel AVR Info Page] - Samples, Links&lt;br /&gt;
* [http://www.elektronik-projekt.de Elektronik Projekt] - Hauptthemen sind AVR und Roboter&lt;br /&gt;
* [http://www.microschematic.com/ AVR Microcontroller inside] (nett gemacht, Engl. Seite am 07-09-2008 nicht erreichbar)&lt;br /&gt;
* [http://electrons.psychogenic.com/avr/ Intro To AVR Microcontrollers] (noch(?) sehr wenig Information)&lt;br /&gt;
* [http://embeddedcompilers.com/avr/ Compilers for AVR family] (C, Pascal, Basic)&lt;br /&gt;
* [http://avrmicrocontrollers.com/ AVR Microcontrollers] - A web site about AVR microcontrollers&lt;br /&gt;
* [http://www.itwissen.info ITWissen.info] (gutes Lexikon)&lt;br /&gt;
* [http://www.evalboard.de  Evalboard] (Linksammlung, Boarddesign, KnowHow, Tools)&lt;br /&gt;
&lt;br /&gt;
=== Entwicklungswerkzeuge (Compiler/Assembler/Debugger/Tools/Libraries) ===&lt;br /&gt;
&lt;br /&gt;
==== C ====&lt;br /&gt;
* [http://sourceforge.net/projects/winavr WinAVR] (pronounced &amp;quot;whenever&amp;quot;) is a suite of executable, open source software development tools for the Atmel AVR series [for the] Windows platform&amp;quot; (includes GNU GCC) &lt;br /&gt;
* [http://sourceforge.net/projects/kontrollerlab KontrollerLab] is a free GPL open-source development environment based on KDE, using the avr-gcc, UISP and AVRDUDE&lt;br /&gt;
* [http://www.nongnu.org/avr-libc/ avr-libc] avr-gcc&#039;s &amp;quot;standard&amp;quot;-library&lt;br /&gt;
&amp;lt;!-- * [http://hubbard.engr.scu.edu/embedded/avr/avrlib/ Procyon AVRlib] a lot of device drivers and Visual-Studio link for avr-gcc --&amp;gt;&lt;br /&gt;
* [http://hubbard.engr.scu.edu/embedded/avr/avrlib/ Procyon AVRlib] a lot of device drivers and Visual-Studio link for avr-gcc&lt;br /&gt;
* [http://rod.info/avr.html rod.info on AVR] esp. for AVR GNU development tools setup under Linux&lt;br /&gt;
* [http://www.sisy.de SiSy AVR] - graphische Entwicklungsumgebung mit C/C++ Codegenerierung aus Struktogrammen und Klassendiagrammen&lt;br /&gt;
* [http://shop.embedit.de/product__206.php AtmanAVR C/C++ IDE]&lt;br /&gt;
* [http://www.iar.com IAR Embedded Workbench]&lt;br /&gt;
* [http://www.hpinfotech.com CodeVisionAVR] C-Compiler für AVRs mit Terminal&lt;br /&gt;
* [http://www.myAVR.de myAVRWorkpad] kompakte Entwicklungsumgebung für AVRs mit Terminal&lt;br /&gt;
* [http://www.amctools.com/vmlab.htm VMLab] komplette IDE mit Debugger und Simulator (auch Peripheriehardware)&lt;br /&gt;
* [http://www.forestmoon.com/Software/AvrIoDesigner/ AVR IO Designer] is a utility to generate initialization source code in C/C++ for the various devices, ports and registers of Atmel AVR processors. The intent is to allow the user to explore the devices specific to a selected processor and experiment with settings thru a user interface that assists in understanding the complexities involved. The user can also assign custom variable names to PORT IO pins thereby keeping track of the IO resources in use. These names are emitted in the generated code for use in the user’s program. (Windows .NET 2.0 erforderlich)&lt;br /&gt;
* [http://www.piconomic.co.za/avrlib/index.html Piconomic AVRLIB] is a collection of firmware for Atmel AVR microcontrollers. The aim is to share source code, experience and expertise (in the eye of the beholder) with the community of engineers, scientists and enthusiasts.&lt;br /&gt;
&lt;br /&gt;
==== Assembler ====&lt;br /&gt;
&lt;br /&gt;
* [http://avr-asm.tripod.com Atmel AVR ASM Site]&lt;br /&gt;
* [http://www.tavrasm.org/ tavrasm] - Toms Linux (Atmel) AVR Assembler&lt;br /&gt;
* [http://www.avr-asm-tutorial.net/gavrasm/index_de.html gavrasm] - Gerds Linux/Win/DOS AVR Assembler &lt;br /&gt;
* [http://avra.sourceforge.net/ avra] - avra ATMEL AVR Assembler für Linux, FreeBSD, AmigaOS und Win32&lt;br /&gt;
* [http://algrom.net/english.html Algorithm Builder] - graphische Makro-Assembler Entwicklungsumgebung&lt;br /&gt;
* [http://www.sisy.de SiSy AVR] - graphische Entwicklungsumgebung mit Assembler Codegenerierung aus Programmablaufplänen&lt;br /&gt;
* [http://www.sbprojects.com/sbasm/sbasm.htm SB-Assembler] - Freeware Cross-Assembler unter DOS. (6502, 6800, 6801, 6804, 6805, 6809, 68HC08, 68HC11, Z8, Z80, Z180, 8080, 8085, 8021, 8041, 8048, 8051, AVR, PIC1684,...)&lt;br /&gt;
* [http://www.myAVR.de myAVRWorkpad] kompakte Entwicklungsumgebung für AVRs mit Terminal&lt;br /&gt;
&lt;br /&gt;
==== Disassembler ====&lt;br /&gt;
&lt;br /&gt;
* [http://www.datarescue.com/idabase/ IDA-Pro] -Disassembler und Debugger für fast alle bekannten Prozessoren. Evaluation Version verfügbar. Tagline: &#039;&#039;The most advanced tool for Hostile Code Analysis, Vulnerability and Software Reverse Engineering&#039;&#039;&lt;br /&gt;
* [http://avr.jassenbaum.de/ja-tools ReAVR] - Disassembler und ACXutility Binary Tool&lt;br /&gt;
* [http://www.visi.com/~dwinker/revava/ revava] - Disassembler&lt;br /&gt;
* [http://www.frozeneskimo.com/electronics/vavrdisasm-free-avr-disassembler/ vAVRdisasm] - Free AVR Disassembler&lt;br /&gt;
* [http://biew.sourceforge.net/en/biew.html BVIEW] is multiplatform portable viewer of binary files with built-in editor in binary, hexadecimal and disassembler modes. It includes &#039;&#039;&#039;AVR&#039;&#039;&#039;/Java/i86-i386-AMD64/ARM-XScale/PPC64 disassemblers, russian codepages convertor, full preview of formats - MZ, NE, PE, NLM, coff32, elf partial - a.out, LE, LX, PharLap; code navigator and more over. (GPL)&lt;br /&gt;
&lt;br /&gt;
==== BASIC ====&lt;br /&gt;
* [http://www.mcselec.com/bascom-avr.htm Bascom AVR]&lt;br /&gt;
* [http://www.fastavr.com FastAVR] - und mit &#039;ASM&#039; Ausgabe, Nokia3310 LCD Unterstützung&lt;br /&gt;
* [http://www.nettypes.de/mbasic mikrocontrollerBASIC Freeware] - mit Simulator für ATmega32, ATmega128 und C-CONTROL.&lt;br /&gt;
* [http://www.mikroe.com/en/compilers/mikrobasic/avr/ mikroBasic] - Comprehensive, stand-alone Basic compiler for AVR microcontrollers&lt;br /&gt;
* [http://home.arcor.de/EDAconsult/Page3/index.html?c~3.1 MCS BASIC-52] - Original-Übersetzung 1988 INTEL MCS BASIC-52 USERS MANUAL 220 Seiten frei Download als PDF&lt;br /&gt;
* [http://www.DieProjektseite.de Beetle-Basic] Leistungsfähiges Basic-Betriebssystem im AVR.&lt;br /&gt;
&lt;br /&gt;
==== Pascal ====&lt;br /&gt;
* [http://www.e-lab.de AVRco Pascal Compiler] - AVR Pascal Compiler mit umfangreicher Funktionslibrary&lt;br /&gt;
* [http://www.mikroe.com/en/compilers/mikropascal/avr/ mikroPascal] - Comprehensive, stand-alone Pascal compiler for AVR microcontrollers&lt;br /&gt;
&lt;br /&gt;
==== Forth ====&lt;br /&gt;
* [http://www.robo-forth.de www.robo-forth.de] - AVR Forth Compiler mit umfangreicher Funktionslibrary für Servos, Motore und Sensoren&lt;br /&gt;
* [http://amforth.sourceforge.net/ amforth] - Forth for Atmel ATmega micro controllers von Matthias Trute. [http://www.mikrocontroller.net/topic/55807#430816 Diskussion]&lt;br /&gt;
&lt;br /&gt;
==== Java ====&lt;br /&gt;
* [http://www.harbaum.org/till/nanovm NanoVM] - Java VM für AVR-Mikrocontroller ([[NanoVM|deutsches Wiki]])&lt;br /&gt;
&lt;br /&gt;
==== Ada ====&lt;br /&gt;
* [http://avr-ada.sourceforge.net/ AVR-Ada] - Ada Compiler innerhalb von GCC (GNAT) für AVR.  Enthält eine kleine Laufzeitbibliothek ohne Tasking und ohne Exceptions.&lt;br /&gt;
&lt;br /&gt;
==== Virgil ====&lt;br /&gt;
* [http://compilers.cs.ucla.edu/virgil/index.html The Virgil Programming Language] is designed for building robust, flexible, and scalable software systems on embedded hardware platforms. Virgil builds on ideas from object-oriented, statically typed languages like Java, providing a clean, consistent source language. Its compiler system provides an efficient implementation for resource-constrained environments.&lt;br /&gt;
&lt;br /&gt;
==== LabVIEW ====&lt;br /&gt;
* http://www.ni.com/embedded/ Informationen zu LabVIEW, der graphischen Entwicklungsumgebung von National Instruments&lt;br /&gt;
* http://www.labviewforum.de/ Deutsches Labview-Forum&lt;br /&gt;
&lt;br /&gt;
=== Tutorials und Beispiele ===&lt;br /&gt;
* [http://www.meinemullemaus.de/elektronik/avr_workshop/index.html AVR Mikrocontroller] Einfühung in AVR Mikrocontroller mit Nachbau des Spiels &amp;quot;Senso&amp;quot;.&lt;br /&gt;
* [http://www.avrbeginners.net AVRBeginners.net] Beginners Guides to AVRs&lt;br /&gt;
* [http://electrons.psychogenic.com/avr/ electrons.psychgenic.com] AVR Microcontroller Section - Einführung und Tutorial (E)&lt;br /&gt;
* [http://www.wikidorf.de/reintechnisch/Inhalt/AVRProjekt-9V-LED-Lampe reintechnisch.de] AVR Tutorial: 9V-LED-Lampe&lt;br /&gt;
* [http://digitaltechnik.mschoeffler.de digitaltechnik.mschoeffler.de] Einführung in die Grundlagen der Digitaltechnik&lt;br /&gt;
* [http://arm.hsz-t.ch arm.hsz-t.ch] Einfühung in ARM7 Mikrocontroller und uClinux.&lt;br /&gt;
* [http://www.schaltungsforum.de Das Schaltungsforum] ist eine Seite für Anfänger und Profis welche ständig mit Tutorials erweitert wird. Stellt Eure Projekte online. Die Seite befindet noch im Aufbau und Eure Mithilfe ist erwünscht.&lt;br /&gt;
* [http://www.mikrocontrollerspielwiese.de mikrocontrollerspielwiese.de] ist eine Seite, die an Anfänger gerichtet ist und Experimente und fertige Projekte komplett mit Code und Eagle-Dokumenten zur Verfügung stellt.&lt;br /&gt;
* [http://www.earthshinedesign.co.uk/ASKManual/Site/ASKManual.html The Complete Beginners Guide to the Arduino]&lt;br /&gt;
* [http://www.codeproject.com/KB/system/ArduinoVB.aspx Arduino with Visual Basic] by Carl Morey auf codeproject.com&lt;br /&gt;
* [http://www.elo-web.de/elo/mikrocontroller-und-programmierung/avr-anwendungen ELO-AVR-Anwendungen] bietet eine wachsende Sammlung kleinerer AVR-Projekte, überwiegend für die ATTiny-Serie.&lt;br /&gt;
* [http://www.schramm-software.de/tipps/ AVR-Tipps] Programmier-Tipps und AVR-Experimente.&lt;br /&gt;
&lt;br /&gt;
==== C ====&lt;br /&gt;
* [[AVR-GCC-Tutorial]]&lt;br /&gt;
* [http://www.smileymicros.com/QuickStartGuide.pdf Quick Start Guide for using the WinAVR Compiler with ATMEL&#039;s AVR Butterfly] ([http://www.smileymicros.com www.smileymicros.com], PDF)&lt;br /&gt;
* [http://www.piconomic.co.za/avr.html Piconomic Design Atmel AVR Course] is for the engineer who wants to switch to the 8-bit Atmel AVR microcontroller and learns by example. C language and compiler experience is a prerequisite. (Beim Nachbau des AVR-Boards &#039;&#039;&#039;Copyright notice&#039;&#039;&#039; beachten!)&lt;br /&gt;
* [http://www.avrtutor.com/tutorial/thermo/contents.htm avrtutor] - an attempt to provide a real tutorial for the ATMEL AVR microcontrollers.&lt;br /&gt;
* [http://www.sparkfun.com/commerce/present.php?p=BEE-1-PowerSupply Spark Fun Electronics] - Beginning Embedded Electronics (Atmega8, englisch)&lt;br /&gt;
* [http://metku.net/index.html?path=articles/microcontroller-part-1/index_eng metku.net] - How to get started with microcontrollers (ATtiny45, Steckbrett)&lt;br /&gt;
&lt;br /&gt;
==== Assembler ====&lt;br /&gt;
* [http://avr-asm.tripod.com Atmel AVR ASM Site]&lt;br /&gt;
* [http://www.avr-asm-tutorial.net Atmel AVR Microcontroller Assembler Tutorial] (D)&lt;br /&gt;
* [http://www.itee.uq.edu.au/~cse/_atmel/AVR_Studio_Tutorial/ Einstieg in AVRStudio 4] (viele Abbildungen, Engl.)&lt;br /&gt;
* [[AVR-Studio]]&lt;br /&gt;
&lt;br /&gt;
==== Bascom ====&lt;br /&gt;
* [http://www.mcselec.com/ MCS Elektronik] BASCOM AVR Demo zum Download&lt;br /&gt;
&lt;br /&gt;
==== Pascal ====&lt;br /&gt;
* [http://www.elektronik-projekt.de/content/download/avrco_tut2.pdf AVRco Pascal Tutorial] - von Markus&lt;br /&gt;
* [http://www.ibrtses.com/embedded/avr.html ein paar Seiten zum AVR] (ASM und Pascal) von ibrt&lt;br /&gt;
&lt;br /&gt;
=== Hardware (Prototypen-Platinen-Boards etc.) ===&lt;br /&gt;
&lt;br /&gt;
* [http://retrodan.tripod.com Atmel AVR Butterfly Site]&lt;br /&gt;
* [http://www.simplesign.de simplesign.de] Controller Module, Bausätze. Auf Kundenwünsche wird sehr gerne eingegangen -&amp;gt; Link geht nicht (13.7.2009)&lt;br /&gt;
* [http://www.fox4you.cc Austria] Development Tools for ATMEL ATmega Microcontrollers Connections via USB and LAN&lt;br /&gt;
* [http://www.kanda.com Kanda] Starter Kits and Development Tools for different Microcontrollers&lt;br /&gt;
* [http://www.dontronics.com Dontronics] Starter Kits and Development Tools for different Microcontrollers, Linkpages for AVR and PIC&lt;br /&gt;
* [http://www.mikrocontroller.com mikrocontroller.com] u.a. Platine AVR-Ctrl, AVR-Webserver (D)&lt;br /&gt;
* [http://mikrocontroller.cco-ev.de/eng/ AVR webserver] RTL8019, 3COM (E) &lt;br /&gt;
* [http://www.microcontroller-starterkits.de Microcontroller-Starterkits] Starter Kits for different Microcontrollers (D)&lt;br /&gt;
* [http://www.olimex.com Olimex Ltd.] DevelopmentBoards and Tools&lt;br /&gt;
* [http://www.krause-robotik.de Krause Robotik] Controller Boards &amp;amp; Zubehör&lt;br /&gt;
* [http://www.robotikhardware.de robotikhardware.de] Controller Boards&lt;br /&gt;
* [http://www.ssv-embedded.de SSV Embedded Systems] 32-bit Mikrocontrollermodule und -boards, Starter Kits etc.&lt;br /&gt;
* [http://shop.embedit.de/browse_002_21__.php Embedit] Mikrocontrollermodule und -boards&lt;br /&gt;
* [http://www.display3000.com Display3000] Farbdisplays, Mikrocontrollermodule und -boards mit TFT-Farbdisplays; Experimentierplatinen und Ansteuerplatinen für TFT Farbdisplays&lt;br /&gt;
* [http://www.glyn.de GLYN High-Tech Distribution] Mikrocontroller Applikationen, TFT-Displays, LCD-Anzeigen, Memory Cards&lt;br /&gt;
* [http://www.myavr.de myAVR] Einsteigerboards und Zubehör&lt;br /&gt;
* [http://www.siphec.com/ SIPHEC] Development Boards für AVR, MSP430, USB&lt;br /&gt;
* [http://www.pollin.de/shop/shop.php?cf=detail.php&amp;amp;pg=OA==&amp;amp;a=MTY5OTgxOTk=&amp;amp;w=OTk4OTY4&amp;amp;ts=0 ATMEL Evaluations-Board Bausatz] ([http://www.pollin.de/shop/downloads/D810038B.PDF PDF]) und [http://www.pollin.de/shop/shop.php?cf=detail.php&amp;amp;pg=OA==&amp;amp;a=MzU5OTgxOTk=&amp;amp;w=OTk4OTY4&amp;amp;ts=0 ATMEL Funk-Evaluations-Board Bausatz] ([http://www.pollin.de/shop/downloads/D810046B.PDF PDF]) von Pollin&lt;br /&gt;
* [http://www.lochraster.org/etherrape/ Etherrape] Atmaga 644 mit Ethernet und TCP/IP als Bausatz.&lt;br /&gt;
* [http://www.ic-board.de/index.php?cat=c4_Programmer.html AVR Programmieradapter],[http://www.ic-board.de/index.php?cat=c3_Funkmodule.html ZigBee-ready Funkmodule/Funk-USB-Sticks] und [http://www.ic-board.de/index.php?cat=c13_ICradio-Bundles.html Funk Starterkits] von In-Circuit&lt;br /&gt;
* [http://www.ic-board.de/index.php?cat=c2_ICnova-Module.html AVR32 AP7000 Linux Board] mit 2xEthernet, TFT, Audio, SDCARD, USB-Host/Devive, Funk...&lt;br /&gt;
* [http://www.freeduino.org/ Freeduino.org] - Riesige Linksammlung zu dem &#039;&#039;&#039;Ardunio&#039;&#039;&#039;(R) AVR-Board (Kit) und dessen Clones und Mutanten (DIY oder Kit)&lt;br /&gt;
* [http://www.freeduino.de/ freeduino.de] - Anleitungen und Tutorials, Arduino Wiki, Blog, Tools in Deutsch&lt;br /&gt;
* [http://www.das-labor.org/wiki/Laborboard Das Laborboard] von das-labor.org (DIY)&lt;br /&gt;
* [http://avrboards.com/ AVR Boards] - Some information about AVR microcontrollers and development boards&lt;br /&gt;
* [http://six.media.mit.edu:8080/6 number six] - Open Source Design, Atmega32. Alle Pins sind auf eine 2x20 Pol Wannenstiftleiste herausgeführt.&lt;br /&gt;
* http://www.maares.de/tools USB Memory Stick am AVR Butterfly. AVR Butterfly Trägerplatine zum Anschluß von VDRIVE, VMUSIC, RFM12.&lt;br /&gt;
* [http://www.wiring.org.co/ Wiring] is an open source programming environment and electronics i/o board for exploring the electronic arts, tangible media, teaching and learning computer programming and prototyping with electronics.&lt;br /&gt;
* [http://binaryideas.blogspot.com/2008/08/project-quick-avr-part-3_26.html QuickAVR] - DIY Prototypenboard zum Aufstecken auf ein Breadboard (ATmega168, 16 MHz, no SMD)&lt;br /&gt;
* [http://www.chip45.com/ chip45] Atmel AVR Module und Boards mit USB, RS232/485, CAN, Ethernet, Funkmodule, sowie ISP Programmieradapter.&lt;br /&gt;
* [http://www.rakers.de/catalog Dr. Rakers] &amp;lt;b&amp;gt;AVR Boards und Experimentierplatinen&amp;lt;/b&amp;gt; mit USB, Ethernet, RS232, CAN, LCD etc. in hochwertiger Qualität zu günstigen Preisen.&lt;br /&gt;
* [http://nibo.nicai-systems.de Roboterbausatz Nibo] - autonomer &amp;lt;b&amp;gt;Roboter&amp;lt;/b&amp;gt; mit einem ATmega128 und einem ATmega88&lt;br /&gt;
* [http://www.aevum-mechatronik.de Modularis] - AVR Mikrocontroller-Boards (z.T. mit Zusatz-Speicher und USB) die über Flachbandkabel erweitert werden können. Es gibt bis jetzt Zubehör-Module mit Taster, Motor H-Brücke, XBee und Winkelsensor.&lt;br /&gt;
* [http://www.comsys.ch/Tern-Embedded-Systeme.151.0.html Tern Embedded Systeme] - C++ programmierbare Kontroller mit 586, i386EX, Am188ES und V25 Prozessoren, Entwicklungstools.&lt;br /&gt;
* [http://www.schramm-software.de/bausatz/ Schramm-Software] - AVR Mikrocontroller-Bausätze&lt;br /&gt;
&lt;br /&gt;
=== Programmierhard- und Software ===&lt;br /&gt;
* [http://www.obdev.at/products/avrusb/avrdoper.html AVR-Doper] Einfach nachzubauender, STK500-kompatibler Programmer mit USB-Anschluss. Beherrscht auch HVSP, nicht jedoch HVPP. Open Source.&lt;br /&gt;
* [http://www.bsdhome.com/avrdude/ AVRDUDE] AVR ISP-Programmerierwerkzeug für Unix/Linux/BSD und Windows. Kommandozeile [http://sourceforge.net/projects/avrdude-gui/ (oder mit GUI)], AVR Butterfly-Unterstützung&lt;br /&gt;
* [http://www.lancos.com/prog.html PonyProg] neben AVR für diverse seriell programmierbare Bauteile (Grafische Nutzeroberfläche und Kommandozeile), siehe auch [[Pony-Prog Tutorial]]&lt;br /&gt;
* [http://savannah.nongnu.org/projects/uisp/ uisp] AVR ISP-Programmierwerkzeug für Unix/Linux/BSD und Windows (Kommandozeile)&lt;br /&gt;
* [http://www.myplace.nu/avr/yaap/ yaap]&lt;br /&gt;
* [http://www.xs4all.nl/~sbolt/e-index.html SP12]&lt;br /&gt;
* [http://www.mikrocontroller-projekte.de/Mikrocontroller/AVR-Prog/AVR-Programmer.html AVR910 kompatibler Programmer] mit aktueller, beschleunigter Firmware.&lt;br /&gt;
* [http://www.der-hammer.info/hvprog STK500 kompatibler Programmer] als Nachbauprojekt. Siehe auch [[STK500]]&lt;br /&gt;
* [http://www.shop.robotikhardware.de/shop/catalog/product_info.php?cPath=73&amp;amp;products_id=41 Preiswerter Standard ISP (STK200 kompatibel)]&lt;br /&gt;
*  [http://www.siwawi.arubi.uni-kl.de/avr_projects/evertool/ Evertool] kombinierter ISP &amp;amp; [[JTAG]] Programmer (kompatibel zum &amp;quot;original&amp;quot; Atmel AVRISP und Atmel JTAGICE) &lt;br /&gt;
* [http://www.olimex.com Olimex] (Bulgarischer Anbieter) Kostengünstig&lt;br /&gt;
* [http://www.avr-projekte.de/isp.htm AVR910-USB Programmer] incl. USB-Modul und USB-&amp;gt;Seriell Wandler&lt;br /&gt;
*[http://www.fischl.de/usbasp/ USBasp] &amp;amp;#8211; USB-Programmer bestehend aus ATmega8 (kein spezieller USB-Chip notwendig)&lt;br /&gt;
* [http://home.arcor.de/bernhard.michelis Amadeus-USB] - Highspeed-Programmer für PIC18, PIC24, dsPIC30, PIC32, dsPIC33 und AVR. Bietet auch Möglichkeiten zur Fehlersuche.&lt;br /&gt;
* [http://www.e-dsp.com Signalgenerator] - Signalgenerator software&lt;br /&gt;
* [http://www.myavr.de/shop/artikel.php?artID=42 mySmartUSB] - USB Programmer und USB-UART-Bridge, AVR910 und AVR911 kompatibel&lt;br /&gt;
* [http://www.shop.robotikhardware.de/shop/catalog/product_info.php?cPath=73&amp;amp;products_id=161 USB-Programmer für Bascom Programmierer]&lt;br /&gt;
* [http://www.virtualserialport.com/ Virtual Serial Port] Software for serial port communication and null-modem emulation&lt;br /&gt;
* [http://www.ic-board.de/index.php?cat=c4_Programmer.html AVR Programmieradapter und JTAGICE MKII]&lt;br /&gt;
* [http://www.helmix.at/hapsim/index.htm HAPSIM graphischer Simulator ] zu graphischen Simulation von Tasten /LED /LCD und Terminal in AVR Studio Freeware !!!&lt;br /&gt;
* [http://www.ic-board.de/index.php?cat=c4_Programmer.html AVR Programmieradapter und JTAGICE MKII]&lt;br /&gt;
* [http://www.myavr.de/download.php?suchwort=ProgTool myAVR ProgTool] nette Programmieroberfläche (free)&lt;br /&gt;
* [http://b9.com/elect/avr/kavrcalc/ KAVRCalc] is a free calculator to assist in programming AVR microcontrollers (Baudrate, Watchdog, Timer, ...)&lt;br /&gt;
* [http://www.chip45.com/CrispAVR-USB CrispAVR-USB] STK500 V2 kompatibler ISP Adapter mit USB Schnittstelle für Atmel AVR Mikrocontroller (1,8V-5,5V).&lt;br /&gt;
* [http://ucom-ir.nicai-systems.de UCOM-IR] - Programmieradapter mit USB Schnittstelle (AT90USB162) und IR-Sender/Empfänger, STK500 V2 kompatibel&lt;br /&gt;
* [http://www.anagate.de/products/programmers.htm AnaGate Programmer] Serielle Programmer mit LAN-Anschluss für I2C und SPI inkl. Programmier-API für Windows/Linux (Shop)&lt;br /&gt;
&lt;br /&gt;
=== Projekte und Quellcodebibliotheken ===&lt;br /&gt;
&lt;br /&gt;
====Bibliotheken====&lt;br /&gt;
* [http://www.nongnu.org/avr-libc/ AVR Libc]&lt;br /&gt;
* [http://hubbard.engr.scu.edu/embedded/avr/avrlib/docs/html/index.html Procyon AVRlib]&lt;br /&gt;
* [http://homepage.hispeed.ch/peterfleury Peter Fleury&#039;s Pages] - UART / LCD (HD44780) / I²C (TWI)/ AVR-GCC Bibliotheken, STK500v2 Bootloader&lt;br /&gt;
*[http://sourceforge.net/projects/avrfix  Fixed Point Library Based on ISO/IEC Standard DTR 18037 for Atmel AVR microcontrollers, u.a. Cordic-Algorithmen] und [http://www.enti.it.uc3m.es/wises07/presentations/session2/05%20-%20Fixed%20Point%20Library%20According%20to%20ISOIEC%20Standard%20DTR%2018037%20for%20Atmel%20AVR%20ProcessorsWISES07-fixedpointlibrary%20-%20Elmenreich.pdf  Kurzbeschreibung dazu als Powerpoint-PDF TU Wien Febr. 2007]&lt;br /&gt;
&lt;br /&gt;
==== Betriebssysteme &amp;amp; Co. ====&lt;br /&gt;
* [http://www.tinyos.net/ TinyOS] - Komponentenbasiertes Betriebssystem für Sensorknoten. Bringt eigene C-ähnliche Hochsprache nesC mit.&lt;br /&gt;
* [http://www.chris.obyrne.com/yavrtos/ YAVRTOS] - Yet Another Atmel® AVR® Real-Time Operating System von Chris O&#039;Byrne (C, Atmega32, GPL3 Lizenz)&lt;br /&gt;
* [http://www.freertos.org/ FreeRTOS] is a portable, open source, mini Real Time Kernel - a free to download and royalty free RTOS that can be used in commercial applications. (AVR, MSP430, PIC, ARM7, ...)&lt;br /&gt;
* [http://www.barello.net/avrx/index.htm AvrX Real Time Kernel] (IAR ASM oder IAR/GCC C, GPL2 Lizenz)&lt;br /&gt;
* [http://scmrtos.sourceforge.net/ scmRTOS] - Single-Chip Microcontroller Real-Time Operating System (C++, AVR, MSP430, Blackfin, ARM7, FR (Fujitsu, [http://www.opensource.org/licenses/mit-license.php MIT Lizenz]).&lt;br /&gt;
* [http://www.circuitcellar.com/avr2004/DA3650.html csRTOS] - cooperative single-stack RTOS aus dem Circuit Cellar AVR 2004 Design Contest.  [http://www.avrfreaks.net/index.php?module=Freaks%20Academy&amp;amp;func=viewItem&amp;amp;item_id=987&amp;amp;item_type=project csRTOS port to ATmega32] und [http://www.avrfreaks.net/index.php?name=PNphpBB2&amp;amp;file=viewtopic&amp;amp;t=50743&amp;amp;start=all&amp;amp;postdays=0&amp;amp;postorder=asc Diskussion] auf www.avrfreaks.net führte zur Weiterentwicklung als [http://www.mtcnet.net/~henryvm/4AvrOS/ 4AvrOS] - cooperative scheduler&lt;br /&gt;
* [http://www.avrfreaks.net/index.php?module=Freaks%20Academy&amp;amp;func=viewItem&amp;amp;item_type=project&amp;amp;item_id=230 OPEX] - freeware cooperative scheduler with lots of calendar and I/O functions von Steve Childress (Download auf www.avrfreaks.net ggf. Registrierung notwendig)&lt;br /&gt;
* [http://www.mikrocontroller.net/topic/12176#79672 Scheduler] von Peter Dannegger&lt;br /&gt;
* [http://www.mikrocontroller.net/topic/25087#186454 RTC-Scheduler] von ape&lt;br /&gt;
* [http://www.sics.se/~adam/pt/ Protothreads] - Lightweight, Stackless Threads in C (open source BSD-style license)&lt;br /&gt;
* [http://www.micrium.com/products/rtos/kernel/rtos.html uC/OS-II] is a real time operating system developed by Jean J. Labrosse. You can obtain the source code for the OS by buying Labrosse&#039;s excellent book &#039;&#039;MicroC/OS-II The Real-Time Kernel (2nd edition)&#039;&#039;. [http://www.ee.lut.fi/staff/Julius.Luukko/ucos-ii/avr/index.shtml Port for AVR (gcc 3.x)] and [http://www.myplace.nu/avr/ucos/index.htm AVR (gcc 2.x)].&lt;br /&gt;
* [http://freshmeat.net/projects/qp/ QP] is a lightweight, portable framework/RTOS for embedded systems (ARM, Cortex-M3, 8051, AVR, MSP430, M16C, HC08, NiosII, and x86). GPL (und kommerzielle Lizenz verfügbar)&lt;br /&gt;
* [http://www.femtoos.org/ Femto OS] von  Ruud Vlaming ist ein preemptives Betriebssystem für die kleinsten Mikrocontroller aus der AVR Serie bis ca. 16 KB ROM und 1 KB RAM. Spezielle Targets sind: ATtiny861/461/261. Geschrieben in C. Freie Software, GPLv3.&lt;br /&gt;
* [http://www.projects-lab.com/?p=344 kaOS] is a real-time, multithreaded, preemptive operating system for the ATmega32 microcontroller, which loads and executes programs from a Secure Digital or MMC card. Authors Nicholas Clark &amp;amp; Adam Liechty. (Circuit Cellar AVR Wettbewerb 2006)&lt;br /&gt;
* [http://helium.sourceforge.net/ Helium] is a minimalistic real-time kernel for the HC(S)08 core by Freescale and Atmel AVR.&lt;br /&gt;
* [http://dev.bertos.org/ BeRTOS] is a completely free, open source, real time operating system (RTOS) suitable for embedded platforms. Runs on many microprocessors and microcontrollers, ranging from 8 bits to 32 bits CPUs and even PCs.&lt;br /&gt;
&lt;br /&gt;
==== Projektsammlungen ====&lt;br /&gt;
&lt;br /&gt;
* [http://www.DieProjektseite.de Die Elektronik-Projektseite und Heimat des BasicBeetle] Hauptthema ist der BasicBeetle. Ein modularer, leistungsfähiger, in Basic programmierbarer Mikrorechner speziell für Steuerungen. Mit vielen Programmen, Tiipps und Tricks, Informationen ...&lt;br /&gt;
* [http://www.Happy-Micro.de Happy-Micro.de] Die Internetsite für Hobbyelektroniker, Mikrocontroller-Anwender, Programmierer und alle, die Spaß an Computern und Elektronik haben. Bei Happy-Micro.de steht der Spaß am Entwickeln von Programmen und Schaltungen im Vordergrund. Jeder Benutzer hat die Möglichkeit auch als Autor mitzumachen und seine Schaltungen oder Programme zu veröffentlichen. Freier Bilderdownload für die eigene Homepage.&lt;br /&gt;
* [http://iwenzo.de Elektronik und Informationen] Wissenswertes aus der Unterhaltungselektronik..&lt;br /&gt;
* [http://instruct1.cit.cornell.edu/courses/ee476/FinalProjects/ Cornell University ECE 476 Microcontroller Design Final Projects]&lt;br /&gt;
* [http://www.serasidis.gr/ Serasidis Vasilis&#039; AVRsite] u.a. GLCD, SMS, PAL&lt;br /&gt;
* [http://www.riccibitti.com Alberto Ricci Bitti] u.a. PAL Video-Interface&lt;br /&gt;
* [http://www.ulrichradig.de Mikrocontroller and more] AVR - Projekte (Ethernet, LCD, Relaiskarte usw.) und mehr&lt;br /&gt;
* [http://home.arcor.de/burkhard-john/index.html Burkhard John] (D)&lt;br /&gt;
* [http://home.planet.nl/~meurs274/ AVRmicrocontrollerprojects] u.a. Text-LCD, Schrittmotor, Thermometer&lt;br /&gt;
* [http://hem.bredband.net/robinstridh/ Robin Stridh] Rotor-Anzeige, Video-Interface&lt;br /&gt;
* [http://www.dertien.dds.nl/content/avrprojects.html dertien.dds.nl AVR-Projects]&lt;br /&gt;
* [http://www.microsps.com MicroSPS.com] Grafische Programmierung des AVR mit EAGLE&lt;br /&gt;
* [http://www.h-mpeg.de h-mpeg Festplatten mp3 Player] IDE Ansteuerung, IDE Filesystem, LCD Ansteuerung etc. in 8K Code. Quelltext unter GPL&lt;br /&gt;
* [http://www.embedtronics.com/ embedtronics.com]&lt;br /&gt;
* [http://www.siwawi.arubi.uni-kl.de/avr_projects  M. Thomas&#039; AVR Projekte] untern Anderem AVR Butterfly avr-gcc-port, DB101 gcc-port, BC100 gcc-port, Bootloader, Programmier- und Debughardware, Software-UART, DS1820-Lib., experimentelle avrdude-Versionen, AVR und CAN mit MCP2515 &amp;lt;!-- Vorsicht &amp;quot;Eigenwerbung&amp;quot; --&amp;gt;&lt;br /&gt;
* [http://www.mictronics.de Michaels Electronic Projects] AVR Projekte (EN) - ua. Sony/Becker CD/MD Wechsler Emulator, RDS-Decoder, GPS Infos, OBD J1850 VPW Interface, USB&amp;lt;&amp;gt;CAN Bus Interface. Informationen zu CD Wechsler Protokollen. MP3stick - MP3 Player mit ATmega128, color LCD, SD/MMC Karte und VS1011b&lt;br /&gt;
* [http://www.stahlbucht.de/elektronik/node13/ node13] modulares AVR 8515 Projekt: eine Controller-Platine, an die sich weitere Ein-Ausgabemodule (Tastenfeld, LEDs, LCD-Modul) anschliessen lassen&lt;br /&gt;
* [http://www.mikrocontroller-projekte.de www.mikrocontroller-projekte.de] Diverse Projekte mit AVR Controllern. AVR910 Programmer, Testboard und Modellbauelektronik&lt;br /&gt;
* [http://www.roboternetz.de/phpBB2 Roboternetz-Mikrocontroller Projekte.de] Diverse Projekte mit AVR und anderen Controllern, insbesondere im Bereich Robotik&lt;br /&gt;
* [http://www.avr-projekte.de AVR-Projekte.de] Belichtungstimer, FT232RL Schaltungen,LED-Fading über Fernbedienung, HD44780-LCD über USB und Seriell, AVR910-USB Programmer, Basteleien: Ätzmaschine,Kompressor.&lt;br /&gt;
* [http://openeeg.sourceforge.net/ openeeg.sourceforge.net] Das OpenEEG Projekt befasst sich mit der Entwicklung eines preiswerten Elektro-Enzephalographie (EEG) Geräts und dessen freier Steuersoftware zur Messung elektrischer Gehirnströme. Sein µPC-Herz ist ein AT90S4433 bzw. ein ATmega8. Ziel sind auch verschiedene EEG Anwendungen z.B. im Bereich mentaler Trainingsmethoden (Neurofeedback).&lt;br /&gt;
* [http://www.amateurfunkbasteln.de/ www.amateurfunkbasteln.de] Seite von Michael Wöste (DL1DMW) u.a. CPU-Board mit AT89C2051, AT89C4051 oder AVR AT90S2313, CPU-Board mit Atmel AT90S8535, Experimentierplatine mit ATmega103, Programmer für AT89C2051/AT89C4051, 32-Kanal-Logik-Analysator bis 40 MHz (Entwurf von David L. Jones)&lt;br /&gt;
* [http://www.atmel.com/dyn/products/app_notes.asp?family_id=607 Atmel - AVR 8-Bit RISC - Application Notes] Anwendungshinweise und Beispiele vom Hersteller&lt;br /&gt;
* [http://www.projects.cappels.org/ Dick Cappels&#039; Project Pages]&lt;br /&gt;
* [http://see-by-touch.sourceforge.net/index.html SeebyTouch - Blinden-Seh-Ersatzsystem] Computerbilder fühlen durch ein einfaches Gerät (Bauanleitung) und freier Software (für 10 Betriebssysteme) - eine neue Erfahrung für alle&lt;br /&gt;
* [http://www.loetstelle.net www.loetstelle.net] Verschiedene kleinere AVR-Projekte rund um LEDs, z.B. RGB Dimmer, Moodlight. Diverse Elektronikprojekte und Grundlagen&lt;br /&gt;
* [http://www.dietmar-weisser.de Selbstbauprojekte Elektronik] kleine Sammlung von Elektronikprojekten zum Thema Leiterplattenfertigung, Hochfrequenztechnik und Mikrocontroller.&lt;br /&gt;
* [http://www.myplace.nu/avr/ Jesper&#039;s AVR pages] Yampp MP3 Player, Yaap Programmer, DDS mit 2313+R2R, Gitarrentuner, Frequenzzähler.&lt;br /&gt;
* [http://www.microsyl.com/ MicroSyl MCU] MP3 Player, MegaLoad, HCLoad, Propeller Clock, Freq Meter, BarCode Reader, Door Bell, OneWire Lib, Text LCD Lib, Graph LCD Lib, Nokia LCD Lib, Led Sign with MMC MemoryCard, Intercom&lt;br /&gt;
* [http://www.jeroen.homeunix.net/ http://www.jeroen.homeunix.net/] Aufbau eines elektronischen Rouletts auf basis eines AVRs&lt;br /&gt;
* [http://thomaspfeifer.net thomaspfeifer.net] Reflow-Ofen, Laminator-Temperaturregelung, USB-Atmel-Programmer, SMD-Tricks u.v.m.&lt;br /&gt;
* [http://www.scienceprog.com Scienceprog - embedded theory and projects] - AVR, ARM theory and projects&lt;br /&gt;
* [http://www.iuse.org Hausautomatisierung] - CAN-Bus mit ATmega32-Controllern und Bedienfeldern, Admin-Tools zum Updaten via CAN, Traffic Dumper etc.&lt;br /&gt;
* [http://www.myevertool.de AVRSAM] - AT91SAM7S Header Board annährend 100% Pinkompatibel zu den folgenden AVR Mikrocontroller: AT90S8535 / ATMEGA8535 / ATMEGA16 / ATMEGA32&lt;br /&gt;
* [http://members.aon.at/hausbus Hausbus Home] - Hausbus-Projekt unter Verwendung von ATmega8, ATtiny13 und ATmega128&lt;br /&gt;
* [http://www.thomas-wedemeyer.de/elektronik/AVR/avr-dcf-clock.html AVR-DCF-Clock] - DCF-Uhr mit bunter LED-Anzeige - ATmega8&lt;br /&gt;
* [http://www.grasbon.de/genuhr.html GenuhR] - DCF-Funkuhr / Wecker/ Timer mit LED-Punktmatrixanzeige. Das Projekt beschreibt den Aufbau des kompletten Gerätes beginnend beim Schaltplan bis hin zur Montage in ein Gehäuse.&lt;br /&gt;
* [http://www.avrguide.com/ AVR Projektsammlung] bei www.avrguide.com&lt;br /&gt;
* AVR Synth http://www.elby-designs.com/avrsynth/avrsyn-about.htm http://www.jarek-synth.strona.pl/&lt;br /&gt;
* [http://elm-chan.org/he_e.html Electronic Lives Manufacturing] - Aufbauten in Fädeldrahttechnik, tlw. auf Japanisch, aber mit englischen Sourcecodes&lt;br /&gt;
* AVR Synthesizer http://www.avrx.se/&lt;br /&gt;
* [http://freenet-homepage.de/wedis-bastelecke/ Wedis-Bastelecke] - Modellbahn DCC-Servo-Zubehördecoder DCC Servo Decoder mit ATmega8 / Servo Differenzierbaugruppe für Modellbau&lt;br /&gt;
* http://www.electronicspit.com - Verschiedene Elektronikprojekte (LED-Matrix, PAL-Video)&lt;br /&gt;
* http://web.archive.org/web/20050415222337/http://www.hebel23.de/ RDS RADIO: ATMega32, TEA5757, T6963C, TDA7330B in C&lt;br /&gt;
* [http://www.gasenzer.dk Analog/Digital and MPU Eletronic Projects] PAL/VGA Terminal, CallerID, Ethernet, Wireless Bridge, LPC2214, AT91RM9200, Sony Unilink Controlled Wireless MP3 Player.&lt;br /&gt;
* [http://www.circuitcellar.com/avr2004/ Circuit Cellar AVR Design Contest 2004] mit Projektbeschreibungen&lt;br /&gt;
* [http://www.circuitcellar.com/avr2006/ Circuit Cellar AVR Design Contest 2006] mit Projektbeschreibungen&lt;br /&gt;
* [http://www.heesch.net/avr.aspx www.heesch.net/avr.aspx] AVR Mikrokontroller Projekte, z.B. IDE-Interface, DS1821 Thermometer, Morse-Dekoder&lt;br /&gt;
* [http://www.schaltungsforum.de Das Schaltungsforum] ist eine Seite für Anfänger und Profis welche ständig mit Tutorials erweitert wird. Stellt Eure Projekte online. Die Seite befindet noch im Aufbau und Eure Mithilfe ist erwünscht.&lt;br /&gt;
* [http://avrprojekte.de/] Viele Projekte mit LEDs(LED-Matrixen) und AVRs&lt;br /&gt;
* [http://arduino.milkcrate.com.au/ little-scale&#039;s arduino page]&lt;br /&gt;
&lt;br /&gt;
==== Schnittstellen ====&lt;br /&gt;
===== TCP/IP =====&lt;br /&gt;
* [http://www.laskater.com/projects/uipAVR.htm TCP/IP Stack für AVR] mit Realtek RTL8019AS oder Axis AX88796 Netzwerk-Chips (open source für avr-gcc und Imagecraft). Passende Hardware in [http://www.edtp.com/ diesem online-shop]&lt;br /&gt;
* [http://www.ethernut.de Ethernut] - AVR based Hardware with Ethernet-Interface, Multithreading OS, Software and Hardwaredesign is free&lt;br /&gt;
* [http://www.ethersex.de/index.php/Feature_Liste Ethersex] - Trotz des bescheuerten Namens sehr empfehlenswert. Viele flexibel einbindbare Module für diverse Hardware.&lt;br /&gt;
* [http://wiki.neo-guerillaz.de OpenMCP] Bekanntes Board auf Basis des ATmega2561 und ENC28j60. Läuft auf auf dem AVR-NETIO und dem myAVR.&lt;br /&gt;
* [http://www.cesko.host.sk/IgorPlugUDP/IgorPlug-UDP%20(AVR)_eng.htm IgorPlug-UDP AVR] - Ethernet &amp;amp; UDP/IP in Software implementiert&lt;br /&gt;
* [http://members.home.nl/bzijlstra/software/examples/RTL8019as.htm] RTL8019 Bascom&lt;br /&gt;
* [http://members.home.nl/bzijlstra/software/examples/RTL8019as.htm AVR und RTL8019]&lt;br /&gt;
* [http://avr.auctionant.de/avr-ip-webcam AVR IP Webcam] &lt;br /&gt;
* http://mikrocontroller.cco-ev.de/de/webcam.php&lt;br /&gt;
* [http://avr.auctionant.de/avrETH1/ avrETH1 - Webserver mit enc28j60 und Webcam-Support]&lt;br /&gt;
* [http://www.sics.se/~adam/uip/ uIP-Stack, Teil des Contiki OS]&lt;br /&gt;
* [http://www.harbaum.org/till/spi2cf/ WLAN-Implementierung auf Basis einer PRISM-CF-Karte und uIP]&lt;br /&gt;
* http://www.circuitcellar.com/AVR2006/winners/DE/AT2581.htm MEGA128(CAN) PCMCIA&lt;br /&gt;
* [http://www.ic-board.de/index.php?cat=c2_ICnova-Module.html AVR32 AP7000 Linux Board] mit 2xEthernet, TFT, Audio, SDCARD, USB-Host/Devive, Funk...&lt;br /&gt;
* [https://berlin.ccc.de/wiki/AVR-Board_mit_Ethernet AVR-Board mit Ethernet mit dem ENC28J60 von Microchip]&lt;br /&gt;
* [http://www.roland-riegel.de/mega-eth/ AVR-Ethernet-Board mit extra SRAM, SD/MMC, USB und zugehöriger Software]&lt;br /&gt;
&lt;br /&gt;
===== CAN =====&lt;br /&gt;
* [http://www.canathome.de/ Can@Home] - CAN als &amp;quot;Installationsbus&amp;quot;, u.a. mit AVRs (D)&lt;br /&gt;
* [http://www.iuse.org/ www.iuse.org] - Hausautomatisierung auf CAN Basis&lt;br /&gt;
* [http://www.port.de/ www.port.de] - Professionelle CAN/CANopen Entwicklungswerkzeuge&lt;br /&gt;
* [http://can-wiki.info CAN-WIKI] - spezielle Wiki Site für CAN bus (Englisch)&lt;br /&gt;
* [[CAN-Bus]] - Eintrag in diesem Wiki&lt;br /&gt;
* [[CAN als Hausbus]] - Eintrag in diesem Wiki&lt;br /&gt;
* [http://www.canhack.de/ www.canhack.de] - Ein Forum, dass sich mit dem CAN bus im Auto beschäftigt&lt;br /&gt;
* [http://www.edevices.lt/  www.edevices.lt ] - USB2CAN inexpensive USB to CAN bus converter&lt;br /&gt;
&lt;br /&gt;
===== USB =====&lt;br /&gt;
* [http://www.cesko.host.sk/IgorPlugUSB/IgorPlug-USB%20(AVR)_eng.htm Igor-Plug] - USB Device interface in AVR Firmware - no extra Interface IC needed, read the License&lt;br /&gt;
* [http://www.obdev.at/products/vusb/index-de.html V-USB] &amp;amp;#8211; USB-Implementation in C nach gleichem Prinzip wie Igor-Plug, aber einfacher zu verwenden, GPL-ähnliche Lizenz (Nutzung des Projekts &#039;&#039;erfordert&#039;&#039; Veröffentlichung), englisch kommentierter Code&lt;br /&gt;
* [http://www.xs4all.nl/~dicks/avr/usbtiny/ USBTiny] &amp;amp;#8211; weitere Software-USB-Implementierung in C; sehr ähnlich AVR-USB; steht aber unter GPL; relativ wenige Beispiele&lt;br /&gt;
* MJoy USB Joystick Controller on AVR ATmega8&lt;br /&gt;
* [http://www.ime.jku.at/tusb/ TUSB3210-Controller, HID, LIBUSB] Ein Projektseminar, in dem es darum ging, die USB-Schnittstelle des TUSB3210 zu aktivieren und die Daten eines ADC an den PC zu senden. USB-Implementierung für µC und PC.&lt;br /&gt;
* [http://www.b-redemann.de Steuern und Messen mit USB - FT232, 245 und 2232] Das aktuelle Buch zu den USB-Controllern von FTDI. Viele Beispielprogramme in C, zwei Projektbeschreibungen: I²C-Bus mit LM75A und ein Web-Projekt. Bauteilesatz und USB-Modul mit dem FT2232 zum schnellen Einstieg in die Thematik. Buch / Teilesatz über Segor oder dieser Seite erhältlich.&lt;br /&gt;
* [http://www.eltima.com/products/usb-over-ethernet/ USB to Ehternet Connector] - Share your USB devices via LAN/Internet&lt;br /&gt;
* [http://www.ixbat.de Viele kleine USB Projekte] Rund um die Bibliothek usbn2mc http://usbn2mc.berlios.de. Dies ist eine einfache Bibliothek für den USBN9604/03 von National Semiconductor&lt;br /&gt;
* [http://www.rahand.eu Mega8D12] - Schritt für Schritt zum virtuellen COM-Port. Ein Einsteiger-Tutorial zur CDC-Klasse mit Schaltung und Firmware (ATmega8 und PDIUSBD12).&lt;br /&gt;
* http://www.maares.de/tools USB_ISO: Isolierter Schnittstellenwandler USB auf RS232 (TTL) mit FT232RL und ADUM1402. Galvanische Trennung für das Zielsystem.&lt;br /&gt;
&lt;br /&gt;
===== DMX512 =====&lt;br /&gt;
* [http://Dworkin-DMX.de Konverter RS232 zum DMX512] Steuerung DMX-fähigen Geräten mit einem PC. Es gibt Low cost Variante zum selber basteln.&lt;br /&gt;
* [http://www.hoelscher-hi.de/hendrik/light/profile.htm Hennes Sites] Bauanleitungen für DMX-Dimmerpacks, DMX-Switchpacks, PWM-Controller, ... Tutorial für Senden und Empfangen von DMX-Daten mit AVRs.&lt;br /&gt;
* [http://www.lj-skinny-development.de/lj2000/ DMX Lichtanlage im Selbstbau] Projekt für den Selbstbau einer kompletten Lichtanlage zur Steuerung über DMX. Projekt beinhaltet alles was man für den Betrieb einer eigenen Lichtanlage benötigt (Mischpult, Steuersoftware, Dimmer, Scanner mit Iris, Shutter-Dimmer, 2 rotierenden Goborädern, 2 Farbrädern, CMY-Farbmischeinheit, Prisma, Fokus ...).&lt;br /&gt;
* [http://digital-enlightenment.de Digital Enlightenment ]Verschiedene DMX-Selbstbauprojekte&lt;br /&gt;
&lt;br /&gt;
===== PS2 =====&lt;br /&gt;
* [http://www.avrfreaks.net/index.php?module=Freaks%20Academy&amp;amp;func=viewItem&amp;amp;item_id=1086&amp;amp;item_type=project&amp;amp;timestamp=2007-09-04%2018:34:41 PC keyboard to an AVR]&lt;br /&gt;
&lt;br /&gt;
===== LANC =====&lt;br /&gt;
* [http://dsc.ijs.si/3dlancmaster/ 3D LANC Master from Damir Vrancic] is a device which keeps in synchronisation some of Sony camcorders by using LANC (CONTROL-L, ACC) protocol. (Open Hardware + Open Source, Atmega8).&lt;br /&gt;
* [http://jochendony.homeip.net/content/view/22/26/ LANC Lib] for AVRGCC. Read and write LANC commands.&lt;br /&gt;
* [http://blog.makezine.com/archive/2008/12/controlling_sony_camcorders_with_th.html Controlling Sony camcorders with the Arduino]&lt;br /&gt;
&lt;br /&gt;
===== MMC/SD-Card =====&lt;br /&gt;
* [http://www.roland-riegel.de/sd-reader/index.html MMC/SD card reader example application] von Roland Riegel (Atmega8, Atmega168 für FAT16)&lt;br /&gt;
* [http://www.captain.at/electronic-atmega-mmc.php MMC Flash] bzw.  [http://www.captain.at/electronic-atmega-sd-card.php SD Flash ] Memory Extension für Atmegas von Captain. (Atmega16, Atmega32)&lt;br /&gt;
* http://arm.hsz-t.ch MMC, SD, SDHC Kartentreiber für ARM7 Mikrocontroller&lt;br /&gt;
* [http://www.mikrocontroller.net/articles/FAT32 Wiki und FAT16/32 Bibliothek für atmega]&lt;br /&gt;
&lt;br /&gt;
==== LC-Displays ====&lt;br /&gt;
&lt;br /&gt;
===== Text (character-mode) HD44870 =====&lt;br /&gt;
* [http://jump.to/fleury P.Fleury]&lt;br /&gt;
* avrfreaks Projekt 59 (Chris E.) und andere&lt;br /&gt;
* Procyon avrlib v. Pascal Slang (GPL)&lt;br /&gt;
* Bray&lt;br /&gt;
* [http://www.sprut.de/electronic/lcd/index.htm Spruts LCD-Seite]&lt;br /&gt;
* [http://elm-chan.org/docs/lcd/lcd3v.html Standard-LCD auf 3V betreiben (eng)]&lt;br /&gt;
* [http://www.harbaum.org/till/lcd2usb LCD2USB, LCD mit AVR am USB betreiben]&lt;br /&gt;
&lt;br /&gt;
===== Grafik T6963C etc. =====&lt;br /&gt;
&lt;br /&gt;
* http://www.holger-klabunde.de/avr/avrboard.htm#t6963&lt;br /&gt;
* [[Projekt T6963-LCD-Ansteuerung]] nur PC, keine Änderung seit Juli 2006&lt;br /&gt;
* avrfreaks.net - TOSHIBA_LCD_T6963C, AVR Graphics&lt;br /&gt;
* http://www.mikrocontroller.net/topic/48456 C&lt;br /&gt;
* http://www.mikrocontroller.net/topic/54563 C&lt;br /&gt;
* http://www.mikrocontroller.net/topic/48584 ASM&lt;br /&gt;
* [http://passworld.co.jp/ForumMSP430/viewtopic.php?t=47 Grafik LCDs] - 128 x 112 Grayscale für MSP430 und andere uCs.&lt;br /&gt;
* http://www.display3000.com/ Farb-TFT-Module inkl. Mikrocontroller (ATMega128; ATMega2561 und AT90CAN128)&lt;br /&gt;
* [http://www.tklinux.de/sed1330.html SED1330 an ATMega]. Library für SED 1330 controller an ATmega&lt;br /&gt;
In der Codesammlung gibt es auch für andere Controller was.&lt;br /&gt;
&lt;br /&gt;
===== Siemens S55/C60 =====&lt;br /&gt;
* [http://sandiding.tripod.com/m55.html S55-Display Pinbelegung]&lt;br /&gt;
* [http://www.mikrocontroller.net/topic/22643 Forumbeitrag]&lt;br /&gt;
&lt;br /&gt;
===== Siemens S65/M65/CX65 =====&lt;br /&gt;
* [http://www.superkranz.de/christian/S65_Display/DisplayIndex.html S65-Display] vom Siemens S65/M65/CX65, 132x176 Pixel, 65536 Farben, günstig als Ersatzteil zu bekommen.&lt;br /&gt;
&lt;br /&gt;
===== Nokia 3210/3310 =====&lt;br /&gt;
* [http://www.microsyl.com MicroSyl.Com]&lt;br /&gt;
&amp;lt;!-- * [http://www.microsyl.com/nokialcd/shematic.gif Belegung] --&amp;gt;&lt;br /&gt;
* [http://www.deramon.de/nokia3310lcd.php Deramon.de]&lt;br /&gt;
&amp;lt;!-- [[Bild:Beispiel.jpg]] --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===== Nokia 6100 LCD =====&lt;br /&gt;
&amp;lt;!-- * [http://www.apetech.de/article.php?artId=3&amp;amp;nnId=12 Nokia 6100 LCD Library] für Nokia-Displays 132x132 Pixel, 4096 Farben mit Philips Controller (bei eBay ziemlich preiswert zu ersteigern) --&amp;gt;&lt;br /&gt;
* [http://www.myplace.nu/mp3/download/download.php Yampp 7 Software Download Seite]: Archiv &amp;quot;yampp-7 with colour LCD firmware&amp;quot; enthält avr-gcc/avr-as Routinen für 6100-LCDs mit Philips- oder Epson-Controller (nicht direkt eine &amp;quot;Library&amp;quot;)&lt;br /&gt;
*[http://www.e-dsp.com/controlling-a-color-graphic-lcd-epson-s1d15g10-controller-with-an-atmel-avr-atmega32l/ S1D15G10]: Routine code für den Epson S1D15G10 Controller&lt;br /&gt;
*[http://thomaspfeifer.net/nokia_6100_display.htm Nokia 6100 Display am AVR] Anzeige von RGB-Bildern (für avr-gcc)&lt;br /&gt;
*[http://www.optixx.org/ www.optixx.org] Code zur Ansteuerung von Philips und Epson&lt;br /&gt;
&lt;br /&gt;
===== KS0108 =====&lt;br /&gt;
* [http://hubbard.engr.scu.edu/embedded/avr/avrlib Procyon avrlib (GPL)]&lt;br /&gt;
* avrfreaks UP&lt;br /&gt;
* apetech.de nicht mehr erreichbar http://www.mikrocontroller.net/topic/68316&lt;br /&gt;
&lt;br /&gt;
====GPS====&lt;br /&gt;
* http://www.holger-klabunde.de/avr/avrboard.htm#GPSdisplay GPS-Daten auf LCD&lt;br /&gt;
* [http://www.geoclub.de/forum57.html www.geoclub.de] - Elektronik beim Geocaching&lt;br /&gt;
* [http://passworld.co.jp/ForumMSP430/viewtopic.php?t=22 passworld.co.jp] - Do It Yourself GPS&lt;br /&gt;
&lt;br /&gt;
== [[8051|8051 / MCS51]] ==&lt;br /&gt;
* [http://mcu8051ide.sourceforge.net/ MCU 8051 IDE] - MCU 8051 IDE is a new modern graphical IDE for microcontrollers based on 8051. MCU 8051 IDE is noncommercial open-source software for Linux.&lt;br /&gt;
* [http://www.rakers.de/catalog Dr. Rakers] Entwicklungssystem mit C-Compiler, BASIC-Compiler und Makroassembler für alle 8051-Mikrocontroller (80C552, 80C515(C), 80C537). Auch für Hobbyisten bezahlbar.&lt;br /&gt;
* [http://www.progshop.com/versand/software/prog-studio/index.html Prog-Studio] - Moderne Assembler Entwicklungsumgebung für 8051 Mikrocontroller mit Debugger, Edit &amp;amp; Continue, Code-Folding, Intelli-Sense, Monitorung und mehr&lt;br /&gt;
* [http://www.yCModule.de yCModule: µController-Systeme] - Preisgünstige µController-Module, ISP-Programmiertools und Applikationsboards&lt;br /&gt;
* [http://www.erikbuchmann.de/ Erik Buchmanns Mikrocontroller-Seite] - Assemblerkurs und mehrere Projekte&lt;br /&gt;
* [http://www.holger-klabunde.de/projects/8051.htm Experimentierboard für 8051 Controller] von Holger Klabunde.&lt;br /&gt;
* [http://www.woe.de.vu/ World Of Electronics] - Projekte mit den 8051-Controllern von Atmel&lt;br /&gt;
* [http://www.thomas-wedemeyer.de/elektronik/8051/8051.html Controllerplatine mit SAB80C535]&lt;br /&gt;
* [http://www.maxim.ph.tc Selbstbau-Programmer] für 2051er&lt;br /&gt;
* [http://www.nomad.ee/micros/8052bas.html 8052 BASIC Projects] - IDE-Interface&lt;br /&gt;
* [http://home.t-online.de/home/s.holst/sh51/index.html Mikrokontroller sh51] Schaltplan für 80C535-Board&lt;br /&gt;
* 8051-Makroassembler [http://plit.de/asem-51/ ASEM-51] (Freeware)&lt;br /&gt;
* [http://sdcc.sourceforge.net/ SDCC - Small Device C Compiler] - freier ANSI-C compiler für Intel 8051, Maxim DS80C390 und Zilog Z80 kompatible Controller.&lt;br /&gt;
* [http://sdccokr.dl9sec.de/ The SDCC Open Knowledge Resource]&lt;br /&gt;
* [http://www.wickenhaeuser.de/ Wickenhäuser C Compiler] - Preisgünstiger C Compiler&lt;br /&gt;
* [http://home.tiscali.cz:8080/~cz056018/lanc_a.htm LANC-Remote] Projekt von Ji&amp;amp;#345;í &amp;amp;#352;mach zur Steuerung von Videorekordern oder Camcordern über das Control-L (LANC) Protokoll mit Hilfe eines AT89C2051.&lt;br /&gt;
* [http://www.microcontroller-starterkits.de Microcontroller-Starterkits] Starter-Kits für verschiedene Microcontroller (D) preisgünstige Platinen (ab 12,95 Euro für AT89S8252). Beim uC-Dualboard : Das Board ist nutzbar mit AVR-Controllern und 8051-Controllern!&lt;br /&gt;
* [http://turbo51.com Turbo51 - Free Pascal compiler for 8051]&lt;br /&gt;
* [http://self8051.de/ self8051.de] - Dein Nachschlagewerk - Befehlsreferenz, Eigenschaften, Derivate&lt;br /&gt;
&lt;br /&gt;
== MSP430 ==&lt;br /&gt;
* [http://www.mathar.com MSP430 Tutorials] - Tutorials, Anleitungen und viele Beispielprojekte mit dem MSP430-Mikrocontroller&lt;br /&gt;
* [http://www.student-zw.fh-kl.de/~stwi0001/imp/msp430/pwm430/index.htm Pulsweitenmodulation mit dem MSP430] - sehr ausführliche Einführung&lt;br /&gt;
* [http://www.thomas-wedemeyer.de/elektronik/msp430/msp430.html Kleine Projekte mit dem MSP430] - Schaltplan und Layout zu einem MSP430F149-Board und einem ADXL-G-Sensor mit MSP430&lt;br /&gt;
* [http://tinymicros.com/embedded/MSP430/ The MSP430 Bugspray Database] - umfangreiche Datenbank für Bugs in MSP430-Controllern&lt;br /&gt;
* [http://msp430.info MSP430.info] - Portalseite für MSP430; Info, Projekte (MIDI, USB)&lt;br /&gt;
* [http://groups.yahoo.com/group/msp430 Yahoo group MSP430] - lebhaftes Forum mit vielen MSP430-Experten&lt;br /&gt;
* [http://homepage.hispeed.ch/py430/mspgcc/ mps430-gdb und Eclipse] - Eine Anleitung von Chris Liechti&lt;br /&gt;
* [http://passworld.co.jp/ForumMSP430 Forum MSP430] - Projekte mit MSP430 (GPS, BlueTooth usw...)&lt;br /&gt;
* TI Design-WEttbewerb: http://www.designmsp430.com/View.aspx (dateien liegen evtl. in /projects/)&lt;br /&gt;
* [http://www.sics.se/project/mspsim MSPsim] - a Java-based simulator of MSP430 sensor network platforms (BSD License (revised))&lt;br /&gt;
* [http://develissimo.net/de/msp430entwicklung MSPGCC + Eclipse + msp430-gdbproxy / Linux / Debian / Ubuntu] - Anleitung / Tutorial zur Installation der MSPGCC Toolchain + Eclipse + msp430-gdbproxy für Linux / Debian / Ubuntu Lang=Deutsch und Englisch&lt;br /&gt;
* [http://travisgoodspeed.blogspot.com/ Travis Goodspeed&#039;s Blog]&lt;br /&gt;
&lt;br /&gt;
== ARM ==&lt;br /&gt;
&lt;br /&gt;
=== Herstellerseiten ===&lt;br /&gt;
* [http://www.arm.com ARM] - Entwickler des ARM-Prozessorkerns (kein Hersteller von ICs)&lt;br /&gt;
* [http://infocenter.arm.com ARM Infocenter] Sammlung Technischer Informationen&lt;br /&gt;
&lt;br /&gt;
* [http://www.analog.com/ Analog Devices] ADuC7xxx ARM7TDMI Serie unter &#039;&#039;Analog Microcontrollers&#039;&#039;&lt;br /&gt;
* [http://www.atmel.com/products/AT91/ Atmel AT91 Startseite]&lt;br /&gt;
* [http://www.at91.com AT91.COM] - Atmel ARM Informationsseite (Forum, Beispielcodes etc.)&lt;br /&gt;
* [http://www.cirrus.com/en/products/pro/techs/T7.html Cirrus Logic]&lt;br /&gt;
* [http://www.filmetrics.com  Filmetrics Inc.] (Filmetrics manufactures affordable thin-film measurement instruments capable of measuring thin films from 3nm to 0.5mm in thickness.)&lt;br /&gt;
* [http://www.freescale.com/mac7100 Freescale MAC7100]&lt;br /&gt;
* [http://www.hilscher.com Hilscher netX] (ARM926 core)&lt;br /&gt;
* [http://www.intel.com/design/intelxscale/ Intel XSCALE Startseite], siehe auch [http://www.marvell.com/ Marvell]&lt;br /&gt;
* [http://www.luminarymicro.com/ Luminiary Micro] Controller mit Cortex M3 core&lt;br /&gt;
* [http://www.standardics.nxp.com/microcontrollers/ NXP (ehemals Philips) Microcontroller Startseite] für sämtliche Mikrocontroller (ARM7, MCS51 etc.), neben LPC2000, LPC3000 auch die LH7xxxx BlueStreak-Serie (ehemals Sharp Microelectronics)&lt;br /&gt;
* [http://www.lpc2000.com lpc2000.com] Infoseite für NXP (ex. Philips) LPC1700 Cortex-M3 basierende Typen, LPC2000, ARM7 basierende Typen und LPC3000, ARM9 basierende Typen. Auch andere Cortex-M3 Bausteine sind erfasst&lt;br /&gt;
* [http://www.okisemi.com/eu/1.Products/ARM32bit.html OKI ARM-Controller Startseite]&lt;br /&gt;
* [http://www.samsung.com/Products/Semiconductor/ Samsung] ARM7/9 unter &#039;&#039;Mobile SoC&#039;&#039;&lt;br /&gt;
* [http://mcu.st.com/mcu/ STMicroelectronics (ST) Microcontroller Startseite] u.a. STR7, STR9, STM32 Support-Forum&lt;br /&gt;
* [http://www.ti.com/ Texas Instruments] TMS470 ARM7TDMI Serie&lt;br /&gt;
&lt;br /&gt;
=== Information (Foren, Mailinglisten, Linksammlungen) ===&lt;br /&gt;
* [http://www.neko.ne.jp/~freewing/cpu/arm_olimex/ Freewing Linksammlung] zu den NXP (ex. Philips) LPC-ARM7-Controllern (Assemblerbeispiele u.a. für Nokia 3310-GLCD)&lt;br /&gt;
* [http://www.open-research.org.uk/ARMuC ARM Microcontroller Wiki]&lt;br /&gt;
&lt;br /&gt;
* [http://tech.groups.yahoo.com/group/ADuC7000/ ADuC7000 Yahoo-Group]&lt;br /&gt;
* [http://www.at91.com AT91 Forum] (Atmel Rousset)&lt;br /&gt;
* [http://tech.groups.yahoo.com/group/AT91SAM/ AT91SAM Yahoo-Group]&lt;br /&gt;
* [http://en.mikrocontroller.net/forum/17 arm-elf-gcc WinARM Forum] (auch für Yagarto)&lt;br /&gt;
* [http://www.codesourcery.com/archives/arm-gnu/maillist.html Sourcery G++ Lite Edition User Forum/Mailing-List&lt;br /&gt;
* [http://tech.groups.yahoo.com/group/gnuarm/ GNUARM Yahoo-Group]&lt;br /&gt;
* [http://www.keil.com/forum/ Keil/ARM Forum]&lt;br /&gt;
* [http://groups.yahoo.com/group/lpc2000/ LPC2000 Yahoo-Group]&lt;br /&gt;
* [http://www.mcu-related.com MCU related] Neuigkeiten zu MCUs, überwiegend ARM / Cortex-M3 basierend mit Vergleichen von RTOS und anderen Entwicklungstools&lt;br /&gt;
* [http://forum.sparkfun.com/ Sparkfun Foren]&lt;br /&gt;
* [http://mcu.st.com/mcu/modules.php?name=Splatt_Forums STMicroelectronis Forum]&lt;br /&gt;
&lt;br /&gt;
=== Entwicklungswerkzeuge (Compiler/Assembler/Debugger/Tools) ===&lt;br /&gt;
&lt;br /&gt;
* [http://www.st-angliamicro.com/software.asp Anglia Idealist IDE und Anglia Toolchain] GNU toolchain für Win32-hosts inkl. Beispielen für STR7, STR9 und STM32. IDE kostenlost aber registrierungspflichtig&lt;br /&gt;
* [http://www.codesourcery.com/gnu_toolchains/ Codesourcery] GNU Toolchains für ARM (Hosts: Linux, MS Windows, Solaris; Targets: arm-elf, arm-linux, SybianOS)&lt;br /&gt;
* [http://devkitpro.org/ devkitPro/devkitARM] GNU-Toolchain für MS-Windows &amp;quot;Hosts&amp;quot;. Vor allem auf GBA abgestimmt aber auch für andere ARM-Controller geeignet (arm-elf)&lt;br /&gt;
* [http://www.gnuarm.org GNU ARM] GNU Compiler-Toolchain für ARM mit binutils, gcc für C, C++, Java, newlib, gdb/Insight. Binaries für Linux und MS-Windows mit Cygwin&lt;br /&gt;
* [http://www.ghs.com/ Green Hills Software]&lt;br /&gt;
* [http://www.hitex.de Hitex] IDE für diverse Compiler, Debugger&lt;br /&gt;
* [http://www.iar.com IAR] Embedded Workbench, kommerzielle IDE/Compiler, codegrößenbeschränkte Evaluierungsversion verfügbar&lt;br /&gt;
* [http://www.isystem.com/ iSYSTEM] Integrated Development Environment, USB/JTAG interface, OnChip Emulation and Trace&lt;br /&gt;
* [http://www.keil.com Keil/ARM RVDK/uVision] kommerzielle IDE/Compiler, unterstützt zwei Compiler (ARM RealView, GNU/gcc), codegrößenbeschränkte Evaluierungsversion verfügbar (IDE/Compiler unbeschränkt für GNU), guter Debugger, guter Simulator (teilw. mit Hardwaresimulation) Simulator und Debugger in der Evaluierungsversion auch bei Nutzung der GNU-Toolchain auf 16kB beschränkt&lt;br /&gt;
* [http://mct.de/download.html#free MCT Demoversion C-Compiler für ARM und 68k] ARM C-Compiler basiert auf GCC laut Herstellerinformation jedoch mit Codegrößenbeschränkung &amp;lt;!-- etwas ungewöhnlich: Codegrößenbeschränkung bei GNU-Toolchain --&amp;gt;&lt;br /&gt;
* [http://www.mpeforth.com www.mpeforth.com] - A free Forth system with 125 page manual for all Philips LPC2xxx CPUs with at least 64k Flash and 16k RAM and cystal frequency of 10, 12, or 14.7456 MHz. &lt;br /&gt;
* [http://www.rowley.co.uk/ Rowley] Kommerzielle IDE für GNU-Compiler, eigene libc (nicht newlib), Debugger (inkl. gutem Support für Wiggler)&lt;br /&gt;
* [http://h-storm.tantos.homedns.org/gcc_arm.htm Tantos gcc for ARM Targets] eine weitere ARM-GNU-Toolchain für MS-Windows &amp;quot;Hosts&amp;quot; &lt;br /&gt;
* [http://www.yagarto.de Yagarto] GNU arm-elf-Toolchain, Eclipse, OpenOCD für Win32 inkl. Setup&lt;br /&gt;
* [http://www.siwawi.arubi.uni-kl.de/avr_projects/arm_projects/index.html#winarm WinARM] eine an WinAVR angelehnte Sammlung von Entwicklungswerkzeugen (binutils, arm-elf-gcc, newlib, &#039;&#039;newlib-lpc&#039;&#039;, Programmers Notepad, &#039;&#039;Beispiel-Makefiles und Beispielcode&#039;&#039;) für alle ARM-Controller. Beispiele für Philips LPC2000 und Atmel AT91SAM7S (ARM7TDMI) u.a.&lt;br /&gt;
* [http://rtlab.tekproj.bth.se/wiki/index.php/Dissy#Architecture_support Dissy] is a disassembler for Linux and UNIX which supports multiple architectures and allows easy navigation through the code. Dissy is implemented in Python and uses objdump for disassembling files.&lt;br /&gt;
* http://arm.hsz-t.ch Entwicklungsumgebung für ARM7 Mikrocontroller basierend auf der Knoppix CD. Keine Harddisk installation nötig für uClinux.&lt;br /&gt;
&lt;br /&gt;
* [http://openocd.berlios.de/web/ OpenOCD] Open On-Chip Debugger: Schnittstelle (&amp;quot;gdb-Server&amp;quot;) zwischen Wiggler-komaptiblem JTAG-Interface und GNU-debugger (gdb/Insight-gdb), ebenfalls Unterstützung für JTAG-Hardware auf FTDI2232-Basis, Flash-Programmierfunktion für LPC2k, AT91SAM7S u.a.&lt;br /&gt;
* [http://macraigor.com/full_gnu.htm OCDLibRemote] Schnittstelle zwischen WIGGLER-kompatibler JTAG Hardware und dem GNU-Debugger (gdb)&lt;br /&gt;
* [http://gdb-jtag-arm.sourceforge.net/ GDB-JTAG-ARM] GDB JTAG Tools&lt;br /&gt;
* [http://jtagpack.sourceforge.net/ JTAG-Pack] GDB JTAG Tools&lt;br /&gt;
* [http://www.hjtag.com H-JTAG] RDI-Interface für Wiggler, Flash-Funktionen für diverse interne und externe Speicher&lt;br /&gt;
* [http://www.clibb.de/ lpc21isp] Flashutility für LPC21xx, ISP via &amp;quot;Bootloader&amp;quot; (&amp;quot;multiplattform&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
*http://www.abatron.ch Abatron] BDI1000 &amp;amp; BDI2000, On-Chip Debuggers für ARM, 68k, Coldfire uvm.&lt;br /&gt;
* [http://www.amontec.com Amontec] JTAGkey, JTAG-Adapter auf Basis des FTDI2232 &lt;br /&gt;
* [http://www.keil.com Keil/ARM ULINK/ULINK2/ULINK-ME] JTAG-Adapter, USB-Anschluss, wird von Keil uVision unterstützt, ULINK2 teilw. auch von Codesourcery G++ (lt. Hestellerangaben)&lt;br /&gt;
* [http://www.kristech.eu Kristech] USB-Scarab, JTAG Adapter, kommt mit eigener Debugger-UI, kompatibel zu Olimex&lt;br /&gt;
* [http://www.lauterbach.de Lauterbach] TRACE32 JTAG-Adapter, USB und Ethernet-Anschluss, eigene Software&lt;br /&gt;
* [http://www.olimex.com Olimex] JTAG-Adapter: Wiggler-Nachbau (ParPort) und  Adapter auf Basis des FTDI2232 (USB)&lt;br /&gt;
* [http://www.ronetix.at/peedi.html Ronetix Peedi]&lt;br /&gt;
* [http://www.segger.de Segger J-Link] JTAG-Adapter, USB-Anschluss, unterstützt z.B. von IAR, Keil uVision (via RDI) (OEM: IAR J-Link, SAM-ICE)&lt;br /&gt;
* [http://www.signalyzer.com/ Signalyzer] Signalyzer Tool, u.a. JTAG-Adapter auf Basis des FTDI2232&lt;br /&gt;
* [http://www.sinelabore.com sinelaboreRT] - generiert leicht lesbaren C-Code aus einer Zustandsmaschine. Die Generierung berücksichtig speziell die Bedürfnisse eingebetteter Echtzeitsysteme.&lt;br /&gt;
&lt;br /&gt;
=== Tutorials und Beispiele ===&lt;br /&gt;
* [http://www.dreamislife.com/arm/ LPC210x ARM7 Microcontroller Tutorial] - Assembler-Beispiele (arm-elf-as) für das Olimex LPC-MT-Board (Philips LPC2106 ARM7TDMI)&lt;br /&gt;
* [http://re-eject.gbadev.org/index.php gcc-Assembler für ARM] - Befehlsübersicht&lt;br /&gt;
* [http://patater.com/gbaguy/gbaasm.htm GBA ASM Tutorial] - ARM7 Assembler Tutorial mit arm-elf-as (&amp;quot;gcc&amp;quot;) (Allgemein und GBA)&lt;br /&gt;
* [http://www.robsite.de/daten/tutorials/devgba/gba_asm1.html GBA Assembler Tutorial] - ARM7TDMI, Schwerpunkt auf GBA&lt;br /&gt;
* [http://www.sparkfun.com/tutorial/ARM/ARM_Cross_Development_with_Eclipse.pdf Eclipse+CDT+gnuarm-Tutorial]&lt;br /&gt;
* [http://mct.de/download/armsamples/map.html Beispiele in C, für ARM7-Controller von Philips und ADI]&lt;br /&gt;
* [http://www.embedded.com/design/opensource/201802580 Embedded.com: Building Bare-Metal ARM Systems with GNU] Teil 10, Links zu den Teilen 1-9 auf der Seite&lt;br /&gt;
* [http://www.sparkfun.com/datasheets/DevTools/SAM7/at91sam7%20serial%20communications.pdf AT91SAM7 Serial Communications] von James P. Lynch (PDF, www.sparkfun.com)&lt;br /&gt;
* [http://www.kaczurba.pl/aduc ADuC7000 Tutorial] von Witold Kaczurba (www.kaczurba.pl)&lt;br /&gt;
&lt;br /&gt;
=== Projekte und Quellcodebibliotheken ===&lt;br /&gt;
* [http://hubbard.engr.scu.edu/embedded/arm/armlib/ Procyon ARMlib-LPC2100] - Treiber, Beispiele (Lizenz: GPL, kaum weiterentwickelt)&lt;br /&gt;
* [http://www.standardics.nxp.com/support/documents/?type=software NXP BlueStreak] Code für LH7xxxx (ehemals Sharp)&lt;br /&gt;
* [http://www.siwawi.arubi.uni-kl.de/avr_projects/arm_projects/index.html M. Thomas&#039; ARM Projekte] &amp;quot;Projectvorlagen&amp;quot; für AT91SAM7 und LPC2000 mit GNU-Toolchain Einsteiger-Projekte für AT91SAM7, LPC2000, ADuC7000 u.a. (u.a. Blinky, UART, Interrupt, C++, GLCD mit KS0108, DS18x20, DCF77, Anpassungen von FAT16/32-Libraries) &amp;lt;!-- noch mehr &amp;quot;Eigenwerbung&amp;quot; --&amp;gt;&lt;br /&gt;
* [http://mcu.st.com/ STMicro] Treiber und Beispiel für STR7, STR9 und STM32&lt;br /&gt;
* [http://www.gnuarm.com/~lpc2000/ Mirror der LPC2100-Group Dateien] (veraltet, aber ohne Yahoo-Account zugänglich.)&lt;br /&gt;
* [http://www.geocities.com/leon_heller/lpc2104.html Simple LPC210x Prototyping System]&lt;br /&gt;
* [http://wiki.sikken.nl/index.php?title=LPCUSB LPCUSB] - Open-source [[USB]] stack for the built-in USB controller in LPC214x microcontrollers von Bertrik Sikken. [http://lpcusb.cvs.sourceforge.net/lpcusb/host/benchmark/main.c?revision=1.2&amp;amp;view=markup Sample code]&lt;br /&gt;
* [http://www.olimex.com Olimex] Einige Beispiele auf den &amp;quot;Produktseiten&amp;quot; der ARM Boards.&lt;br /&gt;
* [[ARM MP3/AAC Player]]&lt;br /&gt;
* [http://www.jcwren.com/arm/ J.C. Wrens Beispielprojekt] für LPC214x&lt;br /&gt;
* [http://www.keil.com/download/list/arm.htm Beispiele von Keil] abgestimmt auf deren Boards und Realview-Toolchain, Portierung auf andere Boards und Compiler relativ einfach, Lizenz beachten.&lt;br /&gt;
* [http://www.luminarymicro.com/ Luminary Micro Driverlib] für Stellaris Cortex-M3&lt;br /&gt;
* [http://r2d2.stefanm.com/gps-tracker.html GPS-Tracker] mit Navigation auf LPC2103-Basis (Complier: GCC)&lt;br /&gt;
* [http://elua.berlios.de elua] Lua für ARM-controller&lt;br /&gt;
* [http://freemodbus.berlios.de/ FreeMODBUS] &amp;quot;A Modbus ASCII/RTU and TCP implementation&amp;quot; (für STR71x, AT91SAM7, LPC214x, auch: AVR, MSP430 u.a.)&lt;br /&gt;
* [http://bettyhacks.com BettyHacks] Freie Firmware für die eingestellte, interaktive TV-Fernbedienung betty-tv&lt;br /&gt;
&lt;br /&gt;
=== Betriebssysteme ===&lt;br /&gt;
* [http://agnix.sourceforge.net/ Agnix]&lt;br /&gt;
* [http://www.bertos.org/ BeRTOS] is a completely free, open source, real time operating system (RTOS) suitable for embedded platforms. Runs on many microprocessors and microcontrollers, ranging from 8 bits to 32 bits CPUs and even PCs. &lt;br /&gt;
* [http://chibios.sourceforge.net/ ChibiOS/RT]&lt;br /&gt;
* [http://sources.redhat.com/ecos/ eCos] - &amp;quot;Real-Time-Operating-System&amp;quot; o.a. auch für ARM7&lt;br /&gt;
* [http://www.freertos.org/ FreeRTOS (.org!)] - &amp;quot;Real-Time-Kernel&amp;quot; unter anderem für ARM7 (LPC2xxx) auch AVR, MSP430, &#039;51er&lt;br /&gt;
* [http://l4ka.org/ L4Ka]&lt;br /&gt;
* [http://www.toradex.com/colibri_downloads/Linux/readme.txt Linux 2.4.29 für Toradex Colibri] basierend auf Intel XScale PXA270&lt;br /&gt;
* [http://www.linux4sam.org Linux4SAM] Informationen, Anleitungen und Code zur Anwendung von Linux auf AT91SAM9xxx&lt;br /&gt;
* [http://www.freertos.com/ NicheTask] (URL ist www.freertos.com aber hat nichts mit FreeRTOS(.org) zu tun)&lt;br /&gt;
* [http://www.ethernut.de/en/software/index.html Nut/OS]&lt;br /&gt;
* [http://nuttx.sourceforge.net/ NuttX RTOS] (ARM7TDMI port for TI TMS320C5471 also called a C5471 or TMS320DM180).&lt;br /&gt;
* [http://www.phoenix-rtos.org/ Phoenix-RTOS]&lt;br /&gt;
* [http://picoos.sourceforge.net/ PicoOS]&lt;br /&gt;
* [http://prex.sourceforge.net Prex] is a portable real-time operating system for embedded systems. The small, reliable, and low power kernel is written in the C language based on microkernel design. The file system, Unix process, and networking features are provided by user mode tasks. (ARM, i386, geplant: MIPS, PowerPC, Hitachi-SH und Win32)&lt;br /&gt;
* [http://www.rtems.org/ RTEMS]&lt;br /&gt;
* [http://www.tnkernel.com/downloads.html TNKernel] - &amp;quot;Real-Time-Kernel&amp;quot; TNKernel ist ein kompakter und sehr schneller Echtzeitkernel unter anderem für ARM7 (Philips LPC2106/LPC21XX/LPC22xx, Samsung S3C44B0X, Atmel AT91SAM7S128, STMicroelectronics STR711FR2)&lt;br /&gt;
* [http://www.ucos-ii.com/ uC/OS-II RTOS]&lt;br /&gt;
* [http://www.DieProjektseite.de BasicBeetle] Basic-Betriebssystem im AVR&lt;br /&gt;
&lt;br /&gt;
=== Hardware (Prototypen-Platinen etc.) ===&lt;br /&gt;
&amp;lt;!-- Ist KEIN ARM-Board, falsche Rubrik! * [http://www.chip45.com/ chip45] Atmel AVR Module und Boards mit USB, RS232/485, CAN, Ethernet, Funkmodule, sowie ISP Programmieradapter --&amp;gt;&lt;br /&gt;
* [http://www.armkits.com/ Embest] Philips, Samsung und Atmel ARM Boards und Module, JTAG-Hard- und Software&lt;br /&gt;
* [http://www.waveplayer.de/ Embedded-Waveplayer] mit ARM7-Prozessor EP7309 (MIDI- und RS232-Steuerung)&lt;br /&gt;
* [http://www.embeddedartists.com/ Embedded Artists] bietet verschiedene preisgünstige Platinen (ab 25 Euro für LPC213x Familie)&lt;br /&gt;
* [http://www.hiteg.com Hiteg] SAMSUNG und Intel XScale basierende boards. (Deutsches Unternehmen in China)&lt;br /&gt;
* [http://www.hitex.de/ Hitex] Starter-Kits für Philips LPC2000, ST STR7, Atmel AT91M&lt;br /&gt;
* [http://www.iar.com/ IAR] Starter-Kits für Atmel, Oki, Philips, ST und TI &lt;br /&gt;
* [http://www.ic-board.de/index.php?cat=c12_ICswift-Module.html ic-board.de] Kommunikationsplattform auf Basis des AT91SAM7X256 mit Ethernet, USB, CAN und Funk Schnittstellen&lt;br /&gt;
* [http://www.keil.com/ Keil] Philips LPC2000 und ST STR7/9 Boards und Starter-Kits&lt;br /&gt;
* [http://www.lpctools.com/ LPCTools] bietet verschiedene Starter Kits für die LPC2000-Familie&lt;br /&gt;
* [http://www.makingthings.com/ MakingThings] Make Controller Kit (AT91SAM7X256)&lt;br /&gt;
* [http://mct.de/index.html MCT Paul und Scherer] Starterkits für ARM7 (NXP LPC2000, ADI ADUC7000)&lt;br /&gt;
* [http://shop.mikrocontroller.net Mikrocontroller.net Shop] Platinen mit AT91SAM7, LPC2xxx, JTAG&lt;br /&gt;
* [http://www.microcontroller-starterkits.de Microcontroller-Starterkits] Starter-Kits für verschiedene Microcontroller (D) preisgünstige Platinen (ab 12,95 Euro für LPC2129 und 2194) sowie Entwicklungsboard komplett bestückt&lt;br /&gt;
* [http://stores.ebay.de/Micro-Research Micro-Research] Development- und Header-Boards für LPC2000 und ADuC7000&lt;br /&gt;
* [http://www.olimex.com Olimex] Bulgarischer Anbieter günstiger ARM Prototypen- und Header-Boards (LPC2000, STR7, AT91SAM, ADI, TI, OKI u.a.)&lt;br /&gt;
* [http://www.propox.com/?lang=en Propox]&lt;br /&gt;
* [http://www.revely.com/ Revely] Evaluations- und Demo-Boards mit Sharp ARM Controllern. Teilweise mit SVGA-Anschluss.&lt;br /&gt;
* [http://www.skpang.co.uk/catalog/index.php SKPang electronics] Entwicklungsboards für diverse ARM7/9 (UK)&lt;br /&gt;
* [http://www.dilnetpc.com SSV Embedded Systems] bietet verschiedene Starter Kits für die verschiedenen DIL/NetPC u.a. (A)DNP/9200 SBC mit AT91RM9200&lt;br /&gt;
* [http://www.taskit.de taskit] [https://ssl.kundenserver.de/taskit.de/at91shop/shop_content.php?coID=10 Development- und Header-Boards für AT91SAM7S/X], AT91RM9200, AT91SAM9&lt;br /&gt;
* [http://www.toradex.com/e/products.html Toradex] Colibri: Intel XScale PXA270 DevKit (Schweiz)&lt;br /&gt;
&lt;br /&gt;
== [[PIC]] ==&lt;br /&gt;
&lt;br /&gt;
=== Herstellerseiten ===&lt;br /&gt;
* [http://www.microchip.com Microchip] Hersteller der PIC Microcontroller&lt;br /&gt;
* [http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&amp;amp;nodeId=1406&amp;amp;dDocName=en010014&amp;amp;part=SW006011 Microchip C18 Student Edition] - die &amp;quot;Student Edition&amp;quot; des Microchip C18 C Compilers für die PIC18 Serie ist kostenlos verfügbar.&lt;br /&gt;
* [http://www.powercontact.de Systemtechnik Leber] Offizieller Microchip Design Partner für professionelles Microcontroller Design und Hersteller von Leistungsstellern, Thyristorstellern und Halbleiterelais...&lt;br /&gt;
&lt;br /&gt;
=== Entwicklungstools / Tutorials / Foren  ===&lt;br /&gt;
* [http://www.osterer.co.at www.osterer.co.at] Entwicklungs-Board mit integrierten Programmer/Debugger für PIC18F4550.&lt;br /&gt;
* [http://www.martins-elektronikwelt.tk www.martins-elektronikwelt.tk] ICD1-Debugger-Nachbau im Kleinstformat u. SMD Technik (so groß wie eine halbe Scheckkarte).&lt;br /&gt;
* [http://www.sprut.de/electronic/pic/index.htm PIC-Microchip-Controller (www.sprut.de)] Diese Seite soll dem Anfänger die ersten Schritte in die Welt der Microcontroller der Firma Microchip erleichtern. Betrachtet werden die 14-Bit-Controller der Serien PIC16Fxxx bzw PIC12Fxxx.&lt;br /&gt;
* [http://www.fernando-heitor.de PIC: Programmierung in CCS (www.fernando-heitor.de)] Dies ist eine weitere Seite die dem Anfänger, der sich mit PICs beschäftigt, auf die Beine hilft. Sie befasst sich hauptsächlich mit dem CCS-Compiler und hat dazu ein sehr gutes Tutorial. Ausserdem bietet die Seite ein Forum speziell für PIC Mikrocontroller.&lt;br /&gt;
* [http://www.cc5x.de CC5X] Programmierkurs für PIC-Microkontroller in C (CC5X Compiler)] Programmierkurs mit Beispielen und Schaltplänen, fertige Hardware- und Softwarelösungen. In diesem Kurs sind auch einige Unterprogramme detailliert erklärt.&lt;br /&gt;
* [http://www.microchipc.com/ MicrochipC.com] Programmieren von PIC-Microcontrollern mit C. (Enthält auch Links und Bootloader für diverse PICs.)&lt;br /&gt;
* [http://www.amodio.biz/projects/PIC10BaseT/index.html Internetworking with Microchip Microcontrollers - PIC18F4620+ENC28J60]&lt;br /&gt;
* [http://pic18fusb.online.fr/wiki/wikka.php?wakka=WikiHome Wiki about Microchip USB PIC] (PIC18F2550, PIC18F4550...)&lt;br /&gt;
* [http://piklab.sourceforge.net/ Piklab] is an integrated development environment for applications based on Microchip PIC and dsPIC microcontrollers similar to the MPLAB environment. It integrates with several compiler and assembler toolchains (like gputils, sdcc, c18) and with the simulator gpsim. It supports the most common programmers (serial, parallel, ICD2, Pickit2, PicStart+) and debuggers (ICD2).&lt;br /&gt;
* [http://www.members.aon.at/electronics/pic/picpgm/_main.html PICPgm - Free PIC Development Programmer for Windows] Einfacher PIC Programmer für Windows. Unterstützt eine Vielzahl von PIC-Chips und wird ständig erweitert.&lt;br /&gt;
* [http://www.stolz.de.be InCircuit-Programmer und -Debugger (www.stolz.de.be)] Einfacher Nachbau des Microchip ICD2s. Zum Programmieren und Debuggen.&lt;br /&gt;
* [http://www.winpicprog.co.uk WinPicProg] Programmer und Tutorials für Anfänger von Nigel Goodwin (Englisch)&lt;br /&gt;
* [http://www.tigal.com EasyPIC3, EasyPIC4, Easy8051A, EasyAVR, Easy-was-weiss-ich (www.tigal.com)] - Distributor für Produkte von [http://www.mikroelektronika.co.yu mikroelektronika] und weiteren Herstellern&lt;br /&gt;
*[http://www.pro-zukunft.de Pro Zukunft] Evaluation-Board für PIC16F84A, hands-on-training und Print-Lehrgang. Für Schulen, Ausbildungsbetriebe &amp;amp; Hobbyelektroniker.&lt;br /&gt;
* [http://www.wselektronik.at www.wselektronik.at] Bausatz für &amp;quot;Full Speed ICD2&amp;quot; (USB2.0, Debugger, Programmer) oder Fertiggerät erhältlich.&lt;br /&gt;
* [http://www.uchobby.com/index.php/2008/04/19/pic-development-linux-style/ How to setup for PIC microcontroller development on Linux] von Steven Moughan&lt;br /&gt;
* [http://www.dattalo.com/gnupic/gpsim.html#docs gpsim] is a full-featured software simulator for Microchip PIC microcontrollers distributed under the GNU General Public License.&lt;br /&gt;
* [http://dev.frozeneskimo.com/software_projects:vpicdisasm vPICdisasm] is a Microchip PIC Mid-Range family firmware disassembler. This single-pass disassembler can read Intel HEX and Motorola S-Record formatted files containing valid PIC firmware. (GPL)&lt;br /&gt;
* [http://pikdev.free.fr/ PiKdev] is a simple graphic IDE for the development of PIC-based applications. It currently supports assembly language. C language is also supported for PIC 18 devices. PiKdev is developed in C++ under Linux and is based on the KDE environment.&lt;br /&gt;
* [http://www.yenka.com/en/Yenka_PICs/ Yenka PICs] lets you write routines using simple flowcharts, and test them on-screen, before using them to program real PIC or PICAXE chips. To help spread the news about Yenka, we&#039;re offering free copies of Yenka PICs for use at home or school.&lt;br /&gt;
&lt;br /&gt;
=== Projektsammlungen/Einzelprojekte ===&lt;br /&gt;
&lt;br /&gt;
* [http://www.martins-elektronikwelt.tk www.martins-elektronikwelt.tk] Viele Projekte mit den PIC Mikrocontrollern, u.a. SMS-Schaltzentrale, SD/MMC-FAT32-MP3-Player, Lichtschranken, Funk-Wetterempfänger, PS/2 am PIC usw.&lt;br /&gt;
* [http://www.Firmware-On-Demand.com Firmware-On-Demand] Umfangreiche Firmware-Bibliothek. &lt;br /&gt;
* [http://www.picguide.org PIC Guide] Eine große Sammlung von PIC-Projekten für den Anfänger&lt;br /&gt;
* [http://www.rentron.com www.rentron.com] Anfänger-taugliche Projekte für PIC und [[8051]] von Reynolds Electronics (Englisch)&lt;br /&gt;
* [http://www.ing-pfenninger.ch/artikel.html PIC-Projekte] Einige PIC-Projekte zum Nachbauen wie IR-Lichtschranke, Frequenzzähler.&lt;br /&gt;
* [http://mondo-technology.com/ SuperProbe] - Logic Probe,(Auf der linken Seite ganz oben) Logic pulser, Frequency Counter, Event Counter, Voltmeter, Diode Junction Voltage, Capacitance Measurement, Inductance Measurement, Signal Generator, Video Patern, Serial Ascii, Midi Note, R/C Servo, Square Wave, Pseudo Random Number, ir38, PWM in einem... (PIC16F870)&lt;br /&gt;
* [http://www.circuitcellar.com/microchip2007/ Microchip 16-Bit Embedded Control 2007 Design Contest] bei [http://www.circuitcellar.com/ Circuit cellar]&lt;br /&gt;
* [http://mondo-technology.com/ Mondo Technologiy] Grosse Ansammlung von PIC-Projekten&lt;br /&gt;
* [http://micrognurtos.sourceforge.net uGNU/RTOS] is a microcontroller-targeted serial real time operating system. It has been ported to USART capable Microchip PIC16 devices. It supports I/O operations and some internal registry operations. The user can interact with the chip through the RS-232 serial cable and a shell. The user can type a small list of commands and see the results on the chip&#039;s outputs. (LGPL)&lt;br /&gt;
&lt;br /&gt;
== [[Z8]] ==&lt;br /&gt;
* [http://www.z8micro.com/forum/ Z8 Encore! Microcontroller Discussion Forum - Dedicated to the ZiLOG Z8 Encore! Microcontroller] Ein der Z8 Encore!-Mikrocontrollerfamilie gewidmetes Diskussionsforum (in Englisch).&lt;br /&gt;
* [http://groups.yahoo.com/group/z8encore/ Yahoo! Groups : z8encore] Yahoo-Gruppe, die sich mit den Z8 Encore! Mikrocontrollern beschäftigt (Anmeldung bei Yahoo erforderlich).&lt;br /&gt;
* [[Zilog Encore Experimentierplatine]] (Z8F6421 Familie mit DIP-40 Gehäuse)&lt;br /&gt;
&lt;br /&gt;
== Programmierbare Logik ([[CPLD]]/[[FPGA]]/[[GAL]]) ==&lt;br /&gt;
&lt;br /&gt;
* [http://www.opencores.org/ OpenCores.org], VHDL Sourcen&lt;br /&gt;
* [http://www.fpga4fun.com/ fpga4fun], umfangreiche Seite mit Einführung und Beispielen, berücksichtigt Xilinx &amp;amp; Altera&lt;br /&gt;
* [http://opencollector.org/history/freecore/ Freecore], unter &#039;Module library&#039; gibt&#039;s einige freie Designs&lt;br /&gt;
* [http://www.cmosexod.com/ CMOSExod], Designs unter &#039;Free IP&#039;&lt;br /&gt;
* [https://digilent.us/ Digilent], Hersteller verschiedener FPGA/CPLD-Boards (u.a. Xilinx Spartan Starter Kit)&lt;br /&gt;
* [http://www.terasic.com.tw/cgi-bin/page/archive.pl?Language=English&amp;amp;CategoryNo=39 Terasic], Anbieter von Altera FPGA-Boards&lt;br /&gt;
* [http://shop.trenz-electronic.de/catalog/ Trenz Elektronik], verkauft verschiedene FPGA/CPLD-Boards&lt;br /&gt;
* [http://www.xess.com/index.html XESS], Anbieter von FPGA-Boards (Xilinx), unter Support gibts es eine Menge Beispiele&lt;br /&gt;
* [http://members.optushome.com.au/jekent/FPGA.htm Private Seite von John Kent], enthält eine Menge Links und auch einige Designs&lt;br /&gt;
* [http://www.mediatronix.com/Tools.htm Mediatronix tools], Picoblaze und DSP tools&lt;br /&gt;
* [http://www.ixo.de/info/usb_jtag/ ixo.de usbjtag] - USB-JTAG Adapter, fast kompatibel zu Altera USB-Blaster, wahlweise basierend auf FT245+CPLD oder Cypress FX2 Controller&lt;br /&gt;
* [http://www.fpgacpu.org/links.html FPGA CPU Links]&lt;br /&gt;
* [http://www.fpga-forum.com/wbb Forum mit allgemeinen Diskussionen zum Thema FPGA und FAQ&#039;s speziell zu den Cesys FPGA Karten]&lt;br /&gt;
* [http://www.cesys.biz Online Shop für Cesys FPGA Karten]&lt;br /&gt;
&lt;br /&gt;
== DSP ==&lt;br /&gt;
&lt;br /&gt;
=== Embedded Linux &amp;amp; DSP ===&lt;br /&gt;
&lt;br /&gt;
* [http://www.tetrix-systems.de/embedded.html combined embedded Linux-DSP Solutions]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Misc. ===&lt;br /&gt;
&lt;br /&gt;
* [http://open.neurostechnology.com/node/1020 TI c54x DSP  Compilertools (ohne Debugger)] frei für Open Source Projekte.&lt;br /&gt;
&lt;br /&gt;
== Wettbewerbe (Contests) == &lt;br /&gt;
&lt;br /&gt;
Verschiedene Hersteller veranstalten zur Promotion ihrer Produkte Designwettbewerbe, aus denen teilweise komplette Projektunterlagen hervorgehen (Schaltung, Source).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2009&#039;&#039;&#039;&lt;br /&gt;
* [http://www.designmsp430.com/ Design MSP430 Ultra-Low Power Challenge]&lt;br /&gt;
* [http://makezine.com/halloweencontest/ Make: Halloween Contest 2009], sponsored by Microchip Technology!&lt;br /&gt;
* [http://www.bricogeek.com/contest/let-arduino-play/resultados.php Let Arduino Play Contest]&lt;br /&gt;
* [http://www.dlpdesign.com/designcontest/ DLP Design DLP-232PC Design Contest]&lt;br /&gt;
* [http://www.libelium.com/tienda/catalog/contest.php Arduino contest by Libelium]&lt;br /&gt;
* [http://www.expli.de/wettbewerb/coole-avr-microcontroller-elektronik-ideen/ EXPLI Elektronik Wettbewerb]: Die coolsten Elektronik Projekte &amp;amp; AVR Microcontroller Anleitungen&lt;br /&gt;
* [http://www.stm32circle.com/projects/contest.php STM32 Primer2 Design Competition 2009]&lt;br /&gt;
* [http://www.parallax.com/tabid/603/Default.aspx 2009 Propeller Design Contest]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2008&#039;&#039;&#039;&lt;br /&gt;
* [http://www.parallax.com/tabid/720/Default.aspx Propeller Design Contest]&lt;br /&gt;
* [http://www.psocidcindia.com/index.php PSoC Innovator Design Challenge India 2008]&lt;br /&gt;
* [http://www.mypic32.com Microchip PIC32 Design Challenge]&lt;br /&gt;
* [http://contest.renesasinteractive.com/ HEW Target Server Design Contest 2008]&lt;br /&gt;
* [http://www.stm32circle.com/projects/result_contest_2008.php STM32 Primer Design Competition 2008]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2007&#039;&#039;&#039;&lt;br /&gt;
* [http://www.circuitcellar.com/wiznet/index.html WIZnet iEthernet Design Contest 2007] &lt;br /&gt;
* [http://www.circuitcellar.com/microchip2007/ Microchip 16-Bit Embedded Control 2007 Design Contest]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2006&#039;&#039;&#039;&lt;br /&gt;
* [http://www.designmsp430.com/View.aspx 2006 MSP430 eZ Design Contest] &lt;br /&gt;
* [http://www.circellar.com/msp430/ MSP430 Design Contest]&lt;br /&gt;
* [http://www.luminarymicro.com/DesignStellaris2006 Luminary Micro DesignStellaris2006]&lt;br /&gt;
* [http://www.circuitcellar.com/avr2006/ Atmel AVR Design Contest 2006] &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2005&#039;&#039;&#039;&lt;br /&gt;
* [http://www.jandspromotions.com/philips2005/index.htm Philips ARM Design Contest 2005] (LPC213x)&lt;br /&gt;
* [http://www.circuitcellar.com/renesas2005m16c/index.htm Renesas M16C Design Contest 2005]&lt;br /&gt;
* [http://www.edn.com/article/CA516007.html Cornelius van Drebbel&#039;s Mad Design Contest] (NEC)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2004&#039;&#039;&#039;&lt;br /&gt;
* [http://www.circuitcellar.com/avr2004/ Atmel AVR 2004 Design Contest]&lt;br /&gt;
* [http://www.circuitcellar.com/psoc2004/ PSoC High Integration Challenge 2004]&lt;br /&gt;
* [http://www.jandspromotions.com/zilog2004/ Zilog 2004 Flash Nets Cash Design Contest] (eZ80Acclaim!)&lt;br /&gt;
* [http://www.jandspromotions.com/wirelesschallenge/index.html 2004 Freescale Wireless Design Challenge] (MC13191/92/93 RF Transceivers, [[Meshnetics Zigbee|ZigBee]])&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2003&#039;&#039;&#039;&lt;br /&gt;
* [http://www.circuitcellar.com/fi2003/ MOTOROLA FLASH INNOVATION 2003 DESIGN CONTEST] (Motorola HC08)&lt;br /&gt;
* [http://www.circuitcellar.com/renesas/ Renesas H8 Design 2003 Contest]&lt;br /&gt;
* [http://www.jandspromotions.com/zilog2003/ ZiLOG Flash for Cash Z8 Encore®! International Design Contest]&lt;br /&gt;
* [http://www.jandspromotions.com/efield203/index.htm 2003 Motorola E-Field Sensor Contest] (MC33794)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2001&#039;&#039;&#039;&lt;br /&gt;
* [http://www.circuitcellar.com/dl2001/ Atmel &#039;Design Logic 2001&#039; Design Contest]&lt;br /&gt;
&lt;br /&gt;
== Interfaces &amp;amp; Protokolle ==&lt;br /&gt;
Siehe auch [[Linksammlung#Schnittstellen]]&lt;br /&gt;
&lt;br /&gt;
=== Infrarot (IR) ===&lt;br /&gt;
&lt;br /&gt;
* [http://www.sbprojects.com/knowledge/ir/ir.htm Übersicht IR-Protokolle] von San Bergmans (engl.): ITT, JVC, NEC, Nokia NRC17, Sharp, Sony SIRC, Philips RC-5, RC-6, RC-MM, RECS80, RCA, X-Sat&lt;br /&gt;
* [http://www.vishay.com/docs/80071/dataform.pdf Data formats fpr IR controls (PDF)] von Vishay.&lt;br /&gt;
&lt;br /&gt;
=== Parallelport ===&lt;br /&gt;
&lt;br /&gt;
* [http://www.projects-lab.com/?p=1139 ECPMON] - ECP Parallel Port Monitor ([[M16C]]/62P) &lt;br /&gt;
&lt;br /&gt;
=== iPod ===&lt;br /&gt;
* [http://ipodlinux.org/IPod_to_T%26A_remotecontrol_adapter IPod to T&amp;amp;A remotecontrol adapter] ([[PIC]]-Projekt)&lt;br /&gt;
&lt;br /&gt;
=== [[RFID]] ===&lt;br /&gt;
&lt;br /&gt;
* [http://www.mwjournal.com/journal/article.asp?HH_ID=AR_905 Radio Frequency Identification: Evolution of Transponder Circuit Design] - Übersichtsartikel aus dem Microwave Journal&lt;br /&gt;
* [http://www.foebud.org/rfid Die StopRFID-Seiten des FoeBuD e.V.]&lt;br /&gt;
* [http://www.rfzone.org/free-rf-ebooks/ PDF-Bücher (englisch) ]- Bücher über RF, Antennen und elektromagnetische Wellen.&lt;br /&gt;
&lt;br /&gt;
* http://cq.cx/proxmark3.pl Jonathan Westhues RFID Leser/Schreiber/Cloner&lt;br /&gt;
&lt;br /&gt;
http://www.message_bocracco.com/&lt;br /&gt;
&lt;br /&gt;
==== 13,56 MHz RFID ====&lt;br /&gt;
* [http://www.openpcd.org/ OpenPCD - a free 13.56MHz RFID reader design] for Proximity Coupling Devices (PCD) based on 13,56MHz communication. This device is able to screen informations from Proximity Integrated Circuit Cards (PICC) conforming to vendor-independent standards such as ISO 14443, ISO 15693 as well as proprietary protocols such as Mifare Classic. (AT91SAM7S128 [[ARM]] Projekt)&lt;br /&gt;
* [http://www.rf-dump.org/ RFDump] is a backend GPL tool to directly interoperate with any RFID ISO-Reader to make the contents stored on RFID tags accessible. (Linux)&lt;br /&gt;
&lt;br /&gt;
==== 2,4 GHz RFID ====&lt;br /&gt;
* [http://www.openbeacon.org/ OpenBeacon] - a free active 2.4GHz beacon design. (Reader: USB oder Ethernet; Tags: RF_Chip: NRF24L01, PIC16F684)&lt;br /&gt;
&lt;br /&gt;
=== [[DMX512]] ===&lt;br /&gt;
* [http://www.soundlight.de/techtips/dmx512/dmx512.htm DMX-512 - was ist das?] Eine Übersicht von SOUNDLIGHT.&lt;br /&gt;
* [http://www.oksidizer.com/electronic/spp2dmx/index_en.html OksiD DMX 3/1 is a Standard Parallel Port DMX 512 interface for IBM compatible PCs]. Drei Output Universe und ein Input Universe (Universe = 512 channels). Open project. All source code and schematics are available for free. &lt;br /&gt;
* [http://www.usbdmx.com/usb_dmx_interface.html USB DMX Interface revision 1.3] - opto isolated, bus powered, DMX512 from/to [[USB]]interface with both in and out universes. Cheap and simple to build.&lt;br /&gt;
* [http://www.dmx512-online.com/ Ujjal&#039;s DMX512 Seite]&lt;br /&gt;
* [http://llg.cubic.org/dmx4linux/ DMX4Linux 2.6] - A DMX device driver package for Linux (incl. hardware schematics with TI [[MSP430]])&lt;br /&gt;
&lt;br /&gt;
=== Verschiedenes ===&lt;br /&gt;
* [http://www.taelektroakustik.de/deu/index.htm T&amp;amp;A Kommandos] - &#039;&#039;&#039;RC&#039;&#039;&#039; und &#039;&#039;&#039;RCII&#039;&#039;&#039; Kommandoset der Philips PRONTO Familie zur Steuerung von Audiogeräten. Dokumentation siehe unter Downloads.&lt;br /&gt;
* [http://www.marjorie.de/ps2/ps2_protocol.htm Das PS/2 Maus und PS/2- oder AT-Tastatur-Protokoll] (Original auf [http://www.computer-engineering.org/])&lt;br /&gt;
* [http://www.hth.com/snap/ S.N.A.P - Scaleable Node Address Protocol]. S.N.A.P is an free and open network protocol. The protocol was primary developed for PLM-24 based home automation and control systems but it is a generic protocol and not limited to this. S.N.A.P can be used in any type of applications where an easy to learn and light weighted network protocol is needed.&lt;br /&gt;
* [http://www.ulrichradig.de/home/index.php/avr/avr_-_rc PPM / PWM Encoder/Decoder für R/C Funkfernsteuerungen] von Ulrich Radig (AVR, C)&lt;br /&gt;
* [http://www.national.com/analog/interface/lvds_owners_manual LVDS Owner&#039;s Manual - 4th Edition] von National Semiconductor&lt;br /&gt;
* [http://sound.westhost.com/heatsinks.htm The Design of Heatsinks]&lt;br /&gt;
* [http://www.mictronics.de/?page=becker Becker Unilink]&lt;br /&gt;
&lt;br /&gt;
== Leiterplattenhersteller ==&lt;br /&gt;
&lt;br /&gt;
siehe [[Platinenhersteller|Platinenhersteller]]&lt;br /&gt;
&lt;br /&gt;
== Schulungen (Online) ==&lt;br /&gt;
&lt;br /&gt;
* [http://www.esacademy.com/myacademy/ www.esacademy.com] (engl.) - C, CAN, I²C, BlueTooth, PWM, USB, 51LPC, ARM (Einführung)&lt;br /&gt;
* [http://www.elprak.ch Elektronik in der Praxis] Präsentationen zu verschiedenen Themen der Elektronik in der Praxis. Lötvideo, das den zeitlichen Ablauf beim Löten anschaulich darstellt.&lt;br /&gt;
* [http://www.national.com/onlineseminar/ www.national.com] - Amplifiers, Audio, Data Acquisition, Die Products, Displays, Interface, Microcontrollers, Military/Aerospace, Power, Thermal Management, Wireless&lt;br /&gt;
* [http://www.circuitrework.com Circuit Technology Center] - Surgeon grade rework and repair, by the book and guaranteed. Deeplink: [http://www.circuitrework.com/guides/guides.shtml Guides]&lt;br /&gt;
* [http://www.onlinetutorials.de/index.htm onlinetutorials.de] - Linksammlung zu Tutorials für höhere Programmiersprachen ([[HLL]]) wie C, C++, Java, BASIC, Perl, PHP, ...&lt;br /&gt;
* [http://www.awce.com/classroom/ AWCE Interactive Classroom] - Embedded Systems (Using the APP-IV with GCC, Getting Started with the PIC 18F Family), Electronics (CLARC/HBSIG DSP Study Group, Basic Circuits), RoadMap to Programmable Logic&lt;br /&gt;
* [http://www.ibiblio.org/kuphaldt/socratic/ Socratic Electronics] (englisch)&lt;br /&gt;
* [http://www.embedded.com/design/multicore/201200638;jsessionid=4T1T0OZQW4PFSQSNDLRSKH0CJUNN2JVN?printable=true The basics of programming embedded processors] von Wayne Wolf. Neun Artikel bei embedded.com (englisch)&lt;br /&gt;
* [http://webcast.berkeley.edu/course_details.php?seriesid=1906978507 EE 42/EE 100 Introduction to Digital Electronics] - Webcast, Spring 2008 (englisch)&lt;br /&gt;
* [http://freevideolectures.com freevideolectures.com] - Webcasts zu  naturwissenschaftlichen Theman (englisch)&lt;br /&gt;
* [http://www.circuitsage.com/ Circuit Sage], a complete source of information to help you design circuits fast. (Linksammlung zu Software, Artikeln Büchern und Websites)&lt;br /&gt;
* [http://www.DieElektronikerseite.de Die Elektronikerseite] Umfangreiche Sammlung von kleinen Lehrgängen und Schaltungen. Ideal für Anfänger aber auch für Fortgeschrittene&lt;br /&gt;
* [http://homepages.internet.lu/absolute3/tronic/ 3D Virtual Development] - Sammlung von vielen Grundschaltungen im Bereich Oszillator, Operationsverstärker, Empfangstechnik. Vereinzelt in Englisch.&lt;br /&gt;
&lt;br /&gt;
== Skripte ==&lt;br /&gt;
&lt;br /&gt;
* [http://www.janson-soft.de/skripte/index.html Linksammlung von Volker Lange-Janson]&lt;br /&gt;
* [http://wwwex.physik.uni-ulm.de/lehre/physikalischeelektronik/phys_elektr/phys_elektr.html Physikalische Elektronik und Messtechnik] von Othmar Marti und Dr. Alfred Plettl, Universität Ulm&lt;br /&gt;
&lt;br /&gt;
== Messequipment ==&lt;br /&gt;
* [http://www.filmetrics.com  Filmetrics Inc.] (Filmetrics manufactures affordable thin-film measurement instruments capable of measuring thin films from 3nm to 0.5mm in thickness.)&lt;br /&gt;
=== Logikanalyse ===&lt;br /&gt;
* [http://www.pctestinstruments.com Intronix LogicPort], Günstiger, aber sehr leistungsfähiger Logikanalysator mit USB-Anschluß an PC (34Ch, 500MHz Timing, 34 x 2kSa mit Kompression, ca. 295 Euro [http://www.shop.display3000.com/elektronik/messgeraete/index.html hier])&lt;br /&gt;
* [http://www.tech-tools.com/dv_main.htm TechTools DigiView], Günstiger Logikanalysator mit USB-Anschluß an PC (18Ch, 100MHz Timing, 128kSa mit Kompression,  [http://elmicro.com/de/digiview.html ca. 430Euro])&lt;br /&gt;
* [http://www.tribalmicro.com/logic_an/ Tribalmicro], PC hosted LA (32ch, 40MHz Timing, 128kSa, ca. 1700$)&lt;br /&gt;
* [http://www.nci-usa.com/frame_products_overview.htm NCI GoLogic], Logikanalysator mit USB-Anschluß an PC (34 oder 72Ch, 500MHz Timing, 1 oder 2MSa, ca. 3000..5500$)&lt;br /&gt;
* [http://www.tek.com/products/logic_analyzers/index.html Tektronix], Verschiedene Geräte, standalone oder modular (ab 34ch, 2GHz Timing, ab 512kSa, gut und teuer)&lt;br /&gt;
* [http://www.home.agilent.com/DEger/nav/-536902443.0/pc.html Agilent], Verschiedene Geräte, standalone, modular oder PC-hosted (ab 34ch, ab 800MHz timing, ab 256kSa, gut und teuer)&lt;br /&gt;
* [http://www.sump.org/projects/analyzer/ Sumps LA], günstiges Projekt für einen LA basierend auf einem Digilent Spartan Board (32ch, 100MHz Timing, 256kSa, Kosten Digilent Board ca. 100$ + Versand/Zoll)&lt;br /&gt;
* [http://www.meilhaus.de/produkte/usb-mobile-messtechnik/?user_produkte%5BPATTR%5D=HPG_3-UPG1_3-UPG2_2&amp;amp;user_produkte%5BPR%5D=8&amp;amp;cHash=2c8edb93e2 Meilhaus Electronic - MEphisto Scope UM203] Robustes, mobiles 16 bit Kombi-Instrument 7 Mess-Geräte in einem! (ab 348€)&lt;br /&gt;
* [http://www.hacker-messtechnik.de/13722/59001.html TravelLogic TL2x36], Logikanalysator zum Anschluß an PC über USB, (36ch, 4GHz timing, 200MHz state, Speicher bis 72MBit, Preis ab ca. 500,- netto)&lt;br /&gt;
* [http://www.inovaflex.de/index.html Bus und Logic Analyzer] 100MHz Samplerate und integrierten SPI, I²C, CAN Interpreter, erweiterbar als Oszilloskop&lt;br /&gt;
* [http://www.saleae.com/logic/ logic] - Logik-Analyzer mit 8 Kanälen, mit Software zur Analyse von SPI, I2C, UART, etc... (ca 150$ + Versand/Zoll)&lt;br /&gt;
&lt;br /&gt;
* Eine Übersicht über verschiedene Selbstbauprojekte: [[Logic_Analyzer]]&lt;br /&gt;
&lt;br /&gt;
=== Oszilloskope ===&lt;br /&gt;
&lt;br /&gt;
siehe die separate [http://www.mikrocontroller.net/articles/Oszilloskop Seite] zum Thema&lt;br /&gt;
&lt;br /&gt;
=== Generatoren ===&lt;br /&gt;
[http://www.meilhaus.de/produkte/mess-und-steuer-karten/?user_produkte%5BPR%5D=23&amp;amp;cHash=64a269a3c6 Meilhaus Electronic - ME-6x00] Waveform-Generator - potentialfrei isolierte 16 bit Analog-Ausgabe-Karte (ab EUR 1138,00)&lt;br /&gt;
&lt;br /&gt;
== Vermischtes == &lt;br /&gt;
&lt;br /&gt;
=== Foren ===&lt;br /&gt;
* [http://www.sparkfun.com/cgi-bin/phpbb/ Spark Fun Electronics] MicroController Ideas and Support (Englisch) ([[AVR]], [[PIC]], [[MSP]], [[ARM]], OpenOCD)&lt;br /&gt;
* [http://www.edaboard.com/ EDAboard.com] International Electronics Forum Center (Englisch)&lt;br /&gt;
* [http://stsboard.de STS Reparatur Forum] Forum für Radio und Fernsehtechniker&lt;br /&gt;
* [http://formu.iwenzo.de Elektronik Reparatur Forum] Informationselektroniker Reparatur Forum&lt;br /&gt;
&lt;br /&gt;
=== Projektsammlungen ===&lt;br /&gt;
Meist in Englisch. &lt;br /&gt;
* [http://circuitscout.com/ Circuit Scout] - Online Suchmaschine&lt;br /&gt;
* [http://www.epanorama.net ePanorama.net]&lt;br /&gt;
* [http://www.commlinx.info Electronic Schematics] from CommLinx Solutions Pty Ltd&lt;br /&gt;
* [http://www.discovercircuits.com Discover Circuits] a collection of 25000+ electronic circuits or schematics&lt;br /&gt;
* [http://www.next.gr/ Next] Electronic Circuit Database&lt;br /&gt;
* [http://www.beyondlogic.org/ BeyondLogic.org] Diverse Mikrocontroller und Interfacing Projekte&lt;br /&gt;
* [http://www.uoguelph.ca/~antoon/circ/circuits.htm Circuits for the Hobbyist] by VA3AVR&lt;br /&gt;
* [http://www.stefpro.de/ StefPro.de] Diverse Projekte und Datenblattsammlung nach Kategorien, Microcontroller, Digital und Analog... Sowie Tutorial &amp;quot;Grundlagen der Bestückung von Platinen&amp;quot; und anderes Wissen&lt;br /&gt;
* [http://www.schaltplaene-online.de/ www.schaltplaene-online.de] Umfangreiche Linksammlung zu Schaltplänen aller Art&lt;br /&gt;
* [http://www.avr-projects.info www.avr-projects.info] Liste mit AVR-Projekten, die von jedem Besucher erweitert werden kann (wiki like)&lt;br /&gt;
* [http://www.halloweenmonsterlist.info/ MoNsTeRlIsT of Halloween Projects]&lt;br /&gt;
* [http://www.open-innovation-projects.org Open Innovation Projects] - Sammlung von offenen Projekten zu physischen Produkten, darunter etliche Mikrocontroller-Projekte. Man kann selber Projekte hinzufügen.&lt;br /&gt;
&lt;br /&gt;
=== Referenzen, Beschreibungen, Standards ===&lt;br /&gt;
* Extraseite: [[Datenblätter]]&lt;br /&gt;
* [http://www.technick.net Technik.Net] Pinouts, Circuits and Guides&lt;br /&gt;
* [http://pinouts.ru/ pinout.ru] und [http://www.hardwarebook.info/ hardwarebook.info] - Online handbooks of hardware pinouts, cables schemes and connectors layouts&lt;br /&gt;
* [http://www.networktechinc.com/technote.html Keyboard, Monitor &amp;amp; Mouse Pinouts] for PC, SUN, MAC, USB, FireWire, RS232, Digital Flat Panel and EVC configurations&lt;br /&gt;
* [http://www.q1.fcen.uba.ar/materias/iqi/joygus/tvgames.html Special joysticks used in TV games]&lt;br /&gt;
* [http://www.cs.net/lucid/intel.htm Intel-Hex-Format]&lt;br /&gt;
* [http://home.teleport.com/~brainy/fat32.htm FAT32 Structure Information] - Written by Jack Dobiash&lt;br /&gt;
* [http://www.pjrc.com/tech/8051/ide/fat32.html Understanding FAT32 Filesystems] mit Beispielen (engl.)&lt;br /&gt;
* [http://www.rev-ed.co.uk/docs/picaxe_manual3.pdf Microcontroller Interfacing Circuits] - Revolution Education Ltd.&lt;br /&gt;
&lt;br /&gt;
=== Online-Bücher ===&lt;br /&gt;
* [http://www.allaboutcircuits.com/ All About Circuits] - Series of online textbooks covering electricity and electronics. The information provided is great for both students and hobbyists who are looking to expand their knowledge in this field. (Englisch)&lt;br /&gt;
* http://www.computer-books.us/ - überwiegend zu höheren Programmiersprachen. Englisch.&lt;br /&gt;
* [http://www.vias.org/feee/index.html FEEE - Fundamentals of Electrical Engineering and Electronics]&lt;br /&gt;
* [http://www.nrbook.com/a/bookcpdf.php Numerical Recipes in C, Second Edition (1992)]&lt;br /&gt;
* [http://www.specamotor.de/freebook.php Electrical drives for precision engineering designs]  Prof.dr.ir. Compter&lt;br /&gt;
&lt;br /&gt;
=== Bedienungsanleitungen / Manuals ===&lt;br /&gt;
* [http://bama.edebris.com/manuals/ BAMA Archiv] &lt;br /&gt;
* [http://www.big-list.com/ Big-List.com] - This is a directory of over 600 dealers in used high technology equipment. Most deal in used electronic test equipment or semiconductor production equipment. Included are dealers in related high technology items, rental companies, equipment auction sites, test equipment manual dealers, foreign (non-U.S.) used equipment dealers, cal labs, and repair services.&lt;br /&gt;
&lt;br /&gt;
=== Ungewöhnliche Basteleien (Hacks) ===&lt;br /&gt;
Auf eigene Gefahr und nicht immer ganz ernst... Meist in Englisch. &lt;br /&gt;
&lt;br /&gt;
* Metablogs (tägliche News)&lt;br /&gt;
** [http://www.makezine.com/ Makezine]&lt;br /&gt;
** [http://www.hackaday.com/ Hack a Day]&lt;br /&gt;
** [http://www.hackedgadgets.com/ HackedGadgets]&lt;br /&gt;
** [http://www.hacknmod.com/ Hack N&#039; Mod]&lt;br /&gt;
&lt;br /&gt;
* Foren&lt;br /&gt;
** [http://www.fingers-welt.de/home.htm Fingers elektrische Welt]&lt;br /&gt;
** [http://forum.hackedgadgets.com/ HackedGadgets Forum]&lt;br /&gt;
** [http://stsboard.de Reparatur Forum]&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
domain expired&lt;br /&gt;
** [http://camerahacking.com camerahacking Forum]&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Projektsammlungen&lt;br /&gt;
** Final Projects der Kurse [http://instruct1.cit.cornell.edu/courses/ee476/FinalProjects/  ECE476] (Microcontroller Design) und [http://instruct1.cit.cornell.edu/courses/ece576/FinalProjects/ ECE576] (Advanced Microcontroller Systems on a Programmable Chip) an der Cornell University &lt;br /&gt;
** [http://www.coolcircuit.com/gadgets/ Cool Circuit]&lt;br /&gt;
** www.electronics-lab.com/blog/ &amp;lt;br&amp;gt; Stand 4.9.09: Warnung: Attackierende Webseite!&lt;br /&gt;
&lt;br /&gt;
* DIY-Anleitungen&lt;br /&gt;
** [http://www.instructables.com/ instructables]&lt;br /&gt;
** [http://www.scitoys.com/ Scitoys] You Can Make With Your Kids&lt;br /&gt;
&lt;br /&gt;
* Mix&lt;br /&gt;
** [http://www.evilmadscientist.com Evil Mad Scientist Laboratories] - u.a. The Flying Spaghetti Monster, on toast ;-)&lt;br /&gt;
** [http://home.earthlink.net/~lenyr/index.html Spark, Bang, Buzz and Other Good Stuff] ([http://www.sparkbangbuzz.com Neue Sachen])&lt;br /&gt;
** [http://www.electricstuff.co.uk/ Mike&#039;s Electric Stuff] - Antique Glass, Tesla coils and high-voltage stuff, Lasers&lt;br /&gt;
** [http://electricity.pbwiki.com/ DHS electricity]&lt;br /&gt;
** [http://www.elephantstaircase.com/wiki/index.php?title=Main_Page Elephant Staircase]&lt;br /&gt;
** [http://mycpu.eu Eine selbstgebaute CPU aus TTL-Gattern]&lt;br /&gt;
** [http://www.knollep.de/ Knolles Bauanleitungen]&lt;br /&gt;
** [http://www.ikalogic.com/index.php ikalogic.com]&lt;br /&gt;
** [http://www.electronicsinfoline.com/ Electronics Infoline]&lt;br /&gt;
** [http://www.uchobby.com/ uC Hobby]&lt;br /&gt;
** [http://elettrolinux.com elettrolinux] - Elektronik und Linux (engl.)&lt;br /&gt;
&lt;br /&gt;
=== Zeitschriften über Elektronik und µC ===&lt;br /&gt;
* [http://www.eue24.net/ E&amp;amp;E Faszination Elektronik] - Das einzigartige Magazin für Elektronik-Entwickler und Elektronik-Interessierte&lt;br /&gt;
* [http://www.embedded.com embedded.com] - Hauptaugenmerk auf die Philosophie drumherum&lt;br /&gt;
* [http://www.siliconchip.com.au/ Silicon Chip] - Freie Artikel unter &#039;&#039;Free Preview&#039;&#039;&lt;br /&gt;
* [http://www.circuitcellar.com/ Circuit Cellar] - Freie Artikel unter &#039;&#039;Digital Library&#039;&#039;&lt;br /&gt;
* [http://www.elektronikpraxis.vogel.de/themen/hardwareentwicklung/mikrocontrollerprozessoren/ Elektronikpraxis - Das professionelle Elektronikmagazin]&lt;br /&gt;
* [http://www.funkamateur.de/ FUNKAMATEUR] - Elektronik, Amateurfunk, CB-Funk u. v. a. m.&lt;br /&gt;
* [http://www.edn.com/ EDN] (etwas schwer zu finden, aber lesenswert: die [http://www.edn.com/index.asp?layout=news&amp;amp;spacedesc=designIdeas Design Ideas])&lt;br /&gt;
* [http://www.franzis.de/elo-das-magazin ELO - Das Magazin] für Elektronik-Einsteiger&lt;br /&gt;
* [http://techonline.com/ TechOnline]&lt;br /&gt;
* [http://www.elektor.de/ Elektor] &lt;br /&gt;
* [http://www.techbriefs.com/tech-briefs/electronics-techbriefs NASA Tech Briefs] - Electronics &amp;amp; Computers&lt;br /&gt;
* [http://et.nmsu.edu/~etti/ Technology Interface Journal]&lt;br /&gt;
* [http://dev.emcelettronica.com/ Your Electronics Open Source]&lt;br /&gt;
* [http://www.element-14.com element14.com] is an information portal and community specifically built for electronic design engineers.&lt;/div&gt;</summary>
		<author><name>Thymythos</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=Diskussion:RFM12_Protokoll_Stack&amp;diff=37991</id>
		<title>Diskussion:RFM12 Protokoll Stack</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=Diskussion:RFM12_Protokoll_Stack&amp;diff=37991"/>
		<updated>2009-07-23T19:48:42Z</updated>

		<summary type="html">&lt;p&gt;Thymythos: /* Anregungen */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Fehler ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;F:&#039;&#039;&#039; &#039;&#039;(17.09.2008)&#039;&#039; Im IE haben die Hamming-Tabellen alle einen schwarzen Hintergrund und schwarze Schrift (Im Firefox ist die Darstellung i.o.)&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;A:&#039;&#039;&#039; Ich hab die Kurzschreibweise für Farben verwendet (#f12 statt #ff1122), ist aber eigentlich leider nur in CSS erlaubt... (Aber es scheint eine gute Methode zu sein um Inhalte vor IE nutzern zu verstecken *g*)&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;fixed!&lt;br /&gt;
&lt;br /&gt;
== Anregungen ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;F:&#039;&#039;&#039; &#039;&#039;(31.08.2008)&#039;&#039; Ist der Code bereits benutzbar? Falls ja fände ein Beispielprogramm sehr hilfreich.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;A:&#039;&#039;&#039; Im LLC fehlt noch ein bisschen was, aber PHY und MAC sind benutzbar.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;I:&#039;&#039;&#039; Der Hersteller empfiehlt 4 bytes Preamble zu senden.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;A:&#039;&#039;&#039; Kann man natürlich machen (und ist immernoch kompatible zum MAC). Bisher war&#039;s bei mir nicht nötig.&lt;br /&gt;
&lt;br /&gt;
== Fragen ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;F:&#039;&#039;&#039; &#039;&#039;(04.09.2008)&#039;&#039; Warum gibt es auf LLC-Ebene keine Paketlängeninformation? (Jörg Wunsch)&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;A:&#039;&#039;&#039; Overhead. Durch das Paketendezeichen ist die Länge definiert. Zugegeben, in manchen Applikationen erscheint es sinnvoll vor dem Empfang des Paketes die Länge zu wissen, aber IP hat z.B. dafür ein eigenes Feld.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;F:&#039;&#039;&#039; &#039;&#039;(07.10.2008)&#039;&#039; Benutzung?&lt;br /&gt;
Der Stack auf Layer 3 sieht ja so eigentlich ganz einfach zu verwenden aus. Aber wie genau benutze ich den jetzt?&lt;br /&gt;
Die einfachste Methode wäre ja beim Layer 3 ein init und sofort Daten draufschieben. Aber ich sehe im Quellcode keine Verbindung zu beispielsweise RFM12_PHY_init(). Also um welche Funktionen muss ich mich wirklich kümmern, um auf Layer 3 Bytes hin und her zu schicken?&lt;br /&gt;
Und ist das bischen was am 31.08.2008 fehlte inzwischen drinne?&lt;br /&gt;
&lt;br /&gt;
[[Benutzer:Malte|Malte]] 19:15, 7. Okt. 2008 (CEST)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;A:&#039;&#039;&#039; So in etwa hab ich mir das API gedacht:&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;quot;rfm12_phy.h&amp;quot;&lt;br /&gt;
#include &amp;quot;rfm12_mac.h&amp;quot;&lt;br /&gt;
#include &amp;quot;rfm12_llc.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
#define MY_RECEIVER  2&lt;br /&gt;
#define MY_PROTOCOL  13&lt;br /&gt;
#define BUF_SIZE     16&lt;br /&gt;
&lt;br /&gt;
uint8_t *buffer = &amp;quot;Hello world&amp;quot;;&lt;br /&gt;
uint8_t pos;&lt;br /&gt;
&lt;br /&gt;
void myrx(uint8_t data) {&lt;br /&gt;
    // TODO: handle rx data&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int16_t mytx(void) {&lt;br /&gt;
    if(pos &amp;lt; sizeof(buffer))&lt;br /&gt;
        return txBuf[pos++];&lt;br /&gt;
    return RFM12_L3_EOD;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void myack(bool ack) {&lt;br /&gt;
    printf(&amp;quot;Sending &amp;quot;);&lt;br /&gt;
    if(ack) printf(&amp;quot;OK\n&amp;quot;);&lt;br /&gt;
    else    printf(&amp;quot;failed\n&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void main() {&lt;br /&gt;
    RFM12_L3_Protocol_t proto = {myrx, mytx, myack};&lt;br /&gt;
&lt;br /&gt;
    RFM12_PHY_init();&lt;br /&gt;
    RFM12_MAC_init();&lt;br /&gt;
    RFM12_MAC_setChannel(1);&lt;br /&gt;
    RFM12_LLC_registerType(MY_PROTOCOL, proto);&lt;br /&gt;
&lt;br /&gt;
    while(1) {&lt;br /&gt;
         while(RFM12_MAC_mediaBusy());&lt;br /&gt;
         pos = 0;&lt;br /&gt;
         RFM12_LLC_sendFrame(MY_PROTOCOL, MY_RECEIVER, false);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;/div&gt;</summary>
		<author><name>Thymythos</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=Diskussion:RFM12_Protokoll_Stack&amp;diff=37990</id>
		<title>Diskussion:RFM12 Protokoll Stack</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=Diskussion:RFM12_Protokoll_Stack&amp;diff=37990"/>
		<updated>2009-07-23T19:48:23Z</updated>

		<summary type="html">&lt;p&gt;Thymythos: /* Anregungen */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Fehler ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;F:&#039;&#039;&#039; &#039;&#039;(17.09.2008)&#039;&#039; Im IE haben die Hamming-Tabellen alle einen schwarzen Hintergrund und schwarze Schrift (Im Firefox ist die Darstellung i.o.)&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;A:&#039;&#039;&#039; Ich hab die Kurzschreibweise für Farben verwendet (#f12 statt #ff1122), ist aber eigentlich leider nur in CSS erlaubt... (Aber es scheint eine gute Methode zu sein um Inhalte vor IE nutzern zu verstecken *g*)&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;fixed!&lt;br /&gt;
&lt;br /&gt;
== Anregungen ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;F:&#039;&#039;&#039; &#039;&#039;(31.08.2008)&#039;&#039; Ist der Code bereits benutzbar? Falls ja fände ein Beispielprogramm sehr hilfreich.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;A:&#039;&#039;&#039; Im LLC fehlt noch ein bisschen was, aber PHY und MAC sind benutzbar.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;I:&#039;&#039;&#039; Der Hersteller empfiehlt 4 bytes Preamble zu senden.&lt;br /&gt;
&#039;&#039;&#039;A:&#039;&#039;&#039; Kann man natürlich machen (und ist immernoch kompatible zum MAC). Bisher war&#039;s bei mir nicht nötig.&lt;br /&gt;
&lt;br /&gt;
== Fragen ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;F:&#039;&#039;&#039; &#039;&#039;(04.09.2008)&#039;&#039; Warum gibt es auf LLC-Ebene keine Paketlängeninformation? (Jörg Wunsch)&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;A:&#039;&#039;&#039; Overhead. Durch das Paketendezeichen ist die Länge definiert. Zugegeben, in manchen Applikationen erscheint es sinnvoll vor dem Empfang des Paketes die Länge zu wissen, aber IP hat z.B. dafür ein eigenes Feld.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;F:&#039;&#039;&#039; &#039;&#039;(07.10.2008)&#039;&#039; Benutzung?&lt;br /&gt;
Der Stack auf Layer 3 sieht ja so eigentlich ganz einfach zu verwenden aus. Aber wie genau benutze ich den jetzt?&lt;br /&gt;
Die einfachste Methode wäre ja beim Layer 3 ein init und sofort Daten draufschieben. Aber ich sehe im Quellcode keine Verbindung zu beispielsweise RFM12_PHY_init(). Also um welche Funktionen muss ich mich wirklich kümmern, um auf Layer 3 Bytes hin und her zu schicken?&lt;br /&gt;
Und ist das bischen was am 31.08.2008 fehlte inzwischen drinne?&lt;br /&gt;
&lt;br /&gt;
[[Benutzer:Malte|Malte]] 19:15, 7. Okt. 2008 (CEST)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;A:&#039;&#039;&#039; So in etwa hab ich mir das API gedacht:&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;quot;rfm12_phy.h&amp;quot;&lt;br /&gt;
#include &amp;quot;rfm12_mac.h&amp;quot;&lt;br /&gt;
#include &amp;quot;rfm12_llc.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
#define MY_RECEIVER  2&lt;br /&gt;
#define MY_PROTOCOL  13&lt;br /&gt;
#define BUF_SIZE     16&lt;br /&gt;
&lt;br /&gt;
uint8_t *buffer = &amp;quot;Hello world&amp;quot;;&lt;br /&gt;
uint8_t pos;&lt;br /&gt;
&lt;br /&gt;
void myrx(uint8_t data) {&lt;br /&gt;
    // TODO: handle rx data&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int16_t mytx(void) {&lt;br /&gt;
    if(pos &amp;lt; sizeof(buffer))&lt;br /&gt;
        return txBuf[pos++];&lt;br /&gt;
    return RFM12_L3_EOD;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void myack(bool ack) {&lt;br /&gt;
    printf(&amp;quot;Sending &amp;quot;);&lt;br /&gt;
    if(ack) printf(&amp;quot;OK\n&amp;quot;);&lt;br /&gt;
    else    printf(&amp;quot;failed\n&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void main() {&lt;br /&gt;
    RFM12_L3_Protocol_t proto = {myrx, mytx, myack};&lt;br /&gt;
&lt;br /&gt;
    RFM12_PHY_init();&lt;br /&gt;
    RFM12_MAC_init();&lt;br /&gt;
    RFM12_MAC_setChannel(1);&lt;br /&gt;
    RFM12_LLC_registerType(MY_PROTOCOL, proto);&lt;br /&gt;
&lt;br /&gt;
    while(1) {&lt;br /&gt;
         while(RFM12_MAC_mediaBusy());&lt;br /&gt;
         pos = 0;&lt;br /&gt;
         RFM12_LLC_sendFrame(MY_PROTOCOL, MY_RECEIVER, false);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;/div&gt;</summary>
		<author><name>Thymythos</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=Platinenhersteller&amp;diff=37845</id>
		<title>Platinenhersteller</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=Platinenhersteller&amp;diff=37845"/>
		<updated>2009-07-18T15:43:08Z</updated>

		<summary type="html">&lt;p&gt;Thymythos: Preisvergleichstabelle&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Einleitung ==&lt;br /&gt;
Die Vor- und Nachteile von Platinenherstellern/-lieferanten werden relativ häufig im [http://www.mikrocontroller.net/forum/platinen Forum] diskutiert (und führen ab und zu zu Flamewars :-). Damit man schnell einen Überblick über die verschiedenen Möglichkeiten erhält, soll hier eine Liste zusammengetragen werden.&lt;br /&gt;
&lt;br /&gt;
Jeder kann/soll seinen Beitrag leisten, d.h. wenn man einen Platinenlieferanten kennt, der noch nicht erwähnt ist, einfach hinzufügen. Falls man den Hersteller nicht so gut kennt, einfach mal den Namen und die URL hinzufügen, es gibt sicherlich andere, die den Hersteller so gut kennen, dass sie sich zutrauen, ein Urteil über die Leistung zu fällen.&lt;br /&gt;
&lt;br /&gt;
Eigentümer oder Mitarbeiter der gelisteten Firmen mögen bitte der Versuchung widerstehen, die Einträge mit werbeähnlichen Texten oder Werbung zu ergänzen. Zufriedene Kunden mögen bitte darauf achten, ihre Zufriedenheit so zu formulieren, dass nicht der Eindruck entsteht, der Eintrag sei von einem Hersteller zur &amp;quot;Verschönerung&amp;quot; gemacht worden.&lt;br /&gt;
&lt;br /&gt;
PS.: Das Ganze soll so ähnlich werden wie [[Elektronik-Versender]], da hat das auch sehr gut geklappt!&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Diese Seite kann nur von angemeldeten Benutzern bearbeitet werden!&#039;&#039;&#039; Bei neuen Einträgen bitte die Sortierung beachten.&lt;br /&gt;
&lt;br /&gt;
Einige Hinweise, Hilfestellungen zur Platinenfertigung und Auftragsvergabe gibt es auch in der [http://www.dse-faq.elektronik-kompendium.de/dse-faq.htm#F.6 de.sci.electronics-FAQ].&lt;br /&gt;
&lt;br /&gt;
===Preise===&lt;br /&gt;
Zur besseren Vergleichbarkeit bei jedem Hersteller dazu schreiben, was &#039;&#039;&#039;eine doppelseitige durchkontaktierte Eurokarte (160mm x 100mm) mit deutscher MwSt.&#039;&#039;&#039; ohne Versand kostet.&lt;br /&gt;
Dazu noch die Lieferzeit und ob Lötstopplack und Bestückungsdruck dabei ist.&lt;br /&gt;
&#039;&#039;Zusätzlich&#039;&#039; kann man noch die Preise für andere Formate, Stückzahlen etc. dazu schreiben.&lt;br /&gt;
&lt;br /&gt;
== Liste der Hersteller ==&lt;br /&gt;
&lt;br /&gt;
=== Deutschland ===&lt;br /&gt;
&lt;br /&gt;
==== amsTechnology ====&lt;br /&gt;
Homepage: http://www.amstechnology.de&lt;br /&gt;
* Leiterplatten und Bestückung (Prototypen und Kleinserien, bis hin zur Großserie)&lt;br /&gt;
* Sehr schnell&lt;br /&gt;
* Ein- und doppelseitige Leiterplatten, Multilayer. &lt;br /&gt;
* Layoutservice&lt;br /&gt;
* SMD- und THT Bestückung&lt;br /&gt;
* Gerätebau&lt;br /&gt;
* günstige Preise&lt;br /&gt;
* sehr gute Qualität&lt;br /&gt;
* Lieferzeit an 3 AT&lt;br /&gt;
* Bauelementebeschaffung auch schon bei 1 Stück (super funktioniert)&lt;br /&gt;
&lt;br /&gt;
==== andus electronic ====&lt;br /&gt;
Homepage: http://www.andus.de&lt;br /&gt;
* Prototypen Fertigung&lt;br /&gt;
* Top Qualität&lt;br /&gt;
* Top Service&lt;br /&gt;
* Vergleichsweise Teuer&lt;br /&gt;
&lt;br /&gt;
==== ANTtronic ====&lt;br /&gt;
Homepage: http://www.anttronic.de/pcb/&lt;br /&gt;
&amp;lt;!-- früher http://www.gsel.de --&amp;gt;&lt;br /&gt;
* gute Preise, aber Lieferzeit beachten!&lt;br /&gt;
&lt;br /&gt;
==== Basista Leiterplatten ====&lt;br /&gt;
Homepage: http://www.basista.de&lt;br /&gt;
* Eurokarte doppelseitig für 52€ inkl. MwSt / mit Stopplack + Best.Druck 94€ inkl. MwSt&lt;br /&gt;
* Prototypen standardmäßig chemisch zinnbehandelt&lt;br /&gt;
* Preise OK&lt;br /&gt;
* Früher geliefert ohne Aufpreis (7 statt 10 AT)&lt;br /&gt;
* Qualität OK&lt;br /&gt;
&lt;br /&gt;
==== Conti ====&lt;br /&gt;
Homepage: http://www.contag.de&lt;br /&gt;
* Berliner Platinenhersteller&lt;br /&gt;
* vergleichsweise teuer, aber dafür schnell (ab 4 Stunden!!)&lt;br /&gt;
&lt;br /&gt;
==== Elischer Leiterplatten ====&lt;br /&gt;
e-mail: Melischer@aol.com&lt;br /&gt;
* sehr gute Preise, Qual.1A&lt;br /&gt;
* 3KW Lieferzeit&lt;br /&gt;
* Daten laut Google:  Dipl.-Ing. A. Elischer, Am Forst 7, 72574 Bad Urach  Tel. 07125-4498&lt;br /&gt;
* Layoutentwurf, LP Entwicklung, herstellen, bestücken, löten, prüfen&lt;br /&gt;
&lt;br /&gt;
==== Fischer Leiterplatten GmbH ====&lt;br /&gt;
Homepage: http://www.f-l.de/&lt;br /&gt;
* 1 Europlatine inkl. Lack, ohne Bestückungsdruck für 46,50€ in 10 Tagen&lt;br /&gt;
* zweiseitig&lt;br /&gt;
* durchkontaktiert&lt;br /&gt;
* Lötstopp&lt;br /&gt;
* Bestückungsdruck einseitig&lt;br /&gt;
* Bohrungen no limit&lt;br /&gt;
* Verkauf nur an Gewerbetreibende&lt;br /&gt;
&lt;br /&gt;
==== HAKA Elektronik-Leiterplatten GmbH ====&lt;br /&gt;
Homepage: http://www.haka-lp.de/&lt;br /&gt;
* bei Platinen kleiner 1 qdm gibt es entsprechend mehr ohne Aufpreis&lt;br /&gt;
* unter Angebote -&amp;gt; Zwillingsangebot gibt es 2 Europakarten (durchkontaktiert, Lötstop) für knapp 50,-, günstig, wenn man sich seines Layouts sicher ist - auch hierbei kostenlose Duplizierung kleinerer Layouts; Zwillingsangebot ist beschränkt auf Eagle- oder Target-3001-Dateien&lt;br /&gt;
* Lieferzeit 10 Werktage&lt;br /&gt;
* sehr gute Qualität&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- Auf der Homepage ist von Platinen nichts mehr zu sehen --Esko&lt;br /&gt;
==== LED-Hobby ====&lt;br /&gt;
Homepage: http://www.led-hobby.de/&lt;br /&gt;
* Kleinster Leiterbahnabstand: 0,2mm&lt;br /&gt;
* Kleinste Leiterbahnbreite: 0,2mm&lt;br /&gt;
* Kleinste Bohrung: 0,3mm&lt;br /&gt;
* Preis 0,35 EUR pro 1 x 1 cm (folglich 56,- EUR fuer eine doppelseitige Europakarte)&lt;br /&gt;
* RoHS-konform, made in Germany.&lt;br /&gt;
* Es sind alle Konturen, durchkontaktierte Bohrungen, Verzinnung (bleifrei) und beidseitiger grüner Lötstopplack enthalten. Kein Aufpreis, kein Grundpreis, keine Nacharbeit. --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== LEITON ====&lt;br /&gt;
Homepage: [http://www.leiton.de/ leiterplatten-online.de]&lt;br /&gt;
* Flexible Leiterplatten online kalkulieren&lt;br /&gt;
* Alle Layouts werden in der CAM eingehend geprüft&lt;br /&gt;
* Schnellste Bearbeitung von Anfragen &lt;br /&gt;
* Diverse Spezialfertigungen (Aluminiumkern, HF, hoch-Tg etc.)&lt;br /&gt;
* Fließender Übergang vom Prototyp in die Serie möglich&lt;br /&gt;
* Niederlassungen in Hongkong &amp;amp; China für Großserien (LeitOn HK Ltd.)&lt;br /&gt;
* Relativ günstig&lt;br /&gt;
* bei mehreren kleinen Leiterplatten wird nach Gesamtfläche berechnet, nicht nach Mindestfläche x Mindestpreis x Stückzahl&lt;br /&gt;
* Doppelseitige Europlatine mit Lötstop in 8 Tagen 61,25 Eur&lt;br /&gt;
* In 15 Tagen 49 Eur&lt;br /&gt;
* Gute Qualität&lt;br /&gt;
* Bis 8-lagig und ab 12 Std.&lt;br /&gt;
&lt;br /&gt;
==== Microcirtec  ====&lt;br /&gt;
Homepage: http://www.microcirtec.de&lt;br /&gt;
* Direct - Online - Shop — zum Kalkulieren-Bestellen und Kaufen&lt;br /&gt;
* Mit Auftragsverfolgung per Online&lt;br /&gt;
* Vom Rapid Prototyping bis zur Rapid Mass-Production&lt;br /&gt;
* Qualität betrachten wir als selbstverständlich&lt;br /&gt;
&lt;br /&gt;
==== mmetoolshop / MME-Leiterplatten ====&lt;br /&gt;
Homepage: http://mme-pcb.de&lt;br /&gt;
eBay: http://stores.ebay.de/mmetoolshop&lt;br /&gt;
* Verkauft sowohl über die eigene Homepage als auch über eBay (zu identischen Konditionen)&lt;br /&gt;
* Europakarte: ES: 20,60 EUR, DSDK: 41,50 EUR&lt;br /&gt;
* Durchkontaktierung bei zweiseitigen Leiterplatten ist im Preis inbegriffen&lt;br /&gt;
* Trennen und Bohren inklusive&lt;br /&gt;
* Stopplack (11€) und Bestückungsdruck (16€) kosten extra&lt;br /&gt;
* min. Abstand 0,20 mm,  min. Leiterbahnbreite 0,20 mm, kleinste Bohrung 0,4 mm&lt;br /&gt;
&amp;lt;!-- * sehr gute Qualität --&amp;gt;&lt;br /&gt;
* Lieferzeit 8-12 Arbeitstage (bei mir waren es nur 5 Werktage)&lt;br /&gt;
* Überlieferung kostet nichts (häufig wird eine Leiterplatte mehr geliefert, bei mir waren es bei vier bestellten Platinen zwei mehr)&lt;br /&gt;
* Mit einer bestellten einseitigen Platine (DIL Bauteile) bin ich sehr zufrieden&lt;br /&gt;
&lt;br /&gt;
==== Multi PCB Ltd. ====&lt;br /&gt;
Homepage: http://www.multipcb.de/leiterplatten.html&lt;br /&gt;
&amp;lt;!-- nur http://www.multipcb.de zeigt ein Upload-Form (6.4.09 FF und IE) --&amp;gt;&lt;br /&gt;
* nur für Gewerbetreibende&lt;br /&gt;
* Eurokarte doppelseitig mit Lötstopplack und Bestückungsdruck 78€ inkl. MwSt&lt;br /&gt;
* Online Kalkulator&lt;br /&gt;
&amp;lt;!-- (wurde von &amp;quot;ordentlich&amp;quot; auf &amp;quot;hervorragend&amp;quot; vom einem sehr zufriedenen Kunden umgeändert oder vom Anbieter? Anbieter finden ihre Produkte hoffentlich alle hervorragend. &amp;quot;Sehr gute Qualität&amp;quot; nun ohnehin schon unten) * hervoragende Qualität bei gutem Preis  * interessant für Serien; neuer günstiger Service für Prototypen --&amp;gt;&lt;br /&gt;
* farbiger Lötstopplack und Bestückungsdruck möglich&lt;br /&gt;
* 48 Stunden Express&lt;br /&gt;
* Kompletter Design-Rule-Check der CAM-Daten&lt;br /&gt;
* Diverse Spezialfertigungen (Flex, Starrflex, Metallkern, HF, hoch-Tg, etc.)&lt;br /&gt;
* Sehr gute Qualität&lt;br /&gt;
&lt;br /&gt;
==== M &amp;amp; V Leiterplatten - Vertriebs GmbH ====&lt;br /&gt;
Homepage: http://www.mvpcb.de/&lt;br /&gt;
* Bin sehr zufrieden, gute Preise, 10 - 14 Tage&lt;br /&gt;
* Top Qualität, nichts auszusetzen&lt;br /&gt;
* Qualität sehr gut, hohe Auflösung, auch SMD fine pitch möglich&lt;br /&gt;
&lt;br /&gt;
==== PCB Pool ====&lt;br /&gt;
Homepage: http://www.pcb-pool.de/&lt;br /&gt;
* ideal für einzelne Boards und Klein(st)serien&lt;br /&gt;
* Preise im üblichen Rahmen&lt;br /&gt;
* Günstigere Preise für 10er oder 20er Auflage&lt;br /&gt;
* sehr gute Qualität&lt;br /&gt;
* Lieferzeit ab 2 AT&lt;br /&gt;
* SMD-Schablonen&lt;br /&gt;
* Kosten vor Bestellung eindeutig ersichtlich - keine unerwarteten Nebenkosten&lt;br /&gt;
&lt;br /&gt;
==== Q-print/Q-PCB ====&lt;br /&gt;
Homepage: http://www.Q-PCB.de&lt;br /&gt;
* ideal für einzelne Boards und Klein(st)serien&lt;br /&gt;
* supergünstige Preise &lt;br /&gt;
* gute Qualität (u.U. Lötstop etwas unsauber)&lt;br /&gt;
* keine Zusatzpreise für 2x Lötstoplack o.ä.&lt;br /&gt;
* 150 µm kleinste Strukturbreite&lt;br /&gt;
* ohne Aufpreis bekommt man entweder HAL oder Ni/Au, gegen Aufpreis kann man aus einem von beiden wählen&lt;br /&gt;
* SMD-Schablonen&lt;br /&gt;
* Lieferzeit ab 4 AT&lt;br /&gt;
* Platine 50mm x 60mm, doppelseitig: ~45€ incl. Versand und Nachnahme&lt;br /&gt;
* Platine 100mm x 160mm, doppelseitig: 49€ +7€ für Lötstopp +7€ Versand&lt;br /&gt;
&lt;br /&gt;
==== The PCB-Shop / Europrint Deutschland GmbH ====&lt;br /&gt;
Homepage: http://www.thepcbshop.com&lt;br /&gt;
* Punktabzug, da der Preisrechner nur mit Internet Explorer funktioniert&lt;br /&gt;
* gute Qualität&lt;br /&gt;
* guter Preis (inkl. gratis Überlieferungen - 30 kleine Platinen bestellt, 35 bekommen)&lt;br /&gt;
* wenig Statusinformationen (Link zur Statusseite kommt per Mail, dort ändert sich der Status und der Empfänger eigentlich täglich - ist aber trotzdem fristgerecht angekommen)&lt;br /&gt;
&lt;br /&gt;
==== Würth Elektronik GmbH &amp;amp; Co. KG ====&lt;br /&gt;
Homepage: http://www.we-online.de&lt;br /&gt;
* gehört sicherlich nicht zu den preisgünstigsten&lt;br /&gt;
* kann Bauteile in der Leiterplatte fertigen (R, C, Potis u.a.)&lt;br /&gt;
* beherrscht Microvias in allen erdenklichen Varianten&lt;br /&gt;
* sehr kompetentes Ansprechpersonal&lt;br /&gt;
&lt;br /&gt;
==== Onlineshop WEdirekt ====&lt;br /&gt;
&amp;lt;!-- Benutzer:Bede hat diese Beitrag eingefügt und sonst nie etwas im Wiki geschrieben, daher höchstwahrscheinlich Spam. Daher positive Meinung entfernt --&amp;gt;&lt;br /&gt;
Homepage: http://www.wedirekt.de&lt;br /&gt;
* PCB&#039;s in Basistechnologie, 2-8 Lagen&lt;br /&gt;
* SMD Schablonen in allen Ausführungen&lt;br /&gt;
* Europlatine doppelseitig mit Lötstopplack 67€ inkl. MwSt&lt;br /&gt;
* Design- und Applikationsfachbücher rund um EMV&lt;br /&gt;
&amp;lt;!-- * online kalkulieren und bestellen&lt;br /&gt;
* günstig, super Qualität  --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Deutschland sehr günstige===&lt;br /&gt;
Diese Hersteller zeichnen sich durch einen sehr günstigen Preis von &#039;&#039;&#039;unter 30€ pro doppelseitiger Eurokarte&#039;&#039;&#039; aus und können &#039;&#039;&#039;keine Durchkontaktierungen&#039;&#039;&#039; herstellen.&lt;br /&gt;
&lt;br /&gt;
==== Cadgrafik Bauriedl (nur Filme) ====&lt;br /&gt;
Homepages: http://cadgrafik-bauriedl.de/leiterplattenfilme.htm&lt;br /&gt;
&amp;lt;!-- identischer Inhalt: http://www.so-pbdl.de/leiterplattenfilme.htm --&amp;gt;&lt;br /&gt;
* Überträgt Layouts auf hochwertige Folie/Film zum Selberätzen&lt;br /&gt;
* 1,15 € / 100 cm² Film, 2,50 € Mindestbestellwert (Stand März 2009)&lt;br /&gt;
* 2 € Porto (Stand März 2009)&lt;br /&gt;
&lt;br /&gt;
==== EBC Utz Kohl ====&lt;br /&gt;
Homepage: [http://www.e-b-c-elektronik.de http://www.e-b-c-elektronik.de]&lt;br /&gt;
* recht einfach gehalten, daher wirklich günstig&lt;br /&gt;
* Ideal für den Bastler, denen es auf den Preis ankommt&lt;br /&gt;
* Geätzt einseitig Euroformat 160 x 100mm 16,- EUR (zzgl 1,- EUR  Entsorgungspauschale pro Platine)&lt;br /&gt;
* Geätzt doppelseitig Euroformat 160 x 100mm 26,20 (zzgl 2,- EUR  Entsorgungspauschale pro Platine)&lt;br /&gt;
* doppelseitige Platinen sind nicht durchkontaktiert !&lt;br /&gt;
* eigentlich ein Ladengeschäft, versendet jedoch auch&lt;br /&gt;
&lt;br /&gt;
==== Objektif Leiterplatten Ätzstudio ====&lt;br /&gt;
e-mail: objektif@gmx.de&lt;br /&gt;
* Europlatine ab 7,-- Euro&lt;br /&gt;
* hohe Qualität&lt;br /&gt;
* Lieferzeit 1 bis 2 Wochen&lt;br /&gt;
* Keine Durchkontaktierungen möglich&lt;br /&gt;
&lt;br /&gt;
==== Platinenbelichter ====&lt;br /&gt;
Homepage: http://www.platinenbelichter.de&lt;br /&gt;
* sehr preiswert&lt;br /&gt;
* Ein- und Doppelseitig bis 300x200mm&lt;br /&gt;
* eine doppelseitige Europlatine kostet 13,50 EUR Grundpreis + Bohrung 1,8cent + Optionen&lt;br /&gt;
* Keine Durchkontaktierungen möglich&lt;br /&gt;
* Lieferzeit von bis zu 8 &#039;&#039;&#039;Arbeits&#039;&#039;&#039;tagen nach Geldeingang&lt;br /&gt;
&lt;br /&gt;
==== Platinendesign ====&lt;br /&gt;
Homepage: http://www.platinendesign.de/&lt;br /&gt;
* sehr preiswert&lt;br /&gt;
* Ein- und Doppelseitig bis 200x250mm&lt;br /&gt;
* eine doppelseitige Europlatine kostet 14 EUR Grundpreis + Bohrung 2cent + Optionen&lt;br /&gt;
* keine Angabe ob Durchkontaktiert&lt;br /&gt;
*Lötstoplack grün&lt;br /&gt;
* Lieferzeit von bis zu 8 &#039;&#039;&#039;Arbeits&#039;&#039;&#039;tagen nach Geldeingang&lt;br /&gt;
&lt;br /&gt;
=== Ausland ===&lt;br /&gt;
&lt;br /&gt;
==== BatchPCB ====&lt;br /&gt;
Homepage: http://www.batchpcb.com (USA)&lt;br /&gt;
* Vermittler und keine eigene Herstellung (&amp;quot;PCB pooling service&amp;quot;), Hersteller vermutlich meist [[Platinenhersteller#Gold Phoenix|Gold Phoenix]]&lt;br /&gt;
* verbandelt mit Sparkfun (&amp;quot;off shoot of Spark Fun Electronics&amp;quot;)&lt;br /&gt;
* &amp;quot;We only offer one service at this time: 2 layer PCBs with soldermask both sides and silkscreen both sides. The minimum trace width is 8mil with 8 mil spacing.&amp;quot;&lt;br /&gt;
* relativ günstig, lange Lieferzeiten, weiteres siehe Homepage und [http://www.batchpcb.com/faq.php BatchPCB FAQ]&lt;br /&gt;
&lt;br /&gt;
==== BILEX-LP ====&lt;br /&gt;
Homepage http://www.bilex-lp.com/ (Bulgarien)&lt;br /&gt;
* deutschsprechender Ansprechpartner&lt;br /&gt;
* liefern bleifreie Platinen(RoHs konform)&lt;br /&gt;
* 31€ für eine doppelseitige Eurokarte ohne Lack und Druck&lt;br /&gt;
* SMD- und THT Bestückung &lt;br /&gt;
* Layoutservice &lt;br /&gt;
* Lieferzeit ab 3-4 AT &lt;br /&gt;
* insgesamt von 5 bis 7 AT Anlieferung bei Airmail (Porto ab 4,-Euro)&lt;br /&gt;
* FedEx wollte von Bulgarien aus ab 27,-Euro, 1-2AT)&lt;br /&gt;
* Löcher größer 6 mm wurden nicht gebohrt, sondern gefreast(gegen Anfrage)&lt;br /&gt;
* Berichtete Qualitätsmängel (mglw. Einzelfälle): ausgefranste Plantinenfräsung, Lötstoplack hebt ab(nur bei Sn-Pb beschichtung, nehmen Sie besser Ni-Au).&lt;br /&gt;
* Fräsungen müssen extra bestellt werden! Aber trotzdem guenstig&lt;br /&gt;
&lt;br /&gt;
==== CUBE CZ s.r.o. ====&lt;br /&gt;
Homepage http://www.cube.cz/ (Tschechische Republik)&lt;br /&gt;
&lt;br /&gt;
==== Euro PCB Ltd. ====&lt;br /&gt;
Homepage http://www.europcb.com/ (Großbritannien)&lt;br /&gt;
* Günstige Leiterplatten&lt;br /&gt;
* Schnelle Lieferung&lt;br /&gt;
* Qualitativ OK&lt;br /&gt;
&lt;br /&gt;
==== Gold Phoenix ====&lt;br /&gt;
Homepage http://www.goldphoenixpcb.biz/ (VR China)&lt;br /&gt;
&lt;br /&gt;
==== MakePCB ====&lt;br /&gt;
Homepage http://www.makepcb.com/ (Shanghai, VR China)&lt;br /&gt;
&lt;br /&gt;
==== OLIMEX Ltd. ====&lt;br /&gt;
Homepage http://www.olimex.com (Bulgarien)&lt;br /&gt;
&lt;br /&gt;
Habe mehrere Jahre bei Olimex meine Prototypen herstellen lassen. Stets saubere Arbeit erhalten. Bis ich denen mal falsche Gerber-Dateien zusandte. Als ich einige Stunden spaeter den Fehler bemerkt hatte, bat ich um Stornierung und Neuzusendung. Gegen ein zusaetzliches Entgelt wurde dies akzeptiert.&lt;br /&gt;
Die angesagten Zusatzkosten wurden zwar von mir nicht abgebucht, aber ich erhielt  1 Woche spaeter die anfaenglich falsch zugesandten PCB&#039;s.&lt;br /&gt;
Die Zusammenfassung des darauffolgenden Email-Verkehrs: Ein Schulterzucken seitens Olimex und die Bitte, eine neue, kostenpflichte Bestellung zu taetigen.&lt;br /&gt;
&lt;br /&gt;
==== PAD2PAD ====&lt;br /&gt;
Homepage http://www.pad2pad.com/ (USA)&lt;br /&gt;
* Bestücken die Platinen auch mit Digikey-Bauteilen.&lt;br /&gt;
&lt;br /&gt;
==== PCBCart ====&lt;br /&gt;
Homepage http://www.pcbcart.com/ (China)&lt;br /&gt;
* auch kompliziertere Designs&lt;br /&gt;
* schnell und zuverlässig&lt;br /&gt;
&lt;br /&gt;
==== PCBPro ====&lt;br /&gt;
Homepage http://www.pcbpro.com/ (USA)&lt;br /&gt;
* Bei größeren Mengen (z.B. 100 Stück) sehr niedrige Preise&lt;br /&gt;
&lt;br /&gt;
==== Top-Tec-PCB ====&lt;br /&gt;
Homepage http://www.top-tec-pcb.com/ (Großbritannien)&lt;br /&gt;
* Günstig für Klein- bis Großserien&lt;br /&gt;
* Discount bei Nachbestellung&lt;br /&gt;
* sehr gute Technik (z.B. 100µm Bohren oder 75µm Leiterbahn)&lt;br /&gt;
* deutschsprechender Ansprechpartner&lt;br /&gt;
* liefern bleifreie Platinen (HAL, chem. Gold, Silber u. Zinn)&lt;br /&gt;
* 48h Eildienst&lt;br /&gt;
&lt;br /&gt;
==== The PCB Shop ====&lt;br /&gt;
Homepage http://www.thepcbshop.com/ (Belgien)&lt;br /&gt;
* Für einfache Sachen&lt;br /&gt;
&lt;br /&gt;
==== PIU-Printex ====&lt;br /&gt;
Homepage http://www.piu-printex.at/ (Österreich)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Preisvergleichstabelle (Stand Juli 2009) ==&lt;br /&gt;
&lt;br /&gt;
Preise für ein oder zwei Europlatinen (160x100), doppelseitig, kein Druck, inkl. MwSt, ohne Versand.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; align=&amp;quot;center&amp;quot; style=&amp;quot;text-align:center&amp;quot;&lt;br /&gt;
!Hersteller || Preis (€) 1x || Preis (€) 2x&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;ohne Lötstopp&#039;&#039;&lt;br /&gt;
|----&lt;br /&gt;
!Basista Leiterplatten&lt;br /&gt;
| 43,66 || 81,61&lt;br /&gt;
|----&lt;br /&gt;
!Fischer Leiterplatten GmbH &lt;br /&gt;
| 39,00 || 80,00&lt;br /&gt;
|-&lt;br /&gt;
!HAKA Elektronik-Leiterplatten GmbH&lt;br /&gt;
| 45,00 || 49,88&lt;br /&gt;
|-&lt;br /&gt;
!LEITON&lt;br /&gt;
| 39,98 || 76,01&lt;br /&gt;
|-&lt;br /&gt;
!MME-Leiterplatten&lt;br /&gt;
| 41,44 || ?&lt;br /&gt;
|-&lt;br /&gt;
!PCB Pool&lt;br /&gt;
| 50,27 || 100,54&lt;br /&gt;
|-&lt;br /&gt;
!Q-print/Q-PCB&lt;br /&gt;
| 48,89 || ?&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;mit Lötstopp&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
!Multi PCB Ltd. &lt;br /&gt;
| 65,60 || 131,20&lt;br /&gt;
|-&lt;br /&gt;
!M &amp;amp; V Leiterplatten - Vertriebs GmbH&lt;br /&gt;
| 62,82 || ?&lt;br /&gt;
|-&lt;br /&gt;
!Onlineshop WEdirekt &lt;br /&gt;
| 67,06 || 94,01&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- == siehe auch ==&lt;br /&gt;
[[Linksammlung#Leiterplattenhersteller|Linksammlung - Abschnitt Platinenhersteller]] --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:Platinen]]&lt;/div&gt;</summary>
		<author><name>Thymythos</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=RFM12&amp;diff=33795</id>
		<title>RFM12</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=RFM12&amp;diff=33795"/>
		<updated>2009-01-13T17:19:59Z</updated>

		<summary type="html">&lt;p&gt;Thymythos: /* Status Read */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Beschreibung der Funkmodule RFM01, RFM02 und RFM12.&lt;br /&gt;
&lt;br /&gt;
Benötigt werden in der Minimal-Version im FIFO-Modus nur die Anschlüsse nSEL, SDO, SDI und SCK, eben das komplette SPI-Interface. Der Zugriff auf das Sende- und Empfangs-FIFO ist per Software möglich, ebenso die Abfrage der Statusbits. Deshalb werden z.B. nIRQ und nFFS nicht unbedingt benötigt. nIRQ signalisiert unter anderem, dass das Modul bereit ist Daten zu empfangen. Wenn Daten empfangen wurden, kann dies über den FFIT-Pin abgefragt werden (falls die Füllschwelle eingestellt wurde). nFFS dient dazu das FIFO direkt anzusprechen (es ist quasi der Chipselect für das FIFO), davon wird in der Minimalversion aber kein Gebrauch gemacht. Der Pin muss daher auf high-Pegel gelegt werden!&lt;br /&gt;
An CLK kann eine Frequenz von 1MHz bis 10MHz eingestellt werden. Hiermit kann dann z.B. der Mikrocontroller versorgt werden.&lt;br /&gt;
Reset ist ein Open-Collector-Ausgang und gleichzeitig der Reset-Eingang. Er sollte daher entweder gar nicht, oder aber hochohmig angeschlossen werden.&lt;br /&gt;
&lt;br /&gt;
Im FIFO-Mode kann das Modul konfiguriert werden mit dem Empfang zu warten, bis die Daten 0x2DD4 empfangen wurden. Sobald dieses Bitmuster empfangen wurde, werden Daten in das FIFO geschrieben, bis man das FIFO abschaltet und die Mustererkennung neu startet.&lt;br /&gt;
&lt;br /&gt;
Als weitere Modi stehen unter anderem ein synchroner Modus zur Verfügung (no FIFO mode), in dem der Sender/Empfänger den Bittakt ausgibt, und synchron dazu die zu sendenden Daten einliest bzw. die empfangenen Daten ausgibt. Der SPI Bus ist trotzdem zur Initialisierung des Moduls notwendig.&lt;br /&gt;
&lt;br /&gt;
== FAQ ==&lt;br /&gt;
&lt;br /&gt;
=== SPI Interface ===&lt;br /&gt;
&lt;br /&gt;
* Maximale Datenrate: 2,5MHz (10MHz Quarz / 4)&lt;br /&gt;
&lt;br /&gt;
=== CLK-Ausgang bleibt bei 1 MHz ===&lt;br /&gt;
&lt;br /&gt;
* Vor dem Umschalten (mit 0xC0E0) länger warten.&lt;br /&gt;
&lt;br /&gt;
=== RFM12 empfängt ein paar Bytes, dann nur Müll ===&lt;br /&gt;
&lt;br /&gt;
* Es wird zu langsam gesendet (TX FIFO underrun)&lt;br /&gt;
* Es wird zu langsam empfangen (RX FIFO overrun)&lt;br /&gt;
&lt;br /&gt;
Die Status-Bits helfen hier beim Debuggen. SPI sollte auf maximaler Transferrate stehen.&lt;br /&gt;
&lt;br /&gt;
=== RFM empfängt nur Müll ===&lt;br /&gt;
&lt;br /&gt;
http://www.mikrocontroller.net/topic/73560#605528&lt;br /&gt;
&lt;br /&gt;
Deine Module verhalten sich normal. Man muß mit den Gain- und AFC-Bits&lt;br /&gt;
eine ganze Weile spielen, bis die Module korrekt laufen (kommt auf die&lt;br /&gt;
Anwendung an). Fakt ist: der Empfänger empfängt ständig Datenmüll als&lt;br /&gt;
Rauschen. Wenn der FIFO durch die Präambel getriggert wird, sind die&lt;br /&gt;
Daten im FIFO ziemlich korrekt, wenn alles &amp;quot;gut&amp;quot; eingestellt ist. Der&lt;br /&gt;
FIFO sollte per Interrupt dann auch sofort abgeholt werden, da sonst das&lt;br /&gt;
nächste Byte das alte direkt überschreibt. Jeder zusammenhängende&lt;br /&gt;
Datensatz (mehrere Bytes an einem Stück) muß von einer Präambel&lt;br /&gt;
eingeleitet werden. Nach dem kompletten Einlesen eines Datensatzes muß&lt;br /&gt;
der FIFO abgeschaltet, wieder eingeschaltet und für den Empfang der&lt;br /&gt;
nächsten Präambel neu scharf gemacht werden.&lt;br /&gt;
&lt;br /&gt;
=== RFM hängt sich auf ===&lt;br /&gt;
&lt;br /&gt;
Wenn man die AFC nicht begrenzt, also keinen Wertebereich vorgibt, die eine maximale Abweichung korrigiert wird passiert es nach einer Weile, dass sich der Empfänger aufhängt, die Offsetbits im Status werden maximal und dann geht gar nichts mehr, er hängt fest.&lt;br /&gt;
&lt;br /&gt;
Siehe auch &lt;br /&gt;
* Forenbeitrag [http://www.mikrocontroller.net/topic/82456#689660 RFM12: Erfahrungen ]&lt;br /&gt;
&lt;br /&gt;
=== Kommunikation mit RFM funktioniert nur sporadisch ===&lt;br /&gt;
&lt;br /&gt;
* Ist die Versorgungsspannung stabil? (evtl. Kondensator einbauen)&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Register ==&lt;br /&gt;
&lt;br /&gt;
Von https://www.mikrocontroller.net/attachment/24947/RFM12.txt&lt;br /&gt;
&lt;br /&gt;
Dieses Dokument beschreibt die Nutzung des RFM12 TRX Moduls!&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039; WICHTIG &#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Dieses Dokument wurde aus mehreren Quellen zusammengestellt, und kann Fehler enthalten!&lt;br /&gt;
Es können Abweichungen in Bezug auf RF01 / RF02 / RF12 / RFM01 / RFM02 und andere Module auftreten!&lt;br /&gt;
Es wurde das Datenblatt vom RFM12B und RF12 von www.hoperf.com als Basis genuzt. Zusätzlich wurden diese Informationen mit Hilfe von Forums-Nutzern (https://www.mikrocontroller.net/topic/71682) weiter vervollständigt!&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039; WICHTIG &#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Hinweis:&#039;&#039;&#039; Die LNA-Eingangsimpedanz beträgt 250 Ohm, und muss beim Anschluss einer 50-Ohm-Antenne entsprechend angepasst werden, um das Rauschen zu minimieren! &#039;&#039; -- (Auf den Pollin-Modulen bereits vorhanden)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configuration Setting ===&lt;br /&gt;
 Hex = 80 &amp;amp; xx&lt;br /&gt;
 Bit-Syntax: &lt;br /&gt;
{| cellpadding=&amp;quot;2&amp;quot; cellspacing=&amp;quot;0&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
!width=&amp;quot;20%&amp;quot;| Byte ||width=&amp;quot;40%&amp;quot;| 1 || 2&lt;br /&gt;
|-&lt;br /&gt;
!Bits&lt;br /&gt;
|{{8Bit|width=100%| 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 }}||{{8Bit|width=100%| el | ef | b1 | b0 | x3 | x2 | x1 | x0}}|}&lt;br /&gt;
 el (TX FIFO) = Sendepuffer für Datentransfer nutzen (1 = An / 0 = Aus)&lt;br /&gt;
 ef (RX FIFO) = Empfangspuffer für Datenspeicherung nutzen (1 = An / 0 = Aus)&lt;br /&gt;
 b... = Zu nutzende Basisfrequenz (00=315MHz / 01=433MHz / 10=868MHz / 11=915MHz)&lt;br /&gt;
 x... = Interner Clock des Chips kann durch verschieben einer Kondensator-Anpass-Stufe bestimmt werden.&lt;br /&gt;
        0,5pF pro Schritt. Basis ist 8,5pF -&amp;gt; (0000=8,5 / 0001=9,0 / 0010=9,5 / ...)&lt;br /&gt;
&lt;br /&gt;
=== Power-Managment ===&lt;br /&gt;
 Hex = 82 &amp;amp; xx&lt;br /&gt;
 Bit-Syntax: 10000010 | er | ebb | et | es | ex | eb | ew | dc&lt;br /&gt;
 er = Empfänger einschalten (1 = an / 0 = Aus)&lt;br /&gt;
 ebb = ... (Synthesizer muss aktiv sein!) (1 = an / 0 = aus)&lt;br /&gt;
 et = Sender einschalten (1 = an / 0 = Aus) (Wenn das TX-Register aktiv und mit Daten gefüllt ist/wurde,&lt;br /&gt;
      werden diese Daten sofort gesendet) (1 = an / 0 = aus)&lt;br /&gt;
 es = Schaltet den Synthesizer ein. (1 = an / 0 = aus)&lt;br /&gt;
 ex = Schaltet den Quarz-Oszilator ein. (1 = an / 0 = aus)&lt;br /&gt;
 eb = Vergleichbar mit BrownOutDetection -&amp;gt; Erkennt eine zu geringe Betriebsspannung und erzeugt einen Interrupt,&lt;br /&gt;
      um einen drohenden Spannungsaufall anzukündigen (1 = An / 0 = Aus)&lt;br /&gt;
 ew = Aktiviert den WakeUpTimer des Prozessors. (1 = an / 0 = aus)&lt;br /&gt;
 dc = Deaktiviert die Ausgabe des SystemClocks auf dem CLK Pin am Chip (1 = Keine ClockAusgabe / 0 = Clock ausgeben)&lt;br /&gt;
&lt;br /&gt;
=== PLL Setting ===&lt;br /&gt;
 Hex = 198 + y&lt;br /&gt;
 Bit-Syntax: 110011000 | ob1 | ob0 | lpx | ddy | ddit | bw1 | bw0&lt;br /&gt;
 ob... = ... (00= 5 oder 10MHz [standard] / 01=3.3MHz / 1x=2.5MHz oder weniger)&lt;br /&gt;
 lpx = Wählt den Low-Power-Mode für den Quarz-Oszilator aus. (0=1ms [620µA] / 1=2ms [460µA])&lt;br /&gt;
 ddy = ...&lt;br /&gt;
 ddi = Schaltet das Dithering in PLL-Schleife ab. (1=abgeschaltet / 0=eingeschaltet)&lt;br /&gt;
 bw... = Wählt die Bandbreite des PLL-Signals aus. (00=86.2kbps [-107dBc/Hz] / 01=256kbps [-102dBc/Hz]) Bei 1MHz Offset Phasenrauschen.&lt;br /&gt;
&lt;br /&gt;
=== LowBatt / µC Clock Control ===&lt;br /&gt;
 Hex = c0 &amp;amp; xx&lt;br /&gt;
 Bit-Syntax: 11000000 | d2 | d1 | d0 | v4 | v3 | v2 | v1 | v0&lt;br /&gt;
 d... = Bestimmt den Teilungsfaktor für die Clockausgabe am CLK-Pin in Abhängigkeit des Internen SystemTakts.&lt;br /&gt;
        (000=1 / 001=1.25 / 010=1.66 / 011=2 / 100=2.5 / 101=3.33 / 110=5 / 111=10)&lt;br /&gt;
 v... = Bestimmt die Minimalspannung, ab der ein Interrupt durchgeführt werden&lt;br /&gt;
 muss. (Ähnlich einer BrownOutDetection). Im Power-Managment muss das eb-Bit&lt;br /&gt;
 aktiv sein, damit dies funktioniert.&lt;br /&gt;
&lt;br /&gt;
=== Frequency-setting ===&lt;br /&gt;
Bestimmt den Offset der Sende- und Empfangsfrequenz. Dieser Offset wird auf das Basisband im Configuration Setting hinzu gerechnet.&lt;br /&gt;
 Hex = a &amp;amp; xxx&lt;br /&gt;
 Bit-Syntax:&lt;br /&gt;
{| cellpadding=&amp;quot;2&amp;quot; cellspacing=&amp;quot;0&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
!width=&amp;quot;20%&amp;quot;| Byte ||width=&amp;quot;40%&amp;quot;| 1 || 2&lt;br /&gt;
|-&lt;br /&gt;
!Bits&lt;br /&gt;
|{{8Bit|width=100%| 1 | 0 | 1 | 0 | f11 | f10 | f9 | f8 }}||{{8Bit|width=100%| f7 | f6 | f5 | f4 | f3 | f2 | f1 | f0}}|}&lt;br /&gt;
&lt;br /&gt;
 f... = Bestimmt den Offsetwert der Frequenz.&lt;br /&gt;
        Als Basis gilt das eingestellte Band im Configuration-Settings-Kommando&lt;br /&gt;
&lt;br /&gt;
freq = 10 * C1 * (C2 + f/4000) [MHz]&lt;br /&gt;
&lt;br /&gt;
{| cellspacing=&amp;quot;0&amp;quot; border=&amp;quot;1&amp;quot; style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
! Band || C1 || C2&lt;br /&gt;
|-&lt;br /&gt;
| 315 || 1 || 31&lt;br /&gt;
|-&lt;br /&gt;
| 433 || 1 || 43&lt;br /&gt;
|-&lt;br /&gt;
| 868 || 2 || 43&lt;br /&gt;
|-&lt;br /&gt;
| 915 || 3 || 30&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Data-Rate ===&lt;br /&gt;
 Hex = c6 &amp;amp; xx&lt;br /&gt;
 Bit-Syntax: 11000110 | cs | r6 | r5 | r4 | r3 | r2 | r1 | r0&lt;br /&gt;
 cs =  Vorteiler, Faktor 7. Hiermit kann ein Vorteiler aktiviert werden,&lt;br /&gt;
       der die errechnete Baudrate (r...) durch 7 teilt.&lt;br /&gt;
 r... = Baudratenteilerfaktor&lt;br /&gt;
&lt;br /&gt;
=== RX Control ===&lt;br /&gt;
 Hex = 94 &amp;amp; xx&lt;br /&gt;
 Bit-Syntax: 10010 | p20 | d1 | d2 | i2 | i1 | i0 | g1 | g0 | r2 | r1 | r0&lt;br /&gt;
 p20 = Bestimmt die Funktion des Pin20 (nINT / VDI) am RFM12 Chip (1 = VDI-Ausgang / 0 = Interrupt-Eingang)&lt;br /&gt;
 d... = (Valid Data Indicator). Definiert die Geschwindigkeit, mit der bestimmt wird, ob ein Signal korrekt ist, oder nicht.&lt;br /&gt;
        (00=schnell / 01=mittel / 10=langsam / 11=immer an). Je nach eingestellter Variante werden&lt;br /&gt;
        unterschiedliche Hardware- und Software-Kombinationen genuzt.&lt;br /&gt;
        Fast:  CR_Lock  OR  DQD  ... Medium:  CR_Lock  AND ( DRSSI  OR  DQD ) ... &lt;br /&gt;
        SLOW: R/S FlipFlop aus (SET)  DRSSI  OR  DQD  OR  CR_Lock  und (CLR)  DRSSI  AND  DQD  AND  CR_Lock .&lt;br /&gt;
 i... = Bestimmt die Bandbreite des Empfängers in KHz (KiloHertz).&lt;br /&gt;
        (000=Reserviert / 001=400 / 010=340 / 011=270 / 100=200 / 101=134 / 110=67 / 111=Reserviert)&lt;br /&gt;
 g... = (LNA-Gain) Verstärkungsfaktor des Rauscharmen-Eingangs-Signal-Verstärkers (LNA Low Noise Amplifier).&lt;br /&gt;
        Werte in dBm (Dezibel [Grösse: Milliwatt]) Mögliche Werte sind: 0 / -6 / -14 / -20&lt;br /&gt;
 r... = (DRSSI = Digital Received Signal Strength Indication) Minimale Empfangssignalfeldstärke.&lt;br /&gt;
        6 dBm pro Schritt: (000=-103 / 001=-97 / 010=-91 / ...)&lt;br /&gt;
&lt;br /&gt;
=== Synchron Pattern ===&lt;br /&gt;
 Hex = ce &amp;amp; xx&lt;br /&gt;
 Bit-Syntax: 11001110 | b7 | b6 | b5 | b4 | b3 | b2 | b1 | b0&lt;br /&gt;
 b... = Legt den Wert fest, der als Synchronisations-Byte für die Datenfilterung verwendet werden soll.&lt;br /&gt;
&lt;br /&gt;
=== Data Filter ===&lt;br /&gt;
 Hex = c2 &amp;amp; xx&lt;br /&gt;
 Bit-Syntax: 11000010 | al | ml | -unknow- (1) | s | -unknow- (1) | f2 | f1 | f0&lt;br /&gt;
 al = Baudratenregenerator schaltet automatisch in den langsamen Modus, &lt;br /&gt;
      sobald er einen Takt erkannt hat.&lt;br /&gt;
 ml = schneller/langsamer Modus&lt;br /&gt;
 -unknown- (1) = ??? (Standard = 1) (Auch im Datenblatt von IA4420 so beschrieben)&lt;br /&gt;
 s = (DataFilter) Typ des Datenfilters (0=DigitalFilter / 1=AnalogFilter).&lt;br /&gt;
     Bei Nutzung des Analog-Filters kann kein FIFO sowie kein ClockRecovery genuzt werden.&lt;br /&gt;
 -unknown- (1) = ??? (Standard = 1) (Auch im Datenblatt von IA4420 so beschrieben)&lt;br /&gt;
 f... = (DQD Threshold) Bestimmt den Schwellwert, ab dem ein Signal als gut empfunden wird,&lt;br /&gt;
         und der Empfänger dieses weiterverarbeiten soll.&lt;br /&gt;
         DQD (data quality detection) zählt die &amp;quot;Spikes&amp;quot; des ungefilterten Signals, und bestimmt darüber die Qualität der Daten.&lt;br /&gt;
&lt;br /&gt;
=== FIFO und RESET-Mode ===&lt;br /&gt;
 Hex = ca &amp;amp; xx&lt;br /&gt;
 Bit-Syntax: 11001010 | f3 | f2 | f1 | f0 | sp | al | ff | dr&lt;br /&gt;
 f... = (FIFO interrupt Level)&lt;br /&gt;
 sp = (Sync-Pattern length) Legt die Länge des Synchron-Patterns fest&lt;br /&gt;
      (0 = 2Byte / 1 = 1Byte)&lt;br /&gt;
 al = (FIFO Fill Condition) Legt den Wert fest, ab dem das Füllen des FIFOs beginnt.&lt;br /&gt;
      (0=Synchron / 1=Ständig). Bei Nutzung des Synchron-Modus, werden erst dann Daten in den FIFO geschrieben,&lt;br /&gt;
      wenn eine definierte 8-Bit od. 16-Bit lange Datenfolge empfangen wurde (Standard ist Hex: 2dd4,&lt;br /&gt;
      das LSB kann geändert werden und stellt das 8-Bit Synchron-Pattern dar).&lt;br /&gt;
 ff = (FIFO Fill) Startet das Einlesen der empfangenen Daten in den FIFO-Puffer.&lt;br /&gt;
      Wenn al (FIFO Fill Condition) auf synchron steht, dann startet das Setzen dieses Bits die Synchronisation-Bit-Erkennung.&lt;br /&gt;
 dr = (Sens Reset Mode) Wenn dieses Bit auf 0 steht, wird bei einer Schwankung von 200mV auf&lt;br /&gt;
      der VCC-Leitung (Spannungsversorgung des Chips), ein System-Reset ausgelöst.&lt;br /&gt;
&lt;br /&gt;
=== Automatic Frequency Control ===&lt;br /&gt;
 Hex = c4 &amp;amp; xx&lt;br /&gt;
 Bit-Syntax: 11000100 | a1 | a0 | rl1 | rl0 | st | fi | oe | en&lt;br /&gt;
 a... = Modus der AFC-Schaltung, 0=Auto, 1=einmalig nach Einschalten, 2=Solange VDI low ist, 3=unabhängig von VDI&lt;br /&gt;
 r... = (Range Limit) Frequenzraster (00=KeineBegrenzung / 01=+15 &amp;gt; -16 / 10=+7 &amp;gt; -8 / 11=+3 &amp;gt; -4)&lt;br /&gt;
 st = Berechneten Offset-Wert übernehmen&lt;br /&gt;
 fi = Genauer Berechnungsmodus (besser aber lansgamer)&lt;br /&gt;
 oe = AFC-Offset freischalten&lt;br /&gt;
 en = AFC-Berechnung aktivieren&lt;br /&gt;
&lt;br /&gt;
=== TX Configuration Control ===&lt;br /&gt;
 Hex = 98 &amp;amp; xx&lt;br /&gt;
 Bit-Syntax: 1001100 | mp | m3 | m2 | m1 | m0 | -unknow- (0) | p2 | p1 | p0&lt;br /&gt;
 mp = (Modulation Polarity) Bestimmt die Richtung der FSK-Erzeugung (invertiert das Spektrum).&lt;br /&gt;
 m... = (fDeviation) Bestimmt den Frequenzabstand des High- und Low-Wertes bei der Ubertragung im FSK-Betrieb. Basis ist der mp-Wert.&lt;br /&gt;
 -unknown- (0) = ??? (Standard = 0) (Auch im Datenblatt von IA4420 so beschrieben)&lt;br /&gt;
 p... = Bestimmt die relative Ausgangsleistung des Senders anhand des dBm-Wertes (Dezibel [Grösse: Milliwat]) 3-dBm-Schritte.&lt;br /&gt;
        (000=0 / 001=-3 / 010=-6 / ...). Der Wert steht im Zusammenhang mit der angeschlossenen Antennen-Impedanz.&lt;br /&gt;
&lt;br /&gt;
=== Wake-Up Timer ===&lt;br /&gt;
 Bestimmt die Zeitperiode der zyklischen Einschaltung des WakeUp-Timers&lt;br /&gt;
 Hex = e &amp;amp; xxx&lt;br /&gt;
 Bit-Syntax: 111 | R4 | R3 | R2 | R1 | R0 | M7 | M6 | M5 | M4 | M3 | M2 | M1 | M0&lt;br /&gt;
 R = Exponent der Zeit&lt;br /&gt;
 M = Zeit&lt;br /&gt;
&lt;br /&gt;
=== Low Duty-Cycle ===&lt;br /&gt;
&lt;br /&gt;
Bestimmt die maximale Sendezeit pro Stunde. Dies ist wichtig, um sich an gesetzliche Frequenzzuteilungsrichtlinien zu halten, die bestimmen, wie lang jemand mit einer definierten Sendeleistung auf einer bestimmten Frequenz (mit eventuell definierter Betriebsart [Modulationstyp]) senden darf.)&lt;br /&gt;
&lt;br /&gt;
 hex = 6400 + Bits&lt;br /&gt;
 Bit-Syntax: 1100100 | r| d6 | d5 | d4 | d3 | d2 | d1 | d0 | en&lt;br /&gt;
 r =  ??????????????????&lt;br /&gt;
 d... = Einschaltdauer während der zyklischen Einschaltung&lt;br /&gt;
 en = zyklische Einschaltung aktivieren&lt;br /&gt;
&lt;br /&gt;
=== RX FIFO Read ===&lt;br /&gt;
 Hex = b000&lt;br /&gt;
 Bit-Syntax: 1011000000000000&lt;br /&gt;
&lt;br /&gt;
Dieses Kommando löst die Rückgabe eines Datenbytes (synchron mit dem 8. Bit) aus. Es ist nötig, dass das ef-Bit (RX-FIFO) im Configuration Setting gesetzt wurde, um diese Funktion nutzen zu können!&lt;br /&gt;
&lt;br /&gt;
=== TX Register Write ===&lt;br /&gt;
Dieses Kommando schreibt Daten in den TX-Puffer. Wenn der Sender aktiv ist, wird dieses sofort gesendet. el (TX-Register) muss im Configuration-Setting-Kommando aktiv sein.&lt;br /&gt;
 Hex = b8 &amp;amp; xx&lt;br /&gt;
 Bit-Syntax: 10111000 | DataByteToSend&lt;br /&gt;
 DataByteToSend = Das Datenbyte, welches gesendet werden soll.&lt;br /&gt;
&lt;br /&gt;
(Senden Funktioniert nur wenn zuvor der Status abgefragt wurde)&lt;br /&gt;
&lt;br /&gt;
=== Status Read ===&lt;br /&gt;
Dieses Kommando löst die Rückgabe des Statusregisters aus, welches nach der ersten 0 im ersten Bit synchron übertragen wird.&lt;br /&gt;
 Hex = 0000&lt;br /&gt;
 Bit-Syntax: 0000000000000000&amp;lt;000&amp;gt;&lt;br /&gt;
 Rückgabe-Syntax: x0 | x1 | x2 | x3 | x4 | x5 | x6 | x7 | x8 | x9 | x10 | x11 | x12 | x13 | x14 | x15 | x16 | x17 | x18&lt;br /&gt;
 x0 -&amp;gt; x5 = Interrupt bits&lt;br /&gt;
 x6 -&amp;gt; x15 = Status Bits&lt;br /&gt;
 x16 -&amp;gt; x18 = FIFO&lt;br /&gt;
 x0 = FFIT / RGIT (RGIT = TX-Register ist bereit neue Daten zu senden ... kann mit dem TX-Register gelöscht werden)&lt;br /&gt;
     (FFIT = Die Anzahl der Datenbits im FIFO-Puffer hat das eingestellte Limit erreicht.&lt;br /&gt;
      Kann mit einer der FIFO-Lesemethoden gelöscht werden)&lt;br /&gt;
 x1 = POR (PowerOnReset)&lt;br /&gt;
 x2 = FFOV / RGUR (RGUR = Der Datenstrom beim Senden ist abgerissen, da nicht schnell genug Daten nachgeladen wurden)&lt;br /&gt;
      (FFOV = Der RX-FIFO ist übergelaufen)&lt;br /&gt;
 x3 = WKUP&lt;br /&gt;
 x4 = EXT (Externer IRq vom nINT-Pin)&lt;br /&gt;
 x5 = LBD (Low Battery Detected)&lt;br /&gt;
 x6 = FFEM (Der FIFO-Puffer ist leer/EMpty)&lt;br /&gt;
 x7 = RSSI/ATS (ATS = )(RSSI = Die Signalstärke ist über dem eingestelltem Limit)&lt;br /&gt;
 x8 = DQD&lt;br /&gt;
 x9 = CRL&lt;br /&gt;
 x10 = ATGL&lt;br /&gt;
 x11 = OFFS_6 (sign of offset)&lt;br /&gt;
 x12 = OFFS_3&lt;br /&gt;
 x13 = OFFS_2&lt;br /&gt;
 x14 = OFFS_1&lt;br /&gt;
 x15 = OFFS_0&lt;br /&gt;
 x16 = FO&lt;br /&gt;
 x17 = FO+1&lt;br /&gt;
 x18 = FO+2&lt;br /&gt;
&lt;br /&gt;
== Bezugsquellen ==&lt;br /&gt;
* [[Elektronikversender#csd-electronics|csd-electronics]]&lt;br /&gt;
* [[Elektronikversender#IT-WNS|IT-WNS]]&lt;br /&gt;
* [[Elektronikversender#Pollin_Electronic|Pollin Electronic]]&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
* [[AVR RFM12]]&lt;br /&gt;
* [[RFM12 Protokoll Stack]]&lt;br /&gt;
* [http://www.mikrocontroller.net/topic/93801 Bezugsquellen]&lt;br /&gt;
* [http://roulette.das-labor.org/trac/browser/microcontroller/src-atmel/lib/rfm12 Library zur Ansteuerung des RFM12]&lt;br /&gt;
&lt;br /&gt;
Folgende Links sind mit Vorsicht zu genießen, da die Datenblätter teilweise  fehlerbehaftet sind. Es empfiehlt sich, direkt mit dem Datenblatt des RF12 (das ist das IC auf dem Modul) zu arbeiten. Dieses ist so gut wie fehlerfrei.&lt;br /&gt;
&lt;br /&gt;
* [http://www.hoperf.com/pdf/RF12.pdf Datenblatt des ICs RF12] (PDF)&lt;br /&gt;
* [http://www.hoperf.com/pdf/RFM12.pdf Datenblatt des Moduls RFM12] (PDF)&lt;br /&gt;
* [http://www.hoperf.com/pdf/RF12_code.pdf Programming Guide] (PDF)&lt;br /&gt;
* [http://www.hoperf.com/pdf/RF12TOOLS.pdf Demo Kit User Manual] (PDF)&lt;br /&gt;
* [http://www.pollin.de/shop/downloads/D810047S.ZIP Beispielprogramm von Pollin] (ZIP)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Bauteile]]&lt;br /&gt;
[[Kategorie:Funk]]&lt;/div&gt;</summary>
		<author><name>Thymythos</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=FIFO&amp;diff=32935</id>
		<title>FIFO</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=FIFO&amp;diff=32935"/>
		<updated>2008-12-05T14:50:38Z</updated>

		<summary type="html">&lt;p&gt;Thymythos: /* FIFO mit C-Präprozessor  */ neu&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Ein FIFO (&amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;irst-&amp;lt;b&amp;gt;I&amp;lt;/b&amp;gt;n-&amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;irst-&amp;lt;b&amp;gt;O&amp;lt;/b&amp;gt;ut) ist ein Pufferspeicher nach dem &amp;quot;Warteschlangen-Prinzip&amp;quot;. Pufferspeicher dienen dazu, für einen Prozessor Daten aufzufangen, die er noch nicht verarbeiten kann. Ein FIFO funktioniert definitionsgemäß so, dass das erste Element (First In), welches &amp;quot;hinten&amp;quot; in die Warteschlange eingefügt wird, später auch als erstes &amp;quot;vorne&amp;quot; herausgeholt wird (First Out). &lt;br /&gt;
&lt;br /&gt;
Das Gegenstück zu FIFO ist LIFO, worunter man einen dem &amp;quot;Stapel-Prinzip&amp;quot; folgenden Pufferspeicher versteht (Last In - First Out; Elemente werden stets &amp;quot;oben auf den Stapel&amp;quot; gelegt und auch stets von oben wieder heruntergenommen).&lt;br /&gt;
&lt;br /&gt;
Ein bekanntes Beispiel für einen FIFO-Speicher ist der des [[UART]]s im PC. Dieser sammelt ankommende Daten solange, bis er fast voll ist (meist 14 Bytes). Dann wird ein [[Interrupt]] ausgelöst und der Prozessor kann &amp;quot;auf einen Rutsch&amp;quot; alle Daten auf einmal auslesen. Ganz am Anfang hatten UARTs keinen FIFO und erzeugten für jedes empfangene Byte einen Interrupt, so wie es heute noch die meisten Mikrocontroller machen. Damit ist aber die CPU-Belastung wesentlich höher, was bei höheren Datenraten zu Problemen führen kann.&lt;br /&gt;
&lt;br /&gt;
Die Umsetzung eines FIFOs in Software heißt Ringpuffer und weist auch eine feste Puffergröße auf. Wesentlicher Vorteil gegenüber der verketteten Liste ist die schnellere Ausführungszeit und der geringere Aufwand.&lt;br /&gt;
&lt;br /&gt;
== Standard-Ringpuffer ==&lt;br /&gt;
&lt;br /&gt;
Vorteile:&lt;br /&gt;
* Simpel&lt;br /&gt;
* Leicht verständlich&lt;br /&gt;
* Daten können auch vom Typ struct sein&lt;br /&gt;
&lt;br /&gt;
Nachteile:&lt;br /&gt;
* Schell aber nicht optimal&lt;br /&gt;
&lt;br /&gt;
=== Beschreibung ===&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Ringpuffer.png|300px]]&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Circular buffer.png|200px]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Die Inhalte des Puffers werden in einem schlichten Array gespeichert und der Zugriff erfolgt über einen Integer-Index. Erreicht ein Index die Obergrenze springt dieser auf Null zurück. Ein größer-gleich statt nur eines ist-gleich Vergleichs ist sicherer gegenüber Programmfehlern, bei denen der Index verstellt wurde.&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
write = write + 1;&lt;br /&gt;
if (write &amp;gt;= BUFFER_SIZE)&lt;br /&gt;
  write = 0;&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
Haben Lese- und Schreib-Index den gleichen Wert wird der Puffer als leer angesehen. Wenn write+1 und read identisch sind wird der Puffer als voll angesehen. Nun fehlt noch der Sonderfall bei dem read gleich Null ist, hier funktioniert der write+1-Vergleich nicht mehr und die Abfrage einer zusätzlichen Bedingung ist zur voll-Abfrage erforderlich.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
read == write =&amp;gt; leer&lt;br /&gt;
&lt;br /&gt;
write + 1 == read || read == 0 &amp;amp;&amp;amp; write+1 == BUFFER_SIZE =&amp;gt; voll&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bei gleichzeitigem Zugriff zwischen UART-ISR und Hauptprogramm muss ausgeschlossen werden, dass das Hauptprogramm beim Lesen aus dem Puffer nicht durch den Interrupt unterbrochen werden kann. Ansonsten können Programmabstürze passieren, deren Ursache oft nicht nachvollziehbar ist. Als Abhilfe dienen [[Interrupt#Atomarer_Datenzugriff|Atomare Abschnitte]], solche können durch keinen Interrupt unterbrochen werden. Die Radialkur deaktiviert alle Interrupts, besser ist die Deaktivierung eines einzelnen Interrupts. Im Allgemeinen werden versäumte Interrupte nach erneuter Aktivierung nachgeholt, da ein Flag gesetzt wurde. Wichtig ist vorallem, dass die Ausführungszeit des Atomaren Abschnitts und der ISR geringer ist als der Intervall in dem Interrupte erfolgen, da ansonsten ein Interrupt verloren gehen könnte.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
cli()&lt;br /&gt;
ret = BufferOut(&amp;amp;var);&lt;br /&gt;
sei()&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Code-Beispiel ===&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#define BUFFER_SIZE 23&lt;br /&gt;
&lt;br /&gt;
struct Buffer {&lt;br /&gt;
  uint8_t data[BUFFER_SIZE];&lt;br /&gt;
  uint8_t read; // zeigt auf das Feld mit dem ältesten Inhalt&lt;br /&gt;
  uint8_t write; // zeigt immer auf leeres Feld&lt;br /&gt;
} buffer = {{}, 0, 0};&lt;br /&gt;
&lt;br /&gt;
uint8_t BufferIn(uint8_t byte)&lt;br /&gt;
{&lt;br /&gt;
  //if (write &amp;gt;= BUFFER_SIZE)&lt;br /&gt;
  //  write = 0; // erhöht sicherheit&lt;br /&gt;
&lt;br /&gt;
  if (buffer.write + 1 == buffer.read || buffer.read == 0 &amp;amp;&amp;amp; buffer.write + 1 == BUFFER_SIZE)&lt;br /&gt;
    return FAIL; // voll&lt;br /&gt;
&lt;br /&gt;
  buffer.data[buffer.write] = byte;&lt;br /&gt;
&lt;br /&gt;
  write = write + 1;&lt;br /&gt;
  if (write &amp;gt;= BUFFER_SIZE)&lt;br /&gt;
    write = 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
uint8_t BufferOut(uint8_t *pByte)&lt;br /&gt;
{&lt;br /&gt;
  if (buffer.read == buffer.write)&lt;br /&gt;
    return FAIL;&lt;br /&gt;
  *pByte = buffer.data[buffer.read];&lt;br /&gt;
&lt;br /&gt;
  buffer.read = buffer.read + 1;&lt;br /&gt;
  if (buffer.read &amp;gt;= BUFFER_SIZE)&lt;br /&gt;
    buffer.read = 0;&lt;br /&gt;
  return SUCCESS;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 2&amp;lt;sup&amp;gt;n&amp;lt;/sup&amp;gt;-Ringpuffer - die schnellste Lösung ==&lt;br /&gt;
&lt;br /&gt;
Vorteile:&lt;br /&gt;
* Durch Bitmaske auf den Feld-Index &#039;&#039;write&#039;&#039; kann der nicht &amp;quot;Amoklaufen&amp;quot; und beliebige Inhalte im Speicher überschreiben&lt;br /&gt;
* Sehr einfach, sehr schnell&lt;br /&gt;
* Daten können auch vom Typ &#039;&#039;struct&#039;&#039; sein&lt;br /&gt;
Nachteile:&lt;br /&gt;
* Nur Größenfaktoren von 2&amp;lt;sup&amp;gt;n&amp;lt;/sup&amp;gt; möglich&lt;br /&gt;
* Nur in speziellen Fällen Pointerreferenz möglich&lt;br /&gt;
&lt;br /&gt;
=== Beschreibung ===&lt;br /&gt;
&lt;br /&gt;
Wenn der Index am oberen Ende angekommen ist springt er an den Anfang zurück. Die Definition der Obergrenze wird nicht durch einen Vergleich realisiert, sondern durch Modulo-Arithmetik. Dies kann sehr einfach und schnell durch Maskieren des Index-Werts umgesetzt werden.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
( write + 1 ) &amp;amp; MASK&lt;br /&gt;
&lt;br /&gt;
15 = 0b00001111&lt;br /&gt;
15 + 1 = 16 = 0b000010000&lt;br /&gt;
16 &amp;amp; MASK = 0b000010000 &amp;amp; 0b000001111 = 0b000000000&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Daraus folgt das &#039;&#039;write&#039;&#039; nur einen Wert zwischen 0 und 15 einnehmen kann. Das ganze funktioniert nur mit Zahlen der Reihe 2&amp;lt;sup&amp;gt;n&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Da der Puffer nur eine endliche Größe aufweist, muss eine voll/leer Indikation verfügbar sein. read == write bedeutet Puffer leer, entsprechend bedeutet write + 1 == read, dass keine weiteren Elemente mehr hinzugefügt werden können, denn sonst würde das Hinzufügen weiterer Daten einen Pufferüberlauf hervorrufen. Für die Behandlung des Pufferüberlaufs gibt es zwei Methoden, nichts tun und Fehler zurück geben oder ältesten Puffer-Inhalt verwerfen (read+1).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
read == ((write + 1) &amp;amp; MASK)&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Auch hier verhindert die Bitmaske einen möglichen Überlauf. Weiter zu beachten ist, dass ein Byte durch die voll/leer Indikation verloren geht, der Puffer hat hier nur eine größe von 15 statt 16 Byte&lt;br /&gt;
&lt;br /&gt;
Und noch ein kleiner Trick. Bei einer Zahl der Reihe 2^n lässt sich auf einfache Weise immer eine passende Bitmaske erzeugen und man sieht gleichzeitig klar die Anzahl der genutzten Bytes.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
# define SIZE 16&lt;br /&gt;
# define MASK (SIZE-1)&lt;br /&gt;
&lt;br /&gt;
16 = 0b010000&lt;br /&gt;
16 - 1 = 0b001111&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im Normalbetrieb sollte der Puffer nie voll ausgereizt sein und wenn der Puffer bereits überläuft ist es für die Systemstabilität und Fehleranlyse oft schon zu spät, denn von einem nicht mehr funktionierenden Gerät lässt sich nur wenig Information herauskitzeln. Da kann ein Frühwarmsystem mehr bieten, wobei zwei Ausprägungen typisch sind, Höchstwert merken und eine Meldeschwelle einführen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
 freeMemory =  (read - write - 1 ) &amp;amp; MASK);&lt;br /&gt;
 if (freeMemory &amp;lt; floodmark)&lt;br /&gt;
   floodmark = freeMemory;&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
 if ( (read - write - 1 ) &amp;amp; MASK) &amp;lt;= FLOODMARK;&lt;br /&gt;
   FloodmarkExcess();&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Code-Beispiel ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#define BUFFER_SIZE 16 // muss 2^n betragen (8, 16, 32, 64 ...)&lt;br /&gt;
#define BUFFER_MASK (BUFFER_SIZE-1) // Klammern auf keinen Fall vergessen&lt;br /&gt;
&lt;br /&gt;
struct Buffer {&lt;br /&gt;
  uint8_t data[BUFFER_SIZE];&lt;br /&gt;
  uint8_t read; // zeigt auf das Feld mit dem ältesten Inhalt&lt;br /&gt;
  uint8_t write; // zeigt immer auf leeres Feld&lt;br /&gt;
} buffer = {{}, 0, 0};&lt;br /&gt;
&lt;br /&gt;
uint8_t BufferIn(uint8_t byte)&lt;br /&gt;
{&lt;br /&gt;
  uint8_t next = ((buffer.write + 1) &amp;amp; BUFFER_MASK);&lt;br /&gt;
  if (buffer.read == next)&lt;br /&gt;
    return FAIL;&lt;br /&gt;
  buffer.data[buffer.write] = byte;&lt;br /&gt;
  // buffer.data[buffer.write &amp;amp; BUFFER_MASK] = byte; // absolut Sicher&lt;br /&gt;
  buffer.write = next;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
uint8_t BufferOut(uint8_t *pByte)&lt;br /&gt;
{&lt;br /&gt;
  if (buffer.read == buffer.write)&lt;br /&gt;
    return FAIL;&lt;br /&gt;
  *pByte = buffer.data[buffer.read];&lt;br /&gt;
  buffer.read = (buffer.read+1) &amp;amp; BUFFER_MASK;&lt;br /&gt;
  return SUCCESS;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== FIFO mit C-Präprozessor ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#ifndef FIFO_H_&lt;br /&gt;
#define FIFO_H_&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
typedef struct {&lt;br /&gt;
	uint8_t _read;&lt;br /&gt;
	uint8_t _write;&lt;br /&gt;
	uint8_t _buffer[64];&lt;br /&gt;
} FIFO64_t;&lt;br /&gt;
&lt;br /&gt;
typedef struct {&lt;br /&gt;
	uint8_t _read;&lt;br /&gt;
	uint8_t _write;&lt;br /&gt;
	uint8_t _buffer[128];&lt;br /&gt;
} FIFO128_t;&lt;br /&gt;
&lt;br /&gt;
#define FIFO_init(fifo)		{ fifo._read = 0; fifo._write = 0; }&lt;br /&gt;
&lt;br /&gt;
#define FIFO_available(fifo)	( fifo._read != fifo._write )&lt;br /&gt;
&lt;br /&gt;
#define FIFO_read(fifo, size) (						\&lt;br /&gt;
	(FIFO_available(fifo)) ?					\&lt;br /&gt;
	fifo._buffer[fifo._read = (fifo._read + 1) &amp;amp; (size-1)] : 0	\&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
#define FIFO_write(fifo, data, size) {								\&lt;br /&gt;
	uint8_t tmphead = ( fifo._write + 1 ) &amp;amp; (size-1); 	/* calculate buffer index */	\&lt;br /&gt;
	if(tmphead != fifo._read) {				/* if buffer is not full */	\&lt;br /&gt;
		fifo._write = tmphead;				/* store new index */		\&lt;br /&gt;
		fifo._buffer[tmphead] = data;			/* store data in buffer */	\&lt;br /&gt;
	}																							\&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#define FIFO64_read(fifo)			FIFO_read(fifo, 64)&lt;br /&gt;
#define FIFO64_write(fifo, data)		FIFO_write(fifo, data, 64)&lt;br /&gt;
&lt;br /&gt;
#define FIFO128_read(fifo)			FIFO_read(fifo, 128)&lt;br /&gt;
#define FIFO128_write(fifo, data)		FIFO_write(fifo, data, 128)&lt;br /&gt;
&lt;br /&gt;
#endif /*FIFO_H_*/&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Weblinks ==&lt;br /&gt;
* [http://en.wikipedia.org/wiki/Circular_buffer Circular buffer], englische Wikipedia&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Grundlagen]]&lt;/div&gt;</summary>
		<author><name>Thymythos</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=AVR_RFM12&amp;diff=32822</id>
		<title>AVR RFM12</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=AVR_RFM12&amp;diff=32822"/>
		<updated>2008-11-30T14:44:26Z</updated>

		<summary type="html">&lt;p&gt;Thymythos: /* Flashcraft Funkboard */ Level 3, Bild rechts&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Schaltungen und Software für AVR und das Funkmodul [[RFM12]].&lt;br /&gt;
&lt;br /&gt;
== SVN ==&lt;br /&gt;
&lt;br /&gt;
svn://mikrocontroller.net/rfm12&lt;br /&gt;
&lt;br /&gt;
Wegen Zugangsdaten bitte bei [http://www.mikrocontroller.net/user/show/andreas Andreas Schwarz] melden.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Software ==&lt;br /&gt;
&lt;br /&gt;
=== Treiber ===&lt;br /&gt;
&lt;br /&gt;
[http://www.mikrocontroller.net/attachment/22473/rfm12_pc.zip Firmware v1.0.0] von Benedikt K.&lt;br /&gt;
&lt;br /&gt;
[http://www.mikrocontroller.net/attachment/23542/RMxx_Driver.tar.bz2 Firmware v2.0.1] von Jürgen Eckert&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot;&lt;br /&gt;
|+ Funktionalität&lt;br /&gt;
|-&lt;br /&gt;
!  || Beschreibung || Software&lt;br /&gt;
|-&lt;br /&gt;
!1. Stufe:&lt;br /&gt;
| Die Daten von der seriellen Schnittstelle werden über die Funkstrecke auf die serielle Schnittstelle der anderen Seite übertragen. (Wir freuen uns über jedes Byte das ankommt)&lt;br /&gt;
| [http://www.mikrocontroller.net/topic/67273#564945 Claude Schwarz], [http://www.mikrocontroller.net/topic/71682#584915 Benedikt K.] oder [http://www.mikrocontroller.net/attachment/36742/RFM12_V3.zip Manuel Stahl]&lt;br /&gt;
|-&lt;br /&gt;
! 2. Stufe:&lt;br /&gt;
| Es findet eine Fehlererkennung (z.B. mit CRC-Summen) statt. Fehlerhafte Daten werden erneut angefordert. Dadurch gehen auf der Funkstrecke keine Daten verloren und es werden keine Daten verfälscht.&lt;br /&gt;
| [http://www.mikrocontroller.net/topic/71682#585851 Benedikt K.]&lt;br /&gt;
|-&lt;br /&gt;
! 3. Stufe:&lt;br /&gt;
| Die Datenübertragung wird individualisiert. Dadurch können zwei Funkstrecken, die im gleichen Empfangsbereich liegen nebeneinander arbeiten, ohne sich zu beeinträchtigen.&lt;br /&gt;
| [[RFM12_Protokoll_Stack]]&lt;br /&gt;
|-&lt;br /&gt;
! 4. Stufe: &lt;br /&gt;
| Die Datenübertragung wird verschlüsselt und damit abhörsicher.&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
!5. Stufe:&lt;br /&gt;
| Neben den Daten der seriellen Schnittstelle werden auch Änderungen der Statusleitungen übertragen. Damit erhält man eine &amp;quot;RS232-Verlängerung&amp;quot; über eine Funkstrecke, die fehlerfrei arbeitet und zu einer Drahtverbindung weitestgehend kompatibel ist.&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== RS232 &amp;lt;-&amp;gt; RFM12 ===&lt;br /&gt;
&lt;br /&gt;
TODO&lt;br /&gt;
&lt;br /&gt;
=== USB &amp;lt;-&amp;gt; RFM12 ===&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;&#039;[http://www.obdev.at/products/avrusb/index.html avrusb]&#039;&#039;&#039; lässt sich ein USB-Slave in Software emulieren.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;[http://www.recursion.jp/avrcdc/ AVR-CDC]&#039;&#039;&#039; läuft mit Anpassung der USB-Pins. &#039;&#039;(Zumindest unter Windows an einem USB2.0-Port)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Adapter für &#039;&#039;&#039;[http://www.embedded-projects.net/?page_id=135 USBprog]:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Funktionierender Code liegt im oben genannten SVN&lt;br /&gt;
* Implementiert die USB-CDC-Klasse (kein Treiber nötig)&lt;br /&gt;
* Sicherung der Übertragung durch Hamming-Code&lt;br /&gt;
* Work in progress... (Manuel Stahl)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Hardware ==&lt;br /&gt;
&lt;br /&gt;
=== Basismodul V1.0 ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Prozessor&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
ATmega8 TQFP32 (kompatibel ATmega48, ATmega88, ATmega168)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Schnittstellen&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* RS232&lt;br /&gt;
* I²C:&lt;br /&gt;
* USB&lt;br /&gt;
* GPIO&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Platine&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[Bild:AVR RFM12 Schematic.png|200px|ATmega48 + USB]]&lt;br /&gt;
[[Bild:AVR RFM12 Board TOP.png|220px|2-lagig top]]&lt;br /&gt;
[[Bild:AVR RFM12 Board BOTTOM.png|240px|2-lagig bottom]]&lt;br /&gt;
[[Bild:AVR_RFM12_Photo.jpg|240px|Photo]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;float:left; border-right:1px solid gray; padding-right:10px;&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Bauteile:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Größe: SMD 0603&lt;br /&gt;
&lt;br /&gt;
* R1, R2: 68R (nur USB)&lt;br /&gt;
* R3, R4: 10k&lt;br /&gt;
* R5: 1k5 (nur USB)&lt;br /&gt;
* C1, C2: 22pF&lt;br /&gt;
* C3 - C9: 100nF&lt;br /&gt;
* Q1: 12Mhz (nur USB)&lt;br /&gt;
* D1, D2: beliebig, Minimelf&lt;br /&gt;
* IC3: MAX3221CUE&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;float:left; border-right:1px solid gray; padding: 0px 0px 10px 10px; width:33%&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Kosten:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* MiniUSB SMD: &#039;&#039;&#039;1,25€&#039;&#039;&#039;&lt;br /&gt;
* HF-Buchse MMCX: &#039;&#039;&#039;4,25€&#039;&#039;&#039;&lt;br /&gt;
* ATmega48: &#039;&#039;&#039;2,85€&#039;&#039;&#039;&lt;br /&gt;
* MAX3221CUE: &#039;&#039;&#039;1,10€&#039;&#039;&#039;&lt;br /&gt;
* Quarz 12Mhz 30ppm: &#039;&#039;&#039;1,19€&#039;&#039;&#039;&lt;br /&gt;
* Kleinkram: &#039;&#039;&#039;&amp;lt; 1,10€&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* habe ein verbindliches Angebot für 24 Stück von http://mme-pcb.de/: &#039;&#039;&#039;4,00€ pro Platine&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;float:left; padding: 0px 0px 10px 10px; width:33%&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039; Bugs / Erweiterungen:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Der 1,5k Widerstand muss direkt an den VCC-Pin angelötet werden (Pad ist nicht verbunden)&lt;br /&gt;
* Beim Fertigen wurde das Polygon, welches das VCC-Signal durch die eine Ecke des ATmega48 leitet, unterbrochen. Hier hilft nur eine Drahtbrücke.&lt;br /&gt;
* Unter den RFM12 und unter das Quarz am Besten Isolierband kleben!&lt;br /&gt;
* Beim Programmieren sollte der SEL des RFM12 (J1 der zweite Pin vom RS232 aus) auf VCC gelegt werden&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear:both&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[http://www.mikrocontroller.net/attachment/24012/RFM12.brd Board (Eagle)]:&lt;br /&gt;
&lt;br /&gt;
[[Bild:AVR RFM12 Board top bestuecken.png|200px|top]]&lt;br /&gt;
[[Bild:Board bottom bestuecken.png|200px|bottom]]&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== Flashcraft Funkboard ===&lt;br /&gt;
&lt;br /&gt;
[http://flashcraft.de/index.php/funkboard-uebersicht Homepage des Projekts]&lt;br /&gt;
&lt;br /&gt;
Eine andere Funklösung mit dem RFM12 bietet das &#039;&#039;&#039;Open Source&#039;&#039;&#039; Flashcraft Funkboard von Florian Scherb.&lt;br /&gt;
&lt;br /&gt;
[[Bild:Flashcraft_funkboard_pic.jpg|right]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Es enthält&#039;&#039;&#039;&lt;br /&gt;
* Funkboard Platine&lt;br /&gt;
* Code für AVR&lt;br /&gt;
* PC Terminalprogramm&lt;br /&gt;
* Dokumentation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Überblick:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# Über 55 Seiten starke Dokumentation&lt;br /&gt;
# PC Terminalprogramm zum Testen und Konfigurieren&lt;br /&gt;
# Abmessungen: 32x34mm, Montage durch 2 Stiftleisten im 2,54mm Raster&lt;br /&gt;
# ATmega32 übernimmt komplette Ansteuerung&lt;br /&gt;
# 3 Schnittstellen sind vorgesehen: I2C, SPI, UART (derzeit nur UART)&lt;br /&gt;
# SMA-Antennenanschluss&lt;br /&gt;
# Niedrige Stromaufnahme: 40mA im normalen Betrieb, 2 Schlafmodis mit Stromverbrauch bis min. 25µA!&lt;br /&gt;
# Betriebsspannungsbereich von 3,2 - 5,4V (mit ATmega32L)&lt;br /&gt;
# 5V oder 3V Spannungsregler onBoard! Direkter Batteriebetrieb möglich; Kann externe Schaltung versorgen! &lt;br /&gt;
# uvm.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Außerdem:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# Kontrolle über fast alle Konfigurationen, direkt im Betrieb änderbar, kein Umprogrammieren notwendig!&lt;br /&gt;
# Zahlreiche Sicherheitsfeatures wie Acknowledge, CRCs,...&lt;br /&gt;
# RS232-Treiberbaustein MAX3221 onBoard. Damit TTL- und RS232-UART möglich&lt;br /&gt;
# Clock Takt am Funkboard abgreifbar, z.B. für externen Mikrocontroller&lt;br /&gt;
# Totzeiten ca. 1,5 Millisekunden beim Wechsel zwischen Sende- und Empfangsbetrieb&lt;br /&gt;
# uvm. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Schaltpläne, Board-Layout, Sourcecodes und andere Files sind auf der [http://flashcraft.de/index.php/funkboard-uebersicht Homepage] des Funkboard-Projekts verfügbar.&#039;&#039;&#039;&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== USBprogRFM12 ===&lt;br /&gt;
&lt;br /&gt;
Da der USBprog genau das SPI-Interface des ATmega32 zur Verfügung stellt, eignet er sich perfekt als USB-RFM12-Adapter.&lt;br /&gt;
&lt;br /&gt;
[[Bild:USBprogRFM12_schematic.png|200px|USBprogRFM12]] [[Bild:USBprogRFM12_board.png|200px|USBprogRFM12]]&lt;br /&gt;
&lt;br /&gt;
[[Bild:USBprogRFM12.jpg|400px|USBprogRFM12]]&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
* [http://www.mikrocontroller.net/topic/65984 Allgemeine Diskussion]&lt;br /&gt;
* [http://www.mikrocontroller.net/topic/71682  bidirektionale RS232 Funkbrücke mit RFM12]&lt;br /&gt;
* [http://www.das-labor.org/wiki/Datenfunk_mit_dem_AVR Datenfunk mit dem AVR] bei das-labor.org&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Projekte]]&lt;br /&gt;
[[Kategorie:AVR]]&lt;br /&gt;
[[Kategorie:Funk]]&lt;/div&gt;</summary>
		<author><name>Thymythos</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=Vorlage:8Bit&amp;diff=32805</id>
		<title>Vorlage:8Bit</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=Vorlage:8Bit&amp;diff=32805"/>
		<updated>2008-11-29T15:08:33Z</updated>

		<summary type="html">&lt;p&gt;Thymythos: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{| cellpadding=&amp;quot;2&amp;quot; cellspacing=&amp;quot;0&amp;quot; border=&amp;quot;0&amp;quot; width=&amp;quot;{{{width}}}&amp;quot;&lt;br /&gt;
|- style=&amp;quot;font-size:80%&amp;quot;&lt;br /&gt;
! style=&amp;quot;border-right:1px solid gray;&amp;quot; | 0&lt;br /&gt;
! style=&amp;quot;border-right:1px solid gray;&amp;quot; | 1&lt;br /&gt;
! style=&amp;quot;border-right:1px solid gray;&amp;quot; | 2 &lt;br /&gt;
! style=&amp;quot;border-right:1px solid gray;&amp;quot; | 3&lt;br /&gt;
! style=&amp;quot;border-right:1px solid gray;&amp;quot; | 4&lt;br /&gt;
! style=&amp;quot;border-right:1px solid gray;&amp;quot; | 5&lt;br /&gt;
! style=&amp;quot;border-right:1px solid gray;&amp;quot; | 6&lt;br /&gt;
! 7&lt;br /&gt;
|- style=&amp;quot;text-align:center&amp;quot;&lt;br /&gt;
| width=&amp;quot;12.8%&amp;quot; style=&amp;quot;border-right:1px solid gray;&amp;quot; | {{{1}}}&lt;br /&gt;
| width=&amp;quot;12.8%&amp;quot; style=&amp;quot;border-right:1px solid gray;&amp;quot; | {{{2}}}&lt;br /&gt;
| width=&amp;quot;12.8%&amp;quot; style=&amp;quot;border-right:1px solid gray;&amp;quot; | {{{3}}}&lt;br /&gt;
| width=&amp;quot;12.8%&amp;quot; style=&amp;quot;border-right:1px solid gray;&amp;quot; | {{{4}}}&lt;br /&gt;
| width=&amp;quot;12.8%&amp;quot; style=&amp;quot;border-right:1px solid gray;&amp;quot; | {{{5}}}&lt;br /&gt;
| width=&amp;quot;12.8%&amp;quot; style=&amp;quot;border-right:1px solid gray;&amp;quot; | {{{6}}}&lt;br /&gt;
| width=&amp;quot;12.8%&amp;quot; style=&amp;quot;border-right:1px solid gray;&amp;quot; | {{{7}}}&lt;br /&gt;
| width=&amp;quot;12.8%&amp;quot; | {{{8}}}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;noinclude&amp;gt;&lt;br /&gt;
Diese Vorlage kann zum Formatieren von Bytes verwendet werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&lt;br /&gt;
{{Vorlage:8Bit|width=200| a | b | c | d | e | f | g | h }}&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;/noinclude&amp;gt;&lt;/div&gt;</summary>
		<author><name>Thymythos</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=RFM12&amp;diff=32804</id>
		<title>RFM12</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=RFM12&amp;diff=32804"/>
		<updated>2008-11-29T14:51:27Z</updated>

		<summary type="html">&lt;p&gt;Thymythos: /* Frequency-setting */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Beschreibung der Funkmodule RFM01, RFM02 und RFM12.&lt;br /&gt;
&lt;br /&gt;
Benötigt werden in der Minimal-Version im FIFO-Modus nur die Anschlüsse nSEL, SDO, SDI und SCK, eben das komplette SPI-Interface. Der Zugriff auf das Sende- und Empfangs-FIFO ist per Software möglich, ebenso die Abfrage der Statusbits. Deshalb werden z.B. nIRQ und nFFS nicht unbedingt benötigt. nIRQ signalisiert unter anderem, dass das Modul bereit ist Daten zu empfangen. Wenn Daten empfangen wurden, kann dies über den FFIT-Pin abgefragt werden (falls die Füllschwelle eingestellt wurde). nFFS dient dazu das FIFO direkt anzusprechen (es ist quasi der Chipselect für das FIFO), davon wird in der Minimalversion aber kein Gebrauch gemacht. Der Pin muss daher auf high-Pegel gelegt werden!&lt;br /&gt;
An CLK kann eine Frequenz von 1MHz bis 10MHz eingestellt werden. Hiermit kann dann z.B. der Mikrocontroller versorgt werden.&lt;br /&gt;
Reset ist ein Open-Collector-Ausgang und gleichzeitig der Reset-Eingang. Er sollte daher entweder gar nicht, oder aber hochohmig angeschlossen werden.&lt;br /&gt;
&lt;br /&gt;
Im FIFO-Mode kann das Modul konfiguriert werden mit dem Empfang zu warten, bis die Daten 0x2DD4 empfangen wurden. Sobald dieses Bitmuster empfangen wurde, werden Daten in das FIFO geschrieben, bis man das FIFO abschaltet und die Mustererkennung neu startet.&lt;br /&gt;
&lt;br /&gt;
Als weitere Modi stehen unter anderem ein synchroner Modus zur Verfügung (no FIFO mode), in dem der Sender/Empfänger den Bittakt ausgibt, und synchron dazu die zu sendenden Daten einliest bzw. die empfangenen Daten ausgibt. Der SPI Bus ist trotzdem zur Initialisierung des Moduls notwendig.&lt;br /&gt;
&lt;br /&gt;
== FAQ ==&lt;br /&gt;
&lt;br /&gt;
=== SPI Interface ===&lt;br /&gt;
&lt;br /&gt;
* Maximale Datenrate: 2,5MHz (10MHz Quarz / 4)&lt;br /&gt;
&lt;br /&gt;
=== CLK-Ausgang bleibt bei 1 MHz ===&lt;br /&gt;
&lt;br /&gt;
* Vor dem Umschalten (mit 0xC0E0) länger warten.&lt;br /&gt;
&lt;br /&gt;
=== RFM12 empfängt ein paar Bytes, dann nur Müll ===&lt;br /&gt;
&lt;br /&gt;
* Es wird zu langsam gesendet (TX FIFO underrun)&lt;br /&gt;
* Es wird zu langsam empfangen (RX FIFO overrun)&lt;br /&gt;
&lt;br /&gt;
Die Status-Bits helfen hier beim Debuggen. SPI sollte auf maximaler Transferrate stehen.&lt;br /&gt;
&lt;br /&gt;
=== RFM empfängt nur Müll ===&lt;br /&gt;
&lt;br /&gt;
http://www.mikrocontroller.net/topic/73560#605528&lt;br /&gt;
&lt;br /&gt;
Deine Module verhalten sich normal. Man muß mit den Gain- und AFC-Bits&lt;br /&gt;
eine ganze Weile spielen, bis die Module korrekt laufen (kommt auf die&lt;br /&gt;
Anwendung an). Fakt ist: der Empfänger empfängt ständig Datenmüll als&lt;br /&gt;
Rauschen. Wenn der FIFO durch die Präambel getriggert wird, sind die&lt;br /&gt;
Daten im FIFO ziemlich korrekt, wenn alles &amp;quot;gut&amp;quot; eingestellt ist. Der&lt;br /&gt;
FIFO sollte per Interrupt dann auch sofort abgeholt werden, da sonst das&lt;br /&gt;
nächste Byte das alte direkt überschreibt. Jeder zusammenhängende&lt;br /&gt;
Datensatz (mehrere Bytes an einem Stück) muß von einer Präambel&lt;br /&gt;
eingeleitet werden. Nach dem kompletten Einlesen eines Datensatzes muß&lt;br /&gt;
der FIFO abgeschaltet, wieder eingeschaltet und für den Empfang der&lt;br /&gt;
nächsten Präambel neu scharf gemacht werden.&lt;br /&gt;
&lt;br /&gt;
=== RFM hängt sich auf ===&lt;br /&gt;
&lt;br /&gt;
Wenn man die AFC nicht begrenzt, also keinen Wertebereich vorgibt, die eine maximale Abweichung korrigiert wird passiert es nach einer Weile, dass sich der Empfänger aufhängt, die Offsetbits im Status werden maximal und dann geht gar nichts mehr, er hängt fest.&lt;br /&gt;
&lt;br /&gt;
Siehe auch &lt;br /&gt;
* Forenbeitrag [http://www.mikrocontroller.net/topic/82456#689660 RFM12: Erfahrungen ]&lt;br /&gt;
&lt;br /&gt;
=== Kommunikation mit RFM funktioniert nur sporadisch ===&lt;br /&gt;
&lt;br /&gt;
* Ist die Versorgungsspannung stabil? (evtl. Kondensator einbauen)&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Register ==&lt;br /&gt;
&lt;br /&gt;
Von https://www.mikrocontroller.net/attachment/24947/RFM12.txt&lt;br /&gt;
&lt;br /&gt;
Dieses Dokument beschreibt die Nutzung des RFM12 TRX Moduls!&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039; WICHTIG &#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Dieses Dokument wurde aus mehreren Quellen zusammengestellt, und kann Fehler enthalten!&lt;br /&gt;
Es können Abweichungen in Bezug auf RF01 / RF02 / RF12 / RFM01 / RFM02 und andere Module auftreten!&lt;br /&gt;
Es wurde das Datenblatt vom RFM12B und RF12 von www.hoperf.com als Basis genuzt. Zusätzlich wurden diese Informationen mit Hilfe von Forums-Nutzern (https://www.mikrocontroller.net/topic/71682) weiter vervollständigt!&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039; WICHTIG &#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Hinweis:&#039;&#039;&#039; Die LNA-Eingangsimpedanz beträgt 250 Ohm, und muss beim Anschluss einer 50-Ohm-Antenne entsprechend angepasst werden, um das Rauschen zu minimieren! &#039;&#039; -- (Auf den Pollin-Modulen bereits vorhanden)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configuration Setting ===&lt;br /&gt;
 Hex = 80 &amp;amp; xx&lt;br /&gt;
 Bit-Syntax: &lt;br /&gt;
{| cellpadding=&amp;quot;2&amp;quot; cellspacing=&amp;quot;0&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
!width=&amp;quot;20%&amp;quot;| Byte ||width=&amp;quot;40%&amp;quot;| 1 || 2&lt;br /&gt;
|-&lt;br /&gt;
!Bits&lt;br /&gt;
|{{8Bit|width=100%| 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 }}||{{8Bit|width=100%| el | ef | b1 | b0 | x3 | x2 | x1 | x0}}|}&lt;br /&gt;
 el (TX FIFO) = Sendepuffer für Datentransfer nutzen (1 = An / 0 = Aus)&lt;br /&gt;
 ef (RX FIFO) = Empfangspuffer für Datenspeicherung nutzen (1 = An / 0 = Aus)&lt;br /&gt;
 b... = Zu nutzende Basisfrequenz (00=315MHz / 01=433MHz / 10=868MHz / 11=915MHz)&lt;br /&gt;
 x... = Interner Clock des Chips kann durch verschieben einer Kondensator-Anpass-Stufe bestimmt werden.&lt;br /&gt;
        0,5pF pro Schritt. Basis ist 8,5pF -&amp;gt; (0000=8,5 / 0001=9,0 / 0010=9,5 / ...)&lt;br /&gt;
&lt;br /&gt;
=== Power-Managment ===&lt;br /&gt;
 Hex = 82 &amp;amp; xx&lt;br /&gt;
 Bit-Syntax: 10000010 | er | ebb | et | es | ex | eb | ew | dc&lt;br /&gt;
 er = Empfänger einschalten (1 = an / 0 = Aus)&lt;br /&gt;
 ebb = ... (Synthesizer muss aktiv sein!) (1 = an / 0 = aus)&lt;br /&gt;
 et = Sender einschalten (1 = an / 0 = Aus) (Wenn das TX-Register aktiv und mit Daten gefüllt ist/wurde,&lt;br /&gt;
      werden diese Daten sofort gesendet) (1 = an / 0 = aus)&lt;br /&gt;
 es = Schaltet den Synthesizer ein. (1 = an / 0 = aus)&lt;br /&gt;
 ex = Schaltet den Quarz-Oszilator ein. (1 = an / 0 = aus)&lt;br /&gt;
 eb = Vergleichbar mit BrownOutDetection -&amp;gt; Erkennt eine zu geringe Betriebsspannung und erzeugt einen Interrupt,&lt;br /&gt;
      um einen drohenden Spannungsaufall anzukündigen (1 = An / 0 = Aus)&lt;br /&gt;
 ew = Aktiviert den WakeUpTimer des Prozessors. (1 = an / 0 = aus)&lt;br /&gt;
 dc = Deaktiviert die Ausgabe des SystemClocks auf dem CLK Pin am Chip (1 = Keine ClockAusgabe / 0 = Clock ausgeben)&lt;br /&gt;
&lt;br /&gt;
=== PLL Setting ===&lt;br /&gt;
 Hex = 198 + y&lt;br /&gt;
 Bit-Syntax: 110011000 | ob1 | ob0 | lpx | ddy | ddit | bw1 | bw0&lt;br /&gt;
 ob... = ... (00= 5 oder 10MHz [standard] / 01=3.3MHz / 1x=2.5MHz oder weniger)&lt;br /&gt;
 lpx = Wählt den Low-Power-Mode für den Quarz-Oszilator aus. (0=1ms [620µA] / 1=2ms [460µA])&lt;br /&gt;
 ddy = ...&lt;br /&gt;
 ddi = Schaltet das Dithering in PLL-Schleife ab. (1=abgeschaltet / 0=eingeschaltet)&lt;br /&gt;
 bw... = Wählt die Bandbreite des PLL-Signals aus. (00=86.2kbps [-107dBc/Hz] / 01=256kbps [-102dBc/Hz]) Bei 1MHz Offset Phasenrauschen.&lt;br /&gt;
&lt;br /&gt;
=== LowBatt / µC Clock Control ===&lt;br /&gt;
 Hex = c0 &amp;amp; xx&lt;br /&gt;
 Bit-Syntax: 11000000 | d2 | d1 | d0 | v4 | v3 | v2 | v1 | v0&lt;br /&gt;
 d... = Bestimmt den Teilungsfaktor für die Clockausgabe am CLK-Pin in Abhängigkeit des Internen SystemTakts.&lt;br /&gt;
        (000=1 / 001=1.25 / 010=1.66 / 011=2 / 100=2.5 / 101=3.33 / 110=5 / 111=10)&lt;br /&gt;
 v... = Bestimmt die Minimalspannung, ab der ein Interrupt durchgeführt werden&lt;br /&gt;
 muss. (Ähnlich einer BrownOutDetection). Im Power-Managment muss das eb-Bit&lt;br /&gt;
 aktiv sein, damit dies funktioniert.&lt;br /&gt;
&lt;br /&gt;
=== Frequency-setting ===&lt;br /&gt;
Bestimmt den Offset der Sende- und Empfangsfrequenz. Dieser Offset wird auf das Basisband im Configuration Setting hinzu gerechnet.&lt;br /&gt;
 Hex = a &amp;amp; xxx&lt;br /&gt;
 Bit-Syntax:&lt;br /&gt;
{| cellpadding=&amp;quot;2&amp;quot; cellspacing=&amp;quot;0&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
!width=&amp;quot;20%&amp;quot;| Byte ||width=&amp;quot;40%&amp;quot;| 1 || 2&lt;br /&gt;
|-&lt;br /&gt;
!Bits&lt;br /&gt;
|{{8Bit|width=100%| 1 | 0 | 1 | 0 | f11 | f10 | f9 | f8 }}||{{8Bit|width=100%| f7 | f6 | f5 | f4 | f3 | f2 | f1 | f0}}|}&lt;br /&gt;
&lt;br /&gt;
 f... = Bestimmt den Offsetwert der Frequenz.&lt;br /&gt;
        Als Basis gilt das eingestellte Band im Configuration-Settings-Kommando&lt;br /&gt;
&lt;br /&gt;
freq = 10 * C1 * (C2 + f/4000) [MHz]&lt;br /&gt;
&lt;br /&gt;
{| cellspacing=&amp;quot;0&amp;quot; border=&amp;quot;1&amp;quot; style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
! Band || C1 || C2&lt;br /&gt;
|-&lt;br /&gt;
| 315 || 1 || 31&lt;br /&gt;
|-&lt;br /&gt;
| 433 || 1 || 43&lt;br /&gt;
|-&lt;br /&gt;
| 868 || 2 || 43&lt;br /&gt;
|-&lt;br /&gt;
| 915 || 3 || 30&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Data-Rate ===&lt;br /&gt;
 Hex = c6 &amp;amp; xx&lt;br /&gt;
 Bit-Syntax: 11000110 | cs | r6 | r5 | r4 | r3 | r2 | r1 | r0&lt;br /&gt;
 cs =  Vorteiler, Faktor 7. Hiermit kann ein Vorteiler aktiviert werden,&lt;br /&gt;
       der die errechnete Baudrate (r...) durch 7 teilt.&lt;br /&gt;
 r... = Baudratenteilerfaktor&lt;br /&gt;
&lt;br /&gt;
=== RX Control ===&lt;br /&gt;
 Hex = 94 &amp;amp; xx&lt;br /&gt;
 Bit-Syntax: 10010 | p20 | d1 | d2 | i2 | i1 | i0 | g1 | g0 | r2 | r1 | r0&lt;br /&gt;
 p20 = Bestimmt die Funktion des Pin20 (nINT / VDI) am RFM12 Chip (1 = VDI-Ausgang / 0 = Interrupt-Eingang)&lt;br /&gt;
 d... = (Valid Data Indicator). Definiert die Geschwindigkeit, mit der bestimmt wird, ob ein Signal korrekt ist, oder nicht.&lt;br /&gt;
        (00=schnell / 01=mittel / 10=langsam / 11=immer an). Je nach eingestellter Variante werden&lt;br /&gt;
        unterschiedliche Hardware- und Software-Kombinationen genuzt.&lt;br /&gt;
        Fast:  CR_Lock  OR  DQD  ... Medium:  CR_Lock  AND ( DRSSI  OR  DQD ) ... &lt;br /&gt;
        SLOW: R/S FlipFlop aus (SET)  DRSSI  OR  DQD  OR  CR_Lock  und (CLR)  DRSSI  AND  DQD  AND  CR_Lock .&lt;br /&gt;
 i... = Bestimmt die Bandbreite des Empfängers in KHz (KiloHertz).&lt;br /&gt;
        (000=Reserviert / 001=400 / 010=340 / 011=270 / 100=200 / 101=134 / 110=67 / 111=Reserviert)&lt;br /&gt;
 g... = (LNA-Gain) Verstärkungsfaktor des Rauscharmen-Eingangs-Signal-Verstärkers (LNA Low Noise Amplifier).&lt;br /&gt;
        Werte in dBm (Dezibel [Grösse: Milliwatt]) Mögliche Werte sind: 0 / -6 / -14 / -20&lt;br /&gt;
 r... = (DRSSI = Digital Received Signal Strength Indication) Minimale Empfangssignalfeldstärke.&lt;br /&gt;
        6 dBm pro Schritt: (000=-103 / 001=-97 / 010=-91 / ...)&lt;br /&gt;
&lt;br /&gt;
=== Synchron Pattern ===&lt;br /&gt;
 Hex = ce &amp;amp; xx&lt;br /&gt;
 Bit-Syntax: 11001110 | b7 | b6 | b5 | b4 | b3 | b2 | b1 | b0&lt;br /&gt;
 b... = Legt den Wert fest, der als Synchronisations-Byte für die Datenfilterung verwendet werden soll.&lt;br /&gt;
&lt;br /&gt;
=== Data Filter ===&lt;br /&gt;
 Hex = c2 &amp;amp; xx&lt;br /&gt;
 Bit-Syntax: 11000010 | al | ml | -unknow- (1) | s | -unknow- (1) | f2 | f1 | f0&lt;br /&gt;
 al = Baudratenregenerator schaltet automatisch in den langsamen Modus, &lt;br /&gt;
      sobald er einen Takt erkannt hat.&lt;br /&gt;
 ml = schneller/langsamer Modus&lt;br /&gt;
 -unknown- (1) = ??? (Standard = 1) (Auch im Datenblatt von IA4420 so beschrieben)&lt;br /&gt;
 s = (DataFilter) Typ des Datenfilters (0=DigitalFilter / 1=AnalogFilter).&lt;br /&gt;
     Bei Nutzung des Analog-Filters kann kein FIFO sowie kein ClockRecovery genuzt werden.&lt;br /&gt;
 -unknown- (1) = ??? (Standard = 1) (Auch im Datenblatt von IA4420 so beschrieben)&lt;br /&gt;
 f... = (DQD Threshold) Bestimmt den Schwellwert, ab dem ein Signal als gut empfunden wird,&lt;br /&gt;
         und der Empfänger dieses weiterverarbeiten soll.&lt;br /&gt;
         DQD (data quality detection) zählt die &amp;quot;Spikes&amp;quot; des ungefilterten Signals, und bestimmt darüber die Qualität der Daten.&lt;br /&gt;
&lt;br /&gt;
=== FIFO und RESET-Mode ===&lt;br /&gt;
 Hex = ca &amp;amp; xx&lt;br /&gt;
 Bit-Syntax: 11001010 | f3 | f2 | f1 | f0 | -unknow- (0) | al | ff | dr&lt;br /&gt;
 f... = (FIFO interrupt Level)&lt;br /&gt;
 -unknown- (0) = ??? (Standard = 0) (Auch im Datenblatt von IA4420 so beschrieben)&lt;br /&gt;
 al = (FIFO Fill Condition) Legt den Wert fest, ab dem das Füllen des FIFOs beginnt.&lt;br /&gt;
      (0=Synchron / 1=Ständig). Bei Nutzung des Synchron-Modus, werden erst dann Daten in den FIFO geschrieben,&lt;br /&gt;
      wenn eine definierte 16Bit-Datenfolge empfangen wurde (Standard ist Hex: 2dd4).&lt;br /&gt;
 ff = (FIFO Fill) Startet das Einlesen der empfangenen Daten in den FIFO-Puffer.&lt;br /&gt;
      Wenn al (FIFO Fill Condition) auf synchron steht, dann startet das Setzen dieses Bits die Synchronisation-Bit-Erkennung.&lt;br /&gt;
 dr = (Sens Reset Mode) Wenn dieses Bit auf 0 steht, wird bei einer Schwankung von 200mV auf&lt;br /&gt;
      der VCC-Leitung (Spannungsversorgung des Chips), ein System-Reset ausgelöst.&lt;br /&gt;
&lt;br /&gt;
=== Automatic Frequency Control ===&lt;br /&gt;
 Hex = c4 &amp;amp; xx&lt;br /&gt;
 Bit-Syntax: 11000100 | a1 | a0 | rl1 | rl0 | st | fi | oe | en&lt;br /&gt;
 a... = Modus der AFC-Schaltung, 0=Auto, 1=einmalig nach Einschalten, 2=Solange VDI low ist, 3=unabhängig von VDI&lt;br /&gt;
 r... = (Range Limit) Frequenzraster (00=KeineBegrenzung / 01=+15 &amp;gt; -16 / 10=+7 &amp;gt; -8 / 11=+3 &amp;gt; -4)&lt;br /&gt;
 st = Berechneten Offset-Wert übernehmen&lt;br /&gt;
 fi = Genauer Berechnungsmodus (besser aber lansgamer)&lt;br /&gt;
 oe = AFC-Offset freischalten&lt;br /&gt;
 en = AFC-Berechnung aktivieren&lt;br /&gt;
&lt;br /&gt;
=== TX Configuration Control ===&lt;br /&gt;
 Hex = 98 &amp;amp; xx&lt;br /&gt;
 Bit-Syntax: 1001100 | mp | m3 | m2 | m1 | m0 | -unknow- (0) | p2 | p1 | p0&lt;br /&gt;
 mp = (Modulation Polarity) Bestimmt die Richtung der FSK-Erzeugung (invertiert das Spektrum).&lt;br /&gt;
 m... = (fDeviation) Bestimmt den Frequenzabstand des High- und Low-Wertes bei der Ubertragung im FSK-Betrieb. Basis ist der mp-Wert.&lt;br /&gt;
 -unknown- (0) = ??? (Standard = 0) (Auch im Datenblatt von IA4420 so beschrieben)&lt;br /&gt;
 p... = Bestimmt die relative Ausgangsleistung des Senders anhand des dBm-Wertes (Dezibel [Grösse: Milliwat]) 3-dBm-Schritte.&lt;br /&gt;
        (000=0 / 001=-3 / 010=-6 / ...). Der Wert steht im Zusammenhang mit der angeschlossenen Antennen-Impedanz.&lt;br /&gt;
&lt;br /&gt;
=== Wake-Up Timer ===&lt;br /&gt;
 Bestimmt die Zeitperiode der zyklischen Einschaltung des WakeUp-Timers&lt;br /&gt;
 Hex = e &amp;amp; xxx&lt;br /&gt;
 Bit-Syntax: 111 | R4 | R3 | R2 | R1 | R0 | M7 | M6 | M5 | M4 | M3 | M2 | M1 | M0&lt;br /&gt;
 R = Exponent der Zeit&lt;br /&gt;
 M = Zeit&lt;br /&gt;
&lt;br /&gt;
=== Low Duty-Cycle ===&lt;br /&gt;
&lt;br /&gt;
Bestimmt die maximale Sendezeit pro Stunde. Dies ist wichtig, um sich an gesetzliche Frequenzzuteilungsrichtlinien zu halten, die bestimmen, wie lang jemand mit einer definierten Sendeleistung auf einer bestimmten Frequenz (mit eventuell definierter Betriebsart [Modulationstyp]) senden darf.)&lt;br /&gt;
&lt;br /&gt;
 hex = 6400 + Bits&lt;br /&gt;
 Bit-Syntax: 1100100 | r| d6 | d5 | d4 | d3 | d2 | d1 | d0 | en&lt;br /&gt;
 r =  ??????????????????&lt;br /&gt;
 d... = Einschaltdauer während der zyklischen Einschaltung&lt;br /&gt;
 en = zyklische Einschaltung aktivieren&lt;br /&gt;
&lt;br /&gt;
=== RX FIFO Read ===&lt;br /&gt;
 Hex = b000&lt;br /&gt;
 Bit-Syntax: 1011000000000000&lt;br /&gt;
&lt;br /&gt;
Dieses Kommando löst die Rückgabe eines Datenbytes (synchron mit dem 8. Bit) aus. Es ist nötig, dass das ef-Bit (RX-FIFO) im Configuration Setting gesetzt wurde, um diese Funktion nutzen zu können!&lt;br /&gt;
&lt;br /&gt;
=== TX Register Write ===&lt;br /&gt;
Dieses Kommando schreibt Daten in den TX-Puffer. Wenn der Sender aktiv ist, wird dieses sofort gesendet. el (TX-Register) muss im Configuration-Setting-Kommando aktiv sein.&lt;br /&gt;
 Hex = b8 &amp;amp; xx&lt;br /&gt;
 Bit-Syntax: 10111000 | DataByteToSend&lt;br /&gt;
 DataByteToSend = Das Datenbyte, welches gesendet werden soll.&lt;br /&gt;
&lt;br /&gt;
(Senden Funktioniert nur wenn zuvor der Status abgefragt wurde)&lt;br /&gt;
&lt;br /&gt;
=== Status Read ===&lt;br /&gt;
Dieses Kommando löst die Rückgabe des Statusregisters aus, welches nach der ersten 0 im ersten Bit synchron übertragen wird.&lt;br /&gt;
 Hex = 0000&lt;br /&gt;
 Bit-Syntax: 0000000000000000&amp;lt;000&amp;gt;&lt;br /&gt;
 Rückgabe-Syntax: x0 | x1 | x2 | x3 | x4 | x5 | x6 | x7 | x8 | x9 | x10 | x11 | x12 | x13 | x14 | x15 | x16 | x17 | x18&lt;br /&gt;
 x0 -&amp;gt; x5 = Interrupt bits&lt;br /&gt;
 x6 -&amp;gt; x15 = Status Bits&lt;br /&gt;
 x16 -&amp;gt; x18 = FIFO&lt;br /&gt;
 x0 = FFIT / RGIT (RGIT = TX-Register ist bereit neue Daten zu senden ... kann mit dem TX-Register gelöscht werden)&lt;br /&gt;
     (FFIT = Die Anzahl der Datenbits im FIFO-Puffer hat das eingestellte Limit erreicht.&lt;br /&gt;
      Kann mit einer der FIFO-Lesemethoden gelöscht werden)&lt;br /&gt;
 x1 = POR (PowerOnReset)&lt;br /&gt;
 x2 = FFOV / RGUR (RGUR = Der Datenstrom beim Senden ist abgerissen, da nicht schnell genug Daten nachgeladen wurden)&lt;br /&gt;
      (FFOV = Der RX-FIFO ist übergelaufen)&lt;br /&gt;
 x3 = WKUP&lt;br /&gt;
 x4 = EXT&lt;br /&gt;
 x5 = LBD&lt;br /&gt;
 x6 = FFBM (Der FIFO-Puffer ist leer)&lt;br /&gt;
 x7 = RSSI/ATS (ATS = )(RSSI = Die Signalstärke ist über dem eingestelltem Limit)&lt;br /&gt;
 x8 = DQD&lt;br /&gt;
 x9 = CRL&lt;br /&gt;
 x10 = ATGL&lt;br /&gt;
 x11 = OFFS_4&lt;br /&gt;
 x12 = OFFS_3&lt;br /&gt;
 x13 = OFFS_2&lt;br /&gt;
 x14 = OFFS_1&lt;br /&gt;
 x15 = OFFS_0&lt;br /&gt;
 x16 = FO&lt;br /&gt;
 x17 = FO+1&lt;br /&gt;
 x18 = FO+2&lt;br /&gt;
&lt;br /&gt;
== Bezugsquellen ==&lt;br /&gt;
* [[Elektronikversender#csd-electronics|csd-electronics]]&lt;br /&gt;
* [[Elektronikversender#IT-WNS|IT-WNS]]&lt;br /&gt;
* [[Elektronikversender#Pollin_Electronic|Pollin Electronic]]&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
* [[AVR RFM12]]&lt;br /&gt;
* [[RFM12 Protokoll Stack]]&lt;br /&gt;
* [http://www.mikrocontroller.net/topic/93801 Bezugsquellen]&lt;br /&gt;
&lt;br /&gt;
Folgende Links sind mit Vorsicht zu genießen, da die Datenblätter teilweise  fehlerbehaftet sind. Es empfiehlt sich, direkt mit dem Datenblatt des RF12 (das ist das IC auf dem Modul) zu arbeiten. Dieses ist so gut wie fehlerfrei.&lt;br /&gt;
&lt;br /&gt;
* [http://www.hoperf.com/pdf/RF12.pdf Datenblatt des ICs RF12] (PDF)&lt;br /&gt;
* [http://www.hoperf.com/pdf/RFM12.pdf Datenblatt des Moduls RFM12] (PDF)&lt;br /&gt;
* [http://www.hoperf.com/pdf/RF12_code.pdf Programming Guide] (PDF)&lt;br /&gt;
* [http://www.hoperf.com/pdf/RF12TOOLS.pdf Demo Kit User Manual] (PDF)&lt;br /&gt;
* [http://www.pollin.de/shop/downloads/D810047S.ZIP Beispielprogramm von Pollin] (ZIP)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Bauteile]]&lt;br /&gt;
[[Kategorie:Funk]]&lt;/div&gt;</summary>
		<author><name>Thymythos</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=RFM12&amp;diff=32803</id>
		<title>RFM12</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=RFM12&amp;diff=32803"/>
		<updated>2008-11-29T14:12:56Z</updated>

		<summary type="html">&lt;p&gt;Thymythos: /* Kommunikation mit RFM funktioniert nur sporadisch */ Linie&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Beschreibung der Funkmodule RFM01, RFM02 und RFM12.&lt;br /&gt;
&lt;br /&gt;
Benötigt werden in der Minimal-Version im FIFO-Modus nur die Anschlüsse nSEL, SDO, SDI und SCK, eben das komplette SPI-Interface. Der Zugriff auf das Sende- und Empfangs-FIFO ist per Software möglich, ebenso die Abfrage der Statusbits. Deshalb werden z.B. nIRQ und nFFS nicht unbedingt benötigt. nIRQ signalisiert unter anderem, dass das Modul bereit ist Daten zu empfangen. Wenn Daten empfangen wurden, kann dies über den FFIT-Pin abgefragt werden (falls die Füllschwelle eingestellt wurde). nFFS dient dazu das FIFO direkt anzusprechen (es ist quasi der Chipselect für das FIFO), davon wird in der Minimalversion aber kein Gebrauch gemacht. Der Pin muss daher auf high-Pegel gelegt werden!&lt;br /&gt;
An CLK kann eine Frequenz von 1MHz bis 10MHz eingestellt werden. Hiermit kann dann z.B. der Mikrocontroller versorgt werden.&lt;br /&gt;
Reset ist ein Open-Collector-Ausgang und gleichzeitig der Reset-Eingang. Er sollte daher entweder gar nicht, oder aber hochohmig angeschlossen werden.&lt;br /&gt;
&lt;br /&gt;
Im FIFO-Mode kann das Modul konfiguriert werden mit dem Empfang zu warten, bis die Daten 0x2DD4 empfangen wurden. Sobald dieses Bitmuster empfangen wurde, werden Daten in das FIFO geschrieben, bis man das FIFO abschaltet und die Mustererkennung neu startet.&lt;br /&gt;
&lt;br /&gt;
Als weitere Modi stehen unter anderem ein synchroner Modus zur Verfügung (no FIFO mode), in dem der Sender/Empfänger den Bittakt ausgibt, und synchron dazu die zu sendenden Daten einliest bzw. die empfangenen Daten ausgibt. Der SPI Bus ist trotzdem zur Initialisierung des Moduls notwendig.&lt;br /&gt;
&lt;br /&gt;
== FAQ ==&lt;br /&gt;
&lt;br /&gt;
=== SPI Interface ===&lt;br /&gt;
&lt;br /&gt;
* Maximale Datenrate: 2,5MHz (10MHz Quarz / 4)&lt;br /&gt;
&lt;br /&gt;
=== CLK-Ausgang bleibt bei 1 MHz ===&lt;br /&gt;
&lt;br /&gt;
* Vor dem Umschalten (mit 0xC0E0) länger warten.&lt;br /&gt;
&lt;br /&gt;
=== RFM12 empfängt ein paar Bytes, dann nur Müll ===&lt;br /&gt;
&lt;br /&gt;
* Es wird zu langsam gesendet (TX FIFO underrun)&lt;br /&gt;
* Es wird zu langsam empfangen (RX FIFO overrun)&lt;br /&gt;
&lt;br /&gt;
Die Status-Bits helfen hier beim Debuggen. SPI sollte auf maximaler Transferrate stehen.&lt;br /&gt;
&lt;br /&gt;
=== RFM empfängt nur Müll ===&lt;br /&gt;
&lt;br /&gt;
http://www.mikrocontroller.net/topic/73560#605528&lt;br /&gt;
&lt;br /&gt;
Deine Module verhalten sich normal. Man muß mit den Gain- und AFC-Bits&lt;br /&gt;
eine ganze Weile spielen, bis die Module korrekt laufen (kommt auf die&lt;br /&gt;
Anwendung an). Fakt ist: der Empfänger empfängt ständig Datenmüll als&lt;br /&gt;
Rauschen. Wenn der FIFO durch die Präambel getriggert wird, sind die&lt;br /&gt;
Daten im FIFO ziemlich korrekt, wenn alles &amp;quot;gut&amp;quot; eingestellt ist. Der&lt;br /&gt;
FIFO sollte per Interrupt dann auch sofort abgeholt werden, da sonst das&lt;br /&gt;
nächste Byte das alte direkt überschreibt. Jeder zusammenhängende&lt;br /&gt;
Datensatz (mehrere Bytes an einem Stück) muß von einer Präambel&lt;br /&gt;
eingeleitet werden. Nach dem kompletten Einlesen eines Datensatzes muß&lt;br /&gt;
der FIFO abgeschaltet, wieder eingeschaltet und für den Empfang der&lt;br /&gt;
nächsten Präambel neu scharf gemacht werden.&lt;br /&gt;
&lt;br /&gt;
=== RFM hängt sich auf ===&lt;br /&gt;
&lt;br /&gt;
Wenn man die AFC nicht begrenzt, also keinen Wertebereich vorgibt, die eine maximale Abweichung korrigiert wird passiert es nach einer Weile, dass sich der Empfänger aufhängt, die Offsetbits im Status werden maximal und dann geht gar nichts mehr, er hängt fest.&lt;br /&gt;
&lt;br /&gt;
Siehe auch &lt;br /&gt;
* Forenbeitrag [http://www.mikrocontroller.net/topic/82456#689660 RFM12: Erfahrungen ]&lt;br /&gt;
&lt;br /&gt;
=== Kommunikation mit RFM funktioniert nur sporadisch ===&lt;br /&gt;
&lt;br /&gt;
* Ist die Versorgungsspannung stabil? (evtl. Kondensator einbauen)&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Register ==&lt;br /&gt;
&lt;br /&gt;
Von https://www.mikrocontroller.net/attachment/24947/RFM12.txt&lt;br /&gt;
&lt;br /&gt;
Dieses Dokument beschreibt die Nutzung des RFM12 TRX Moduls!&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039; WICHTIG &#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Dieses Dokument wurde aus mehreren Quellen zusammengestellt, und kann Fehler enthalten!&lt;br /&gt;
Es können Abweichungen in Bezug auf RF01 / RF02 / RF12 / RFM01 / RFM02 und andere Module auftreten!&lt;br /&gt;
Es wurde das Datenblatt vom RFM12B und RF12 von www.hoperf.com als Basis genuzt. Zusätzlich wurden diese Informationen mit Hilfe von Forums-Nutzern (https://www.mikrocontroller.net/topic/71682) weiter vervollständigt!&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039; WICHTIG &#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Hinweis:&#039;&#039;&#039; Die LNA-Eingangsimpedanz beträgt 250 Ohm, und muss beim Anschluss einer 50-Ohm-Antenne entsprechend angepasst werden, um das Rauschen zu minimieren! &#039;&#039; -- (Auf den Pollin-Modulen bereits vorhanden)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configuration Setting ===&lt;br /&gt;
 Hex = 80 &amp;amp; xx&lt;br /&gt;
 Bit-Syntax: &lt;br /&gt;
{| cellpadding=&amp;quot;2&amp;quot; cellspacing=&amp;quot;0&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
!width=&amp;quot;20%&amp;quot;| Byte ||width=&amp;quot;40%&amp;quot;| 1 || 2&lt;br /&gt;
|-&lt;br /&gt;
!Bits&lt;br /&gt;
|{{8Bit|width=100%| 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 }}||{{8Bit|width=100%| el | ef | b1 | b0 | x3 | x2 | x1 | x0}}|}&lt;br /&gt;
 el (TX FIFO) = Sendepuffer für Datentransfer nutzen (1 = An / 0 = Aus)&lt;br /&gt;
 ef (RX FIFO) = Empfangspuffer für Datenspeicherung nutzen (1 = An / 0 = Aus)&lt;br /&gt;
 b... = Zu nutzende Basisfrequenz (00=315MHz / 01=433MHz / 10=868MHz / 11=915MHz)&lt;br /&gt;
 x... = Interner Clock des Chips kann durch verschieben einer Kondensator-Anpass-Stufe bestimmt werden.&lt;br /&gt;
        0,5pF pro Schritt. Basis ist 8,5pF -&amp;gt; (0000=8,5 / 0001=9,0 / 0010=9,5 / ...)&lt;br /&gt;
&lt;br /&gt;
=== Power-Managment ===&lt;br /&gt;
 Hex = 82 &amp;amp; xx&lt;br /&gt;
 Bit-Syntax: 10000010 | er | ebb | et | es | ex | eb | ew | dc&lt;br /&gt;
 er = Empfänger einschalten (1 = an / 0 = Aus)&lt;br /&gt;
 ebb = ... (Synthesizer muss aktiv sein!) (1 = an / 0 = aus)&lt;br /&gt;
 et = Sender einschalten (1 = an / 0 = Aus) (Wenn das TX-Register aktiv und mit Daten gefüllt ist/wurde,&lt;br /&gt;
      werden diese Daten sofort gesendet) (1 = an / 0 = aus)&lt;br /&gt;
 es = Schaltet den Synthesizer ein. (1 = an / 0 = aus)&lt;br /&gt;
 ex = Schaltet den Quarz-Oszilator ein. (1 = an / 0 = aus)&lt;br /&gt;
 eb = Vergleichbar mit BrownOutDetection -&amp;gt; Erkennt eine zu geringe Betriebsspannung und erzeugt einen Interrupt,&lt;br /&gt;
      um einen drohenden Spannungsaufall anzukündigen (1 = An / 0 = Aus)&lt;br /&gt;
 ew = Aktiviert den WakeUpTimer des Prozessors. (1 = an / 0 = aus)&lt;br /&gt;
 dc = Deaktiviert die Ausgabe des SystemClocks auf dem CLK Pin am Chip (1 = Keine ClockAusgabe / 0 = Clock ausgeben)&lt;br /&gt;
&lt;br /&gt;
=== PLL Setting ===&lt;br /&gt;
 Hex = 198 + y&lt;br /&gt;
 Bit-Syntax: 110011000 | ob1 | ob0 | lpx | ddy | ddit | bw1 | bw0&lt;br /&gt;
 ob... = ... (00= 5 oder 10MHz [standard] / 01=3.3MHz / 1x=2.5MHz oder weniger)&lt;br /&gt;
 lpx = Wählt den Low-Power-Mode für den Quarz-Oszilator aus. (0=1ms [620µA] / 1=2ms [460µA])&lt;br /&gt;
 ddy = ...&lt;br /&gt;
 ddi = Schaltet das Dithering in PLL-Schleife ab. (1=abgeschaltet / 0=eingeschaltet)&lt;br /&gt;
 bw... = Wählt die Bandbreite des PLL-Signals aus. (00=86.2kbps [-107dBc/Hz] / 01=256kbps [-102dBc/Hz]) Bei 1MHz Offset Phasenrauschen.&lt;br /&gt;
&lt;br /&gt;
=== LowBatt / µC Clock Control ===&lt;br /&gt;
 Hex = c0 &amp;amp; xx&lt;br /&gt;
 Bit-Syntax: 11000000 | d2 | d1 | d0 | v4 | v3 | v2 | v1 | v0&lt;br /&gt;
 d... = Bestimmt den Teilungsfaktor für die Clockausgabe am CLK-Pin in Abhängigkeit des Internen SystemTakts.&lt;br /&gt;
        (000=1 / 001=1.25 / 010=1.66 / 011=2 / 100=2.5 / 101=3.33 / 110=5 / 111=10)&lt;br /&gt;
 v... = Bestimmt die Minimalspannung, ab der ein Interrupt durchgeführt werden&lt;br /&gt;
 muss. (Ähnlich einer BrownOutDetection). Im Power-Managment muss das eb-Bit&lt;br /&gt;
 aktiv sein, damit dies funktioniert.&lt;br /&gt;
&lt;br /&gt;
=== Frequency-setting ===&lt;br /&gt;
Bestimmt den Offset der Sende- und Empfangsfrequenz. Dieser Offset wird auf das Basisband im Configuration Setting hinzu gerechnet.&lt;br /&gt;
 Hex = a &amp;amp; xxx&lt;br /&gt;
 Bit-Syntax: 1010 | f11 | f10 | f9 | f8 | f7 | f6 | f5 | f4 | f3 | f2 | f1 | f0&lt;br /&gt;
 f... = Bestimmt den Offsetwert der Frequenz.&lt;br /&gt;
        Als Basis gilt das eingestellte Band im Configuration-Settings-Kommando&lt;br /&gt;
&lt;br /&gt;
=== Data-Rate ===&lt;br /&gt;
 Hex = c6 &amp;amp; xx&lt;br /&gt;
 Bit-Syntax: 11000110 | cs | r6 | r5 | r4 | r3 | r2 | r1 | r0&lt;br /&gt;
 cs =  Vorteiler, Faktor 7. Hiermit kann ein Vorteiler aktiviert werden,&lt;br /&gt;
       der die errechnete Baudrate (r...) durch 7 teilt.&lt;br /&gt;
 r... = Baudratenteilerfaktor&lt;br /&gt;
&lt;br /&gt;
=== RX Control ===&lt;br /&gt;
 Hex = 94 &amp;amp; xx&lt;br /&gt;
 Bit-Syntax: 10010 | p20 | d1 | d2 | i2 | i1 | i0 | g1 | g0 | r2 | r1 | r0&lt;br /&gt;
 p20 = Bestimmt die Funktion des Pin20 (nINT / VDI) am RFM12 Chip (1 = VDI-Ausgang / 0 = Interrupt-Eingang)&lt;br /&gt;
 d... = (Valid Data Indicator). Definiert die Geschwindigkeit, mit der bestimmt wird, ob ein Signal korrekt ist, oder nicht.&lt;br /&gt;
        (00=schnell / 01=mittel / 10=langsam / 11=immer an). Je nach eingestellter Variante werden&lt;br /&gt;
        unterschiedliche Hardware- und Software-Kombinationen genuzt.&lt;br /&gt;
        Fast:  CR_Lock  OR  DQD  ... Medium:  CR_Lock  AND ( DRSSI  OR  DQD ) ... &lt;br /&gt;
        SLOW: R/S FlipFlop aus (SET)  DRSSI  OR  DQD  OR  CR_Lock  und (CLR)  DRSSI  AND  DQD  AND  CR_Lock .&lt;br /&gt;
 i... = Bestimmt die Bandbreite des Empfängers in KHz (KiloHertz).&lt;br /&gt;
        (000=Reserviert / 001=400 / 010=340 / 011=270 / 100=200 / 101=134 / 110=67 / 111=Reserviert)&lt;br /&gt;
 g... = (LNA-Gain) Verstärkungsfaktor des Rauscharmen-Eingangs-Signal-Verstärkers (LNA Low Noise Amplifier).&lt;br /&gt;
        Werte in dBm (Dezibel [Grösse: Milliwatt]) Mögliche Werte sind: 0 / -6 / -14 / -20&lt;br /&gt;
 r... = (DRSSI = Digital Received Signal Strength Indication) Minimale Empfangssignalfeldstärke.&lt;br /&gt;
        6 dBm pro Schritt: (000=-103 / 001=-97 / 010=-91 / ...)&lt;br /&gt;
&lt;br /&gt;
=== Synchron Pattern ===&lt;br /&gt;
 Hex = ce &amp;amp; xx&lt;br /&gt;
 Bit-Syntax: 11001110 | b7 | b6 | b5 | b4 | b3 | b2 | b1 | b0&lt;br /&gt;
 b... = Legt den Wert fest, der als Synchronisations-Byte für die Datenfilterung verwendet werden soll.&lt;br /&gt;
&lt;br /&gt;
=== Data Filter ===&lt;br /&gt;
 Hex = c2 &amp;amp; xx&lt;br /&gt;
 Bit-Syntax: 11000010 | al | ml | -unknow- (1) | s | -unknow- (1) | f2 | f1 | f0&lt;br /&gt;
 al = Baudratenregenerator schaltet automatisch in den langsamen Modus, &lt;br /&gt;
      sobald er einen Takt erkannt hat.&lt;br /&gt;
 ml = schneller/langsamer Modus&lt;br /&gt;
 -unknown- (1) = ??? (Standard = 1) (Auch im Datenblatt von IA4420 so beschrieben)&lt;br /&gt;
 s = (DataFilter) Typ des Datenfilters (0=DigitalFilter / 1=AnalogFilter).&lt;br /&gt;
     Bei Nutzung des Analog-Filters kann kein FIFO sowie kein ClockRecovery genuzt werden.&lt;br /&gt;
 -unknown- (1) = ??? (Standard = 1) (Auch im Datenblatt von IA4420 so beschrieben)&lt;br /&gt;
 f... = (DQD Threshold) Bestimmt den Schwellwert, ab dem ein Signal als gut empfunden wird,&lt;br /&gt;
         und der Empfänger dieses weiterverarbeiten soll.&lt;br /&gt;
         DQD (data quality detection) zählt die &amp;quot;Spikes&amp;quot; des ungefilterten Signals, und bestimmt darüber die Qualität der Daten.&lt;br /&gt;
&lt;br /&gt;
=== FIFO und RESET-Mode ===&lt;br /&gt;
 Hex = ca &amp;amp; xx&lt;br /&gt;
 Bit-Syntax: 11001010 | f3 | f2 | f1 | f0 | -unknow- (0) | al | ff | dr&lt;br /&gt;
 f... = (FIFO interrupt Level)&lt;br /&gt;
 -unknown- (0) = ??? (Standard = 0) (Auch im Datenblatt von IA4420 so beschrieben)&lt;br /&gt;
 al = (FIFO Fill Condition) Legt den Wert fest, ab dem das Füllen des FIFOs beginnt.&lt;br /&gt;
      (0=Synchron / 1=Ständig). Bei Nutzung des Synchron-Modus, werden erst dann Daten in den FIFO geschrieben,&lt;br /&gt;
      wenn eine definierte 16Bit-Datenfolge empfangen wurde (Standard ist Hex: 2dd4).&lt;br /&gt;
 ff = (FIFO Fill) Startet das Einlesen der empfangenen Daten in den FIFO-Puffer.&lt;br /&gt;
      Wenn al (FIFO Fill Condition) auf synchron steht, dann startet das Setzen dieses Bits die Synchronisation-Bit-Erkennung.&lt;br /&gt;
 dr = (Sens Reset Mode) Wenn dieses Bit auf 0 steht, wird bei einer Schwankung von 200mV auf&lt;br /&gt;
      der VCC-Leitung (Spannungsversorgung des Chips), ein System-Reset ausgelöst.&lt;br /&gt;
&lt;br /&gt;
=== Automatic Frequency Control ===&lt;br /&gt;
 Hex = c4 &amp;amp; xx&lt;br /&gt;
 Bit-Syntax: 11000100 | a1 | a0 | rl1 | rl0 | st | fi | oe | en&lt;br /&gt;
 a... = Modus der AFC-Schaltung, 0=Auto, 1=einmalig nach Einschalten, 2=Solange VDI low ist, 3=unabhängig von VDI&lt;br /&gt;
 r... = (Range Limit) Frequenzraster (00=KeineBegrenzung / 01=+15 &amp;gt; -16 / 10=+7 &amp;gt; -8 / 11=+3 &amp;gt; -4)&lt;br /&gt;
 st = Berechneten Offset-Wert übernehmen&lt;br /&gt;
 fi = Genauer Berechnungsmodus (besser aber lansgamer)&lt;br /&gt;
 oe = AFC-Offset freischalten&lt;br /&gt;
 en = AFC-Berechnung aktivieren&lt;br /&gt;
&lt;br /&gt;
=== TX Configuration Control ===&lt;br /&gt;
 Hex = 98 &amp;amp; xx&lt;br /&gt;
 Bit-Syntax: 1001100 | mp | m3 | m2 | m1 | m0 | -unknow- (0) | p2 | p1 | p0&lt;br /&gt;
 mp = (Modulation Polarity) Bestimmt die Richtung der FSK-Erzeugung (invertiert das Spektrum).&lt;br /&gt;
 m... = (fDeviation) Bestimmt den Frequenzabstand des High- und Low-Wertes bei der Ubertragung im FSK-Betrieb. Basis ist der mp-Wert.&lt;br /&gt;
 -unknown- (0) = ??? (Standard = 0) (Auch im Datenblatt von IA4420 so beschrieben)&lt;br /&gt;
 p... = Bestimmt die relative Ausgangsleistung des Senders anhand des dBm-Wertes (Dezibel [Grösse: Milliwat]) 3-dBm-Schritte.&lt;br /&gt;
        (000=0 / 001=-3 / 010=-6 / ...). Der Wert steht im Zusammenhang mit der angeschlossenen Antennen-Impedanz.&lt;br /&gt;
&lt;br /&gt;
=== Wake-Up Timer ===&lt;br /&gt;
 Bestimmt die Zeitperiode der zyklischen Einschaltung des WakeUp-Timers&lt;br /&gt;
 Hex = e &amp;amp; xxx&lt;br /&gt;
 Bit-Syntax: 111 | R4 | R3 | R2 | R1 | R0 | M7 | M6 | M5 | M4 | M3 | M2 | M1 | M0&lt;br /&gt;
 R = Exponent der Zeit&lt;br /&gt;
 M = Zeit&lt;br /&gt;
&lt;br /&gt;
=== Low Duty-Cycle ===&lt;br /&gt;
&lt;br /&gt;
Bestimmt die maximale Sendezeit pro Stunde. Dies ist wichtig, um sich an gesetzliche Frequenzzuteilungsrichtlinien zu halten, die bestimmen, wie lang jemand mit einer definierten Sendeleistung auf einer bestimmten Frequenz (mit eventuell definierter Betriebsart [Modulationstyp]) senden darf.)&lt;br /&gt;
&lt;br /&gt;
 hex = 6400 + Bits&lt;br /&gt;
 Bit-Syntax: 1100100 | r| d6 | d5 | d4 | d3 | d2 | d1 | d0 | en&lt;br /&gt;
 r =  ??????????????????&lt;br /&gt;
 d... = Einschaltdauer während der zyklischen Einschaltung&lt;br /&gt;
 en = zyklische Einschaltung aktivieren&lt;br /&gt;
&lt;br /&gt;
=== RX FIFO Read ===&lt;br /&gt;
 Hex = b000&lt;br /&gt;
 Bit-Syntax: 1011000000000000&lt;br /&gt;
&lt;br /&gt;
Dieses Kommando löst die Rückgabe eines Datenbytes (synchron mit dem 8. Bit) aus. Es ist nötig, dass das ef-Bit (RX-FIFO) im Configuration Setting gesetzt wurde, um diese Funktion nutzen zu können!&lt;br /&gt;
&lt;br /&gt;
=== TX Register Write ===&lt;br /&gt;
Dieses Kommando schreibt Daten in den TX-Puffer. Wenn der Sender aktiv ist, wird dieses sofort gesendet. el (TX-Register) muss im Configuration-Setting-Kommando aktiv sein.&lt;br /&gt;
 Hex = b8 &amp;amp; xx&lt;br /&gt;
 Bit-Syntax: 10111000 | DataByteToSend&lt;br /&gt;
 DataByteToSend = Das Datenbyte, welches gesendet werden soll.&lt;br /&gt;
&lt;br /&gt;
(Senden Funktioniert nur wenn zuvor der Status abgefragt wurde)&lt;br /&gt;
&lt;br /&gt;
=== Status Read ===&lt;br /&gt;
Dieses Kommando löst die Rückgabe des Statusregisters aus, welches nach der ersten 0 im ersten Bit synchron übertragen wird.&lt;br /&gt;
 Hex = 0000&lt;br /&gt;
 Bit-Syntax: 0000000000000000&amp;lt;000&amp;gt;&lt;br /&gt;
 Rückgabe-Syntax: x0 | x1 | x2 | x3 | x4 | x5 | x6 | x7 | x8 | x9 | x10 | x11 | x12 | x13 | x14 | x15 | x16 | x17 | x18&lt;br /&gt;
 x0 -&amp;gt; x5 = Interrupt bits&lt;br /&gt;
 x6 -&amp;gt; x15 = Status Bits&lt;br /&gt;
 x16 -&amp;gt; x18 = FIFO&lt;br /&gt;
 x0 = FFIT / RGIT (RGIT = TX-Register ist bereit neue Daten zu senden ... kann mit dem TX-Register gelöscht werden)&lt;br /&gt;
     (FFIT = Die Anzahl der Datenbits im FIFO-Puffer hat das eingestellte Limit erreicht.&lt;br /&gt;
      Kann mit einer der FIFO-Lesemethoden gelöscht werden)&lt;br /&gt;
 x1 = POR (PowerOnReset)&lt;br /&gt;
 x2 = FFOV / RGUR (RGUR = Der Datenstrom beim Senden ist abgerissen, da nicht schnell genug Daten nachgeladen wurden)&lt;br /&gt;
      (FFOV = Der RX-FIFO ist übergelaufen)&lt;br /&gt;
 x3 = WKUP&lt;br /&gt;
 x4 = EXT&lt;br /&gt;
 x5 = LBD&lt;br /&gt;
 x6 = FFBM (Der FIFO-Puffer ist leer)&lt;br /&gt;
 x7 = RSSI/ATS (ATS = )(RSSI = Die Signalstärke ist über dem eingestelltem Limit)&lt;br /&gt;
 x8 = DQD&lt;br /&gt;
 x9 = CRL&lt;br /&gt;
 x10 = ATGL&lt;br /&gt;
 x11 = OFFS_4&lt;br /&gt;
 x12 = OFFS_3&lt;br /&gt;
 x13 = OFFS_2&lt;br /&gt;
 x14 = OFFS_1&lt;br /&gt;
 x15 = OFFS_0&lt;br /&gt;
 x16 = FO&lt;br /&gt;
 x17 = FO+1&lt;br /&gt;
 x18 = FO+2&lt;br /&gt;
&lt;br /&gt;
== Bezugsquellen ==&lt;br /&gt;
* [[Elektronikversender#csd-electronics|csd-electronics]]&lt;br /&gt;
* [[Elektronikversender#IT-WNS|IT-WNS]]&lt;br /&gt;
* [[Elektronikversender#Pollin_Electronic|Pollin Electronic]]&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
* [[AVR RFM12]]&lt;br /&gt;
* [[RFM12 Protokoll Stack]]&lt;br /&gt;
* [http://www.mikrocontroller.net/topic/93801 Bezugsquellen]&lt;br /&gt;
&lt;br /&gt;
Folgende Links sind mit Vorsicht zu genießen, da die Datenblätter teilweise  fehlerbehaftet sind. Es empfiehlt sich, direkt mit dem Datenblatt des RF12 (das ist das IC auf dem Modul) zu arbeiten. Dieses ist so gut wie fehlerfrei.&lt;br /&gt;
&lt;br /&gt;
* [http://www.hoperf.com/pdf/RF12.pdf Datenblatt des ICs RF12] (PDF)&lt;br /&gt;
* [http://www.hoperf.com/pdf/RFM12.pdf Datenblatt des Moduls RFM12] (PDF)&lt;br /&gt;
* [http://www.hoperf.com/pdf/RF12_code.pdf Programming Guide] (PDF)&lt;br /&gt;
* [http://www.hoperf.com/pdf/RF12TOOLS.pdf Demo Kit User Manual] (PDF)&lt;br /&gt;
* [http://www.pollin.de/shop/downloads/D810047S.ZIP Beispielprogramm von Pollin] (ZIP)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Bauteile]]&lt;br /&gt;
[[Kategorie:Funk]]&lt;/div&gt;</summary>
		<author><name>Thymythos</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=AVR-GCC-Tutorial&amp;diff=32707</id>
		<title>AVR-GCC-Tutorial</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=AVR-GCC-Tutorial&amp;diff=32707"/>
		<updated>2008-11-24T13:09:50Z</updated>

		<summary type="html">&lt;p&gt;Thymythos: /* TODO */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Vorwort =&lt;br /&gt;
&lt;br /&gt;
Dieses Tutorial soll den Einstieg in die Programmierung von Atmel [[AVR]]-Mikrocontrollern in der Programmiersprache [[C]] mit dem freien C-Compiler [[AVR-GCC]] erleichtern.&lt;br /&gt;
&lt;br /&gt;
Vorausgesetzt werden Grundkenntnisse der Progammiersprache C. Diese Kenntnisse kann man sich online erarbeiten, z. B. mit dem [http://www.schellong.de/c.htm C Tutorial von Helmut Schellong]. Nicht erforderlich sind Vorkenntnisse in der Programmierung von Mikrocontrollern, weder in Assembler noch in einer anderen Sprache. &lt;br /&gt;
&lt;br /&gt;
In diesem Text wird häufig auf die Standardbibliothek avr-libc verwiesen, für die es eine [http://www.nongnu.org/avr-libc/user-manual/index.html Online-Dokumentation] gibt, in der sich auch viele nützliche Informationen zum Compiler und zur Programmierung von AVR Controllern finden. Bei WinAVR gehört die avr-libc Dokumentation zum Lieferumfang und wird mitinstalliert.&lt;br /&gt;
&lt;br /&gt;
Der Compiler und die Standardbibliothek avr-libc werden stetig weiterentwickelt. Erläuterungen und Beispiele beziehen sich auf den C-Compiler avr-gcc ab Version 3.4 und die avr-libc ab Version 1.4.3. Die Unterschiede zu älteren Versionen werden im Haupttext und Anhang zwar erläutert, Anfängern sei jedoch empfohlen, die aktuellen Versionen zu nutzen (für MS-Windows: aktuelle Version des [[WinAVR]]-Pakets; für Linux gibt es CDK4AVR: http://cdk4avr.sf.net oder auch fertige Pakete bei verschiedenen Distributionen.). &lt;br /&gt;
&lt;br /&gt;
Das ursprüngliche Tutorial stammt von Christian Schifferle, viele neue Abschnitte und aktuelle Anpassungen von Martin Thomas.&lt;br /&gt;
&lt;br /&gt;
Dieses Tutorial ist in PDF-Form erhältlich bei:&lt;br /&gt;
http://www.siwawi.arubi.uni-kl.de/avr_projects/AVR-GCC-Tutorial_-_www_mikrocontroller_net.pdf&lt;br /&gt;
(nicht immer auf aktuellem Stand)&lt;br /&gt;
&lt;br /&gt;
= Benötigte Werkzeuge =&lt;br /&gt;
&lt;br /&gt;
Um eigene Programme für AVRs mittels avr-gcc/avr-libc zu erstellen und zu testen, wird folgende Hard- und Software benötigt:&lt;br /&gt;
&lt;br /&gt;
* Platine oder Versuchsaufbau für die Aufnahme eines AVR Controllers, der vom avr-gcc Compiler unterstützt wird (alle ATmegas und die meisten AT90, siehe Dokumentation der avr-libc für unterstützte Typen). Dieses Testboard kann durchaus auch selbst gelötet oder auf einem Steckbrett aufgebaut werden. Einige Registerbeschreibungen dieses Tutorials beziehen sich auf den inzwischen veralteten AT90S2313. Der weitaus größte Teil des Textes ist aber für alle Controller der AVR-Familie gültig. Brauchbare Testplattformen sind auch das [[STK500]] und der [[AVR Butterfly]] von Atmel. Weitere Infos findet man [[AVR#Starterkits|hier]].&lt;br /&gt;
&lt;br /&gt;
* Der avr-gcc Compiler und die avr-libc. Kostenlos erhältlich für nahezu alle Plattformen und Betriebssysteme. Für MS-Windows im Paket [[WinAVR]]; für Unix/Linux siehe auch Hinweise im Artikel [[AVR-GCC]].&lt;br /&gt;
&lt;br /&gt;
* Programmiersoftware und -[[AVR In System Programmer |hardware]] z. B. PonyProg (siehe auch: [[Pony-Prog Tutorial]]) oder [[AVRDUDE]] mit [[STK200]]-Dongle oder die von Atmel verfügbare Hard- und Software ([[STK500]], Atmel AVRISP, [[AVR-Studio]]).&lt;br /&gt;
&lt;br /&gt;
* Nicht unbedingt erforderlich, aber zur Simulation und zum Debuggen unter MS-Windows recht nützlich: [[AVR-Studio]] (siehe Abschnitt [[AVR-GCC-Tutorial#Exkurs: Makefiles|Exkurs: Makefiles]]).&lt;br /&gt;
&lt;br /&gt;
= Was tun, wenn&#039;s nicht &amp;quot;klappt&amp;quot;? =&lt;br /&gt;
&lt;br /&gt;
* Herausfinden, ob es tatsächlich ein avr(-gcc) spezifisches Problem ist oder nur die eigenen C-Kenntnisse einer Auffrischung bedürfen. Allgemeine C-Fragen kann man eventuell &amp;quot;beim freundlichen Programmierer zwei Büro-, Zimmer- oder Haustüren weiter&amp;quot; loswerden. Ansonsten: [[C]]-Buch (gibt&#039;s auch &amp;quot;gratis&amp;quot; online) lesen.&lt;br /&gt;
&lt;br /&gt;
* Die [[AVR Checkliste]] durcharbeiten.&lt;br /&gt;
&lt;br /&gt;
* Die &#039;&#039;&#039;[http://www.nongnu.org/avr-libc/user-manual/index.html Dokumentation der avr-libc]&#039;&#039;&#039; lesen, vor allem (aber nicht nur) den Abschnitt Related Pages/&#039;&#039;&#039;Frequently Asked Questions&#039;&#039;&#039; = Oft gestellte Fragen (und Antworten dazu). Z.Zt leider nur in englischer Sprache verfügbar.&lt;br /&gt;
&lt;br /&gt;
* Den Artikel [[AVR-GCC]] in diesem Wiki lesen.&lt;br /&gt;
&lt;br /&gt;
* Das [http://www.mikrocontroller.net/forum/2 GCC-Forum auf  www.mikrocontroller.net] nach vergleichbaren Problemen absuchen.&lt;br /&gt;
&lt;br /&gt;
* Das avr-gcc-Forum bei [http://www.avrfreaks.net avrfreaks] nach vergleichbaren Problemen absuchen.&lt;br /&gt;
&lt;br /&gt;
* Das [http://lists.gnu.org/archive/html/avr-gcc-list/ Archiv der avr-gcc Mailing-Liste] nach vergleichbaren Problemen absuchen.&lt;br /&gt;
&lt;br /&gt;
* Nach Beispielcode suchen. Vor allem im &#039;&#039;Projects&#039;&#039;-Bereich von [http://www.avrfreaks.net AVRFREAKS] (anmelden).&lt;br /&gt;
&lt;br /&gt;
* Google oder yahoo befragen schadet nie.&lt;br /&gt;
&lt;br /&gt;
* Bei Problemen mit der Ansteuerung interner AVR-Funktionen mit C-Code: das Datenblatt des Controllers lesen (ganz und am Besten zweimal). Datenblätter sind  auf den [http://www.atmel.com Atmel Webseiten] als pdf-Dateien verfügbar. Das komplette Datenblatt (complete) und nicht die Kurzfassung (summary) verwenden.&lt;br /&gt;
&lt;br /&gt;
* Die Beispieleprogramme im [[AVR-Tutorial]] sind zwar in AVR-Assembler verfasst, Erläuterungen und Vorgehensweisen sind aber auch auf C-Programme übertragbar.&lt;br /&gt;
&lt;br /&gt;
* Einen Beitrag in eines der Foren oder eine Mail an die Mailing-Liste schreiben. Dabei möglichst viel Information geben: Controller, Compilerversion, genutzte Bibliotheken, Ausschnitte aus dem Quellcode oder besser ein [http://www.mikrocontroller.net/topic/72767#598986 Testprojekt] mit allen notwendigen Dateien, um das Problem nachzuvollziehen, sowie genaue Fehlermeldungen bzw. Beschreibung des Fehlverhaltens. Bei Ansteuerung externer Geräte die Beschaltung beschreiben oder skizzieren (z. B. mit [http://www.tech-chat.de/ Andys ASCII Circuit]). Siehe dazu auch: &#039;&#039;&#039;[http://www.lugbz.org/documents/smart-questions_de.html &amp;quot;Wie man Fragen richtig stellt&amp;quot;]&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
= Erzeugen von Maschinencode =&lt;br /&gt;
&lt;br /&gt;
Aus dem C-Quellcode erzeugt der avr-gcc Compiler (zusammen mit Hilfsprogrammen wie z.&amp;amp;nbsp;B. Präprozessor, Assembler und Linker) Maschinencode für den AVR-Controller. Üblicherweise liegt dieser Code dann im Intel Hex-Format vor (&amp;quot;Hex-Datei&amp;quot;). Die Programmiersoftware (z.&amp;amp;nbsp;B. [[AVRDUDE]], PonyProg oder AVRStudio/STK500-plugin) liest diese Datei ein und überträgt die enthaltene Information (den Maschinencode) in den Speicher des Controllers. Im Prinzip sind also &amp;quot;nur&amp;quot; der avr-gcc-Compiler (und wenige Hilfsprogramme) mit den &amp;quot;richtigen&amp;quot; Optionen aufzurufen, um aus C-Code eine &amp;quot;Hex-Datei&amp;quot; zu erzeugen. Grundsätzlich stehen dazu zwei verschiedene Ansätze zur Verfügung:&lt;br /&gt;
&lt;br /&gt;
* Die Verwendung einer integrierten Entwicklungsumgebung (IDE = &#039;&#039;&#039;I&#039;&#039;&#039;ntegrated &#039;&#039;&#039;D&#039;&#039;&#039;evelopment &#039;&#039;&#039;E&#039;&#039;&#039;nvironment), bei der alle Einstellungen z.&amp;amp;nbsp;B. in Dialogboxen durchgeführt werden können. Unter Anderem kann AVRStudio ab Version 4.12 (kostenlos auf [http://www.atmel.com/ atmel.com]) zusammen mit WinAVR als integrierte Entwicklungsumgebung für den Compiler avr-gcc genutzt werden (dazu müssen AVRStudio und WinAVR auf dem Rechner installiert sein). Weitere IDEs für den avr-gcc (ohne Anspruch auf Vollständigkeit): AtmanAvr C (relativ günstig), KamAVR (kostenlos), VMLab (ab Version 3.12 ebenfalls kostenlos). Integrierte Entwicklungsumgebungen unterscheiden sich stark in Ihrer Bedienung und stehen auch nicht für alle Plattformen zur Verfügung, auf denen der Compiler  ausführbar ist (z.&amp;amp;nbsp;B. AVRStudio nur für MS-Windows). Zur Anwendung des avr-gcc Compilers mit IDEs sei hier auf deren Dokumentation verwiesen. &lt;br /&gt;
&lt;br /&gt;
* Die Nutzung des Programms make mit passenden Makefiles. In den folgenden Abschnitten wird die Generierung von Maschinencode für einen AVR (&amp;quot;hex-Datei&amp;quot;) aus C-Quellcode (&amp;quot;c-Dateien&amp;quot;) anhand von &amp;quot;make&amp;quot; und den &amp;quot;Makefiles&amp;quot; näher erläutert. Viele der darin beschriebenen Optionen findet man auch im Konfigurationsdialog des avr-gcc-Plugins von AVRStudio (AVRStudio generiert ein makefile in einem Unterverzeichnis des Projektverzeichnisses). &lt;br /&gt;
&lt;br /&gt;
Beim Wechsel vom makefile-Ansatz nach WinAVR-Vorlage zu AVRStudio ist darauf zu achten, dass AVRStudio (Stand: AVRStudio Version 4.13) bei einem neuen Projekt die Optimierungsoption (vgl. Abschnitt [[AVR-GCC-Tutorial#Exkurs: Makefiles|Exkurs: Makefiles]], typisch: -Os) nicht einstellt und die mathematische Bibliothek der avr-libc (libm.a, Linker-Option -lm) nicht einbindet. Beides ist Standard bei Verwendung von makefiles nach WinAVR-Vorlage und sollte daher auch im Konfigurationsdialog des avr-gcc-Plugins von AVRStudio &amp;quot;manuell&amp;quot; eingestellt werden, um auch mit AVRStudio kompakten Code zu erzeugen.&lt;br /&gt;
&lt;br /&gt;
= Einführungsbeispiel =&lt;br /&gt;
&lt;br /&gt;
Zum Einstieg ein kleines Beispiel, an dem die Nutzung des Compilers und der Hilfsprogramme (der sogenannten &#039;&#039;Toolchain&#039;&#039;) demonstriert wird. Detaillierte Erläuterungen folgen in den weiteren Abschnitten dieses Tutorials.&lt;br /&gt;
&lt;br /&gt;
Das Programm soll auf einem AVR Mikrocontroller einige Ausgänge ein- und andere ausschalten. Das Beispiel ist für einen ATmega16 programmiert ([http://www.atmel.com/dyn/resources/prod_documents/doc2466.pdf Datenblatt]), kann aber sinngemäß für andere Controller der AVR-Familie modifiziert werden. &lt;br /&gt;
&lt;br /&gt;
Zunächst der Quellcode der Anwendung, der in einer Text-Datei mit dem Namen &#039;&#039;main.c&#039;&#039; abgespeichert wird.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
/* Alle Zeichen zwischen Schrägstrich-Stern &lt;br /&gt;
   und Stern-Schrägstrich sind lediglich Kommentare */&lt;br /&gt;
&lt;br /&gt;
// Zeilenkommentare sind ebenfalls möglich&lt;br /&gt;
// alle auf die beiden Schrägstriche folgenden&lt;br /&gt;
// Zeichen einer Zeile sind Kommentar&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;          // (1)&lt;br /&gt;
&lt;br /&gt;
int main (void) {            // (2)&lt;br /&gt;
&lt;br /&gt;
   DDRB  = 0xff;             // (3)&lt;br /&gt;
   PORTB = 0x03;             // (4)&lt;br /&gt;
&lt;br /&gt;
   while(1) {                // (5a)&lt;br /&gt;
     /* &amp;quot;leere&amp;quot; Schleife*/;  // (5b)&lt;br /&gt;
   }                         // (5c)&lt;br /&gt;
&lt;br /&gt;
   /* wird nie erreicht */&lt;br /&gt;
   return 0;                 // (6)&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* In der mit (1) markierten Zeile wird eine so genannte Header-Datei eingebunden. In io.h sind die Registernamen definiert, die im späteren Verlauf genutzt werden.&lt;br /&gt;
&lt;br /&gt;
* Bei (2) beginnt das eigentliche Programm. Jedes C-Programm beginnt mit den Anweisungen in der Funktion main.&lt;br /&gt;
&lt;br /&gt;
* Die Anschlüsse eines AVR (&amp;quot;Beinchen&amp;quot;) werden zu Blöcken zusammengefasst, einen solchen Block bezeichnet man als Port. Beim ATmega16 hat jeder Port 8 Anschlüsse, bei kleineren AVRs können einem Port auch weniger als 8 Anschlüsse zugeordnet sein. Da per Definition (Datenblatt) alle gesetzten Bits in einem Richtungsregister den entsprechenden Anschluss auf Ausgang schalten, werden mit DDRB=0xff alle Anschlüsse des Ports B zu Ausgängen.&lt;br /&gt;
&lt;br /&gt;
* (4) stellt die Werte der Ausgänge ein. Die den ersten beiden Bits des Ports zugeordneten Anschlüsse (PB0 und PB1) werden 1, alle anderen Anschlüsse des Ports B (PB2-PB7) zu 0. Aktivierte Ausgänge (logisch 1 oder &amp;quot;high&amp;quot;) liegen auf Betriebsspannung (VCC, meist 5 Volt), nicht aktivierte Ausgänge führen 0 Volt (GND, Bezugspotential).&lt;br /&gt;
&lt;br /&gt;
* (5) ist die so genannte Hauptschleife (main-loop). Dies ist eine Programmschleife, welche kontinuierlich wiederkehrende Befehle enthält. In diesem Beispiel ist sie leer. Der Controller durchläuft die Schleife immer wieder, ohne dass etwas passiert (außer das Strom verbraucht wird). Eine solche Schleife ist notwendig, da es auf dem Controller kein Betriebssystem gibt, das nach Beendigung des Programmes die Kontrolle übernehmen könnte. Ohne diese Schleife wäre der Zustand des Controllers nach dem Programmende undefiniert.&lt;br /&gt;
&lt;br /&gt;
* (6) wäre das Programmende. Die Zeile ist nur aus Gründen der C-Kompatibilität enthalten: int main(void) besagt, dass die Funktion einen Wert zurückgibt. Die Anweisung wird aber nicht erreicht, da das Programm die Hauptschleife nie verlässt.&lt;br /&gt;
&lt;br /&gt;
Um diesen Quellcode in ein auf dem Controller lauffähiges Programm zu übersetzen, wird hier ein Makefile genutzt. Das verwendete Makefile findet sich auf der Seite [[Beispiel Makefile]] und basiert auf der Vorlage, die in WinAVR mitgeliefert wird und wurde bereits angepasst (Controllertyp ATmega16). Man kann das Makefile bearbeiten und an andere Controller anpassen oder sich mit dem Programm MFile menügesteuert ein Makefile &amp;quot;zusammenklicken&amp;quot;. Das Makefile speichert man unter dem Namen Makefile (ohne Endung) im selben Verzeichnis, in dem auch die Datei main.c mit dem Programmcode abgelegt ist. Detailliertere Erklärungen zur Funktion von Makefiles finden sich im folgenden Abschnitt [[AVR-GCC-Tutorial#Exkurs: Makefiles|Exkurs: Makefiles]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
D:\tmp\gcc_tut\quickstart&amp;gt;dir&lt;br /&gt;
&lt;br /&gt;
 Verzeichnis von D:\tmp\gcc_tut\quickstart&lt;br /&gt;
&lt;br /&gt;
28.11.2006  22:53    &amp;lt;DIR&amp;gt;          .&lt;br /&gt;
28.11.2006  22:53    &amp;lt;DIR&amp;gt;          ..&lt;br /&gt;
28.11.2006  20:06               118 main.c&lt;br /&gt;
28.11.2006  20:03            16.810 Makefile&lt;br /&gt;
               2 Datei(en)         16.928 Bytes&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nun gibt man &#039;&#039;make all&#039;&#039; ein. Falls das mit WinAVR installierte Programmers Notepad genutzt wird, gibt es dazu einen Menüpunkt im Tools Menü. Sind alle Einstellungen korrekt, entsteht eine Datei main.hex, in der der Code für den AVR enthalten ist. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
D:\tmp\gcc_tut\quickstart&amp;gt;make all&lt;br /&gt;
&lt;br /&gt;
-------- begin --------&lt;br /&gt;
avr-gcc (GCC) 3.4.6&lt;br /&gt;
Copyright (C) 2006 Free Software Foundation, Inc.&lt;br /&gt;
This is free software; see the source for copying conditions.  There is NO&lt;br /&gt;
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Compiling C: main.c&lt;br /&gt;
avr-gcc -c -mmcu=atmega16 -I. -gdwarf-2 -DF_CPU=1000000UL -Os -funsigned-char -f&lt;br /&gt;
unsigned-bitfields -fpack-struct -fshort-enums -Wall -Wstrict-prototypes -Wundef&lt;br /&gt;
 -Wa,-adhlns=obj/main.lst  -std=gnu99 -Wundef -MD -MP -MF .dep/main.o.d main.c -&lt;br /&gt;
o obj/main.o&lt;br /&gt;
&lt;br /&gt;
Linking: main.elf&lt;br /&gt;
avr-gcc -mmcu=atmega16 -I. -gdwarf-2 -DF_CPU=1000000UL -Os -funsigned-char -funs&lt;br /&gt;
igned-bitfields -fpack-struct -fshort-enums -Wall -Wstrict-prototypes -Wundef -W&lt;br /&gt;
a,-adhlns=obj/main.o  -std=gnu99 -Wundef -MD -MP -MF .dep/main.elf.d obj/main.o&lt;br /&gt;
--output main.elf -Wl,-Map=main.map,--cref    -lm&lt;br /&gt;
&lt;br /&gt;
Creating load file for Flash: main.hex&lt;br /&gt;
avr-objcopy -O ihex -R .eeprom main.elf main.hex&lt;br /&gt;
&lt;br /&gt;
[...]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Inhalt der hex-Datei kann nun zum Controller übertragen werden. Dies kann z.&amp;amp;nbsp;B. über In-System-Programming (ISP) erfolgen, das im [[AVR-Tutorial: Equipment]] beschrieben ist. Makefiles nach der WinAVR/MFile-Vorlage sind für die Nutzung des Programms [[AVRDUDE]] vorbereitet. Wenn man den Typ und Anschluss des Programmiergerätes richtig eingestellt hat, kann mit &#039;&#039;make program&#039;&#039; die Übertragung mittels AVRDUDE gestartet werden. Jede andere Software, die hex-Dateien lesen und zu einem AVR übertragen kann (z.&amp;amp;nbsp;B. [[Pony-Prog_Tutorial|Ponyprog]], yapp, AVRStudio), kann natürlich ebenfalls genutzt werden.&lt;br /&gt;
&lt;br /&gt;
Startet man nun den Controller (Reset-Taster oder Stromzufuhr aus/an), werden vom Programm die Anschlüsse PB0 und PB1 auf 1 gesetzt. Man kann mit einem Messgerät nun an diesem Anschluss die Betriebsspannung messen oder eine LED leuchten lassen (Anode an den Pin, Vorwiderstand nicht vergessen). An den Anschlüssen PB2-PB7 misst man 0 Volt. Eine mit der Anode mit einem dieser Anschlüsse verbundene LED leuchtet nicht.&lt;br /&gt;
&lt;br /&gt;
= Exkurs: Makefiles =&lt;br /&gt;
&lt;br /&gt;
Wenn man bisher gewohnt ist, mit integrierten Entwicklungsumgebungen à la Visual-C Programme zu erstellen, wirkt das makefile-Konzept auf den ersten Blick etwas kryptisch. Nach kurzer Einarbeitung ist diese Vorgehensweise jedoch sehr praktisch. Diese Dateien (üblicher Name: &#039;Makefile&#039; ohne Dateiendung) dienen der Ablaufsteuerung des Programms make, das auf allen Unix/Linux-Systemen installiert sein sollte, und in einer Fassung fuer MS-Windows auch in [[WinAVR]] (Unterverzeichnis utils/bin) enthalten ist.&lt;br /&gt;
&lt;br /&gt;
Im Unterverzeichnis &#039;&#039;sample&#039;&#039; einer WinAVR-Installation findet man eine sehr brauchbare Vorlage, die sich einfach an das eigene Projekt anpassen lässt ([[Media:Makefile|lokale Kopie Stand Sept. 2004]]). Wahlweise kann man auch [http://www.sax.de/~joerg/mfile/ mfile] von Jörg Wunsch nutzen. mfile erzeugt ein makefile nach Einstellungen in einer grafischen Nutzeroberfläche, wird bei WinAVR mitinstalliert, ist aber als TCL/TK-Programm auf nahezu allen Plattformen lauffähig.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Die folgenden Ausführungen beziehen sich auf das WinAVR Beispiel-Makefile.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Ist im Makefile alles richtig eingestellt, genügt es, sich drei Parameter zu merken, die über die shell bzw. die Windows-Kommandozeile (cmd.exe/command.com) als Parameter an &amp;quot;make&amp;quot; übergeben werden. Das Programm make sucht sich &amp;quot;automatisch&amp;quot; das Makefile im aktuellen Arbeitsverzeichnis und führt die darin definierten Operationen für den entsprechenden Aufrufparameter durch.&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
| &#039;&#039;make all&#039;&#039;&lt;br /&gt;
| Erstellt aus den im Makefile angegebenen Quellcodes eine &#039;&#039;hex&#039;&#039;-Datei (und ggf. auch &#039;&#039;eep&#039;&#039;-Datei).&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;make program&#039;&#039;&lt;br /&gt;
| Überträgt die hex-Datei (und wahlweise auch die eep-Datei für den EEPROM) zum AVR. &lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;make clean&#039;&#039;&lt;br /&gt;
| löscht alle temporären Dateien, also auch die hex-Datei&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Diese Aufrufe können in die allermeisten Editoren in &amp;quot;Tool-Menüs&amp;quot; eingebunden werden. Dies erspart den Kontakt mit der Kommandozeile. Bei WinAVR sind die Aufrufe bereits im Tools-Menü des mitgelieferten Editors Programmers-Notepad eingefügt.&lt;br /&gt;
&lt;br /&gt;
Üblicherweise sind folgende Daten im Makefile anzupassen:&lt;br /&gt;
* Controllertyp&lt;br /&gt;
&lt;br /&gt;
* Quellcode-Dateien (c-Dateien)&lt;br /&gt;
&lt;br /&gt;
* Typ und Anschluss des Programmiergeräts&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Seltener sind folgende Einstellungen durchzuführen:&lt;br /&gt;
* Grad der Optimierung&lt;br /&gt;
&lt;br /&gt;
* Methode zur Erzeugung der Debug-Symbole (Debug-Format)&lt;br /&gt;
&lt;br /&gt;
* Assembler-Quellcode-Dateien (S-Dateien)&lt;br /&gt;
&lt;br /&gt;
Die in den folgenden Unterabschnitten gezeigten Makefile-Ausschnitte sind für ein Programm, das auf einem ATmega8 ausgeführt werden soll. Der Quellcode besteht aus den c-Dateien superprog.c (darin main()), uart.c, lcd.c und 1wire.c. Im Quellcodeverzeichnis befinden sich diese Dateien: superprog.c, uart.h, uart.c, lcd.h, lcd.c, 1wire.h, 1wire.c und das makefile (die angepasste Kopie des WinAVR-Beispiels).&lt;br /&gt;
&lt;br /&gt;
Der Controller wird mittels [[AVRDUDE]] über ein [[STK200]]-Programmierdongle an der Schnittstelle lpt1 (bzw. /dev/lp0) programmiert. Im Quellcode sind auch Daten für die &#039;&#039;section .eeprom&#039;&#039; definiert (siehe Abschnitt [[AVR-GCC-Tutorial#EEPROM|Speicherzugriffe]]), diese sollen beim Programmieren gleich mit ins EEPROM geschrieben werden. &lt;br /&gt;
&lt;br /&gt;
== Controllertyp setzen ==&lt;br /&gt;
&lt;br /&gt;
Dazu wird die &amp;quot;make-Variable&amp;quot; MCU entsprechend dem Namen des verwendeten Controllers gesetzt. Eine Liste der von avr-gcc und der avr-libc unterstützten Typen findet sich in der [http://www.nongnu.org/avr-libc/user-manual/index.html Dokumentation der avr-libc].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;code&amp;quot;&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
# Kommentare in Makefiles beginnen mit einem Doppelkreuz &lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
# ATmega8 at work&lt;br /&gt;
MCU = atmega8&lt;br /&gt;
# oder MCU = atmega16 &lt;br /&gt;
# oder MCU = at90s8535&lt;br /&gt;
# oder ...&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Quellcode-Dateien eintragen ==&lt;br /&gt;
&lt;br /&gt;
Der Name der Quellcodedatei, welche die Funktion main enthält, wird hinter TARGET eingetragen. Dies jedoch ohne die Endung &#039;&#039;.c&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;code&amp;quot;&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
TARGET = superprog&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Besteht das Projekt wie im Beispiel aus mehr als einer Quellcodedatei, sind die weiteren c-Dateien (nicht die Header-Dateien, vgl. [[Include-Files (C)]]) durch Leerzeichen getrennt bei SRC einzutragen. Die bei TARGET definierte Datei ist schon in der SRC-Liste enthalten. Diesen Eintrag nicht löschen!&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;code&amp;quot;&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
SRC = $(TARGET).c uart.c lcd.c 1wire.c &lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Alternativ kann man die Liste der Quellcodedateien auch mit dem Operator += erweitern.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;code&amp;quot;&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
SRC = $(TARGET).c uart.c 1wire.c&lt;br /&gt;
# lcd-Code fuer Controller xyz123 (auskommentiert)&lt;br /&gt;
# SRC += lcd_xyz.c&lt;br /&gt;
# lcd-Code fuer &amp;quot;Standard-Controller&amp;quot; (genutzt)&lt;br /&gt;
SRC += lcd.c&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Programmiergerät einstellen ==&lt;br /&gt;
&lt;br /&gt;
Die Vorlagen sind auf die Programmiersoftware [[AVRDUDE]] angepasst, jedoch lässt sich auch andere Programmiersoftware einbinden, sofern diese über Kommandozeile gesteuert werden kann (z.&amp;amp;nbsp;B. stk500.exe, uisp, sp12).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;code&amp;quot;&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
# Einstellung fuer STK500 an com1 (auskommentiert)&lt;br /&gt;
# AVRDUDE_PROGRAMMER = stk500&lt;br /&gt;
# com1 = serial port. Use lpt1 to connect to parallel port.&lt;br /&gt;
# AVRDUDE_PORT = com1    # programmer connected to serial device&lt;br /&gt;
&lt;br /&gt;
# Einstellung fuer STK200-Dongle an lpt1&lt;br /&gt;
AVRDUDE_PROGRAMMER = stk200&lt;br /&gt;
AVRDUDE_PORT = lpt1&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sollen Flash(=.hex) und EEPROM(=.eep) zusammen auf den Controller programmiert werden, ist das Kommentarzeichen vor AVRDUDE_WRITE_EEPROM zu löschen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;code&amp;quot;&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
# auskommentiert: EERPOM-Inhalt wird nicht mitgeschrieben&lt;br /&gt;
#AVRDUDE_WRITE_EEPROM = -U eeprom:w:$(TARGET).eep&lt;br /&gt;
&lt;br /&gt;
# nicht auskommentiert: EERPOM-Inhalt wird mitgeschrieben&lt;br /&gt;
AVRDUDE_WRITE_EEPROM = -U eeprom:w:$(TARGET).eep&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Anwendung ==&lt;br /&gt;
&lt;br /&gt;
Das erstellte Makefile und der Code müssen im gleichen Ordner sein, auch sollte der Dateiname nicht verändert werden. &lt;br /&gt;
&lt;br /&gt;
Die Eingabe von &#039;&#039;make all&#039;&#039; im Arbeitsverzeichnis mit dem Makefile und den Quellcodedateien erzeugt (unter anderem) die Dateien superprog.hex und superprog.eep. Abhängigkeiten zwischen den einzelnen c-Dateien werden dabei automatisch berücksichtigt. Die &#039;&#039;superprog.hex&#039;&#039; und &#039;&#039;superprog.eep&#039;&#039; werden mit &#039;&#039;make program&#039;&#039; zum Controller  übertragen. Mit &#039;&#039;make clean&#039;&#039; werden alle temporären Dateien gelöscht (=&amp;quot;aufgeräumt&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
== Sonstige Einstellungen ==&lt;br /&gt;
&lt;br /&gt;
=== Optimierungsgrad ===&lt;br /&gt;
&lt;br /&gt;
Der gcc-Compiler kennt verschiedene Stufen der Optimierung. Nur zu Testzwecken sollte die Optimierung ganz deaktiviert werden (&#039;&#039;OPT = 0&#039;&#039;). Die weiteren möglichen Optionen weisen den Compiler an, möglichst kompakten oder möglichst schnellen Code zu erzeugen. In den weitaus meisten Fällen ist &#039;&#039;OPT = s&#039;&#039; die empfohlene Einstellung, damit wird kompakter und oft auch der schnellste Maschinencode erzeugt. Beim Update auf eine neue Compilerversion ist zu beachten, dass diese möglicherweise intern andere Optimierungsalgorithmen verwendet und sich dadurch die Größe des Machinencodes etwas ändert, ohne dass man im Quellcode etwas geändert hat.&lt;br /&gt;
&lt;br /&gt;
Als Orientierungswerte die Größe des Maschinencodes bei verschiedenen Optionen für einen nicht näher spezifizierten relativ kleinen Testcode bei Verwendung einer nicht näher spezifizierten Compilerversion. &lt;br /&gt;
&lt;br /&gt;
* -O0 : 12&#039;217 Byte&lt;br /&gt;
&lt;br /&gt;
* -O1 : 9&#039;128 Byte&lt;br /&gt;
&lt;br /&gt;
* -O2 : 1&#039;670 Byte&lt;br /&gt;
&lt;br /&gt;
* -O3 : 3&#039;004 Byte&lt;br /&gt;
&lt;br /&gt;
* -Os : 1&#039;695 Byte&lt;br /&gt;
&lt;br /&gt;
Im diesem Testfall führt die Option -O2 mit zum kompaktesten Code, dies  allerdings hier nur mit 25 Bytes &amp;quot;Vorsprung&amp;quot;. Es kann durchaus sein, dass nur wenige Programmerweiterungen dazu führen, dass Compilieren mit -Os wieder in kompakteren Code resultiert.&lt;br /&gt;
&lt;br /&gt;
Siehe dazu auch: &lt;br /&gt;
* [http://www.nongnu.org/avr-libc/user-manual/using_tools.html#gcc_optO avr-libc manual Abschnitt Using the gnu-tools/Compiler-Optionen]&lt;br /&gt;
&lt;br /&gt;
* [http://www.nongnu.org/avr-libc/user-manual/FAQ.html#faq_optflags avr-libc Manual FAQ Nr. 16] (Stand avr-libc Version 1.4.5)&lt;br /&gt;
&lt;br /&gt;
=== Debug-Format ===&lt;br /&gt;
&lt;br /&gt;
Unterstützt werden die Formate stabs und dwarf-2. Das Format wird hinter &#039;&#039;DEBUG =&#039;&#039; eingestellt. Siehe dazu Abschnitt &#039;&#039;Eingabedateien zur Simulation&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Assembler-Dateien ===&lt;br /&gt;
&lt;br /&gt;
Die im Projekt genutzten Assembler-Dateien werden hinter ASRC durch Leerzeichen getrennt aufgelistet. Assembler-Dateien haben immer die Endung .S (großes S). Ist zum Beispiel der Assembler-Quellcode eines Software-UARTs in einer Datei softuart.S enthalten, lautet die Zeile: &#039;&#039;ASRC = softuart.S&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Taktfrequenz ===&lt;br /&gt;
&lt;br /&gt;
Neuere Versionen der WinAVR/Mfile Vorlage für Makefiles beinhalten die Definition einer Variablen F_CPU (WinAVR 2/2005). Darin wird die Taktfrequenz des Controllers in Hertz eingetragen. Die Definition steht dann im gesamten Projekt ebenfalls unter der Bezeichnung F_CPU zur Verfügung (z.&amp;amp;nbsp;B. um daraus UART-, SPI- oder ADC-Frequenzeinstellungen abzuleiten).&lt;br /&gt;
&lt;br /&gt;
Die Angabe hat rein &amp;quot;informativen&amp;quot; Charakter, die tatsächliche Taktrate wird über den externen Takt (z.&amp;amp;nbsp;B. Quarz) bzw. die Einstellung des internen R/C-Oszillators  bestimmt. Die Nutzung von F_CPU hat also nur Sinn, wenn die Angabe mit dem tatsächlichen Takt übereinstimmt.&lt;br /&gt;
&lt;br /&gt;
Innerhalb neuerer Versionen der avr-libc (ab Version 1.2) wird die Definition der Taktfrequenz (F_CPU) zur Berechnung der Wartefunktionen in delay.h genutzt. Diese funktionieren nur dann korrekt, wenn F_CPU mit der tatsächlichen Taktfrequenz übereinstimmt.&lt;br /&gt;
F_CPU muss dazu jedoch nicht unbedingt im makefile definiert werden. Es reicht aus, wird aber bei mehrfacher Anwendung unübersichtlich, vor &#039;&#039;#include &amp;lt;util/delay.h&amp;gt;&#039;&#039; (veraltet: &#039;&#039;#include &amp;lt;avr/delay.h&amp;gt;&#039;&#039;) ein &#039;&#039;#define F_CPU [hier Takt in Hz]UL&#039;&#039; einzufügen. Bei Nutzung von delay.h ist darauf zu achten, dass die Optimierung des Compilers nicht ausgeschaltet ist, sonst wird sehr viel Code erzeugt und die Wartezeit stimmt nicht mit der gewünschten Zeitspanne überein. Vgl. dazu den [http://www.nongnu.org/avr-libc/user-manual/group__util__delay.html entsprechenden Abschnitt der Dokumentation].&lt;br /&gt;
&lt;br /&gt;
== Eingabedateien zur Simulation in AVR-Studio ==&lt;br /&gt;
&lt;br /&gt;
Mit älteren AVR-Studio-Versionen kann man nur auf Grundlage so genannter &#039;&#039;coff&#039;&#039;-Dateien simulieren. Neuere Versionen von AVR-Studio (ab 4.10.356) unterstützen zudem das modernere aber noch experimentelle dwarf-2-Format, das ab WinAVR 20040722 (avr-gcc 3.4.1/Binutils inkl. Atmel add-ons) &amp;quot;direkt&amp;quot; vom Compiler erzeugt wird.&lt;br /&gt;
&lt;br /&gt;
; Vorgehensweise bei dwarf-2:&lt;br /&gt;
* Im Makefile bei DEBUG: &amp;lt;div class=&amp;quot;code&amp;quot;&amp;gt;&amp;lt;pre&amp;gt;DEBUG=dwarf-2&amp;lt;/pre&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;make all&#039;&#039; (evtl. vorher &#039;&#039;make clean&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
* Die erzeugte &#039;&#039;elf&#039;&#039;-Datei (im Beispiel oben &#039;&#039;superprog.elf&#039;&#039;) in AVR-Studio laden&lt;br /&gt;
&lt;br /&gt;
* AVR-Simulator und zu simulierenden Controller wählen, &amp;quot;Finish&amp;quot;&lt;br /&gt;
&lt;br /&gt;
* Weiteres siehe AVR-Studio Online-Hilfe&lt;br /&gt;
&lt;br /&gt;
; Vorgehensweise bei extcoff: (sollte nur noch in Ausnahmefällen genutzt werden)&lt;br /&gt;
&lt;br /&gt;
* Im Makefile bei DEBUG: &amp;lt;div class=&amp;quot;code&amp;quot;&amp;gt;&amp;lt;pre&amp;gt;DEBUG=stabs&amp;lt;/pre&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;make extcoff&#039;&#039; (evtl. vorher &#039;&#039;make clean&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
* Die erzeugte &#039;&#039;cof&#039;&#039;-Datei (im Beispiel oben &#039;&#039;superprog.cof&#039;&#039;) in AVR-Studio laden&lt;br /&gt;
&lt;br /&gt;
* AVR-Simulator und zu simulierenden Controller wählen, &amp;quot;Finish&amp;quot;&lt;br /&gt;
&lt;br /&gt;
* Weiteres siehe AVR-Studio Online-Hilfe&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Beim Simulieren scheinen oft &amp;quot;Variablen zu fehlen&amp;quot;. Ursache dafür ist, dass der Compiler diese &amp;quot;Variablen&amp;quot; direkt Registern zuweist. Dies kann vermieden werden, indem die Optimierung abgeschaltet wird (im makefile). Man simuliert dann jedoch ein vom optimierten Code stark abweichendes Programm. Das Abschalten der Optimierung wird nicht empfohlen.&lt;br /&gt;
&lt;br /&gt;
Statt des Software-Simulators kann das AVR-Studio auch genutzt werden, um mit dem ATMEL JTAGICE, einem Nachbau davon (BootICE, Evertool o.&amp;amp;nbsp;ä.) oder dem ATMEL JTAGICE MKII &amp;quot;im System&amp;quot; zu debuggen. Dazu sind keine speziellen Einstellungen im makefile erforderlich. Debugging bzw. &amp;quot;In-System-Emulation&amp;quot; mit dem JTAGICE und JTAGICE MKII sind in der AVR-Studio Online-Hilfe beschrieben.&lt;br /&gt;
&lt;br /&gt;
Die Verwendung von Makefiles bietet noch viele weitere Möglichkeiten, einige davon werden im Anhang [[AVR-GCC-Tutorial#Zus.C3.A4tzliche_Funktionen_im_Makefile|Zusätzliche Funktionen im Makefile]] erläutert.&lt;br /&gt;
&lt;br /&gt;
= Ganzzahlige (Integer) Datentypen =&lt;br /&gt;
&lt;br /&gt;
Bei der Programmierung von Mikrokontrollern ist die Definition einiger ganzzahliger Datentypen sinnvoll, an denen eindeutig die Bit-Länge abgelesen werden kann.&lt;br /&gt;
&lt;br /&gt;
Standardisierte Datentypen werden in der Header-Datei stdint.h definiert. &lt;br /&gt;
Zur Nutzung der standardisierten Typen bindet man die &amp;quot;Definitionsdatei&amp;quot; wie folgt ein:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
// ab avr-libc Version 1.2.0 möglich und empfohlen:&lt;br /&gt;
#include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
// veraltet: #include &amp;lt;inttypes.h&amp;gt;&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Einige der dort definierten Typen (avr-libc Version 1.0.4):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
typedef signed char        int8_t;&lt;br /&gt;
typedef unsigned char      uint8_t;&lt;br /&gt;
&lt;br /&gt;
typedef short              int16_t;&lt;br /&gt;
typedef unsigned short     uint16_t;&lt;br /&gt;
&lt;br /&gt;
typedef long               int32_t;&lt;br /&gt;
typedef unsigned long      uint32_t;&lt;br /&gt;
&lt;br /&gt;
typedef long long          int64_t;&lt;br /&gt;
typedef unsigned long long uint64_t;&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* int8_t steht für einen 8-Bit Integer mit einem Wertebereich -128 bis +127.&lt;br /&gt;
&lt;br /&gt;
* uint8_t steht für einen 8-Bit Integer ohne Vorzeichen (unsigned int) mit einem Wertebereich von 0 bis 255&lt;br /&gt;
&lt;br /&gt;
* int16_t steht für einen 16-Bit Integer mit einem Wertebereich -32768 bis +32767.&lt;br /&gt;
&lt;br /&gt;
* uint16_t steht für einen 16-Bit Integer ohne Vorzeichen (unsigned int) mit einem Wertebereich von 0 bis 65535.&lt;br /&gt;
&lt;br /&gt;
Die Typen ohne vorangestelltes &#039;&#039;u&#039;&#039; werden als vorzeichenbehaftete Zahlen abgespeichert. Typen mit vorgestelltem &#039;&#039;u&#039;&#039; dienen der Ablage von postiven Zahlen (inkl. 0). Siehe dazu auch: [http://www.nongnu.org/avr-libc/user-manual/index.html Dokumentation der avr-libc] Abschnitt Modules/(Standard) Integer Types.&lt;br /&gt;
&lt;br /&gt;
= Bitfelder =&lt;br /&gt;
&lt;br /&gt;
Beim Programmieren von Mikrocontrollern muss auf jedes Byte oder sogar auf&lt;br /&gt;
jedes Bit geachtet werden. Oft müssen wir in einer Variablen lediglich den&lt;br /&gt;
Zustand 0 oder 1 speichern. Wenn wir nun zur Speicherung eines einzelnen Wertes&lt;br /&gt;
den kleinsten bekannten Datentypen, nämlich &#039;&#039;&#039;unsigned char&#039;&#039;&#039;, nehmen, dann&lt;br /&gt;
verschwenden wir 7 Bits, da ein &#039;&#039;&#039;unsigned char&#039;&#039;&#039; ja 8 Bits breit ist.&lt;br /&gt;
&lt;br /&gt;
Hier bietet uns die Programmiersprache C ein mächtiges Werkzeug an, mit dessen&lt;br /&gt;
Hilfe wir 8 Bits in eine einzelne Bytevariable zusammenfassen und (fast) wie&lt;br /&gt;
8 einzelne Variablen ansprechen können. Die Rede ist von so genannten Bitfeldern. Diese werden als Strukturelemente definiert. Sehen wir uns dazu doch am besten gleich ein Beispiel an:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
struct {&lt;br /&gt;
   unsigned bStatus_1:1; // 1 Bit für bStatus_1&lt;br /&gt;
   unsigned bStatus_2:1; // 1 Bit für bStatus_2&lt;br /&gt;
   unsigned bNochNBit:1; // Und hier noch mal ein Bit&lt;br /&gt;
   unsigned b2Bits:2;    // Dieses Feld ist 2 Bits breit&lt;br /&gt;
   // All das hat in einer einzigen Byte-Variable Platz.&lt;br /&gt;
   // die 3 verbleibenden Bits bleiben ungenutzt&lt;br /&gt;
} x;&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Zugriff auf ein solches Feld erfolgt nun wie beim Strukturzugriff bekannt&lt;br /&gt;
über den Punkt- oder den Dereferenzierungs-Operator:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
x.bStatus_1 = 1;&lt;br /&gt;
x.bStatus_2 = 0;&lt;br /&gt;
x.b2Bits = 3;&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bitfelder sparen Platz im RAM, zu Lasten von Platz im Flash, verschlechtern aber unter Umständen die Les- und Wartbarkeit des Codes. Anfängern wird deshalb geraten, ein &amp;quot;ganzes&amp;quot; Byte (uint8_t) zu nutzen, auch wenn nur ein Bitwert gespeichert werden soll.&lt;br /&gt;
&lt;br /&gt;
Wenn man nur ein paar wenige Variablen vom Typ bool verwenden möchte, kann man&lt;br /&gt;
auch die Headerdatei &amp;lt;stdbool.h&amp;gt; einbinden und sich dann wie gewohnt einen Booltyp anlegen. Variablen dieses Typs brauchen dennoch 1 Byte Speicher, ermöglichen aber eine genaue Unterscheidung zwischen Zahlenvariable und boolscher Variable.&lt;br /&gt;
&lt;br /&gt;
= Grundsätzlicher Programmaufbau eines &amp;amp;micro;C-Programms =&lt;br /&gt;
&lt;br /&gt;
Wir unterscheiden zwischen 2 verschiedenen Methoden, um ein&lt;br /&gt;
Mikrocontroller-Programm zu schreiben, und zwar völlig unabhängig davon, in&lt;br /&gt;
welcher Programmiersprache das Programm geschrieben wird.&lt;br /&gt;
&lt;br /&gt;
== Sequentieller Programmablauf ==&lt;br /&gt;
&lt;br /&gt;
Bei dieser Programmiertechnik wird eine Endlosschleife programmiert, welche im&lt;br /&gt;
Wesentlichen immer den gleichen Aufbau hat:&lt;br /&gt;
&lt;br /&gt;
[[Image:Sequentielle Programme.gif]]&lt;br /&gt;
&lt;br /&gt;
== Interruptgesteuerter Programmablauf ==&lt;br /&gt;
&lt;br /&gt;
Bei dieser Methode werden beim Programmstart zuerst die gewünschten Interruptquellen aktiviert und dann in eine Endlosschleife gegangen, in welcher Dinge erledigt werden können, welche nicht zeitkritisch sind. Wenn ein Interrupt ausgelöst wird, so wird automatisch die zugeordnete Interruptfunktion ausgeführt.&lt;br /&gt;
&lt;br /&gt;
[[Image:Interrupt Programme.gif]]&lt;br /&gt;
&lt;br /&gt;
= Zugriff auf Register =&lt;br /&gt;
&lt;br /&gt;
Die AVR-Controller verfügen über eine Vielzahl von Registern. Die meisten&lt;br /&gt;
davon sind sogenannte Schreib-/Leseregister. Das heißt, das Programm kann die&lt;br /&gt;
Inhalte der Register sowohl auslesen als auch beschreiben.&lt;br /&gt;
&lt;br /&gt;
Register haben einen besonderen Stellenwert bei den AVR Controllern. Sie dienen dem Zugriff auf die Ports und die Schnittstellen des Controllers. Wir unterscheiden zwischen 8-Bit und 16-Bit Registern. Vorerst behandeln wir mal&lt;br /&gt;
die 8-Bit Register.&lt;br /&gt;
&lt;br /&gt;
Einzelne Register sind bei allen AVRs vorhanden, andere wiederum nur bei bestimmten Typen. So sind beispielsweise die Register, welche für den Zugriff auf den UART notwendig sind, selbstverständlich nur bei denjenigen Modellen vorhanden, welche über einen integrierten Hardware UART bzw. USART verfügen.&lt;br /&gt;
&lt;br /&gt;
Die Namen der Register sind in den Headerdateien zu den entsprechenden AVR-Typen definiert. Dazu muss man den Namen der controllerspezifischen Headerdatei nicht kennen. Es reicht aus, die allgemeine Headerdatei &#039;&#039;avr/io.h&#039;&#039; einzubinden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ist im Makefile der MCU-Typ z.&amp;amp;nbsp;B. mit dem Inhalt atmega8 definiert (und wird somit per -mmcu=atmega8 an den Compiler übergeben), wird beim Einlesen der io.h-Datei implizit (&amp;quot;automatisch&amp;quot;) auch die iom8.h-Datei mit den Register-Definitionen für den ATmega8 eingelesen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- Wohl besser als Anhang - spaeter... --&amp;gt;&lt;br /&gt;
Intern wird diese &amp;quot;Automatik&amp;quot; wie folgt realisiert: Der Controllertyp wird dem Compiler als Parameter übergeben (vgl. &#039;&#039;avr-gcc -c -mmcu=atmega16 [...]&#039;&#039; im Einführungsbeispiel). Wird ein Makefile nach der WinAVR/mfile-Vorlage verwendet, setzt man die Variable &#039;&#039;MCU&#039;&#039;, der Inhalt dieser Variable wird dann an passender Stelle für die Compilerparameter verwendet. Der Compiler definiert intern eine dem mmcu-Parameter zugeordnete &amp;quot;Variable&amp;quot; (genauer: ein Makro) mit dem Namen des Controllers, vorangestelltem &#039;&#039;__AVR_&#039;&#039; und angehängten Unterstrichen (z.B. wird bei &#039;&#039;-mmcu=atmega16&#039;&#039; das Makro &#039;&#039;__AVR_ATmega16__&#039;&#039; definiert). Beim Einbinden der Header-Datei &#039;&#039;avr/io.h&#039;&#039; wird geprüft, ob das jeweilige Makro definiert ist und die zum Controller passende Definitionsdatei eingelesen. Zur Veranschaulichung einige Ausschnitte aus einem Makefile:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
[...]&lt;br /&gt;
# MCU Type (&amp;quot;name&amp;quot;) setzen:&lt;br /&gt;
MCU = atmega16&lt;br /&gt;
[...]&lt;br /&gt;
&lt;br /&gt;
[...]&lt;br /&gt;
## Verwendung des Inhalts von MCU (hier atmega16) fuer die &lt;br /&gt;
## Compiler- und Assembler-Parameter&lt;br /&gt;
ALL_CFLAGS = -mmcu=$(MCU) -I. $(CFLAGS) $(GENDEPFLAGS)&lt;br /&gt;
ALL_CPPFLAGS = -mmcu=$(MCU) -I. -x c++ $(CPPFLAGS) $(GENDEPFLAGS)&lt;br /&gt;
ALL_ASFLAGS = -mmcu=$(MCU) -I. -x assembler-with-cpp $(ASFLAGS)&lt;br /&gt;
[...]&lt;br /&gt;
&lt;br /&gt;
[...]&lt;br /&gt;
## Aufruf des Compilers:&lt;br /&gt;
## mit den Parametern ($(ALL_CFLAGS) ist -mmcu=$(MCU)[...] = -mmcu=atmega16[...]&lt;br /&gt;
$(OBJDIR)/%.o : %.c&lt;br /&gt;
	@echo&lt;br /&gt;
	@echo $(MSG_COMPILING) $&amp;lt;&lt;br /&gt;
	$(CC) -c $(ALL_CFLAGS) $&amp;lt; -o $@ &lt;br /&gt;
[...]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Da --mmcu=atmega16 übergeben wurde, wird __AVR_ATmega16__ definiert und kann in avr/io.h zur Fallunterscheidung genutzt werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
// avr/io.h &lt;br /&gt;
// (bei WinAVR-Standardinstallation in C:\WinAVR\avr\include\avr)&lt;br /&gt;
[...]&lt;br /&gt;
#if defined (__AVR_AT94K__)&lt;br /&gt;
#  include &amp;lt;avr/ioat94k.h&amp;gt;&lt;br /&gt;
// [...]&lt;br /&gt;
#elif defined (__AVR_ATmega16__)&lt;br /&gt;
// da __AVR_ATmega16__ definiert ist, wird avr/iom16.h eingebunden:&lt;br /&gt;
#  include &amp;lt;avr/iom16.h&amp;gt;&lt;br /&gt;
// [...]&lt;br /&gt;
#else&lt;br /&gt;
#  if !defined(__COMPILING_AVR_LIBC__)&lt;br /&gt;
#    warning &amp;quot;device type not defined&amp;quot;&lt;br /&gt;
#  endif&lt;br /&gt;
#endif&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Schreiben in Register ==&lt;br /&gt;
&lt;br /&gt;
Zum Schreiben kann man Register einfach wie eine Variable setzen. In Quellcodes, die für ältere Versionen des avr-gcc/der avr-libc entwickelt wurden, erfolgt der Schreibzugriff über die Funktion outp(). Aktuelle Versionen des Compilers unterstützen den Zugriff nun direkt und outp() ist nicht mehr erforderlich.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
int main(void)&lt;br /&gt;
{&lt;br /&gt;
    /* Setzt das Richtungsregister des Ports A auf 0xff &lt;br /&gt;
       (alle Pins als Ausgang, vgl. Abschnitt Zugriff auf Ports): */&lt;br /&gt;
    DDRA = 0xff;    &lt;br /&gt;
&lt;br /&gt;
    /* Setzt PortA auf 0x03, Bit 0 und 1 &amp;quot;high&amp;quot;, restliche &amp;quot;low&amp;quot;: */&lt;br /&gt;
    PORTA = 0x03;   &lt;br /&gt;
    ...&lt;br /&gt;
&lt;br /&gt;
    // Setzen der Bits 0,1,2,3 und 4&lt;br /&gt;
    // Binär 00011111 = Hexadezimal 1F&lt;br /&gt;
    DDRB = 0x1F;    /* direkte Zuweisung - unübersichtlich */&lt;br /&gt;
&lt;br /&gt;
    /* Ausführliche Schreibweise: identische Funktionalität, mehr Tipparbeit&lt;br /&gt;
       aber übersichtlicher und selbsterklärend: */&lt;br /&gt;
    DDRB = (1 &amp;lt;&amp;lt; DDB0) | (1 &amp;lt;&amp;lt; DDB1) | (1 &amp;lt;&amp;lt; DDB2) | (1 &amp;lt;&amp;lt; DDB3) | (1 &amp;lt;&amp;lt; DDB4); &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die ausführliche Schreibweise sollte bevorzugt verwendet werden, da dadurch die Zuweisungen selbsterklärend sind und somit der Code leichter nachvollzogen werden kann. Atmel verwendet sie auch bei Beispielen in Datenblätten und in den allermeisten Quellcodes zu Application-Notes.&lt;br /&gt;
&lt;br /&gt;
Der gcc C-Compiler (genauer der Präprozessor) unterstützt ab Version 4.3.0 Konstanten im Binärformat, z.B. DDRB&amp;amp;nbsp;=&amp;amp;nbsp;0b00011111 (für WinAVR wurden schon ältere Versionen des gcc entsprechend angepasst). Diese Schreibweise ist jedoch nicht standardkonform und man sollte sie daher insbesondere dann nicht verwenden, wenn Code mit anderen ausgetauscht oder mit anderen Compilern bzw. älteren Versionen des gcc genutzt werden soll.  &lt;br /&gt;
&lt;br /&gt;
=== Verändern von Registerinhalten ===&lt;br /&gt;
&lt;br /&gt;
Einzelne Bits setzt und löscht man &amp;quot;Standard-C-konform&amp;quot; mittels logischer (Bit-) Operationen. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
 x |= (1 &amp;lt;&amp;lt; Bitnummer);  // Hiermit wird ein Bit in x gesetzt&lt;br /&gt;
 x &amp;amp;= ~(1 &amp;lt;&amp;lt; Bitnummer); // Hiermit wird ein Bit in x geloescht&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Es wird jeweils nur der Zustand des angegebenen Bits geändert, der vorherige Zustand der anderen Bits bleibt erhalten. &lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
#define MEINBIT 2&lt;br /&gt;
...&lt;br /&gt;
PORTA |= (1 &amp;lt;&amp;lt; MEINBIT);    /* setzt Bit 2 an PortA auf 1 */&lt;br /&gt;
PORTA &amp;amp;= ~(1 &amp;lt;&amp;lt; MEINBIT);   /* loescht Bit 2 an PortA */&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit dieser Methode lassen sich auch mehrere Bits eines Registers gleichzeitig setzen und löschen.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
DDRA &amp;amp;= ~( (1&amp;lt;&amp;lt;PA0) | (1&amp;lt;&amp;lt;PA3) );  /* PA0 und PA3 als Eingaenge */&lt;br /&gt;
PORTA |= (1&amp;lt;&amp;lt;PA0) | (1&amp;lt;&amp;lt;PA3);      /* Interne Pull-Up fuer beide einschalten */&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In Quellcodes, die für ältere Version den des avr-gcc/der avr-libc entwickelt wurden, werden einzelne Bits mittels der Funktionen sbi und cbi gesetzt bzw. gelöscht. Beide Funktionen sind nicht mehr erforderlich.&lt;br /&gt;
&lt;br /&gt;
Siehe auch:&lt;br /&gt;
* [[Bitmanipulation]]&lt;br /&gt;
* [http://www.nongnu.org/avr-libc/user-manual/index.html Dokumentation der avr-libc] Abschnitt Modules/Special Function Registers&lt;br /&gt;
&lt;br /&gt;
== Lesen aus Registern ==&lt;br /&gt;
&lt;br /&gt;
Zum Lesen kann man auf Register einfach wie auf eine Variable zugreifen. In Quellcodes, die für ältere Versionen des avr-gcc/der avr-libc entwickelt wurden, erfolgt der Lesezugriff über die Funktion inp(). Aktuelle Versionen des Compilers unterstützen den Zugriff nun direkt und inp() ist nicht mehr erforderlich.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
uint8_t foo;&lt;br /&gt;
&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
int main(void)&lt;br /&gt;
{&lt;br /&gt;
    /* kopiert den Status der Eingabepins an PortB &lt;br /&gt;
       in die Variable foo: */&lt;br /&gt;
    foo = PINB;    &lt;br /&gt;
    //...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Zustände von Bits erfolgt durch Einlesen des gesamten Registerinhalts und ausblenden der Bits deren Zustand nicht von Interesse ist. Einige Beispiele zum Prüfen ob Bits gesetzt oder gelöscht sind:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#define MEINBIT0 0 &lt;br /&gt;
#define MEINBIT2 2&lt;br /&gt;
&lt;br /&gt;
uint8_t i;&lt;br /&gt;
&lt;br /&gt;
extern test1();&lt;br /&gt;
&lt;br /&gt;
// Funkion test1 aufrufen, wenn Bit 0 in Register PINA gesetzt (1) ist&lt;br /&gt;
i = PINA;         // Inhalt in Arbeitsvariable&lt;br /&gt;
i = i &amp;amp; 0x01;     // alle Bits bis auf Bit 0 ausblenden (logisches und)&lt;br /&gt;
                  // falls das Bit gesetzt war, hat i den Inhalt 1&lt;br /&gt;
if ( i != 0 ) {   // Ergebnis ungleich 0 (wahr)? &lt;br /&gt;
  test1()         // dann muss Bit 0 in i gesetzt sein -&amp;gt; Funktion aufrufen&lt;br /&gt;
}&lt;br /&gt;
// verkürzt:&lt;br /&gt;
if ( ( PINA &amp;amp; 0x01 ) != 0 ) {&lt;br /&gt;
  test1();&lt;br /&gt;
}&lt;br /&gt;
// nochmals verkürzt:&lt;br /&gt;
if ( PINA &amp;amp; 0x01 ) {&lt;br /&gt;
  test1();&lt;br /&gt;
}&lt;br /&gt;
// mit definierter Bitnummer:&lt;br /&gt;
if ( PINA &amp;amp; ( 1 &amp;lt;&amp;lt; MEINBIT0 ) ) {&lt;br /&gt;
  test(1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Funktion aufrufen, wenn Bit 0 oder Bit 2 gesetzt ist&lt;br /&gt;
if ( PINA &amp;amp; 0x05 ) {&lt;br /&gt;
  test1();  // Vergleich &amp;lt;&amp;gt; 0 (wahr), also muss Bit 0 oder 2 gesetzt sein&lt;br /&gt;
}&lt;br /&gt;
// mit definierten Bitnummern:&lt;br /&gt;
if ( PINA &amp;amp; ( ( 1 &amp;lt;&amp;lt; MEINBIT0 ) | ( 1 &amp;lt;&amp;lt; MEINBIT2 ) ) ) {&lt;br /&gt;
  test1();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Funktion aufrufen, wenn Bit 0 und Bit 2 gesetzt sind&lt;br /&gt;
if ( ( PINA &amp;amp; 0x05 ) == 0x05 ) {  // nur wahr, wenn beide Bits gesetzt&lt;br /&gt;
  test1();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Funktion test2() aufrufen, wenn Bit 0 gelöscht (0) ist&lt;br /&gt;
i = PINA;        // einlesen in temporäre Variable&lt;br /&gt;
i = i &amp;amp; 0x01;    // maskieren von B&lt;br /&gt;
if ( i == 0 ) {  // Vergleich ist wahr, wenn Bit 0 nicht gesetzt ist&lt;br /&gt;
  test2();&lt;br /&gt;
}&lt;br /&gt;
// analog mit !-Operator (not)&lt;br /&gt;
if ( !i ) {&lt;br /&gt;
  test2();&lt;br /&gt;
}&lt;br /&gt;
// nochmals verkürzt:&lt;br /&gt;
if ( !( PINA &amp;amp; 0x01 ) ) {&lt;br /&gt;
  test2();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die AVR-Bibliothek (avr-libc) stellt auch Funktionen (Makros) zur Abfrage eines einzelnen Bits eines Registers zur Verfügung, diese sind bei anderen Compilern meist nicht verfügbar (können aber dann einfach durch Macros &amp;quot;nachgerüstet&amp;quot; werden).&lt;br /&gt;
&lt;br /&gt;
;bit_is_set (&amp;lt;Register&amp;gt;,&amp;lt;Bitnummer&amp;gt;): Die Funktion &#039;&#039;bit_is_set&#039;&#039; prüft, ob ein Bit gesetzt ist. Wenn das Bit gesetzt ist, wird ein Wert ungleich 0 zurückgegeben. Genau genommen ist es die Wertigkeit des abgefragten Bits, also 1 für Bit0, 2 für Bit1, 4 für Bit2 etc.&lt;br /&gt;
&lt;br /&gt;
;bit_is_clear (&amp;lt;Register&amp;gt;,&amp;lt;Bitnummer&amp;gt;): Die Funktion &#039;&#039;bit_is_clear&#039;&#039; prüft, ob ein Bit gelöscht ist. Wenn das Bit gelöscht ist, also auf 0 ist, wird ein Wert ungleich 0 zurückgegeben.&lt;br /&gt;
&lt;br /&gt;
Die Funktionen (eigentlich Makros) bit_is_clear bzw. bit_is_set sind nicht erforderlich, man kann und sollte C-Syntax verwenden, die universell verwendbar und portabel ist. Siehe auch [[Bitmanipulation]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Warten auf einen bestimmten Zustand ===&lt;br /&gt;
&lt;br /&gt;
Es gibt in der Bibliothek avr-libc Funktionen, die warten, bis ein bestimmter Zustand eines Bits erreicht ist. Es ist allerdings normalerweise eine eher unschöne Programmiertechnik, da in diesen Funktionen &amp;quot;blockierend&amp;quot; gewartet wird. Der Programmablauf bleibt also an dieser Stelle stehen, bis das maskierte Ereignis erfolgt ist. Setzt man den Watchdog ein, muss man darauf achten, dass dieser auch noch getriggert wird (Zurücksetzen des Watchdogtimers). &lt;br /&gt;
&lt;br /&gt;
Die Funktion &#039;&#039;&#039;loop_until_bit_is_set&#039;&#039;&#039; wartet in einer Schleife, bis das definierte Bit gesetzt ist. Wenn das Bit beim Aufruf der Funktion bereits gesetzt ist, wird die Funktion sofort wieder verlassen. Das niederwertigste Bit hat die Bitnummer 0. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
/* Warten bis Bit Nr. 2 (das dritte Bit) in Register PINA gesetzt (1) ist */&lt;br /&gt;
&lt;br /&gt;
#define WARTEPIN PINA&lt;br /&gt;
#define WARTEBIT PA2&lt;br /&gt;
&lt;br /&gt;
// mit der avr-libc Funktion:&lt;br /&gt;
loop_until_bit_is_set(WARTEPIN, WARTEBIT);&lt;br /&gt;
&lt;br /&gt;
// dito in &amp;quot;C-Standard&amp;quot;:&lt;br /&gt;
// Durchlaufe die (leere) Schleife solange das WARTEBIT in Register WARTEPIN&lt;br /&gt;
// _nicht_ ungleich 0 (also 0) ist.&lt;br /&gt;
while ( !(WARTEPIN &amp;amp; (1 &amp;lt;&amp;lt; WARTEBIT)) ) ;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die Funktion &#039;&#039;&#039;loop_until_bit_is_clear&#039;&#039;&#039; wartet in einer Schleife, bis das definierte Bit gelöscht ist. Wenn das Bit beim Aufruf der Funktion bereits gelöscht ist, wird die Funktion sofort wieder verlassen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
/* Warten bis Bit Nr. 4 (das fuenfte Bit) in Register PINB geloescht (0) ist */&lt;br /&gt;
#define WARTEPIN PINB&lt;br /&gt;
#define WARTEBIT PB4&lt;br /&gt;
&lt;br /&gt;
// avr-libc-Funktion:&lt;br /&gt;
loop_until_bit_is_clear(WARTEPIN, WARTEBIT);&lt;br /&gt;
&lt;br /&gt;
// dito in &amp;quot;C-Standard&amp;quot;:&lt;br /&gt;
// Durchlaufe die (leere) Schleife solange das WARTEBIT in Register WARTEPIN&lt;br /&gt;
// gesetzt (1) ist &lt;br /&gt;
while ( WARTEPIN &amp;amp; (1&amp;lt;&amp;lt;WARTEBIT) ) ;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Universeller und auch auf andere Plattformen besser übertragbar ist die Verwendung von C-Standardoperationen.&lt;br /&gt;
&lt;br /&gt;
Siehe auch: &lt;br /&gt;
* [http://www.nongnu.org/avr-libc/user-manual/index.html Dokumentation der avr-libc] Abschnitt Modules/Special Function Registers&lt;br /&gt;
* [[Bitmanipulation]]&lt;br /&gt;
&lt;br /&gt;
= Zugriff auf IO-Ports =&lt;br /&gt;
&lt;br /&gt;
Alle Ports der AVR-Controller werden über Register gesteuert. Dazu sind&lt;br /&gt;
jedem Port 3 Register zugeordnet:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;DDRx&#039;&#039;&#039; &lt;br /&gt;
| Datenrichtungsregister für Port&#039;&#039;&#039;x&#039;&#039;&#039;. &lt;br /&gt;
&#039;&#039;&#039;x&#039;&#039;&#039; entspricht &#039;&#039;&#039;A&#039;&#039;&#039;, &#039;&#039;&#039;B&#039;&#039;&#039;, &#039;&#039;&#039; C&#039;&#039;&#039;, &#039;&#039;&#039;D&#039;&#039;&#039; usw. (abhängig von der Anzahl der Ports des verwendeten AVR). Bit im Register gesetzt (1) für Ausgang, Bit gelöscht (0) für Eingang.&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;PINx&#039;&#039;&#039;&lt;br /&gt;
| Eingangsadresse für Port&#039;&#039;&#039;x&#039;&#039;&#039;. &lt;br /&gt;
Zustand des Ports. Die Bits in PINx entsprechen dem Zustand der als Eingang definierten Portpins. Bit 1 wenn Pin &amp;quot;high&amp;quot;, Bit 0 wenn Portpin low.&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;PORTx&#039;&#039;&#039;&lt;br /&gt;
| Datenregister für Port&#039;&#039;&#039;x&#039;&#039;&#039;. &lt;br /&gt;
Dieses Register wird verwendet, um die Ausgänge eines Ports anzusteuern. Bei Pins, die mittels DDRx auf Eingang geschaltet wurden, können über PORTx&lt;br /&gt;
die internen Pull-Up Widerstände aktiviert oder deaktiviert werden (1 = aktiv).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Jeder AVR implementiert eine unterschiedliche Menge an GPIO-Registern&lt;br /&gt;
(GPIO - General Purpose Input/Output). Die folgenden Beispiele gehen von einem AVR aus, der sowohl Port A als auch Port B besitzt. Sie müssen für andere AVRs (zum Beispiel ATmega8/48/88/168) entsprechend angepasst werden.&lt;br /&gt;
&lt;br /&gt;
== Datenrichtung bestimmen ==&lt;br /&gt;
&lt;br /&gt;
Zuerst muss die Datenrichtung der verwendeten Pins bestimmt werden. Um dies zu erreichen, wird das Datenrichtungsregister des entsprechenden Ports beschrieben.&lt;br /&gt;
&lt;br /&gt;
Für jeden Pin, der als Ausgang verwendet werden soll, muss dabei das&lt;br /&gt;
entsprechende Bit auf dem Port gesetzt werden. Soll der Pin als Eingang&lt;br /&gt;
verwendet werden, muss das entsprechende Bit gelöscht sein.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
Angenommen am Port B sollen die Pins 0 bis 4 als Ausgänge definiert werden, die noch verbleibenden Pins 5 bis 7 sollen als Eingänge fungieren. Dazu ist es daher notwendig, im für das Port B zuständigen Datenrichtungsregister DDRB folgende Bitkonfiguration einzutragen&lt;br /&gt;
&lt;br /&gt;
   +---+---+---+---+---+---+---+---+&lt;br /&gt;
   | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 1 |&lt;br /&gt;
   +---+---+---+---+---+---+---+---+&lt;br /&gt;
     7   6   5   4   3   2   1   0&lt;br /&gt;
&lt;br /&gt;
In C liest sich das dann so:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
// in io.h wird u.a. DDRB definiert:&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
// Setzen der Bits 0,1,2,3 und 4&lt;br /&gt;
// Binär 00011111 = Hexadezimal 1F&lt;br /&gt;
DDRB = 0x1F;    /* direkte Zuweisung - unübersichtlich */&lt;br /&gt;
&lt;br /&gt;
/* Ausführliche Schreibweise: identische Funktionalität, mehr Tipparbeit&lt;br /&gt;
   aber übersichtlicher und selbsterklärend: */&lt;br /&gt;
DDRB = (1 &amp;lt;&amp;lt; DDB0) | (1 &amp;lt;&amp;lt; DDB1) | (1 &amp;lt;&amp;lt; DDB2) | (1 &amp;lt;&amp;lt; DDB3) | (1 &amp;lt;&amp;lt; DDB4); &lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Pins 5 bis 7 werden (da 0) als Eingänge geschaltet. Weitere Beispiele:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
// Alle Pins des Ports B als Ausgang definieren:&lt;br /&gt;
DDRB = 0xff; &lt;br /&gt;
// Pin0 wieder auf Eingang und andere im ursprünglichen Zustand belassen:&lt;br /&gt;
DDRB &amp;amp;= ~( 1 &amp;lt;&amp;lt; DDB0 );&lt;br /&gt;
// Pin 3 und 4 auf Eingang und andere im ursprünglichen Zustand belassen:&lt;br /&gt;
DDRB &amp;amp;= ~( ( 1 &amp;lt;&amp;lt; DDB3 ) | ( 1&amp;lt;&amp;lt;DDB4) );&lt;br /&gt;
// Pin 0 und 3 wieder auf Ausgang und andere im ursprünglichen Zustand belassen:&lt;br /&gt;
DDRB |= ( 1 &amp;lt;&amp;lt; DDB0) | ( 1 &amp;lt;&amp;lt; DDB3 );&lt;br /&gt;
// Alle Pins auf Eingang:&lt;br /&gt;
DDRB = 0x00;&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Vordefinierte Bitnummern für I/O-Register ==&lt;br /&gt;
&lt;br /&gt;
Die Bitnummern (z.B. PCx, PINCx und DDCx für den Port C) sind in den io*.h-Dateien der avr-libc definiert und dienen lediglich der besseren Lesbarkeit. Man muss diese Definitionen nicht verwenden oder kann auch einfach &amp;quot;immer&amp;quot; PAx, PBx, PCx usw. nutzen, auch wenn der Zugriff auf Bits in DDRx- oder PINx-Registern erfolgt. Für den Compiler sind die Ausdrücke (1&amp;lt;&amp;lt;PC7), (1&amp;lt;&amp;lt;DDC7) und (1&amp;lt;&amp;lt;PINC7) identisch zu (1&amp;lt;&amp;lt;7) (genauer: der Präprozessor ersetzt die Ausdrücke (1&amp;lt;&amp;lt;PC7),... zu (1&amp;lt;&amp;lt;7)). Ein Ausschnitt der Definitionen für Port C eines ATmega32 aus der iom32.h-Datei zur Verdeutlichung (analog für die weiteren Ports):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
/* PORTC */&lt;br /&gt;
#define PC7     7&lt;br /&gt;
#define PC6     6&lt;br /&gt;
#define PC5     5&lt;br /&gt;
#define PC4     4&lt;br /&gt;
#define PC3     3&lt;br /&gt;
#define PC2     2&lt;br /&gt;
#define PC1     1&lt;br /&gt;
#define PC0     0&lt;br /&gt;
&lt;br /&gt;
/* DDRC */&lt;br /&gt;
#define DDC7    7&lt;br /&gt;
#define DDC6    6&lt;br /&gt;
#define DDC5    5&lt;br /&gt;
#define DDC4    4&lt;br /&gt;
#define DDC3    3&lt;br /&gt;
#define DDC2    2&lt;br /&gt;
#define DDC1    1&lt;br /&gt;
#define DDC0    0&lt;br /&gt;
&lt;br /&gt;
/* PINC */&lt;br /&gt;
#define PINC7   7&lt;br /&gt;
#define PINC6   6&lt;br /&gt;
#define PINC5   5&lt;br /&gt;
#define PINC4   4&lt;br /&gt;
#define PINC3   3&lt;br /&gt;
#define PINC2   2&lt;br /&gt;
#define PINC1   1&lt;br /&gt;
#define PINC0   0&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Digitale Signale ==&lt;br /&gt;
&lt;br /&gt;
Am einfachsten ist es, digitale Signale mit dem Mikrocontroller zu erfassen bzw. auszugeben.&lt;br /&gt;
&lt;br /&gt;
== Ausgänge ==&lt;br /&gt;
Will man als Ausgang definierte Pins (entsprechende DDRx-Bits = 1) auf Logisch 1 setzen, setzt man die  entsprechenden Bits im Portregister.&lt;br /&gt;
&lt;br /&gt;
Mit dem Befehl&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
    PORTB = 0x04; /* besser PORTB=(1&amp;lt;&amp;lt;PB2) */&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
wird also der Ausgang an Pin PB2 gesetzt (Beachte, dass die Bits immer &#039;&#039;von 0 an&#039;&#039; gezählt werden, das niederwertigste Bit ist also Bitnummer 0 und nicht etwa Bitnummer 1).&lt;br /&gt;
&lt;br /&gt;
Man beachte, dass bei der Zuweisung mittels &#039;&#039;&#039;=&#039;&#039;&#039; immer alle Pins gleichzeitig angegeben werden. Man sollte also, wenn nur bestimmte Ausgänge geschaltet werden sollen, zuerst den aktuellen Wert des Ports einlesen und das Bit des gewünschten Ports in diesen Wert einfließen lassen. Will man also nur den dritten Pin (Bit Nr. 2) an Port B auf &amp;quot;high&amp;quot; setzen und den Status der anderen Ausgänge unverändert lassen, nutze man diese Form:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
    PORTB = PORTB | 0x04; /* besser: PORTB = PORTB | ( 1&amp;lt;&amp;lt;PB2 ) */&lt;br /&gt;
    /* vereinfacht durch Nutzung des |= Operators : */&lt;br /&gt;
    PORTB |= (1&amp;lt;&amp;lt;PB2);&lt;br /&gt;
&lt;br /&gt;
    /* auch mehrere &amp;quot;gleichzeitig&amp;quot;: */&lt;br /&gt;
    PORTB |= (1&amp;lt;&amp;lt;PB4) | (1&amp;lt;&amp;lt;PB5); /* Pins PB4 und PB5 &amp;quot;high&amp;quot; */&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Ausschalten&amp;quot;, also  Ausgänge auf &amp;quot;low&amp;quot; setzen, erfolgt analog:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
    PORTB &amp;amp;= ~(1&amp;lt;&amp;lt;PB2); /* löscht Bit 2 in PORTB und setzt damit Pin PB2 auf low */ &lt;br /&gt;
    PORTB &amp;amp;= ~( (1&amp;lt;&amp;lt;PB4) | (1&amp;lt;&amp;lt;PB5) ); /* Pin PB4 und Pin PB5 &amp;quot;low&amp;quot; */&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In Quellcodes, die für ältere Version den des avr-gcc/der avr-libc entwickelt wurden, werden einzelne Bits mittels der Funktionen sbi und cbi gesetzt bzw. gelöscht. Beide Funktionen sind in aktuellen Versionen der avr-libc nicht mehr enthalten und auch nicht mehr erforderlich.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Falls der Anfangszustand von Ausgängen kritisch ist, muss die Reihenfolge beachtet werden, mit der die Datenrichtung (DDRx) eingestellt und der Ausgabewert (PORTx) gesetzt wird:&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Für Ausgangspins, die mit Anfangswert &amp;quot;high&amp;quot; initialisiert werden sollen:&lt;br /&gt;
* zuerst die Bits im PORTx-Register setzen&lt;br /&gt;
* anschließend die Datenrichtung auf Ausgang stellen&lt;br /&gt;
&lt;br /&gt;
Daraus ergibt sich die Abfolge für einen Pin, der bisher als Eingang mit abgeschaltetem Pull-Up konfiguriert ware:&lt;br /&gt;
* setze PORTx: interner Pull-Up aktiv&lt;br /&gt;
* setze DDRx: Ausgang (&amp;quot;high&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
Bei der Reihenfolge erst DDRx und dann PORTx, kann es zu einem kurzen &amp;quot;low-Puls&amp;quot; kommen, der auch externe Pull-Up-Widerstände &amp;quot;überstimmt&amp;quot;. Die (ungünstige) Abfolge: Eingang -&amp;gt; setze DDRx: Ausgang (auf &amp;quot;low&amp;quot;, da PORTx nach Reset 0) -&amp;gt; setze PORTx: Ausgang auf high. Vergleiche dazu auch das Datenblatt Abschnitt &#039;&#039;Configuring the Pin&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== Eingänge (Wie kommen Signale in den &amp;amp;micro;C) ==&lt;br /&gt;
&lt;br /&gt;
Die digitalen Eingangssignale können auf verschiedene Arten zu unserer Logik gelangen.&lt;br /&gt;
&lt;br /&gt;
=== Signalkopplung ===&lt;br /&gt;
&lt;br /&gt;
Am einfachsten ist es, wenn die Signale direkt aus einer anderen digitalen Schaltung übernommen werden können. Hat der Ausgang der entsprechenden Schaltung TTL-Pegel dann können wir sogar direkt den Ausgang der Schaltung mit einem Eingangspin von unserem Controller verbinden.&lt;br /&gt;
&lt;br /&gt;
Hat der Ausgang der anderen Schaltung keinen TTL-Pegel so müssen wir den Pegel über entsprechende Hardware (z.B. Optokoppler, [[Widerstand#Spannungsteiler|Spannungsteiler]], &amp;quot;Levelshifter&amp;quot; aka [[Pegelwandler]]) anpassen.&lt;br /&gt;
&lt;br /&gt;
Die Masse der beiden Schaltungen muss selbstverständlich miteinander verbunden werden. Der Software selber ist es natürlich letztendlich egal, wie das Signal eingespeist wird. Wir können ja ohnehin lediglich prüfen, ob an einem Pin unseres Controllers eine logische 1 (Spannung größer ca. 0,7*Vcc) oder eine logische 0 (Spannung kleiner ca. 0,2*Vcc) anliegt. Detaillierte Informationen darüber, ab welcher Spannung ein Eingang als 0 (&amp;quot;low&amp;quot;) bzw. 1 (&amp;quot;high&amp;quot;) erkannt wird, liefert die Tabelle DC Characteristics im Datenblatt des genutzten Controllers.&lt;br /&gt;
&lt;br /&gt;
Die Abfrage der Zustände der Portpins erfolgt direkt über den Registernamen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;font color=&amp;quot;#FF0000&amp;quot;&amp;gt;Dabei ist wichtig, zur Abfrage der Eingänge &#039;&#039;&#039;nicht&#039;&#039;&#039; etwa Portregister &#039;&#039;&#039;PORTx&#039;&#039;&#039; zu verwenden, &#039;&#039;&#039;sondern&#039;&#039;&#039; Eingangsregister &#039;&#039;&#039;PINx&#039;&#039;&#039;. Die Abfrage der Pinzustände über PORTx statt PINx ist ein häufiger Fehler beim AVR-&amp;quot;Erstkontakt&amp;quot;.&amp;lt;/font&amp;gt; (Ansonsten liest man nicht den Zustand der Eingänge, sondern den Status der internen Pull-Up-Widerstände.)&lt;br /&gt;
&lt;br /&gt;
Will man also die aktuellen Signalzustände von Port D abfragen und in eine Variable namens bPortD abspeichern, schreibt man folgende Befehlszeilen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
uint8_t bPortD;&lt;br /&gt;
...&lt;br /&gt;
bPortD = PIND;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit den C-Bitoperationen kann man den Status der Bits abfragen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
/* Fuehre Aktion aus, wenn Bit Nr. 1 (das &amp;quot;zweite&amp;quot; Bit) in PINC gesetzt (1) ist */&lt;br /&gt;
if ( PINC &amp;amp; (1&amp;lt;&amp;lt;PINC1) ) {&lt;br /&gt;
  /* Aktion */&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* Fuehre Aktion aus, wenn Bit Nr. 2 (das &amp;quot;dritte&amp;quot; Bit) in PINB geloescht (0) ist */&lt;br /&gt;
if ( !(PINB &amp;amp; (1&amp;lt;&amp;lt;PINB2)) ) {&lt;br /&gt;
  /* Aktion */&lt;br /&gt;
}&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Tasten und Schalter ===&lt;br /&gt;
&lt;br /&gt;
Der Anschluss mechanischer Kontakte an den Mikrocontroller gestaltet sich ebenfalls ganz einfach, wobei wir zwei unterschiedliche Methoden unterscheiden müssen (&#039;&#039;Active Low&#039;&#039; und &#039;&#039;Active High&#039;&#039;):&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Active Low&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Active High&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| [[Image:Active Low.gif]]&lt;br /&gt;
| [[Image:Active High.gif]]&lt;br /&gt;
|- &lt;br /&gt;
| Bei dieser Methode wird der Kontakt zwischen den Eingangspin des Controllers und Masse geschaltet.&lt;br /&gt;
&lt;br /&gt;
Damit bei offenem Schalter der Controller kein undefiniertes Signal bekommt wird zwischen die Versorgungsspannung und den Eingangspin ein sogenannter Pull-Up Widerstand geschaltet. Dieser dient dazu, den Pegel bei geöffnetem Schalter auf logisch 1 zu ziehen.&lt;br /&gt;
&lt;br /&gt;
Der Widerstandswert des Pull-Up Widerstands ist an sich nicht kritisch.  Wird er allerdings zu hoch gewählt, ist die Wirkung eventuell nicht gegeben. Als üblicher Wert haben sich 10 kOhm eingebürgert.&lt;br /&gt;
&lt;br /&gt;
Die AVRs haben sogar an den meisten Pins softwaremäßig zuschaltbare interne Pull-Up Widerstände, welche wir natürlich auch verwenden können.&lt;br /&gt;
&lt;br /&gt;
| Hier wird der Kontakt zwischen die Versorgungsspannung und den Eingangspin geschaltet.&lt;br /&gt;
&lt;br /&gt;
Damit bei offener Schalterstellung kein undefiniertes Signal am Controller ansteht, wird zwischen den Eingangspin und die Masse ein Pull-Down Widerstand geschaltet. Dieser dient dazu, den Pegel bei geöffneter Schalterstellung auf logisch 0 zu halten.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Pull-Up Widerstände aktivieren ====&lt;br /&gt;
&lt;br /&gt;
Die internen Pull-Up Widerstände von Vcc zu den einzelnen Portpins werden über das Register &#039;&#039;&#039; PORTx&#039;&#039;&#039; aktiviert bzw. deaktiviert, wenn ein Pin als &#039;&#039;&#039; Eingang&#039;&#039;&#039; geschaltet ist.&lt;br /&gt;
&lt;br /&gt;
Wird der Wert des entsprechenden Portpins auf 1 gesetzt, so ist der Pull-Up Widerstand aktiviert. Bei einem Wert von 0 ist der Pull-Up Widerstand nicht aktiv. Man sollte jeweils entweder den internen oder einen externen Pull-Up Widerstand verwenden, aber nicht beide zusammen.&lt;br /&gt;
&lt;br /&gt;
Im Beispiel werden alle Pins des Ports D als Eingänge geschaltet und alle Pull-Up Widerstände aktiviert. Weiterhin wird Pin PC7 als Eingang geschaltet und dessen interner Pull-Up Widerstand aktiviert, ohne die Einstellungen für die anderen Portpins (PC0-PC6) zu verändern.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
DDRD  = 0x00; /* alle Pins von Port D als Eingang */&lt;br /&gt;
PORTD = 0xff; /* interne Pull-Ups an allen Port-Pins aktivieren */&lt;br /&gt;
...&lt;br /&gt;
DDRC  &amp;amp;= ~(1&amp;lt;&amp;lt;DDC7);  /* Pin PC7 als Eingang */&lt;br /&gt;
PORTC |= (1&amp;lt;&amp;lt;PC7);    /* internen Pull-Up an PC7 aktivieren */&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== (Tasten-)Entprellung ====&lt;br /&gt;
&lt;br /&gt;
Nun haben alle mechanischen Kontakte, sei es von Schaltern, Tastern oder auch von Relais, die unangenehme Eigenschaft zu prellen. Dies bedeutet, dass beim Schließen des Kontaktes derselbe nicht direkt Kontakt herstellt, sondern mehrfach ein- und ausschaltet bis zum endgültigen Herstellen des Kontaktes.&lt;br /&gt;
&lt;br /&gt;
Soll nun mit einem schnellen Mikrocontroller gezählt werden, wie oft ein solcher Kontakt geschaltet wird, dann haben wir ein Problem, weil das Prellen als mehrfache Impulse gezählt wird. Diesem Phänomen muss beim Schreiben des Programms unbedingt Rechnung getragen werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;lt;inttypes.h&amp;gt;&lt;br /&gt;
#ifndef F_CPU&lt;br /&gt;
#warning &amp;quot;F_CPU war noch nicht definiert, wird nun mit 3686400 definiert&amp;quot;&lt;br /&gt;
#define F_CPU 3686400UL     /* Quarz mit 3.6864 Mhz  */&lt;br /&gt;
#endif&lt;br /&gt;
#include &amp;lt;util/delay.h&amp;gt;     /* bei alter avr-libc: #include &amp;lt;avr/delay.h&amp;gt; */      &lt;br /&gt;
&lt;br /&gt;
/* Einfache Funktion zum Entprellen eines Tasters */&lt;br /&gt;
inline uint8_t debounce(volatile uint8_t *port, uint8_t pin)&lt;br /&gt;
{&lt;br /&gt;
    if ( ! (*port &amp;amp; (1 &amp;lt;&amp;lt; pin)) )&lt;br /&gt;
    {&lt;br /&gt;
        /* Pin wurde auf Masse gezogen, 100ms warten   */&lt;br /&gt;
        _delay_ms(50);  // max. 262.1 ms / F_CPU in MHz&lt;br /&gt;
        _delay_ms(50); &lt;br /&gt;
        if ( *port &amp;amp; (1 &amp;lt;&amp;lt; pin) )&lt;br /&gt;
        {&lt;br /&gt;
            /* Anwender Zeit zum Loslassen des Tasters geben */&lt;br /&gt;
            _delay_ms(50);&lt;br /&gt;
            _delay_ms(50); &lt;br /&gt;
            return 1;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int main(void)&lt;br /&gt;
{&lt;br /&gt;
    DDRB &amp;amp;= ~( 1 &amp;lt;&amp;lt; PB0 );                 /* PIN PB0 auf Eingang (Taster)            */&lt;br /&gt;
    PORTB |= ( 1 &amp;lt;&amp;lt; PB0 );                 /* Pullup-Widerstand aktivieren            */&lt;br /&gt;
    ...&lt;br /&gt;
    if (debounce(&amp;amp;PINB, PB0))             /* Falls Taster an PIN PB0 gedrueckt..    */&lt;br /&gt;
        PORTD = PIND ^ ( 1 &amp;lt;&amp;lt; PD7 );  /* ..LED an Port PD7 an-&lt;br /&gt;
                                   bzw. ausschalten */&lt;br /&gt;
    ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bei diesem Beispiel ist zu beachten, dass der AVR im Falle eines Tastendrucks 200ms wartet, also brach liegt. Bei zeitkritische Anwendungen sollte man ein anderes Verfahren nutzen (z.B. Abfrage der Tastenzustände in einer Timer-Interrupt-Service-Routine).&lt;br /&gt;
&lt;br /&gt;
Zum Thema Entprellen siehe auch:&lt;br /&gt;
* Artikel [[Entprellung]]&lt;br /&gt;
&lt;br /&gt;
== Analog ==&lt;br /&gt;
&lt;br /&gt;
Die Verarbeitung von analogen Eingangswerten und die Ausgabe von Analogwerten wird in Kapitel [[AVR-GCC-Tutorial#Analoge_Ein-_und_Ausgabe|Analoge Ein- und Ausgabe]] behandelt.&lt;br /&gt;
&lt;br /&gt;
== 16-Bit Portregister (ADC, ICR1, OCR1, TCNT1, UBRR) ==&lt;br /&gt;
&lt;br /&gt;
Einige der Portregister in den AVR-Controllern sind 16 Bit breit. Im Datenblatt sind diese Register üblicherweise mit dem Suffix &amp;quot;L&amp;quot; (LSB) und &amp;quot;H&amp;quot; (MSB) versehen. Die avr-libc definiert zusätzlich die meisten dieser Variablen die Bezeichnung ohne &amp;quot;L&amp;quot; oder &amp;quot;H&amp;quot;. Auf diese kann direkt zugewiesen bzw. zugegriffen werden. Die Konvertierung von 16-bit Wort nach 2*8-bit Byte erfolgt intern.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
uint16_t foo;&lt;br /&gt;
&lt;br /&gt;
foo=ADC; /* setzt die Wort-Variable foo auf den Wert der letzten AD-Wandlung */&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Falls ben&amp;amp;ouml;tigt, kann eine 16-Bit Variable auch recht einfach manuell in ihre zwei 8-Bit Bestandteile zerlegt werden. Folgendes Beispiel demonstriert dies anhand des pseudo- 16-Bit Registers UBRR.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
/* Diese Variante ist normal am effizientesten */&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
#ifndef F_CPU&lt;br /&gt;
#define F_CPU 3686400&lt;br /&gt;
#endif&lt;br /&gt;
#define UART_BAUD_RATE 9600&lt;br /&gt;
&lt;br /&gt;
typedef union {&lt;br /&gt;
        uint16_t i16;&lt;br /&gt;
        struct {&lt;br /&gt;
                uint8_t i8l;&lt;br /&gt;
                uint8_t i8h;&lt;br /&gt;
        };&lt;br /&gt;
} convert16to8;&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
convert16to8 baud;&lt;br /&gt;
baud.i16 = F_CPU / (UART_BAUD_RATE * 16L) -1;&lt;br /&gt;
UBRRH = baud.i8h;&lt;br /&gt;
UBRRL = baud.i8l;&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
/* Alternative 1:*/&lt;br /&gt;
#include &amp;lt;inttypes.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
uint16_t wFoo16;&lt;br /&gt;
uint8_t bFooLow, bFooHigh;&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
wFoo16   = 0xAA55;                 /* zu &amp;quot;zerlegende&amp;quot; 16Bit-Integer */&lt;br /&gt;
bFooHigh = (uint8_t)(wFoo16 &amp;gt;&amp;gt; 8); /* MS-Byte */&lt;br /&gt;
bFooLow  = (uint8_t)(wFoo16);      /* LS-Byte */&lt;br /&gt;
&lt;br /&gt;
/* Alternative 2:*/&lt;br /&gt;
&lt;br /&gt;
#define us0(Data) (*((unsigned char *)(&amp;amp;Data)))&lt;br /&gt;
#define us1(Data) (*((unsigned char *)((&amp;amp;Data)+1)))&lt;br /&gt;
bFooHigh = us1(wFoo16);&lt;br /&gt;
bFoolow  = us0(wFoo16);&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bei einigen AVR-Typen (z.B. ATmega8) teilen sich UBRRH und UCSRC die gleiche Memory-Adresse. Damit der AVR trotzdem zwischen den beiden Registern unterscheiden kann, bestimmt das Bit7 (URSEL) welches Register tats&amp;amp;auml;chlich beschrieben werden soll. &#039;&#039;1000 0011&#039;&#039; (0x83) adressiert demnach UCSRC und &amp;amp;uuml;bergibt den Wert &#039;&#039;3&#039;&#039; und &#039;&#039;0000 0011&#039;&#039; (0x3) adressiert UBRRH und &amp;amp;uuml;bergibt ebenfalls den Wert &#039;&#039;3&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
Bei einigen 16-bit Registern (insbesondere die der 16-bit Timer) erfolgen Schreibzugriffe über das sogenannte &#039;&#039;temporary Register&#039;&#039;. Die Reihenfolge der Zugriffe bestimmt, wann der Wert tatsächlich ins Register geschrieben wird. Typisch wird erst das High-Byte beschrieben (xxxH) und intern im temporary Register zwischengespeichert. Nachdem das Low-Byte (xxxL) geschrieben wurde, setzt der Controller mit diesem und dem im temporary Register zwischengespeicherten Wert für das High-Byte das 16-bit Register. Dabei ist zu beachten, dass intern nur ein temporary Register verfügbar ist, welches in Interruptroutinen mglw. mit einem anderen Wert überschrieben wird, wenn dort ebenfalls 16-bit Register beschrieben werden. avr-gcc/avr-libc berücksichtigen die korrekte Reihenfolge automatisch, wenn die Register mit ihrem &amp;quot;16-bit Label&amp;quot; (ohne H bzw. L) angesprochen werden, dabei ist der Schutz des temporary Registers vor Überschreiben durch Interruptroutinen dennoch zu beachten (im Zweifel beim Schreibzugriff die Interrupts kurzzeitig global deaktivieren).&lt;br /&gt;
&lt;br /&gt;
Im Umgang mit 16-Bit Registern siehe auch:&lt;br /&gt;
* [http://www.nongnu.org/avr-libc/user-manual/index.html Dokumentation der avr-libc] Abschnitt Related Pages/Frequently Asked Questions/Nr. 8&lt;br /&gt;
* Datenblatt Abschnitt &#039;&#039;Accessing 16-bit Registers&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== IO-Register als Parameter und Variablen ==&lt;br /&gt;
&lt;br /&gt;
Um Register als Parameter für eigene Funktionen übergeben zu können, muss man sie als einen volatile uint8_t Pointer übergeben. Zum Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
uint8_t key_pressed(const volatile uint8_t *inputreg, uint8_t inputbit)&lt;br /&gt;
{&lt;br /&gt;
  static uint8_t last_state = 0;&lt;br /&gt;
 &lt;br /&gt;
  if ( last_state == ( *inputreg &amp;amp; (1&amp;lt;&amp;lt;inputbit) ) ) {&lt;br /&gt;
     return 0; /* keine Änderung */&lt;br /&gt;
  }&lt;br /&gt;
 &lt;br /&gt;
  /* Wenn doch, warten bis etwaiges Prellen vorbei ist: */&lt;br /&gt;
  _delay_ms(20);&lt;br /&gt;
&lt;br /&gt;
  /* Zustand für nächsten Aufruf merken: */&lt;br /&gt;
  last_state = ( *inputreg &amp;amp; (1&amp;lt;&amp;lt;inputbit) );&lt;br /&gt;
 &lt;br /&gt;
  /* und den entprellten Tastendruck zurückgeben: */&lt;br /&gt;
  return ( *inputreg &amp;amp; (1&amp;lt;&amp;lt;inputbit) );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* Beispiel für einen Funktionsaufruf: */&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
uint8_t i;&lt;br /&gt;
&lt;br /&gt;
//...&lt;br /&gt;
    i = key_pressed( &amp;amp;PINB, PB1 );&lt;br /&gt;
//...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein Aufruf der Funktion mit call by value würde Folgendes bewirken: Beim Funktionseintritt wird nur eine Kopie des momentanen Portzustandes angefertigt, die sich unabhängig vom tatsächlichen Zustand das Ports nicht mehr ändert, womit die Funktion wirkungslos wäre. Die Übergabe eines Zeigers wäre die Lösung, wenn der Compiler nicht optimieren würde. Denn dadurch wird im Programm nicht von der Hardware gelesen, sondern wieder nur von einem Abbild im Speicher. Das Ergebnis wäre das gleiche wie oben. Mit dem Schlüsselwort volatile sagt man nun dem Compiler, dass die entsprechende Variable entweder durch andere Softwareroutinen (Interrupts) oder durch die Hardware verändert werden kann.&lt;br /&gt;
&lt;br /&gt;
Im Übrigen können mit volatile gekennzeichnete Variablen auch als const deklariert werden, um sicherzustellen, dass sie nur noch von der Hardware änderbar sind.&lt;br /&gt;
&lt;br /&gt;
= Der UART =&lt;br /&gt;
&lt;br /&gt;
== Allgemeines zum UART ==&lt;br /&gt;
&lt;br /&gt;
Über den [[UART]] kann ein AVR leicht mit einer [[RS-232]]-Schnittstelle eines PC oder sonstiger Geräte mit &amp;quot;serieller Schnittstelle&amp;quot; verbunden werden. &lt;br /&gt;
&lt;br /&gt;
Mögliche Anwendungen des UART:&lt;br /&gt;
&lt;br /&gt;
* Debug-Schnittstelle: z.B. zur Anzeige von Zwischenergebnissen (&amp;quot;printf-debugging&amp;quot; - hier besser &amp;quot;UART-debugging&amp;quot;) auf einem PC. Auf dem Rechner reicht dazu ein [[RS-232#Terminalprogramme|Terminalprogramm]] (MS-Windows: Hyperterm oder besser [http://braypp.googlepages.com/terminal Bray-Terminal], [http://www.der-hammer.info/terminal/ HTerm]; Unix/Linux z.B. minicom). Ein direkter Anschluss ist aufgrund unterschiedlicher Pegel nicht möglich, jedoch sind entsprechende Schnittstellen-ICs wie z.B. ein MAX232 günstig und leicht zu integrieren. Rechner ohne serielle Schnittstelle können über fertige USB-seriell-Adapter angeschlossen werden. &lt;br /&gt;
* &amp;quot;Mensch-Maschine Schnittstelle&amp;quot;: z.B. Konfiguration und Statusabfrage über eine &amp;quot;Kommandozeile&amp;quot; oder Menüs (siehe z.B. Forumsbeitrag [http://www.mikrocontroller.net/topic/52985 Auswertung RS232-Befehle]) &lt;br /&gt;
* Übertragen von gespeicherten Werten: z.B. bei einem Datenlogger&lt;br /&gt;
* Anschluss von Geräten mit serieller Schnittstelle (z.B. (Funk-)Modems, Mobiltelefone, Drucker, Sensoren, &amp;quot;intelligente&amp;quot; LC-Displays, GPS-Empfänger). &lt;br /&gt;
* &amp;quot;Feldbusse&amp;quot; auf RS485/RS422-Basis mittels entsprechenden Bustreiberbausteinen (z.B. MAX485)&lt;br /&gt;
* DMX, Midi etc.&lt;br /&gt;
* LIN-Bus (&#039;&#039;&#039;L&#039;&#039;&#039;ocal &#039;&#039;&#039;I&#039;&#039;&#039;nterconnect &#039;&#039;&#039;N&#039;&#039;&#039;etwork): Preiswerte Sensoren/Aktoren in der Automobiltechnik und darüber hinaus&lt;br /&gt;
&lt;br /&gt;
Einige AVR-Controller haben ein bis zwei vollduplexfähigen UART (&#039;&#039;&#039;U&#039;&#039;&#039;niversal &#039;&#039;&#039;A&#039;&#039;&#039;synchronous &#039;&#039;&#039;R&#039;&#039;&#039;eceiver and &#039;&#039;&#039;T&#039;&#039;&#039;ransmitter) schon eingebaut (&amp;quot;Hardware-UART&amp;quot;). &lt;br /&gt;
Übrigens: Vollduplex heißt nichts anderes, als dass der Baustein gleichzeitig senden und empfangen kann.&lt;br /&gt;
&lt;br /&gt;
Neuere AVRs (ATmega, ATtiny) verfügen über einen oder zwei U&#039;&#039;&#039;S&#039;&#039;&#039;ART(s), dieser unterscheidet sich vom UART hauptsächlich durch interne FIFO-Puffer für Ein- und Ausgabe und erweiterte Konfigurationsmöglichkeiten. Die Puffergröße ist allerdings nur 1 Byte.&lt;br /&gt;
&lt;br /&gt;
Der UART wird über vier separate Register angesprochen. USARTs der ATMEGAs verfügen über mehrere zusätzliche Konfigurationsregister. Das Datenblatt gibt darüber Auskunft. Die Folgende Tabelle gibt nur die Register für die (veralteten) UARTs wieder.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;UCR&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;U&#039;&#039;&#039;ART &#039;&#039;&#039;C&#039;&#039;&#039;ontrol &#039;&#039;&#039;R&#039;&#039;&#039;egister.&amp;lt;br /&amp;gt;&lt;br /&gt;
In diesem Register stellen wir ein, wie wir den UART verwenden möchten.&amp;lt;br /&amp;gt;&lt;br /&gt;
Das Register ist wie folgt aufgebaut:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Bit&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 7&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 6&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 5&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 4&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 2&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Name&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;RXCIE&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;TXCIE&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;UDRIE&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;RXEN&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;TXEN&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;CHR9&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;RXB8&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;TXB8&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;R/W&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | W&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Initialwert&#039;&#039;&#039;&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;
| 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;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;RXCIE&#039;&#039;&#039; (&#039;&#039;&#039;RX&#039;&#039;&#039; &#039;&#039;&#039;C&#039;&#039;&#039;omplete &#039;&#039;&#039;I&#039;&#039;&#039;nterrupt &#039;&#039;&#039;E&#039;&#039;&#039;nable)&lt;br /&gt;
:Wenn dieses Bit gesetzt ist, wird ein UART RX Complete Interrupt ausgelöst, wenn ein Zeichen vom UART empfangen wurde. Das Global Enable Interrupt Flag muss selbstverständlich auch gesetzt sein.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;TXCIE&#039;&#039;&#039; (&#039;&#039;&#039;TX&#039;&#039;&#039; &#039;&#039;&#039;C&#039;&#039;&#039;omplete &#039;&#039;&#039;I&#039;&#039;&#039;nterrupt &#039;&#039;&#039;E&#039;&#039;&#039;nable)&lt;br /&gt;
:Wenn dieses Bit gesetzt ist, wird ein UART TX Complete Interrupt ausgelöst, wenn ein Zeichen vom UART gesendet wurde. Das Global Enable Interrupt Flag muss selbstverständlich auch gesetzt sein.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;UDRIE&#039;&#039;&#039; (&#039;&#039;&#039;U&#039;&#039;&#039;ART &#039;&#039;&#039;D&#039;&#039;&#039;ata &#039;&#039;&#039;R&#039;&#039;&#039;egister &#039;&#039;&#039;E&#039;&#039;&#039;mpty &#039;&#039;&#039;I&#039;&#039;&#039;nterrupt &#039;&#039;&#039;E&#039;&#039;&#039;nable)&lt;br /&gt;
:Wenn dieses Bit gesetzt ist, wird ein UART Datenregister Leer Interrupt ausgelöst, wenn der UART wieder bereit ist um ein neues zu sendendes Zeichen zu übernehmen. Das Global Enable Interrupt Flag muss selbstverständlich auch gesetzt sein.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;RXEN&#039;&#039;&#039; (&#039;&#039;&#039;R&#039;&#039;&#039;eceiver &#039;&#039;&#039;E&#039;&#039;&#039;nable)&lt;br /&gt;
:Nur wenn dieses Bit gesetzt ist, arbeitet der Empfänger des UART überhaupt. Wenn das Bit nicht gesetzt ist, kann der entsprechende Pin des AVR als normaler I/O-Pin verwendet werden. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;TXEN&#039;&#039;&#039; (&#039;&#039;&#039;T&#039;&#039;&#039;ransmitter &#039;&#039;&#039;E&#039;&#039;&#039;nable)&lt;br /&gt;
:Nur wenn dieses Bit gesetzt ist, arbeitet der Sender des UART überhaupt. Wenn das Bit nicht gesetzt ist, kann der entsprechende Pin des AVR als normaler I/O-Pin verwendet werden.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;CHR9&#039;&#039;&#039; (9 Bit Characters)&lt;br /&gt;
:Wenn dieses Bit gesetzt ist, können 9 Bit lange Zeichen übertragen und empfangen werden. Das 9. Bit kann bei Bedarf als zusätzliches Stopbit oder als Paritätsbit verwendet werden. Man spricht dann von einem 11-Bit Zeichenrahmen:&lt;br /&gt;
:1 Startbit + 8 Datenbits + 1 Stopbit + 1 Paritätsbit = 11 Bits&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;RXB8&#039;&#039;&#039; (Receive Data Bit 8)&lt;br /&gt;
:Wenn das vorher erwähnte CHR9-Bit gesetzt ist, dann enthält dieses Bit das 9. Datenbit eines empfangenen Zeichens.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;TXB8&#039;&#039;&#039; (Transmit Data Bit 8)&lt;br /&gt;
:Wenn das vorher erwähnte CHR9-Bit gesetzt ist, dann muss in dieses Bit das 9. Bit des zu sendenden Zeichens eingeschrieben werden bevor das eigentliche Datenbyte in das Datenregister geschrieben wird.&lt;br /&gt;
&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;USR&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;U&#039;&#039;&#039;ART &#039;&#039;&#039;S&#039;&#039;&#039;tatus &#039;&#039;&#039;R&#039;&#039;&#039;egister.&amp;lt;br /&amp;gt;&lt;br /&gt;
Hier teilt uns der UART mit, was er gerade so macht.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Bit&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 7&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 6&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 5&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 4&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 2&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Name&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;RXC&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;TXC&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;UDRE&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;FE&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;OR&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;R/W&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Initialwert&#039;&#039;&#039;&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;
| 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;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;RXC&#039;&#039;&#039; (UART Receive Complete)&lt;br /&gt;
:Dieses Bit wird vom AVR gesetzt, wenn ein empfangenes Zeichen vom Empfangs-Schieberegister in das Empfangs-Datenregister transferiert wurde.&lt;br /&gt;
:Das Zeichen muss nun schnellstmöglich aus dem Datenregister ausgelesen werden. Falls dies nicht erfolgt bevor ein weiteres Zeichen komplett empfangen wurde wird eine Überlauf-Fehlersituation eintreffen. Mit dem Auslesen des Datenregisters wird das Bit automatisch gelöscht.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;TXC&#039;&#039;&#039; (UART Transmit Complete)&lt;br /&gt;
:Dieses Bit wird vom AVR gesetzt, wenn das im Sende-Schieberegister befindliche Zeichen vollständig ausgegeben wurde und kein weiteres Zeichen im Sendedatenregister ansteht. Dies bedeutet also, wenn die Kommunikation vollumfänglich abgeschlossen ist.&lt;br /&gt;
:Dieses Bit ist wichtig bei Halbduplex-Verbindungen, wenn das Programm nach dem Senden von Daten auf Empfang schalten muss. Im Vollduplexbetrieb brauchen wir dieses Bit nicht zu beachten.&lt;br /&gt;
:Das Bit wird nur dann automatisch gelöscht, wenn der entsprechende Interrupthandler aufgerufen wird, ansonsten müssen wir das Bit selber löschen.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;UDRE&#039;&#039;&#039; (&#039;&#039;&#039;U&#039;&#039;&#039;ART &#039;&#039;&#039;D&#039;&#039;&#039;ata &#039;&#039;&#039;R&#039;&#039;&#039;egister &#039;&#039;&#039;E&#039;&#039;&#039;mpty)&lt;br /&gt;
:Dieses Bit zeigt an, ob der Sendepuffer bereit ist, um ein zu sendendes Zeichen aufzunehmen. Das Bit wird vom AVR gesetzt (1), wenn der Sendepuffer leer ist. Es wird gelöscht (0), wenn ein Zeichen im Sendedatenregister vorhanden ist und noch nicht in das Sendeschieberegister übernommen wurde. Atmel empfiehlt aus Kompatibilitätsgründen mit kommenden µC, UDRE auf 0 zu setzen, wenn das UCSRA Register beschrieben wird.&lt;br /&gt;
:Das Bit wird automatisch gelöscht, wenn ein Zeichen in das Sendedatenregister geschrieben wird.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;FE&#039;&#039;&#039; (&#039;&#039;&#039;F&#039;&#039;&#039;raming &#039;&#039;&#039;E&#039;&#039;&#039;rror)&lt;br /&gt;
:Dieses Bit wird vom AVR gesetzt, wenn der UART einen Zeichenrahmenfehler detektiert, d.h. wenn das Stopbit eines empfangenen Zeichens 0 ist.&lt;br /&gt;
:Das Bit wird automatisch gelöscht, wenn das Stopbit des empfangenen Zeichens 1 ist.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;OR&#039;&#039;&#039; (&#039;&#039;&#039;O&#039;&#039;&#039;ver&#039;&#039;&#039;R&#039;&#039;&#039;un)&amp;lt;br /&amp;gt;&lt;br /&gt;
:Dieses Bit wird vom AVR gesetzt, wenn unser Programm das im Empfangsdatenregister bereit liegende Zeichen nicht abholt bevor das nachfolgende Zeichen komplett empfangen wurde.&lt;br /&gt;
:Das nachfolgende Zeichen wird verworfen.&lt;br /&gt;
:Das Bit wird automatisch gelöscht, wenn das empfangene Zeichen in das Empfangsdatenregister transferiert werden konnte.&lt;br /&gt;
&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;UDR&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;U&#039;&#039;&#039;ART &#039;&#039;&#039;D&#039;&#039;&#039;ata &#039;&#039;&#039;R&#039;&#039;&#039;egister.&amp;lt;br /&amp;gt;&lt;br /&gt;
Hier werden Daten zwischen UART und CPU übertragen. Da der UART im&lt;br /&gt;
Vollduplexbetrieb gleichzeitig empfangen und senden kann, handelt es sich&lt;br /&gt;
hier physikalisch um 2 Register, die aber über die gleiche I/O-Adresse&lt;br /&gt;
angesprochen werden. Je nachdem, ob ein Lese- oder ein Schreibzugriff auf&lt;br /&gt;
den UART erfolgt wird automatisch das richtige UDR angesprochen.&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;UBRR&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;U&#039;&#039;&#039;ART &#039;&#039;&#039;B&#039;&#039;&#039;aud &#039;&#039;&#039;R&#039;&#039;&#039;ate &#039;&#039;&#039;R&#039;&#039;&#039;egister.&amp;lt;br /&amp;gt;&lt;br /&gt;
In diesem Register müssen wir dem UART mitteilen, wie schnell wir gerne&lt;br /&gt;
kommunizieren möchten. Der Wert, der in dieses Register geschrieben&lt;br /&gt;
werden muss, errechnet sich nach folgender Formel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
\begin{matrix}&lt;br /&gt;
\mathrm{UBRR} = \frac{\mathrm{Taktfrequenz}}{\mathrm{Baudrate} \cdot 16} - 1&lt;br /&gt;
\end{matrix}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Es sind Baudraten bis zu 115200 Baud und höher möglich.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Die Hardware ==&lt;br /&gt;
&lt;br /&gt;
Der UART basiert auf normalem TTL-Pegel mit 0V (LOW) und 5V (HIGH). Die&lt;br /&gt;
Schnittstellenspezifikation für RS-232 definiert jedoch -3V ... -12V (LOW) und&lt;br /&gt;
+3 ... +12V (HIGH). Zudem muss der Signalaustausch zwischen AVR und&lt;br /&gt;
Partnergerät invertiert werden. Für die Anpassung der Pegel und das&lt;br /&gt;
Invertieren der Signale gibt es fertige Schnittstellenbausteine. Der bekannteste&lt;br /&gt;
davon ist wohl der MAX232. &lt;br /&gt;
&amp;lt;!-- &amp;quot;Hackerloesung&amp;quot; auskommentiert - nicht so gut in einem &amp;quot;Einsteiger-Tutorial&amp;quot; - mthomas&lt;br /&gt;
Allerdings kostet der auch wieder Geld und benötigt&lt;br /&gt;
zusätzlich immerhin 4 externe Elkos.&lt;br /&gt;
&lt;br /&gt;
Die in den PC eingebauten Schnittstellen vertragen ohne Klagen auch den&lt;br /&gt;
TTL-Pegel vom AVR. Allerdings müssen wir immer noch die Signale invertieren. Im&lt;br /&gt;
einfachtesn Fall verwenden wir dazu jeweils einen einfachen NPN-Transistor und 2&lt;br /&gt;
Widerstände. Näheres dazu erfahrt ihr in den folgenden Übungen.--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Streikt die Kommunikation per UART, so ist oft eine fehlerhafte Einstellung der Baudrate die Ursache. Die Konfiguration auf eine bestimmte Baudrate ist abhängig von der Taktfrequenz des Controllers. Gerade bei neu aufgebauten Schaltungen (bzw. neu gekauften Controllern) sollte man sich daher noch einmal vergewissern, dass der Controller auch tatsächlich mit der vermuteten Taktrate arbeitet und nicht z.B. den bei einigen Modellen werksseitig eingestellten internen [[Oszillator]] statt eines externen Quarzes nutzt. Die Werte der verschiedenen fuse-bits im Fehlerfall also beispielsweise mit &#039;&#039;[[AVRDUDE]]&#039;&#039; kontrollieren und falls nötig anpassen. Grundsätzlich empfiehlt sich auch immer ein Blick in die [[AVR_Checkliste]].&lt;br /&gt;
&lt;br /&gt;
== UART initialisieren ==&lt;br /&gt;
&lt;br /&gt;
Wir wollen nun Daten mit dem UART auf die serielle Schnittstelle ausgeben. Dazu müssen wir den UART zuerst mal initialisieren. Dazu setzen wir je nach gewünschter Funktionsweise die benötigten Bits im &#039;&#039;&#039;U&#039;&#039;&#039;ART &#039;&#039;&#039;C&#039;&#039;&#039;ontrol &#039;&#039;&#039;R&#039;&#039;&#039;egister.&lt;br /&gt;
&lt;br /&gt;
Da wir vorerst nur senden möchten und noch keine Interrupts auswerten wollen, gestaltet sich die Initialisierung wirklich sehr einfach, da wir lediglich das &#039;&#039;&#039;Transmitter Enable&#039;&#039;&#039; Bit setzen müssen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
    UCR |= (1&amp;lt;&amp;lt;TXEN);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Neuere AVRs mit USART haben mehrere Konfigurationsregister und erfordern eine etwas andere Konfiguration. Für einen ATmega16 z.B.:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
    UCSRB |= (1&amp;lt;&amp;lt;TXEN);                            // UART TX einschalten&lt;br /&gt;
    UCSRC |= (1&amp;lt;&amp;lt;URSEL)|(1 &amp;lt;&amp;lt; UCSZ1)|(1 &amp;lt;&amp;lt; UCSZ0); // Asynchron 8N1&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nun ist noch das Baudratenregister &#039;&#039;&#039;UBRR&#039;&#039;&#039; einzustellen. Bei neueren AVRs besteht es aus zwei Registern &#039;&#039;&#039;UBRRL&#039;&#039;&#039; und &#039;&#039;&#039;UBRRH&#039;&#039;&#039;. Der Wert dafür ergibt sich aus der angegebenen Formel durch Einsetzen der Taktfrequenz und der gewünschten Übertragungsrate. Das Berechnen der Formel wird dem [[C-Präprozessor|Präprozessor]] überlassen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
/* UART-Init beim AT90S2313 */&lt;br /&gt;
&lt;br /&gt;
#ifndef F_CPU&lt;br /&gt;
/* In neueren Version der WinAVR/Mfile Makefile-Vorlage kann&lt;br /&gt;
   F_CPU im Makefile definiert werden, eine nochmalige Definition&lt;br /&gt;
   hier wuerde zu einer Compilerwarnung fuehren. Daher &amp;quot;Schutz&amp;quot; durch&lt;br /&gt;
   #ifndef/#endif &lt;br /&gt;
&lt;br /&gt;
   Dieser &amp;quot;Schutz&amp;quot; kann zu Debugsessions führen, wenn AVRStudio &lt;br /&gt;
   verwendet wird und dort eine andere, nicht zur Hardware passende &lt;br /&gt;
   Taktrate eingestellt ist: Dann wird die folgende Definition &lt;br /&gt;
   nicht verwendet, sondern stattdessen der Defaultwert (8 MHz?) &lt;br /&gt;
   von AVRStudio - daher Ausgabe einer Warnung falls F_CPU&lt;br /&gt;
   noch nicht definiert: */&lt;br /&gt;
#warning &amp;quot;F_CPU war noch nicht definiert, wird nun nachgeholt mit 4000000&amp;quot;&lt;br /&gt;
#define F_CPU 4000000UL    // Systemtakt in Hz - Definition als unsigned long beachten &amp;gt;&amp;gt; Ohne ergeben Fehler in der Berechnung&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
#define BAUD 9600UL          // Baudrate&lt;br /&gt;
&lt;br /&gt;
// Berechnungen&lt;br /&gt;
#define UBRR_VAL ((F_CPU+BAUD*8)/(BAUD*16)-1)   // clever runden&lt;br /&gt;
#define BAUD_REAL (F_CPU/(16*(UBRR_VAL+1)))     // Reale Baudrate&lt;br /&gt;
#define BAUD_ERROR ((BAUD_REAL*1000)/BAUD) // Fehler in Promille, 1000 = kein Fehler.&lt;br /&gt;
&lt;br /&gt;
#if ((BAUD_ERROR&amp;lt;990) || (BAUD_ERROR&amp;gt;1010))&lt;br /&gt;
  #error Systematischer Fehler der Baudrate grösser 1% und damit zu hoch! &lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
int main(void)&lt;br /&gt;
{&lt;br /&gt;
    UCR |= (1&amp;lt;&amp;lt;TXEN);&lt;br /&gt;
    UBRR = UBRR_VAL;&lt;br /&gt;
    //...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&amp;lt;!-- mthomas: warum nicht UL?, wird von AVRStudio auch mit UL übergeben --&amp;gt;&lt;br /&gt;
Wieder für den Mega16 mit zwei Registern für die Baudrateneinstellung eine etwas andere Programmierung. Wichtig ist, dass UBRRH &#039;&#039;&#039;vor&#039;&#039;&#039; UBRRL geschrieben wird.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
  /* USART-Init beim ATmega16 */&lt;br /&gt;
&lt;br /&gt;
int main(void)&lt;br /&gt;
{&lt;br /&gt;
    UCSRB |= (1&amp;lt;&amp;lt;TXEN);                // UART TX einschalten&lt;br /&gt;
    UCSRC |= (1&amp;lt;&amp;lt;URSEL)|(3&amp;lt;&amp;lt;UCSZ0);    // Asynchron 8N1 &lt;br /&gt;
&lt;br /&gt;
    UBRRH = UBRR_VAL &amp;gt;&amp;gt; 8;&lt;br /&gt;
    UBRRL = UBRR_VAL &amp;amp; 0xFF;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für einige AVR (z.B. ATmega169, ATmega48/88/168, AT90CAN jedoch nicht für z.B. ATmega16/32, ATmega128, ATtiny2313) wird durch die Registerdefinitionen der avr-libc (io*.h) auch für Controller mit zwei UBRR-Registern (UBRRL/UBRRH) ein UBRR bzw. UBRR0 als &amp;quot;16-bit-Register&amp;quot; definiert und man kann auch Werte direkt per UBRR = UBRR_VAL zuweisen. Intern werden dann zwei Zuweisungen für UBRRH und UBRRL generiert. Dies ist nicht bei allen Controllern möglich, da die beiden Register nicht bei allen aufeinanderfolgende Addressen aufweisen. Die getrennte Zuweisung an UBRRH und UBRRL wie im Beispiel gezeigt ist universeller und portabler und daher vorzuziehen.&lt;br /&gt;
&lt;br /&gt;
Die Makros sind sehr praktisch, da sie sowohl automatisch den Wert für UBRR als auch den Fehler in der generierten Baudrate berechnen und im Falle einer Überschreitung (+/-1%) einen Fehler und somit Abbruch im Compilerablauf generieren. Damit können viele Probleme mit &amp;quot;UART sendet komische Zeichen&amp;quot; vermieden werden. Ausserdem kann man mühelos die Einstellung an eine neue Taktfrequenz bzw. Baudrate anpassen, ohne selber rechnen oder in Tabellen nachschlagen zu müssen.&lt;br /&gt;
&lt;br /&gt;
Siehe auch:&lt;br /&gt;
* [http://www.wormfood.net/avrbaudcalc.php WormFood&#039;s AVR Baud Rate Calculator] online.&lt;br /&gt;
&lt;br /&gt;
== Senden mit dem UART ==&lt;br /&gt;
&lt;br /&gt;
=== Senden einzelner Zeichen ===&lt;br /&gt;
&lt;br /&gt;
Um nun ein Zeichen auf die Schnittstelle auszugeben, müssen wir dasselbe&lt;br /&gt;
lediglich in das &#039;&#039;&#039;U&#039;&#039;&#039;ART &#039;&#039;&#039;D&#039;&#039;&#039;ata &#039;&#039;&#039;R&#039;&#039;&#039;egister schreiben. Vorher ist zu prüfen, ob das UART-Modul bereit ist, das zu sendende Zeichen entgegenzunehmen. Die Bezeichnungen des/der Statusregisters mit dem Bit UDRE ist abhängig vom Controllertypen (vgl. Datenblatt).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
    // bei AVR mit einem UART (&amp;quot;classic AVR&amp;quot; z.B. AT90S8515)&lt;br /&gt;
    while (!(USR &amp;amp; (1&amp;lt;&amp;lt;UDRE)))  /* warten bis Senden moeglich                   */&lt;br /&gt;
    {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    UDR = &#039;x&#039;;                  /* schreibt das Zeichen x auf die Schnittstelle */&lt;br /&gt;
&lt;br /&gt;
    /** ODER **/&lt;br /&gt;
&lt;br /&gt;
    // bei neueren AVRs steht der Status in UCSRA/UCSR0A/UCSR1A, hier z.B. fuer ATmega16:&lt;br /&gt;
    while (!(UCSRA &amp;amp; (1&amp;lt;&amp;lt;UDRE)))  /* warten bis Senden moeglich                   */&lt;br /&gt;
    {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    UDR = &#039;x&#039;;                    /* schreibt das Zeichen x auf die Schnittstelle */&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Schreiben einer Zeichenkette (String) ===&lt;br /&gt;
&lt;br /&gt;
Die Aufgabe &amp;quot;String senden&amp;quot; wird durch zwei Funktionen abgearbeitet. Die universelle/controllerunabhängige Funktion uart_puts übergibt jeweils ein Zeichen der Zeichenkette an eine Funktion uart_putc, die abhängig von der vorhandenen Hardware implementiert werden muss. In der Funktion zum Senden eines Zeichens ist darauf zu achten, dass vor dem Senden geprüft wird, ob der UART bereit ist den &amp;quot;Sendeauftrag&amp;quot; entgegenzunehmen. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
// putc fuer AVR mit einem UART (z.B. AT90S8515)&lt;br /&gt;
int uart_putc(unsigned char c)&lt;br /&gt;
{&lt;br /&gt;
    while(!(USR &amp;amp; (1 &amp;lt;&amp;lt; UDRE)))  /* warte, bis UDR bereit */&lt;br /&gt;
    {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    UDR = c;                     /* sende Zeichen */&lt;br /&gt;
    return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/** ODER **/&lt;br /&gt;
&lt;br /&gt;
// bei neueren AVRs andere Bezeichnung fuer die Statusregister, hier ATmega16:&lt;br /&gt;
int uart_putc(unsigned char c)&lt;br /&gt;
{&lt;br /&gt;
    while (!(UCSRA &amp;amp; (1&amp;lt;&amp;lt;UDRE)))  /* warten bis Senden moeglich */&lt;br /&gt;
    {&lt;br /&gt;
    }                             &lt;br /&gt;
&lt;br /&gt;
    UDR = c;                      /* sende Zeichen */&lt;br /&gt;
    return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* puts ist unabhaengig vom Controllertyp */&lt;br /&gt;
void uart_puts (char *s)&lt;br /&gt;
{&lt;br /&gt;
    while (*s)&lt;br /&gt;
    {   /* so lange *s != &#039;\0&#039; also ungleich dem &amp;quot;String-Endezeichen&amp;quot; */&lt;br /&gt;
        uart_putc(*s);&lt;br /&gt;
        s++;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die in uart_putc verwendeten Schleifen, in denen gewartet wird bis die UART-Hardware zum senden bereit ist, sind insofern etwas kritisch, da während des Sendens eines Strings nicht mehr auf andere Ereignisse reagieren werden kann. Universeller ist die Nutzung von FIFO(first-in first-out)-Puffern, in denen die zu sendenden bzw. empfangenen Zeichen/Bytes zwischengespeichert und in Interruptroutinen an die U(S)ART-Hardware weitergegeben bzw. von ihr ausgelesen werden. Dazu existieren fertige Komponenten (Bibliotheken, Libraries), die man recht einfach in eigene Entwicklungen integrieren kann. Es empfiehlt sich, diese Komponenten zu nutzen und das Rad nicht neu zu erfinden.&lt;br /&gt;
&lt;br /&gt;
=== Schreiben von Variableninhalten ===&lt;br /&gt;
&lt;br /&gt;
Sollen Inhalte von Variablen (Ganzzahlen, Fließkomma) in &amp;quot;menschenlesbarer&amp;quot; Form gesendet werden, ist vor dem Transfer eine Umwandlung in Zeichen (&amp;quot;ASCII&amp;quot;) erforderlich. Bei nur einer Ziffer ist diese Umwandlung relativ einfach: man addiert den ASCII-Wert von Null zur Ziffer und kann diesen Wert direkt senden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
// hier uart_putc (s.o.)&lt;br /&gt;
&lt;br /&gt;
// Ausgabe von 0123456789&lt;br /&gt;
char c;&lt;br /&gt;
&lt;br /&gt;
for (uint8_t i=0; i&amp;lt;=9; ++i) {&lt;br /&gt;
    c = i + &#039;0&#039;;&lt;br /&gt;
    uart_putc( c );&lt;br /&gt;
    // verkuerzt: uart_putc( i + &#039;0&#039; );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Soll mehr als eine Ziffer ausgegeben werden, bedient man sich zweckmäßigerweise vorhandener Funktionen zur Umwandlung von Zahlen in Zeichenketten/Strings. Die Funktion der avr-libc zur Umwandlung von vorzeichenbehafteten 16bit-Ganzzahlen (int16_t) in Zeichenketten heißt &#039;&#039;itoa&#039;&#039; (Integer to ASCII). Man muss der Funktion einen Speicherbereich zur Verarbeitung (buffer) mit Platz für alle Ziffern, das String-Endezeichen (&#039;\0&#039;) und evtl. das Vorzeichen bereitstellen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
// hier uart_init, uart_putc, uart_puts (s.o.)&lt;br /&gt;
&lt;br /&gt;
int main(void)&lt;br /&gt;
{&lt;br /&gt;
   char s[7];&lt;br /&gt;
   int16_t i = -12345;&lt;br /&gt;
   &lt;br /&gt;
   uart_init();&lt;br /&gt;
&lt;br /&gt;
   itoa( i, s, 10 ); // 10 fuer radix -&amp;gt; Dezimalsystem&lt;br /&gt;
   uart_puts( s );&lt;br /&gt;
&lt;br /&gt;
   // da itoa einen Zeiger auf den Beginn von s zurueckgibt verkuerzt auch:&lt;br /&gt;
   uart_puts( itoa( i, s, 10 ) );&lt;br /&gt;
&lt;br /&gt;
   while (1) {&lt;br /&gt;
      ;&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
   return 0; // never reached &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für vorzeichenlose 16bit-Ganzzahlen (uint16_t) exisitert &#039;&#039;utoa&#039;&#039;. Die Funktionen für 32bit-Ganzzahlen (int32_t und uint32_t) heißen &#039;&#039;ltoa&#039;&#039; bzw. &#039;&#039;ultoa&#039;&#039;. Da 32bit-Ganzzahlen mehr Stellen aufweisen können, ist ein entsprechend größerer Pufferspeicher vorzusehen.&lt;br /&gt;
&lt;br /&gt;
Auch Fließkommazahlen (float/double) können mit breits vorhandenen Funktionen in Zeichenfolgen umgewandelt werden, dazu existieren die Funktionen &#039;&#039;dtostre&#039;&#039; und &#039;&#039;dtostrf&#039;&#039;. dtostre nutzt Exponentialschreibweise (&amp;quot;engineering&amp;quot;-Format). (Hinweis: z.Zt. existiert im avr-gcc kein &amp;quot;echtes&amp;quot; double, intern wird immer mit &amp;quot;einfacher Genauigkeit&amp;quot;, entsprechend float, gerechnet.) &lt;br /&gt;
&lt;br /&gt;
dtostrf und dtostre benötigen die libm.a der avr-libc. Bei Nutzung von Makefiles ist der Parameter -lm in in LDFLAGS anzugeben (Standard in den WinAVR/mfile-Makefilevorlagen). Nutzt man AVRStudio als IDE für den GNU-Compiler (gcc-Plugin) ist die libm.a unter Libaries auszuwählen: Project -&amp;gt; Configurations Options -&amp;gt; Libaries -&amp;gt; libm.a mit dem Pfeil nach rechts einbinden. Siehe auch die [[FAQ#Aktivieren_der_Floating_Point_Version_von_sprintf_beim_WinAVR_mit_AVR-Studio|FAQ]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
// hier uart_init, uart_putc, uart_puts (s.o.)&lt;br /&gt;
&lt;br /&gt;
/* lt. avr-libc Dokumentation:&lt;br /&gt;
char* dtostrf(&lt;br /&gt;
  double __val,&lt;br /&gt;
  char   __width,&lt;br /&gt;
  char   __prec,&lt;br /&gt;
  char * __s&lt;br /&gt;
)  &lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
int main(void)&lt;br /&gt;
{&lt;br /&gt;
   // Pufferspeicher ausreichend groß&lt;br /&gt;
   // evtl. Vorzeichen + width + Endezeichen:&lt;br /&gt;
   char s[8]; &lt;br /&gt;
   float f = -12.345;&lt;br /&gt;
   &lt;br /&gt;
   uart_init();&lt;br /&gt;
&lt;br /&gt;
   dtostrf( f, 6, 3, s ); &lt;br /&gt;
   uart_puts( s );&lt;br /&gt;
&lt;br /&gt;
   // verkürzt: uart_puts( dtostrf( f, 7, 3, s ) );&lt;br /&gt;
&lt;br /&gt;
   while (1) {&lt;br /&gt;
      ;&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
   return 0; // never reached &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Empfangen ==&lt;br /&gt;
=== einzelne Zeichen empfangen ===&lt;br /&gt;
&lt;br /&gt;
Zum Empfang von Zeichen muss der Empfangsteil des UART bei der Initialisierung aktiviert werden, indem das RXEN-Bit im jeweiligen Konfigurationsregister (UCSRB bzw UCSR0B/UCSR1B) gesetzt wird. Im einfachsten Fall wird solange gewartet, bis ein Zeichen empfangen wurde, dieses steht dann im UART-Datenregister (UDR bzw. UDR0 und UDR1 bei AVRs mit 2 UARTS) zur Verfügung (sogen. &amp;quot;Polling-Betrieb&amp;quot;). Ein Beispiel für den ATmega16:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;inttypes.h&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/* Zusaetzlich zur Baudrateneinstellung und der weiteren Initialisierung: */&lt;br /&gt;
void Usart_EnableRX(void)&lt;br /&gt;
{&lt;br /&gt;
    UCSRB |= ( 1 &amp;lt;&amp;lt; RXEN );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* Zeichen empfangen */&lt;br /&gt;
uint8_t uart_getc(void)&lt;br /&gt;
{&lt;br /&gt;
    while (!(UCSRA &amp;amp; (1&amp;lt;&amp;lt;RXC)))   // warten bis Zeichen verfuegbar&lt;br /&gt;
        ;&lt;br /&gt;
    return UDR;                   // Zeichen aus UDR an Aufrufer zurueckgeben&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Diese Funktion blockiert den Programmablauf. Alternativ kann das RXC-Bit in einer Programmschleife abgefragt werden und dann nur bei gesetztem RXC-Bit UDR ausgelesen werden. Eleganter und in den meisten Anwendungsfällen &amp;quot;stabiler&amp;quot; ist die Vorgehensweise, die empfangenen Zeichen in einer Interrupt-Routine einzulesen und zur späteren Verarbeitung in einem Eingangsbuffer (FIFO-Buffer) zwischenzuspeichern. Dazu existieren fertige und gut getestete [[Libraries|Bibliotheken]] &amp;lt;!-- &amp;quot;echte Libraries&amp;quot; (.a) wie im Verweis beschrieben sind hier eigentlich nicht gemeint, verwirrt hier etwas, da AVR-&amp;quot;Libraries&amp;quot; meist per #defines anpassbare Source-Codes sind, vielleicht so: --&amp;gt; und Quellcodekomponenten (z.B. UART-Library von P. Fleury, procyon-avrlib und einige in der &amp;quot;Academy&amp;quot; von avrfreaks.net).&lt;br /&gt;
&lt;br /&gt;
siehe auch:&lt;br /&gt;
* [http://www.nongnu.org/avr-libc/user-manual/group__avr__stdlib.html Dokumenation der avr-libc/stdlib.h]&lt;br /&gt;
* [http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Die_Nutzung_von_printf Die Nutzung von printf]&lt;br /&gt;
* [http://homepage.hispeed.ch/peterfleury/ Peter Fleurys] UART-Bibiliothek fuer avr-gcc/avr-libc&lt;br /&gt;
&amp;lt;!-- nimmermehr: * siehe auch: Weiterführende Informationen inkl. Beispielen für die Nutzung von stdio-Funktionen (printf etc.) im [[AVR-Tutorial:_UART]]. --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
TODO: 9bit&lt;br /&gt;
&lt;br /&gt;
=== Empfang von Zeichenketten (Strings) ===&lt;br /&gt;
&lt;br /&gt;
Beim Empfang von Zeichenketten, muß man sich zunächst darüber im klaren sein, daß es ein Kriterium geben muß, an dem der µC erkennen kann, wann ein String zu Ende ist. Sehr oft wird dazu das Zeichen &#039;Return&#039; benutzt, um das Ende eines Strings zu markieren. Dies ist vom Benutzer einfach eingebbar und er ist auch daran gewöhnt, daß er eine Eingabezeile mit einem Druck auf die Return Taste abgeschlossen wird.&lt;br /&gt;
&lt;br /&gt;
Prinzipiell gibt es jedoch keine Einschränkung bezüglich dieses speziellen Zeichens. Es muß nur sichergestellt werden, daß dieses spezielle &#039;Ende eines Strings&#039; - Zeichen nicht mit einem im Text vorkommenden Zeichen verwechselt werden kann. Wenn also im zu übertragenden Text beispielsweise kein &#039;;&#039; vorkommt, dann spricht nichts dagegen, einen String mit einem &#039;;&#039; abschließen zu lassen.&lt;br /&gt;
&lt;br /&gt;
Im Folgenden wird die durchaus übliche Annahme getroffen, daß eine Stringübertragung identisch ist mit der Übertragung einer Textzeile und daher mit einem Return (&#039;\n&#039;) abgeschlossen wird.&lt;br /&gt;
&lt;br /&gt;
Das Problem der Übertragung eines Strings reduziert sich damit auf die Aufgabenstellung: Empfange und Sammle Zeichen in einem char Array, bis entweder das Array voll ist oder das &#039;String Ende Zeichen&#039; empfangen wurde. Danach wird der empfangene Text noch mit einem &#039;\0&#039; Zeichen abgeschlossen um einen Standard C-String daraus zu machen, mit dem dann weiter gearbeitet werden kann.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;C&amp;gt;&lt;br /&gt;
/* Zeichen empfangen */&lt;br /&gt;
uint8_t uart_getc(void)&lt;br /&gt;
{&lt;br /&gt;
    while (!(UCSRA &amp;amp; (1&amp;lt;&amp;lt;RXC)))   // warten bis Zeichen verfuegbar&lt;br /&gt;
        ;&lt;br /&gt;
    return UDR;                   // Zeichen aus UDR an Aufrufer zurueckgeben&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void uart_gets( char* Buffer, uint8_t MaxLen )&lt;br /&gt;
{&lt;br /&gt;
  uint8_t NextChar;&lt;br /&gt;
  uint8_t StringLen = 0;&lt;br /&gt;
&lt;br /&gt;
  NextChar = uart_getc();         // Warte auf und empfange das nächste Zeichen&lt;br /&gt;
&lt;br /&gt;
                                  // Sammle solange Zeichen, bis:&lt;br /&gt;
                                  // * entweder das String Ende Zeichen kam&lt;br /&gt;
                                  // * oder das aufnehmende Array voll ist&lt;br /&gt;
  while( NextChar != &#039;\n&#039; &amp;amp;&amp;amp; StringLen &amp;lt; MaxLen - 1 ) {&lt;br /&gt;
    *Buffer++ = NextChar;&lt;br /&gt;
    StringLen++;&lt;br /&gt;
    NextChar = uart_getc();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
                                  // Noch ein &#039;\0&#039; anhängen um einen Standard&lt;br /&gt;
                                  // C-String daraus zu machen&lt;br /&gt;
  *Buffer = &#039;\0&#039;;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/C&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Beim Aufruf ist darauf zu achten, dass das empfangende Array auch mit einer&lt;br /&gt;
vernünftigen Größe definiert wird.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;C&amp;gt;&lt;br /&gt;
  char Line[40];      // String mit maximal 39 zeichen&lt;br /&gt;
&lt;br /&gt;
  uart_gets( Line, sizeof( Line ) );&lt;br /&gt;
&amp;lt;/C&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bei der Benutzung von sizeof() ist allerdings zu beachten, dass sizeof() nicht die Anzahl der Elemente des Arrays liefert, sondern die Länge in Byte. Da ein char nur ein Byte lang ist, passt der Aufruf &#039;uart_gets(Line, sizeof( Line ) );&#039; in diesem Fall. Falls man - aus welchen Gründen auch immer - andere Datentypen benutzen möchte, sollte man zur korrekten Angabe der Array-Länge folgende Vorgehensweise bevorzugen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;C&amp;gt;&lt;br /&gt;
  int Line[40];      // Array vom Typ int&lt;br /&gt;
&lt;br /&gt;
  uart_gets( Line, sizeof( Line ) / sizeof( Line[0] ) );&lt;br /&gt;
&amp;lt;/C&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Interruptbetrieb==&lt;br /&gt;
&lt;br /&gt;
Beim ATMEGA8 muss das RXCIE Bit im Register UCSRB gesetzt werden, damit ein Interrupt ausgelöst werden kann.&lt;br /&gt;
Der Interrupt wird immer ausgelöst, wenn Daten erfolgreich empfangen wurden.&lt;br /&gt;
&lt;br /&gt;
Zusätzlich braucht man die Routine:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
ISR (USART_RXC_vect) {&lt;br /&gt;
   //irgendein Code&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
natürlich muss &amp;quot;Global Interrupt Enable&amp;quot; Aktiviert sein.&lt;br /&gt;
!! Nur getestet beim ATMEGA8 !!&lt;br /&gt;
&lt;br /&gt;
[BAUSTELLE! Aus Lerngründen eventuell als eigenen UART-Interrupt-Block hinter den grundlegenden Interrupt-Teil im Tutorial und hier eine kurze Einführung und einen Verweis darauf anbieten.]&lt;br /&gt;
&lt;br /&gt;
* Unterschied Polling-Betrieb (bisher, oben) und Interrupt-Betrieb&lt;br /&gt;
* Empfangen (Receive)&lt;br /&gt;
** Verändertes UART-Init, ISR (RXC), ggf. Fallstricke ([http://www.mikrocontroller.net/topic/84256#707214 UDR in der ISR lesen!]), Philosophie einer ISR (kurz und schmerzlos), Datenaustausch ISR zu Restprogramm (volatile)&lt;br /&gt;
** Einfachstbeispiel ([http://www.mikrocontroller.net/topic/84228#707052 Echo] (noch buggy beim Datenzugriff, siehe Lit. 2+3!)), ggf. LED zur ISR-Empfangsanzeige oder Overflow-Anzeige&lt;br /&gt;
* FIFO-Puffer, Ringpuffer&lt;br /&gt;
* Senden (Transmit)&lt;br /&gt;
** Variante &amp;quot;UART Data Register Empty&amp;quot; (UDRE) &lt;br /&gt;
** Variante &amp;quot;UART Transmit Complete&amp;quot; (TXC) &lt;br /&gt;
* Fertige UART-Bibliotheken (-&amp;gt;Fleury, -&amp;gt;Procyon)&lt;br /&gt;
* Literatur: &lt;br /&gt;
** 1/ [http://www.avrfreaks.net/index.php?name=PNphpBB2&amp;amp;file=viewtopic&amp;amp;t=48188 avrfreaks.net Tutorial] inkl. Diskussion (engl.)&lt;br /&gt;
** 2/ avr-libc FAQ: [http://www.nongnu.org/avr-libc/user-manual/FAQ.html#faq_16bitio Why do some 16-bit timer registers sometimes get trashed?]&lt;br /&gt;
** 3/ [[Interrupt]] und atomarer Datenzugriff&lt;br /&gt;
&lt;br /&gt;
==Software-UART==&lt;br /&gt;
&lt;br /&gt;
Falls die Zahl der vorhandenen Hardware-UARTs nicht ausreicht, können weitere Schnittstellen über sogennante Software-UARTs ergänzt werden. Es gibt dazu (mindestens) zwei Ansätze: &lt;br /&gt;
* Der bei AVRs üblichste Ansatz basiert auf dem Prinzip, dass ein externer Interrupt-Pin für den Empfang (&amp;quot;RX&amp;quot;) genutzt wird. Das Startbit löst den Interrupt aus, in der Interrupt-Routine (ISR) wird der externe Interrupt deaktiviert und ein Timer aktiviert. In der Interrupt-Routine des Timers wird der Zustand des Empfangs-Pins entsprechend der Baudrate abgetastet. Nach Empfang des Stop-Bits wird der externe Interrupt wieder aktiviert. Senden kann über einen beliebigen Pin (&amp;quot;TX&amp;quot;) erfolgen, der entsprechend der Baudrate und dem zu sendenden Zeichen auf 0 oder 1 gesetzt wird. Die Implementierung ist nicht ganz einfach, es existieren dazu aber fertige Bibliotheken (z.B. bei [http://www.avrfreaks.net/ avrfreaks] oder in der [http://hubbard.engr.scu.edu/embedded/avr/avrlib/ Procyon avrlib]).&lt;br /&gt;
* Ein weiterer Ansatz erfordert keinen Pin mit &amp;quot;Interrupt-Funktion&amp;quot; aber benötigt mehr Rechenzeit. Jeder Input-Pin kann als Empfangspin (RX) dienen. Über einen Timer wird der Zustand des RX-Pins mit einem vielfachen der Baudrate abgetastet (dreifach scheint üblich) und High- bzw. Lowbits anhand einer Mindestanzahl identifiziert. (Beispiel: &amp;quot;Generic Software Uart&amp;quot; Application-Note von IAR)&lt;br /&gt;
&lt;br /&gt;
Neuere AVRs (z.B. ATtiny26 oder ATmega48,88,168,169) verfügen über ein Universal Serial Interface (USI), das teilweise UART-Funktion übernehmen kann. Atmel stellt eine Application-Note bereit, in der die Nutzung des USI als UART erläutert wird (im Prinzip &amp;quot;Hardware-unterstützter Software-UART&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
==Handshaking==&lt;br /&gt;
Wenn der Sender ständig sendet, wird irgendwann der Fall eintreten, daß der Empfänger nicht bereit ist, neue Zeichen zu empfangen. In diesem Fall muß durch ein &#039;&#039;&#039;Handshake-Verfahren&#039;&#039;&#039; die Situation bereinigt werden. Handshake bedeutet nichts anderes, als daß der Empfänger dem Sender mitteilt, daß er zur Zeit keine Daten annehmen kann und der Sender die Übertragung der nächsten Zeichen solange einstellen soll, bis der Empfänger signalisiert, daß er wieder Zeichen aufnehmen kann.&lt;br /&gt;
===Hardwarehandshake (RTS/CTS)===&lt;br /&gt;
Beim Hardwarehandshake werden zusätzlich zu den beiden Daten-Übertragungsleitungen noch 2 weitere Leitungen benötigt: &#039;&#039;&#039;RTS&#039;&#039;&#039; (&#039;&#039;&#039;R&#039;&#039;&#039;equest &#039;&#039;&#039;T&#039;&#039;&#039;o &#039;&#039;&#039;S&#039;&#039;&#039;end) und &#039;&#039;&#039;CTS&#039;&#039;&#039; (&#039;&#039;&#039;C&#039;&#039;&#039;lear &#039;&#039;&#039;T&#039;&#039;&#039;o &#039;&#039;&#039;S&#039;&#039;&#039;end). Jeder der beiden Kommunikationspartner ist verpflichtet, bevor ein Zeichen gesendet wird, den Zustand der &#039;&#039;&#039;RTS&#039;&#039;&#039; Leitung zu überprüfen. Nur wenn die Gegenstelle darauf Empfangsbereitschaft signalisiert, darf das Zeichen gesendet werden. Um der Gegenstelle zu signalisieren, daß sie zur Zeit keine Zeichen schicken soll, wird die Leitung &#039;&#039;&#039;CTS&#039;&#039;&#039; benutzt.&lt;br /&gt;
&lt;br /&gt;
===Softwarehandshake (XON/XOFF)===&lt;br /&gt;
Beim Softwarehandshake sind keine speziellen Leitungen notwendig. Statt dessen werden besondere ASCII-Zeichen benutzt, die der Gegenstelle signalisieren, daß Senden einzustellen bzw. wieder aufzunehmen.&amp;lt;br /&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;XOFF&#039;&#039;&#039; Aufforderung das Senden einzustellen&lt;br /&gt;
* &#039;&#039;&#039;XON&#039;&#039;&#039;  Gegenstelle darf wieder senden&lt;br /&gt;
&lt;br /&gt;
Nachteilig bei einem Softwarehandshake ist es, dass dadurch keine direkte binäre Datenübertragung mehr möglich ist. Von den möglichen 256 Bytewerten werden ja 2 (nämlich &#039;&#039;&#039;XON&#039;&#039;&#039; und &#039;&#039;&#039;XOFF&#039;&#039;&#039;) für besondere Zwecke benutzt und fallen daher aus.&lt;br /&gt;
&lt;br /&gt;
==Fehlersuche==&lt;br /&gt;
Erstaunlich oft wird im Forum der Hilferuf laut: &amp;quot;Meine UART funktioniert nicht, was mache ich falsch&amp;quot;. In der überwiegenden Mehrzahl der Fälle stellt sich dann heraus, daß es sich um ein Hardwareproblem handelt, wobei da wiederrum der Löwenanteil auf das Konto einer nicht korrekt eingestellten Taktrate geht: Der µC benutzt nicht einen angeschlossenen Quarz, so wie er auch im Programm eingetragen ist, sondern läuft immer noch mit dem internen RC-Takt. Daraus resultiert aber auch, daß der Baudraten Konfigurationswert falsch berechnet wird.&lt;br /&gt;
&lt;br /&gt;
Eine Checkliste zum Aufspüren solcher Fehler findet sich [[AVR_Checkliste#UART.2FUSART|hier]].&lt;br /&gt;
&lt;br /&gt;
= Analoge Ein- und Ausgabe =&lt;br /&gt;
&lt;br /&gt;
Analoge Eingangswerte werden in der Regel über den AVR Analog-Digital-Converter (AD-Wandler, ADC) eingelesen, der in vielen Typen verfügbar ist (typisch 10bit Auflösung). Durch diesen werden analogen Signale (Spannungen) in digitale Zahlenwerte gewandelt. Bei AVRs, die über keinen internen AD-Wandler verfügen (z.B. ATmega162), kann durch externe Beschaltung (R/C-Netzwerk und &amp;quot;Zeitmessung&amp;quot;) die Funktion des AD-Wandlers &amp;quot;emuliert&amp;quot; werden.&lt;br /&gt;
&lt;br /&gt;
Es existieren keine AVRs mit eingebautem Digital-Analog-Konverter (DAC). Diese Funktion muss durch externe Komponenten nachgebildet werden (z.B. PWM und &amp;quot;Glättung&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Unabhängig davon besteht natürlich immer die Möglichkeit, spezielle Bausteine zur Analog-Digital- bzw. Digital-Analog-Wandlung zu nutzen und diese über eine digitale Schnittstelle (z.b. SPI oder I2C) mit einem AVR anzusteuern.&lt;br /&gt;
&lt;br /&gt;
== AC (Analog Comparator) ==&lt;br /&gt;
&lt;br /&gt;
Der Comparator vergleicht 2 Spannungen an den Pins AIN0 und AIN1 und gibt einen Status aus welche der beiden Spannungen größer ist. AIN0 Dient dabei als Referenzspannung (Sollwert) und AIN1 als Vergleichsspannung (Istwert). Als Referenzspannung kann auch alternativ eine interne Referenzspannung ausgewählt werden.&amp;lt;BR&amp;gt;&lt;br /&gt;
&amp;lt;BR&amp;gt;&lt;br /&gt;
Liegt die Vergleichsspannung (IST) unter der der Referenzspannung (SOLL) gibt der Comperator eine logische 1 aus. Ist die Vergleichsspannung hingegen größer als die Referenzspannung wird eine logische 0 ausgegeben.&amp;lt;BR&amp;gt;&lt;br /&gt;
&amp;lt;BR&amp;gt;&lt;br /&gt;
Der Comperator arbeitet völlig autark bzw. parallel zum Prozessor. Für mobile Anwendungen empfiehlt es sich ihn abzuschalten sofern er nicht benötigt wird, da er ansonsten Strom benötigt. Der Comparator kann Interruptgesteuert abgefragt werden oder im Pollingbetrieb.&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Steuer- bzw. Statusregister ist wie folgt aufgebaut:&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ACSR (0x28) - Analog Comparator Status Register&amp;lt;BR&amp;gt;&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Bit&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 7&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 6&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 5&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 4&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 2&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Name&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ACD&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ACBG&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ACO&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ACI&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ACIE&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ACIC&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ACIS1&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ACIS0&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;R/W&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Initialwert&#039;&#039;&#039;&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; | n/a&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;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
Bit 7 ACD - Analog Comparator Disable: 0 = Comparator ein, 1 = Comparator aus. Wird dieses Bit geändert kann ein Interrupt ausgelöst werden. Soll dies vermieden werden muß das Bit 3 ACIE ggf. abgeschaltet werden.&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
Bit 6 ACBG - Analog Comparator Bandgap Select: Ermöglicht das umschalten zwischen interner und externer Referenzspannung. 1 = interne (~1,3 Volt), 0 = externe Referenzspannung (an Pin AIN0)&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
Bit 5 ACO - Analog Comparator Output: Hier wird das Ergebnis des Vergleichs angezeigt. Es liegt typischerweise nach 1-2 Taktzyklen vor. &amp;lt;BR&amp;gt;&lt;br /&gt;
Ergebnis: &amp;lt;BR&amp;gt;IST &amp;lt; SOLL --&amp;gt; 1&amp;lt;BR&amp;gt;&lt;br /&gt;
IST &amp;gt; SOLL --&amp;gt; 0&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
Bit 4 ACI - Analog Comparator Interrupt Flag: Dieses Bit wird von der Hardware gesetzt wenn ein Interruptereignis das in Bit 0 und 1 definiert ist eintritt. Dieses Bit löst noch keinen Interrupt aus! Die Interruptroutine wird nur dann ausgeführt wenn das Bit 3 ACIE gesetzt ist und global Interrupts erlaubt sind (I-Bit in SREG=1). Das Bit 4 ACI wird wieder gelöscht wenn die Interruptroutine ausgeführt wurde oder wenn manuell das Bit auf 1 gesetzt wird. Das Bit kann für Abfragen genutzt werden, steuert oder konfuguriert aber nicht den Comparator.&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
Bit 3 ACIE - Analog Comparator Interrupt Enable: Ist das Bit auf 1 gesetzt wird immer ein Interrupt ausgelöst wenn das Ereignis das in Bit 1 und 0 definiert ist eintritt.&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
Bit 2 ACIC - Analog Comparator Input Capture Enable: Wird das Bit gesetzt wird der Comparatorausgang intern mit dem Counter 1 verbunden. Es könnten damit z.b. die Anzahl der Vergleiche im Counter1 gezählt werden. Um den Comparator an den Timer1 Input Capture Interrupt zu verbinden muß im Timerregister das TICIE1 Bit auf 1 gesetzt werden. Der Trigger wird immer dann ausgelöst wenn das in Bit 1 und 0 definierte Ereignis eintritt.&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
Bit 1,0 ACIS1,ACIS0 - Analog Comparator Interrupt select: Hier wird definiert welche Ereignisse einen Interrupt auslösen sollen:&amp;lt;BR&amp;gt;&lt;br /&gt;
00 = Interrupt auslösen bei jedem Flankenwechsel&amp;lt;BR&amp;gt;&lt;br /&gt;
10 = Interrupt auslösen bei fallender Flanke&amp;lt;BR&amp;gt;&lt;br /&gt;
11 = Interrupt auslösen bei steigender Flanke&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
Werden diese Bit geändert kann ein Interrupt ausgelöst werden. Soll dies vermieden werden muß das Bit 3 gelöscht werden.&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== ADC (Analog Digital Converter) ==&lt;br /&gt;
&lt;br /&gt;
Der Analog-Digital-Konverter (ADC) wandelt analoge Signale in digitale Werte um, welche vom Controller interpretiert werden können. Einige AVR-Typen haben bereits einen mehrkanaligen Analog-Digital-Konverter eingebaut. Die Genauigkeit, mit welcher ein analoges Signal aufgelöst werden kann, wird durch die Auflösung des ADC in Anzahl Bits angegeben, man hört bzw. liest jeweils von 8-Bit-ADC oder 10-Bit-ADC oder noch höher. ADCs die in AVRs enthalten sind haben zur Zeit eine maximale Auflösung von 10-Bit.&lt;br /&gt;
&lt;br /&gt;
Ein ADC mit 8 Bit Auflösung kann somit das analoge Signal mit einer Genauigkeit von 1/256 des Maximalwertes darstellen. Wenn wir nun mal annehmen, wir hätten eine Spannung zwischen 0 und 5 Volt und eine Auflösung von 3 Bit, dann könnten&lt;br /&gt;
die Werte 0V, 0.625V, 1.25, 1.875V, 2.5V, 3.125V, 3.75, 4.375, 5V&lt;br /&gt;
daherkommen, siehe dazu folgende Tabelle:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div align=&amp;quot;center&amp;quot;&amp;gt;&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;Eingangsspannung am ADC&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;Entsprechender Messwert&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0...&amp;lt;0.625V&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0.625...&amp;lt;1.25V&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1.25...&amp;lt;1.875V&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 2&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1.875...&amp;lt;2.5V&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 2.5...&amp;lt;3.125V&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 4&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3.125...&amp;lt;3.75V&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 5&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3.75...&amp;lt;4.375V&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 6&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 4.375...5V&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 7&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Angaben sind natürlich nur ungefähr. Je höher nun die Auflösung des Analog-Digital-Konverters ist, also je mehr Bits er hat, um so genauer kann der Wert erfasst werden.&lt;br /&gt;
&lt;br /&gt;
=== Der interne ADC im AVR ===&lt;br /&gt;
&lt;br /&gt;
Wenn es einmal etwas genauer sein soll, dann müssen wir auf einen AVR mit eingebautem Analog-Digital-Wandler (ADC) zurückgreifen, die über mehrere Kanäle verfügen. Kanäle heißt in diesem Zusammenhang, dass zwar bis zu zehn analoge Eingänge am AVR verfügbar sind, aber nur ein &amp;quot;echter&amp;quot; Analog-Digital-Wandler zur Verfügung steht, vor der eigentlichen Messung ist also einzustellen, welcher Kanal (&amp;quot;Pin&amp;quot;) mit dem Wandler verbunden und gemessen wird.&lt;br /&gt;
&lt;br /&gt;
Die Umwandlung innerhalb des AVR basiert auf der schrittweisen Näherung. Beim AVR müssen die Pins &#039;&#039;&#039;AGND&#039;&#039;&#039; und &#039;&#039;&#039;AVCC&#039;&#039;&#039; beschaltet werden. Für genaue Messungen sollte AVCC über ein L-C Netzwerk mit VCC verbunden werden, um Spannungsspitzen und -einbrüche vom Analog-Digital-Wandler fernzuhalten. Im Datenblatt findet sich dazu eine Schaltung, die 10uH und 100nF vorsieht.&lt;br /&gt;
&lt;br /&gt;
Das Ergebnis der Analog-Digital-Wandlung wird auf eine Referenzspannung bezogen. Aktuelle AVRs bieten drei Möglichkeiten zur Wahl dieser Spannung:&lt;br /&gt;
&lt;br /&gt;
* Eine externe Referenzspannung von maximal &#039;&#039;&#039;Vcc&#039;&#039;&#039; am Anschlusspin &#039;&#039;&#039;AREF&#039;&#039;&#039;. Die minimale (externe) Referenzspannung darf jedoch nicht beliebig niedrig sein, vgl. dazu das (aktuellste) Datenblatt des verwendeten Controllers. &lt;br /&gt;
&lt;br /&gt;
* Verfügt der AVR über eine interne Referenzspannung, kann diese genutzt werden. Alle aktuellen AVRs mit internem AD-Wandler sollten damit ausgestattet sein (vgl. Datenblatt: 2,56V oder 1,1V je nach Typ). Das Datenblatt gibt auch über die Genauigkeit dieser Spannung Auskunft.&lt;br /&gt;
&lt;br /&gt;
* Die &#039;&#039;&#039;interne&#039;&#039;&#039; Referenzspannung wird auf &#039;&#039;&#039;Vcc&#039;&#039;&#039; bezogen, eine externe Referenzspannung auf &#039;&#039;&#039;GND (Masse)&#039;&#039;&#039;. Davon unabhängig werden digitalisierte Spannungen &#039;&#039;&#039;immer&#039;&#039;&#039; auf GND bezogen. Beim ATMEGA8 z.B. ist der Pin AREF über 32kOhm mit GND verbunden, d.h. man muss diese doch extrem niedrige Eingangsimpedanz mit in die Berechnung für einen Spannungsteiler einbeziehen, bzw. kann diesen Widerstand als R2 gleich mit benutzen. Formel für Spannungsteiler: Udiv = U / ((R1 + R2) / R2)&lt;br /&gt;
&lt;br /&gt;
Bei Nutzung von Vcc oder der internen Referenz wird empfohlen, einen Kondensator zwischen dem AREF-Pin und GND anzuordnen. Die Festlegung, welche Spannungsreferenz genutzt wird, erfolgt z.B. beim ATmega16 mit den Bits REFS1/REFS0 im ADMUX-Register. Die zu messende Spannung muss im Bereich zwischen &#039;&#039;&#039;AGND&#039;&#039;&#039; und &#039;&#039;&#039;AREF&#039;&#039;&#039; (egal ob intern oder extern) liegen. &lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;&#039;ADC&#039;&#039;&#039; kann in zwei verschiedenen Betriebsarten verwendet werden:&lt;br /&gt;
&lt;br /&gt;
; Einfache Wandlung (Single Conversion) : In dieser Betriebsart wird der Wandler bei Bedarf vom Programm angestoßen für jeweils eine Messung.&lt;br /&gt;
&lt;br /&gt;
; Frei laufend (Free Running) : In dieser Betriebsart erfasst der Wandler permanent die anliegende Spannung und schreibt diese in das &#039;&#039;&#039;ADC Data Register&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==== Die Register des ADC ====&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;&#039;ADC&#039;&#039;&#039; verfügt über eigene Register. Im Folgenden die Registerbeschreibung eines  ATMega16, welcher über 8 ADC-Kanäle verfügt. Die Register unterscheiden sich jedoch nicht erheblich von denen anderer AVRs (vgl. Datenblatt).&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;ADCSRA&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;ADC&#039;&#039;&#039; &#039;&#039;&#039;C&#039;&#039;&#039;ontrol and &#039;&#039;&#039;S&#039;&#039;&#039;tatus &#039;&#039;&#039;R&#039;&#039;&#039;egister A.&amp;lt;br /&amp;gt;&lt;br /&gt;
In diesem Register stellen wir ein, wie wir den &#039;&#039;&#039;ADC&#039;&#039;&#039; verwenden möchten.&amp;lt;br /&amp;gt;&lt;br /&gt;
Das Register ist wie folgt aufgebaut:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Bit&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 7&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 6&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 5&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 4&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 2&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Name&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ADEN&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ADSC&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ADFR&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ADIF&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ADIE&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ADPS2&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ADPS1&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ADPS0&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;R/W&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Initialwert&#039;&#039;&#039;&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;
| 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;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ADEN&#039;&#039;&#039; (&#039;&#039;&#039;AD&#039;&#039;&#039;C &#039;&#039;&#039;En&#039;&#039;&#039;able)&lt;br /&gt;
:Dieses Bit muss gesetzt werden, um den &#039;&#039;&#039; ADC&#039;&#039;&#039; überhaupt zu aktivieren. Wenn das Bit nicht gesetzt ist, können die Pins wie normale I/O-Pins verwendet werden.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ADSC&#039;&#039;&#039; (&#039;&#039;&#039;AD&#039;&#039;&#039;C &#039;&#039;&#039;S&#039;&#039;&#039;tart &#039;&#039;&#039;C&#039;&#039;&#039;onversion)&lt;br /&gt;
:Mit diesem Bit wird ein Messvorgang gestartet. In der frei laufenden Betriebsart muss das Bit gesetzt werden, um die kontinuierliche Messung zu aktivieren.&lt;br /&gt;
:Wenn das Bit nach dem Setzen des &#039;&#039;&#039;ADEN&#039;&#039;&#039;-Bits zum ersten Mal gesetzt wird, führt der Controller zuerst eine zusätzliche Wandlung und erst dann die eigentliche Wandlung aus. Diese zusätzliche Wandlung wird zu Initialisierungszwecken durchgeführt.&lt;br /&gt;
:Das Bit bleibt nun so lange auf 1, bis die Umwandlung abgeschlossen ist, im Initialisierungsfall entsprechend bis die zweite Umwandlung erfolgt ist und geht danach auf 0.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ADFR&#039;&#039;&#039; (&#039;&#039;&#039;AD&#039;&#039;&#039;C &#039;&#039;&#039;F&#039;&#039;&#039;ree &#039;&#039;&#039;R&#039;&#039;&#039;un select)&lt;br /&gt;
:Mit diesem Bit wird die Betriebsart eingestellt.&lt;br /&gt;
:Ist das Bit auf 1 gesetzt arbeitet der ADC im Freerunning Modus. Dabei wird das Datenregister permanent aktualisiert. Ist das Bit hingegen auf 0 gesetzt macht der ADC nur eine Single Conversion. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ADIF&#039;&#039;&#039; (&#039;&#039;&#039;AD&#039;&#039;&#039;C &#039;&#039;&#039;I&#039;&#039;&#039;nterrupt &#039;&#039;&#039;F&#039;&#039;&#039;lag)&lt;br /&gt;
:Dieses Bit wird vom &#039;&#039;&#039; ADC&#039;&#039;&#039; gesetzt, sobald eine Umwandlung erfolgt ist und das &#039;&#039;&#039;ADC Data Register&#039;&#039;&#039; aktualisiert wurde. Das Bit wird bei lesendem Zugriff auf &#039;&#039;&#039;ADC(L,H)&#039;&#039;&#039; automatisch (d.h. durch die Hardware) gelöscht.&lt;br /&gt;
:Wenn das &#039;&#039;&#039;ADIE&#039;&#039;&#039; Bit sowie das &#039;&#039;&#039;I-Bit&#039;&#039;&#039; im AVR &#039;&#039;&#039;Statusregister&#039;&#039;&#039; gesetzt ist, wird der &#039;&#039;&#039;ADC Interrupt&#039;&#039;&#039; ausgelöst und die Interrupt-Behandlungsroutine aufgerufen.&lt;br /&gt;
:Das Bit wird automatisch gelöscht, wenn die Interrupt-Behandlungsroutine aufgerufen wird. Es kann jedoch auch gelöscht werden, indem eine logische 1 in das Register geschrieben wird.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ADIE&#039;&#039;&#039; (&#039;&#039;&#039;AD&#039;&#039;&#039;C &#039;&#039;&#039;I&#039;&#039;&#039;nterrupt &#039;&#039;&#039;E&#039;&#039;&#039;nable)&lt;br /&gt;
:Wenn dieses Bit gesetzt ist und ebenso das &#039;&#039;&#039; I-Bit&#039;&#039;&#039; im Statusregister &#039;&#039;&#039;SREG&#039;&#039;&#039;, dann wird der &#039;&#039;&#039; ADC-Interrupt&#039;&#039;&#039; aktiviert.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ADPS2...ADPS0&#039;&#039;&#039; (&#039;&#039;&#039;AD&#039;&#039;&#039;C &#039;&#039;&#039;P&#039;&#039;&#039;rescaler &#039;&#039;&#039;S&#039;&#039;&#039;elect Bits)&lt;br /&gt;
:Diese Bits bestimmen den Teilungsfaktor zwischen der Taktfrequenz und dem Eingangstakt des &#039;&#039;&#039;ADC&#039;&#039;&#039;.&lt;br /&gt;
:Der &#039;&#039;&#039;ADC&#039;&#039;&#039; benötigt einen eigenen Takt, welchen er sich selber aus der CPU-Taktfreqenz erzeugt. Der &#039;&#039;&#039;ADC&#039;&#039;&#039;-Takt sollte zwischen 50 und 200kHz sein.&lt;br /&gt;
:Der Vorteiler muss also so eingestellt werden, dass die CPU-Taktfrequenz dividiert durch den Teilungsfaktor einen Wert zwischen 50-200kHz ergibt.&lt;br /&gt;
:Bei einer CPU-Taktfrequenz von 4MHz beispielsweise rechnen wir&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;&lt;br /&gt;
\begin{matrix}&lt;br /&gt;
TF_{min}=\frac{CLK}{200\,\mathrm{kHz}}=\frac{4000000}{200000}=\mathbf{20}&lt;br /&gt;
\\&lt;br /&gt;
\\&lt;br /&gt;
TF_{max}=\frac{CLK}{50\,\mathrm{kHz}}=\frac{4000000}{50000}=\mathbf{80}&lt;br /&gt;
\end{matrix}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Somit kann hier der Teilungsfaktor 32 oder 64 verwendet werden. Im Interesse der schnelleren Wandlungszeit werden wir hier den Faktor 32 einstellen.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&lt;br /&gt;
{| style=&amp;quot;&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ADPS2&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ADPS1&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ADPS0&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;Teilungsfaktor&#039;&#039;&#039;&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;
| align=&amp;quot;center&amp;quot; | 2&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;
| align=&amp;quot;center&amp;quot; | 2&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;
| align=&amp;quot;center&amp;quot; | 4&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;
| align=&amp;quot;center&amp;quot; | 8&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;
| align=&amp;quot;center&amp;quot; | 16&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;
| align=&amp;quot;center&amp;quot; | 32&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;
| align=&amp;quot;center&amp;quot; | 64&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;
| align=&amp;quot;center&amp;quot; | 128&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;ADCL&#039;&#039;&#039;&amp;lt;br /&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;ADCH&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;ADC &#039;&#039;&#039; Data Register&amp;lt;br /&amp;gt;&lt;br /&gt;
Wenn eine Umwandlung abgeschlossen ist, befindet sich der gemessene Wert in&lt;br /&gt;
diesen beiden Registern. Von &#039;&#039;&#039;ADCH&#039;&#039;&#039; werden nur die beiden niederwertigsten Bits verwendet. Es müssen immer beide Register ausgelesen werden, und zwar immer &#039;&#039;&#039;in der Reihenfolge: ADCL, ADCH&#039;&#039;&#039;. &lt;br /&gt;
Der effektive Messwert ergibt sich dann zu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
x = ADCL;       // mit uint16_t x&lt;br /&gt;
x += (ADCH&amp;lt;&amp;lt;8); // in zwei Zeilen (LSB/MSB-Reihenfolge und&lt;br /&gt;
                // C-Operatorpriorität sichergestellt)&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
oder &lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
x = ADCW; // je nach AVR auch x = ADC (siehe avr/ioxxx.h)&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;ADMUX&amp;amp;nbsp;&amp;amp;nbsp;&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;AD&#039;&#039;&#039;C &#039;&#039;&#039;Mu&#039;&#039;&#039;ltiple&#039;&#039;&#039;x&#039;&#039;&#039;er Select Register&amp;lt;br /&amp;gt;&lt;br /&gt;
Mit diesem Register wird der zu messende Kanal ausgewählt. Beim 90S8535&lt;br /&gt;
kann jeder Pin von Port A als &#039;&#039;&#039;ADC&#039;&#039;&#039;-Eingang verwendet werden (=8 Kanäle).&amp;lt;br /&amp;gt;&lt;br /&gt;
Das Register ist wie folgt aufgebaut:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Bit&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 7&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 6&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 5&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 4&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 2&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Name&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;REFS1&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;REFS0&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ADLAR&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;MUX4&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;MUX3&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;MUX2&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;MUX1&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;MUX0&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;R/W&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Initialwert&#039;&#039;&#039;&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;
| 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;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;REFS1...REFS0&#039;&#039;&#039; (&#039;&#039;&#039;Ref&#039;&#039;&#039;erence&#039;&#039;&#039;S&#039;&#039;&#039;election Bits)&lt;br /&gt;
:Mit diesen Bits kann die Referenzspannung eingestellt werden:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&lt;br /&gt;
{| style=&amp;quot;&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;REFS1&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;REFS0&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;Referenzspanung&#039;&#039;&#039;&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; | Externes AREF&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; | AVCC als Referenz&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; | Reserviert&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; | Interne 2,56 Volt&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ADLAR&#039;&#039;&#039; (&#039;&#039;&#039;ADC &#039;&#039;&#039; &#039;&#039;&#039;L&#039;&#039;&#039;eft &#039;&#039;&#039;A&#039;&#039;&#039;djust &#039;&#039;&#039;R&#039;&#039;&#039;esult)&lt;br /&gt;
:Das ADLAR Bit verändert das Aussehen des Ergebnisses der AD-Wandlung. Bei einer logischen 1 wird das Ergebnis linksbündig ausgegeben, bei einer 0 rechtsündig. Eine Änderung in diesem Bit beeinflusst das Ergebnis sofort, ganz egal ob bereits eine Wandlung läuft.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;MUX4...MUX0&#039;&#039;&#039;&lt;br /&gt;
:Mit diesen 5 Bits wird der zu messende Kanal bestimmt. Wenn man einen einfachen 1-kanaligen ADC verwendet wird einfach die entsprechende Pinnummer des Ports in die Bits 0...2 eingeschrieben.&lt;br /&gt;
:Wenn das Register beschrieben wird, während dem eine Umwandlung läuft, so wird zuerst die aktuelle Umwandlung auf dem bisherigen Kanal beendet. Dies ist vor allem beim frei laufenden Betrieb zu berücksichtigen.&lt;br /&gt;
&lt;br /&gt;
:Eine Empfehlung ist deswegen diese, dass der frei laufende Betrieb nur bei einem einzelnen zu verwendenden Analogeingang verwendet werden sollte, wenn man sich Probleme bei der Umschalterei ersparen will.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Aktivieren des ADC ====&lt;br /&gt;
&lt;br /&gt;
Um den &#039;&#039;&#039; ADC&#039;&#039;&#039; zu aktivieren, müssen wir das &#039;&#039;&#039;ADEN&#039;&#039;&#039;-Bit im &#039;&#039;&#039;ADCSR&#039;&#039;&#039;-Register&lt;br /&gt;
setzen. Im gleichen Schritt legen wir auch gleich die Betriebsart fest. &lt;br /&gt;
&lt;br /&gt;
Ein kleines Beispiel für den &amp;quot;single conversion&amp;quot;-Mode bei einem ATmega169 und Nutzung der internen Referenzspannung (beim &#039;169 1,1V bei anderen AVRs auch 2,56V). D.h. das Eingangssignal darf diese Spannung nicht überschreiten, gegebenenfalls mit Spannungsteiler einstellen. Ergebnis der Routine ist der ADC-Wert, also 0 für 0-Volt und 1023 für V_ref-Volt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
uint16_t ReadChannel(uint8_t mux)&lt;br /&gt;
{&lt;br /&gt;
  uint8_t i;&lt;br /&gt;
  uint16_t result;&lt;br /&gt;
&lt;br /&gt;
  ADMUX = mux;                      // Kanal waehlen&lt;br /&gt;
  ADMUX |= (1&amp;lt;&amp;lt;REFS1) | (1&amp;lt;&amp;lt;REFS0); // interne Referenzspannung nutzen&lt;br /&gt;
&lt;br /&gt;
  ADCSRA = (1&amp;lt;&amp;lt;ADEN) | (1&amp;lt;&amp;lt;ADPS1) | (1&amp;lt;&amp;lt;ADPS0);    // Frequenzvorteiler &lt;br /&gt;
                               // setzen auf 8 (1) und ADC aktivieren (1)&lt;br /&gt;
&lt;br /&gt;
  /* nach Aktivieren des ADC wird ein &amp;quot;Dummy-Readout&amp;quot; empfohlen, man liest&lt;br /&gt;
     also einen Wert und verwirft diesen, um den ADC &amp;quot;warmlaufen zu lassen&amp;quot; */&lt;br /&gt;
  ADCSRA |= (1&amp;lt;&amp;lt;ADSC);              // eine ADC-Wandlung &lt;br /&gt;
  while ( ADCSRA &amp;amp; (1&amp;lt;&amp;lt;ADSC) ) {&lt;br /&gt;
     ;     // auf Abschluss der Konvertierung warten &lt;br /&gt;
  }&lt;br /&gt;
  result = ADCW;  // ADCW muss einmal gelesen werden,&lt;br /&gt;
                  // sonst wird Ergebnis der nächsten Wandlung&lt;br /&gt;
                  // nicht übernommen.&lt;br /&gt;
&lt;br /&gt;
  /* Eigentliche Messung - Mittelwert aus 4 aufeinanderfolgenden Wandlungen */&lt;br /&gt;
  result = 0; &lt;br /&gt;
  for( i=0; i&amp;lt;4; i++ )&lt;br /&gt;
  {&lt;br /&gt;
    ADCSRA |= (1&amp;lt;&amp;lt;ADSC);            // eine Wandlung &amp;quot;single conversion&amp;quot;&lt;br /&gt;
    while ( ADCSRA &amp;amp; (1&amp;lt;&amp;lt;ADSC) ) {&lt;br /&gt;
      ;   // auf Abschluss der Konvertierung warten&lt;br /&gt;
    }&lt;br /&gt;
    result += ADCW;		    // Wandlungsergebnisse aufaddieren&lt;br /&gt;
  }&lt;br /&gt;
  ADCSRA &amp;amp;= ~(1&amp;lt;&amp;lt;ADEN);             // ADC deaktivieren (2)&lt;br /&gt;
&lt;br /&gt;
  result /= 4;                     // Summe durch vier teilen = arithm. Mittelwert&lt;br /&gt;
&lt;br /&gt;
  return result;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
/* Beispielaufrufe: */&lt;br /&gt;
&lt;br /&gt;
void foo(void)&lt;br /&gt;
{&lt;br /&gt;
  uint16_t adcval;&lt;br /&gt;
&lt;br /&gt;
  adcval = ReadChannel(0); /* MUX-Bits auf 0b0000 -&amp;gt; Channel 0 */&lt;br /&gt;
  ...&lt;br /&gt;
  adcval = ReadChannel(2); /* MUX-Bits auf 0b0010 -&amp;gt; Channel 2 */&lt;br /&gt;
  ...&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im Beispiel wird bei jedem Aufruf der ADC aktiviert und nach der Wandlung wieder abgeschaltet, das spart Strom. Will man dies nicht, verschiebt man die mit (1) gekennzeichneten Zeilen in eine Funktion adc_init() o.ä. und löscht die mit (2) markierten Zeilen. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- &lt;br /&gt;
Das Löschen des ADIF-Flags sollte, &#039;&#039;&#039;entgegen&#039;&#039;&#039; der [http://www.nongnu.org/avr-libc/user-manual/FAQ.html#faq_intbits FAQ], mit&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  ADCSRA |= (1&amp;lt;&amp;lt;ADIF);&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
erfolgen. Die Methode in der FAQ eignet sich nur für Register in denen &#039;&#039;&#039;nur&#039;&#039;&#039; Interrupt-Flags stehen.&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Analog-Digital-Wandlung ohne internen ADC ===&lt;br /&gt;
&lt;br /&gt;
==== Messen eines Widerstandes ====&lt;br /&gt;
&lt;br /&gt;
Analoge Werte lassen sich ohne Analog-Digital-Wandler auch indirekt ermitteln. Im Folgenden wird die Messung des an einem Potentiometer eingestellten Widerstands anhand der Ladekurve eines Kondensators erläutert. Bei dieser Methode wird nur ein Portpin benötigt, ein Analog-Digital-Wandler oder Analog-Comparator ist nicht erforderlich. Es wird dazu ein Kondensator und der Widerstand (das Potentiometer) in Reihe zwischen Vorsorgungsspannung und Masse/GND geschaltet (sogen. RC-Netzwerk). Zusätzlich wird eine Verbindung der Leitung zwischen Kondensator und Potentiometer zu einem Portpin des Controllers hergestellt. Die folgende Abbildung verdeutlicht die erforderliche Schaltung. &lt;br /&gt;
&lt;br /&gt;
[[Image:Poti.gif]]&lt;br /&gt;
&lt;br /&gt;
Wird der Portpin des Controllers auf Ausgang konfiguriert (im Beispiel &#039;&#039;DDRD&amp;amp;nbsp;|=&amp;amp;nbsp;(1&amp;lt;&amp;lt;PD2)&#039;&#039;) und dieser Ausgang auf Logisch 1 (&amp;quot;High&amp;quot;, &#039;&#039;PORTD&amp;amp;nbsp;|=&amp;amp;nbsp;(1&amp;lt;&amp;lt;PD2)&#039;&#039;) geschaltet, liegt an beiden &amp;quot;Platten&amp;quot; des Kondensators das gleiche Potential &#039;&#039;&#039;VCC&#039;&#039;&#039; an und der Kondensator somit entladen. (Klingt komisch, mit &#039;&#039;&#039; Vcc&#039;&#039;&#039; entladen, ist aber so, da an beiden Seiten des Kondensators das gleiche Potential anliegt und somit eine Potentialdifferenz von 0V besteht =&amp;gt; Kondensator ist entladen).&lt;br /&gt;
&lt;br /&gt;
Nach einer gewissen Zeit ist der Kondensator entladen und der Portpin wird als Eingang konfiguriert (&#039;&#039;DDRD&amp;amp;nbsp;&amp;amp;=&amp;amp;nbsp;~(1&amp;lt;&amp;lt;PD2); PORTD&amp;amp;nbsp;&amp;amp;=&amp;amp;nbsp;~(1&amp;lt;&amp;lt;PD2)&#039;&#039;), wodurch dieser hochohmig wird. Der Status des Eingangspin (in PIND) ist Logisch 1 (High). Der Kondensator lädt sich jetzt über das Poti auf, dabei steigt der Spannungsabfall über dem Kondensator und derjenige über dem Poti sinkt. Fällt nun der Spannungsabfall über dem Poti unter die Thresholdspannung des Eingangspins (2/5 Vcc, also ca. 2V), wird das Eingangssignal als LOW erkannt (Bit in PIND wird 0). Die Zeitspanne zwischen der Umschaltung von Entladung auf Aufladung und dem Wechsel des Eingangssignals von High auf Low ist ein Maß für den am Potentiometer eingestellten Widerstand. Zur Zeitmessung kann einer der im Controller vorhandenen Timer genutzt werden. Der 220 Ohm Widerstand dient dem Schutz des Controllers. Es würde sonst bei Maximaleinstellung des Potentionmeters (hier 0 Ohm) ein zu hoher Strom fließen, der die Ausgangsstufe des Controllers zerstört. &lt;br /&gt;
&lt;br /&gt;
Mit einem weiteren Eingangspin und ein wenig Software können wir auch eine Kalibrierung realisieren, um den Messwert in einen vernünftigen Bereich (z.B: 0...100 % oder so) umzurechnen. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- Link 404 =&amp;gt; auskommentiert, mthomas 9.2.2008 &lt;br /&gt;
Ein Beispielprogramm findet sich auf [http://www.mypage.bluewin.ch/ch_schifferle/ Christian Schifferles Web-Seite] im Archiv &#039;&#039;ATMEL.ZIP&#039;&#039;, welches unter den Titel &#039;&#039;Tutorial &amp;quot;Programmieren mit C für Atmel Mikrocontroller&#039;&#039; heruntergeladen werden kann. --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== ADC über Komparator ====&lt;br /&gt;
&lt;br /&gt;
Es gibt einen weiteren Weg, eine analoge Spannung mit Hilfe des&lt;br /&gt;
Komparators, welcher in fast jedem AVR integriert ist, zu messen. Siehe dazu&lt;br /&gt;
auch die Application Note AVR400 von Atmel.&lt;br /&gt;
&lt;br /&gt;
Dabei wird das zu messende Signal auf den invertierenden Eingang&lt;br /&gt;
des Komparators geführt. Zusätzlich wird ein Referenzsignal an den nicht&lt;br /&gt;
invertierenden Eingang des Komparators angeschlossen. Das Referenzsignal wird&lt;br /&gt;
hier auch wieder über ein RC-Glied erzeugt, allerdings mit festen Werten für R&lt;br /&gt;
und C.&lt;br /&gt;
&lt;br /&gt;
[[Image:ADC ueber Komparator.gif]]&lt;br /&gt;
&lt;br /&gt;
Das Prinzip der Messung ist nun dem vorhergehenden recht&lt;br /&gt;
ähnlich. Durch Anlegen eines LOW-Pegels an Pin 2 wird der Kondensator zuerst&lt;br /&gt;
einmal entladen. Auch hier muss darauf geachtet werden, dass der Entladevorgang&lt;br /&gt;
genügend lang dauert.&amp;lt;br /&amp;gt;&lt;br /&gt;
Nun wird Pin 2 auf HIGH gelegt. Der Kondensator wird geladen. Wenn die Spannung&lt;br /&gt;
über dem Kondensator die am Eingangspin anliegende Spannung erreicht hat&lt;br /&gt;
schaltet der Komparator durch. Die Zeit, welche benötigt wird, um den&lt;br /&gt;
Kondensator zu laden kann nun auch wieder als Maß für die Spannung an Pin 1&lt;br /&gt;
herangezogen werden.&lt;br /&gt;
&lt;br /&gt;
Ich habe es mir gespart, diese Schaltung auch aufzubauen und&lt;br /&gt;
zwar aus mehreren Gründen:&lt;br /&gt;
&lt;br /&gt;
# 3 Pins notwendig.&lt;br /&gt;
# Genauigkeit vergleichbar mit einfacherer Lösung.&lt;br /&gt;
# War einfach zu faul.&lt;br /&gt;
&lt;br /&gt;
Der Vorteil dieser Schaltung liegt allerdings darin, dass damit&lt;br /&gt;
direkt Spannungen gemessen werden können.&lt;br /&gt;
&lt;br /&gt;
== DAC (Digital Analog Converter) ==&lt;br /&gt;
&lt;br /&gt;
Mit Hilfe eines Digital-Analog-Konverters (&#039;&#039;&#039;DAC&#039;&#039;&#039;) können wir nun auch Analogsignale ausgeben. Es gibt hier mehrere Verfahren. &amp;lt;!-- Wenn wir beim ADC die Möglichkeit haben, mit externen Komponenten zu operieren, müssen wir bei der DAC-Wandlung mit dem auskommen, was der Controller selber zu bieten hat. --mt: hmm, richtig? verstaendlich? redundant? --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== DAC über mehrere digitale Ausgänge ===&lt;br /&gt;
&lt;br /&gt;
Wenn wir an den Ausgängen des Controllers ein entsprechendes&lt;br /&gt;
Widerstandsnetzwerk aufbauen haben wir die Möglichkeit, durch die Ansteuerung&lt;br /&gt;
der Ausgänge über den Widerständen einen Addierer aufzubauen, mit dessen&lt;br /&gt;
Hilfe wir eine dem Zahlenwert proportionale Spannung erzeugen können. Das&lt;br /&gt;
Schaltbild dazu kann etwa so aussehen:&lt;br /&gt;
&lt;br /&gt;
[[Image:DAC R2R.gif]]&lt;br /&gt;
&lt;br /&gt;
Es sollten selbstverständlich möglichst genaue Widerstände verwendet&lt;br /&gt;
werden, also nicht unbedingt solche mit einer Toleranz von 10% oder mehr.&lt;br /&gt;
Weiterhin empfiehlt es sich, je nach Anwendung den Ausgangsstrom über einen&lt;br /&gt;
Operationsverstärker zu verstärken.&lt;br /&gt;
&lt;br /&gt;
=== PWM (Pulsweitenmodulation) ===&lt;br /&gt;
&lt;br /&gt;
Wir kommen nun zu einem Thema, welches in aller Munde ist, aber viele&lt;br /&gt;
Anwender verstehen nicht ganz, wie &#039;&#039;&#039;[[PWM]]&#039;&#039;&#039; eigentlich funktioniert.&lt;br /&gt;
&lt;br /&gt;
Wie wir alle wissen, ist ein Mikrocontroller ein rein digitales Bauteil.&lt;br /&gt;
Definieren wir einen Pin als Ausgang, dann können wir diesen Ausgang entweder&lt;br /&gt;
auf HIGH setzen, worauf am Ausgang die Versorgungsspannung &#039;&#039;&#039; Vcc&#039;&#039;&#039; anliegt, oder aber wir setzen den Ausgang auf LOW, wonach dann &#039;&#039;&#039; 0V&#039;&#039;&#039; am Ausgang liegt. Was passiert aber nun, wenn wir periodisch mit einer festen Frequenz zwischen HIGH und LOW umschalten? - Richtig, wir erhalten eine Rechteckspannung, wie die folgende Abbildung zeigt:&lt;br /&gt;
&lt;br /&gt;
[[Image:PWM Theorie 1.gif]]&lt;br /&gt;
&lt;br /&gt;
Diese Rechteckspannung hat nun einen arithmetischen Mittelwert, &lt;br /&gt;
der je nach Pulsbreite kleiner oder größer ist.&lt;br /&gt;
&lt;br /&gt;
[[Image:PWM Theorie 2.gif]]&lt;br /&gt;
&lt;br /&gt;
Wenn wir nun diese pulsierende Ausgangsspannung noch über ein RC-Glied filtern/&amp;quot;glätten&amp;quot;, dann haben wir schon eine entsprechende Gleichspannung erzeugt.&lt;br /&gt;
&lt;br /&gt;
Mit den AVRs können wir direkt &#039;&#039;&#039;PWM&#039;&#039;&#039;-Signale erzeugen. &lt;br /&gt;
Dazu dient der 16-Bit Zähler, welcher im sogenannten &#039;&#039;&#039;PWM&#039;&#039;&#039;-Modus betrieben werden kann.&lt;br /&gt;
&lt;br /&gt;
Hinweis:&lt;br /&gt;
:In den folgenden Überlegungen wird als Controller der 90S2313 vorausgesetzt. Die Theorie ist bei anderen AVR-Controllern vergleichbar, die Pinbelegung allerdings nicht unbedingt, weshalb ein Blick ins entsprechende Datenblatt dringend angeraten wird.&lt;br /&gt;
&lt;br /&gt;
Um den &#039;&#039;&#039;PWM&#039;&#039;&#039;-Modus zu aktivieren, müssen im Timer/Counter1 Control&lt;br /&gt;
Register A &#039;&#039;&#039;TCCR1A&#039;&#039;&#039; die Pulsweiten-Modulatorbits &#039;&#039;&#039;PWM10&#039;&#039;&#039; bzw. &#039;&#039;&#039;PWM11&#039;&#039;&#039; entsprechend nachfolgender Tabelle gesetzt werden:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;PWM11&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;PWM10&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Bedeutung&#039;&#039;&#039;&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;
| PWM-Modus des Timers ist nicht aktiv.&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;
| 8-Bit PWM.&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;
| 9-Bit PWM.&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;
| 10-Bit PWM.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Der Timer/Counter zählt nun permanent von 0 bis zur Obergrenze&lt;br /&gt;
und wieder zurück, er wird also als sogenannter Auf-/Ab Zähler betrieben. &lt;br /&gt;
Die Obergrenze hängt davon ab, ob wir mit 8, 9 oder 10-Bit PWM arbeiten wollen:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;Auflösung&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;Obergrenze&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Frequenz&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 8&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 255&lt;br /&gt;
| f&amp;lt;sub&amp;gt;TC1&amp;lt;/sub&amp;gt; / 510&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 9&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 511&lt;br /&gt;
| f&amp;lt;sub&amp;gt;TC1&amp;lt;/sub&amp;gt; / 1022&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 10&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1023&lt;br /&gt;
| f&amp;lt;sub&amp;gt;TC1&amp;lt;/sub&amp;gt; / 2046&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Zusätzlich muss mit den Bits &#039;&#039;&#039;COM1A1&#039;&#039;&#039; und &#039;&#039;&#039;COM1A0&#039;&#039;&#039; desselben&lt;br /&gt;
Registers die gewünschte Ausgabeart des Signals definiert werden:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;COM1A1&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;COM1A0&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Bedeutung&#039;&#039;&#039;&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;
| Keine Wirkung, Pin wird nicht geschaltet.&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;
| Keine Wirkung, Pin wird nicht geschaltet.&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;
| Nicht invertierende PWM.&amp;lt;br /&amp;gt;&lt;br /&gt;
Der Ausgangspin wird gelöscht beim Hochzählen und gesetzt beim&lt;br /&gt;
Herunterzählen.&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;
| Invertierende PWM.&amp;lt;br /&amp;gt;&lt;br /&gt;
Der Ausgangspin wird gelöscht beim Herunterzählen und gesetzt beim&lt;br /&gt;
Hochzählen.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Der entsprechende Befehl, um beispielsweise den Timer/Counter als&lt;br /&gt;
nicht invertierenden 10-Bit PWM zu verwenden, heißt dann:&lt;br /&gt;
&lt;br /&gt;
alte Schreibweise (PWMxx wird nicht mehr akzeptiert)&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
TCCR1A = (1&amp;lt;&amp;lt;PWM11)|(1&amp;lt;&amp;lt;PWM10)|(1&amp;lt;&amp;lt;COM1A1);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
neue Schreibweise&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
TCCR1A = (1&amp;lt;&amp;lt;WGM11)|(1&amp;lt;&amp;lt;WGM10)|(1&amp;lt;&amp;lt;COM1A1);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Damit der Timer/Counter überhaupt läuft, müssen wir im Control&lt;br /&gt;
Register B &#039;&#039;&#039;TCCR1B&#039;&#039;&#039; noch den gewünschten Takt (Vorteiler) einstellen und&lt;br /&gt;
somit auch die Frequenz des &#039;&#039;&#039;PWM&#039;&#039;&#039;-Signals bestimmen.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;CS12&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;CS11&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;CS10&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Bedeutung&#039;&#039;&#039;&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;
| Stop. Der Timer/Counter wird gestoppt.&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;
| CK&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;
| CK / 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;
| CK / 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;
| CK / 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;
| CK / 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;
| Externer Pin 1, negative 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;
| Externer Pin 1, positive Flanke&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Also um einen Takt von CK / 1024 zu generieren, verwenden wir&lt;br /&gt;
folgenden Befehl:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
TCCR1B = (1&amp;lt;&amp;lt;CS12) | (1&amp;lt;&amp;lt;CS10);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jetzt muss nur noch der Vergleichswert festgelegt werden. Diesen&lt;br /&gt;
schreiben wir in das 16-Bit Timer/Counter Output Compare Register &#039;&#039;&#039;OCR1A&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
OCR1A = xxx;&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die folgende Grafik soll den Zusammenhang zwischen dem Vergleichswert und dem generierten &#039;&#039;&#039;PWM&#039;&#039;&#039;-Signal aufzeigen.&lt;br /&gt;
&lt;br /&gt;
[[Image:PWM Theorie 3.gif]]&lt;br /&gt;
&lt;br /&gt;
[[Image:PWM Theorie 4.gif]]&lt;br /&gt;
&lt;br /&gt;
Ach ja, fast hätte ich&#039;s vergessen. Das generierte &#039;&#039;&#039;PWM&#039;&#039;&#039;-Signal&lt;br /&gt;
wird am Output Compare Pin &#039;&#039;&#039;OC1&#039;&#039;&#039; des Timers ausgegeben und leider können wir&lt;br /&gt;
deshalb auch beim AT90S2313 nur ein einzelnes &#039;&#039;&#039;PWM&#039;&#039;&#039;-Signal mit dieser Methode generieren. Andere AVR-Typen verfügen über bis zu vier PWM-Ausgänge. Zu beachten ist außerdem, das wenn der OC Pin aktiviert ist, er nichtmehr wie üblich funktioniert und z.B. nicht einfach über PINx ausgelesen werden kann.&lt;br /&gt;
&lt;br /&gt;
Ein Programm, welches an einem ATMega8 den Fast-PWM Modus verwendet, den Modus 14, könnte so aussehen&lt;br /&gt;
&amp;lt;C&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
int main()&lt;br /&gt;
{&lt;br /&gt;
  // OC1A auf Ausgang&lt;br /&gt;
  DDRB = (1 &amp;lt;&amp;lt; PB1 );&lt;br /&gt;
&lt;br /&gt;
  //&lt;br /&gt;
  // Timer 1 einstellen&lt;br /&gt;
  //  &lt;br /&gt;
  // Modus 14:&lt;br /&gt;
  //    Fast PWM, Top von ICR1&lt;br /&gt;
  //&lt;br /&gt;
  //     WGM13    WGM12   WGM11    WGM10&lt;br /&gt;
  //      1        1       1        0&lt;br /&gt;
  //&lt;br /&gt;
  //    Timer Vorteiler: 1&lt;br /&gt;
  //     CS12     CS11    CS10&lt;br /&gt;
  //       0        0       1&lt;br /&gt;
  //&lt;br /&gt;
  //  Steuerung des Ausgangsport: Set at BOTTOM, Clear at match&lt;br /&gt;
  //     COM1A1   COM1A0&lt;br /&gt;
  //       1        0&lt;br /&gt;
 &lt;br /&gt;
  TCCR1A = (1&amp;lt;&amp;lt;COM1A1) | (1&amp;lt;&amp;lt;WGM11);&lt;br /&gt;
  TCCR1B = (1&amp;lt;&amp;lt;WGM13) | (1&amp;lt;&amp;lt;WGM12) | (1&amp;lt;&amp;lt;CS10);&lt;br /&gt;
 &lt;br /&gt;
  //&lt;br /&gt;
  //  den Endwert (TOP) für den Zähler setzen&lt;br /&gt;
  //  der Zähler zählt bis zu diesem Wert&lt;br /&gt;
&lt;br /&gt;
  ICR1 = 0x6FFF;&lt;br /&gt;
 &lt;br /&gt;
  //&lt;br /&gt;
  // der Compare Wert&lt;br /&gt;
  // Wenn der Zähler diesen Wert erreicht, wird mit&lt;br /&gt;
  // obiger Konfiguration der OC1A Ausgang abgeschaltet&lt;br /&gt;
  // Sobald der Zähler wieder bei 0 startet, wird der&lt;br /&gt;
  // Ausgang wieder auf 1 gesetzt&lt;br /&gt;
  //&lt;br /&gt;
  // Durch Verändern dieses Wertes, werden die unterschiedlichen&lt;br /&gt;
  // PWM Werte eingestellt.&lt;br /&gt;
&lt;br /&gt;
  OCR1A = 0x3FFF;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  while( 1 )&lt;br /&gt;
    ;  &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/C&amp;gt;&lt;br /&gt;
&lt;br /&gt;
PWM Mode Tabelle aus dem Datenblatt des Atmega 8515:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;Mode&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;WGM13&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;WGM12&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;WGM11&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;WGM10&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;Timer/Counter Mode of Operation&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;TOP&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;Update of OCR1x at&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;TOV1 Flag set on&#039;&#039;&#039;&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;
| 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; | Normal&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0xFFFF&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | Immediate&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | MAX&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;
| 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; | PWM, Phase Correct, 8-Bit&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0x00FF&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | TOP&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | BOTTOM&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 2&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;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | PWM, Phase Correct, 9-Bit&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0x01FF&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | TOP&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | BOTTOM&lt;br /&gt;
|-&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3&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;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | PWM, Phase Correct, 10-Bit&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0x03FF&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | TOP&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | BOTTOM&lt;br /&gt;
|-&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 4&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;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | CTC&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | OCR1A&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | Immediate&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | MAX&lt;br /&gt;
|-&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 5&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;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | Fast PWM, 8-Bit&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0x00FF&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | BOTTOM&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | TOP&lt;br /&gt;
|-&lt;br /&gt;
&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 6&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;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | Fast PWM, 9-Bit&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0x01FF&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | BOTTOM&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | TOP&lt;br /&gt;
|-&lt;br /&gt;
&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 7&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;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | Fast PWM, 10-Bit&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0x03FF&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | BOTTOM&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | TOP&lt;br /&gt;
|-&lt;br /&gt;
&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 8&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;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | PWM, Phase an Frequency Correct&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | ICR1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | BOTTOM&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | BOTTOM&lt;br /&gt;
|-    &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 9&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;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | PWM, Phase an Frequency Correct&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | OCR1A&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | BOTTOM&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | BOTTOM&lt;br /&gt;
|-&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 10&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;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | PWM, Phase Correct&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | ICR1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | TOP&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | BOTTOM&lt;br /&gt;
|-&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 11&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;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | PWM, Phase an Frequency Correct&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | OCR1A&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | TOP&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | BOTTOM&lt;br /&gt;
|-&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 12&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;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | CTC&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | ICR1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | Immediate&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | MAX&lt;br /&gt;
|-&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 13&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;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | Reserved&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | -&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | -&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | -&lt;br /&gt;
|-&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 14&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;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | Fast PWM&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | ICR1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | BOTTOM&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | TOP&lt;br /&gt;
|-&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 15&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;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | Fast PWM&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | OCR1A&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | BOTTOM&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | TOP&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Für Details der PWM Möglichkeiten, muß immer das jeweilge Datenblatt des Prozessors konsultiert werden, da sich die unterschiedlichen Prozessoren in ihren Möglichkeiten doch stark unterscheiden. Auch muß man aufpassen, welches zu setzende Bit in welchem Register sind. Auch hier kann es sein, dass gleichnamige Konfigurationsbits in unterschiedlichen Konfigurationsregistern (je nach konkretem Prozessortyp) sitzen.&lt;br /&gt;
&lt;br /&gt;
= LCD-Ansteuerung =&lt;br /&gt;
&lt;br /&gt;
==Das LCD und sein Controller==&lt;br /&gt;
&lt;br /&gt;
Die meisten Text-LCDs verwenden den Controller [[HD44780|&#039;&#039;&#039;HD44780&#039;&#039;&#039;]] oder einen kompatiblen (z.B. KS0070) und haben 14 oder 16 Pins. Die Pinbelegung an der LCD-Controller-Platine ist praktisch immer gleich: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;table width=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;th width=&amp;quot;50&amp;quot; align=&amp;quot;left&amp;quot;&amp;gt;Pin #&amp;lt;/th&amp;gt;&amp;lt;th  width=&amp;quot;70&amp;quot; align=&amp;quot;left&amp;quot;&amp;gt;Bezeichnung&amp;lt;/th&amp;gt;&amp;lt;th align=&amp;quot;left&amp;quot;&amp;gt;Funktion&amp;lt;/th&amp;gt;&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;1&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Vss&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;GND&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;2&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Vcc&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;5V&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;3&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Vee&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Kontrastspannung (0V bis 5V)&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;4&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;RS&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Register Select (Befehle/Daten)&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;5&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;RW&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Read/Write&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;6&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;E&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Enable&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;7&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;DB0&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Datenbit 0&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;8&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;DB1&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Datenbit 1&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;9&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;DB2&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Datenbit 2&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;10&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;DB3&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Datenbit 3&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;11&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;DB4&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Datenbit 4&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;12&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;DB5&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Datenbit 5&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;13&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;DB6&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Datenbit 6&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;14&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;DB7&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Datenbit 7&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;15&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;A&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;LED-Beleuchtung, Anode&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;16&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;K&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;LED-Beleuchtung, Kathode&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Achtung: Unbedingt von der richtigen Seite zu zählen anfangen! Meistens ist neben Pin 1 eine kleine 1 auf der LCD-Platine, ansonsten im Datenblatt nachschauen. &lt;br /&gt;
&lt;br /&gt;
Bei LCDs mit 16-poligem Anschluss sind die beiden letzten Pins für die Hintergrundbeleuchtung reserviert. Hier unbedingt das Datenblatt zu Rate ziehen, die beiden Anschlüsse sind je nach Hersteller verdreht beschaltet. Falls kein Datenblatt vorliegt, kann man mit einem Durchgangsprüfer feststellen, welcher Anschluss mit Masse (GND) verbunden ist.&lt;br /&gt;
&lt;br /&gt;
Vss wird ganz einfach an GND angeschlossen und Vcc an 5V. Vee kann man testweise auch an GND legen. Wenn das LCD dann zu dunkel sein sollte muss man ein 10k-Potentiometer zwischen GND und 5V schalten, mit dem Schleifer an Vee: &lt;br /&gt;
&lt;br /&gt;
[[Bild:LCD_Vee.gif]]&lt;br /&gt;
&lt;br /&gt;
Es gibt zwei verschiedene Möglichkeiten zur Ansteuerung eines solchen Displays: den &#039;&#039;&#039;8-bit-&#039;&#039;&#039; und den &#039;&#039;&#039;4-bit-&#039;&#039;&#039;Modus.&lt;br /&gt;
* Für den &#039;&#039;&#039;8-bit-Modus&#039;&#039;&#039; werden (wie der Name schon sagt) alle acht Datenleitungen zur Ansteuerung verwendet, somit kann durch einen Zugriff immer ein ganzes Byte übertragen werden.&lt;br /&gt;
* Der &#039;&#039;&#039;4-bit-Modus&#039;&#039;&#039; verwendet nur die oberen vier Datenleitungen (&#039;&#039;&#039;DB4-DB7&#039;&#039;&#039;). Um ein Byte zu übertragen braucht man somit zwei Zugriffe, wobei zuerst das höherwertige &#039;&#039;&#039;&amp;quot;Nibble&amp;quot;&#039;&#039;&#039; (= 4 Bits), also Bit 4 bis Bit 7 übertragen wird und dann das niederwertige, also Bit 0 bis Bit 3. Die unteren Datenleitungen des LCDs, die beim Lesezyklus Ausgänge sind, lässt man offen (siehe Datasheets, z.B. vom KS0070).&lt;br /&gt;
&lt;br /&gt;
Der 4-bit-Modus hat den Vorteil, dass man 4 IO-Pins weniger benötigt als beim 8-bit-Modus, weshalb ich mich hier für eine Ansteuerung mit 4bit entschieden habe. &lt;br /&gt;
&lt;br /&gt;
Neben den vier Datenleitungen (DB4, DB5, DB6 und DB7) werden noch die Anschlüsse &#039;&#039;&#039;RS&#039;&#039;&#039;, &#039;&#039;&#039;RW&#039;&#039;&#039; und &#039;&#039;&#039;E&#039;&#039;&#039; (ist in manchen Unterlagen auch &#039;&#039;&#039;EN&#039;&#039;&#039;  für &#039;&#039;Enable&#039;&#039; abgekürzt) benötigt. &lt;br /&gt;
&lt;br /&gt;
* Über &#039;&#039;&#039;RS&#039;&#039;&#039; wird ausgewählt, ob man einen Befehl oder ein Datenbyte an das LCD schicken möchte. Ist RS Low, dann wird das ankommende Byte als Befehl interpretiert, ist RS high, dann wird das Byte auf dem LCD angezeigt. &lt;br /&gt;
* &#039;&#039;&#039;RW&#039;&#039;&#039; legt fest, ob geschrieben oder gelesen werden soll. High bedeutet lesen, low bedeutet schreiben. Wenn man RW auf lesen einstellt und RS auf Befehl, dann kann man das &#039;&#039;&#039;Busy-Flag&#039;&#039;&#039; an DB7 lesen, das anzeigt, ob das LCD den vorhergehenden Befehl fertig verarbeitetet hat (diese Methode u.a. in der LCD-Library von Peter Fleury verwendet). Ist RS auf Daten eingestellt, dann kann man z.B. den Inhalt des Displays lesen - was jedoch nur in den wenigsten Fällen Sinn macht. Deshalb kann man RW dauerhaft auf low lassen (= an GND anschließen), so dass man noch ein IO-Pin am Controller einspart. Der Nachteil ist, dass man dann das Busy-Flag nicht lesen kann, weswegen man nach jedem Befehl vorsichtshalber ein paar Mikrosekunden warten sollte, um dem LCD Zeit zum Ausführen des Befehls zu geben. Dummerweise schwankt die Ausführungszeit von Display zu Display und ist auch von der Betriebsspannung abhängig. Für professionellere Sachen also lieber den IO-Pin opfern und Busy abfragen.&lt;br /&gt;
* Der &#039;&#039;&#039;E&#039;&#039;&#039; Anschluss schließlich signalisiert dem LCD, dass die übrigen Datenleitungen jetzt korrekte Pegel angenommen haben und es die gewünschten Daten von den Datenleitungen bzw. Kommandos von den Datenleitungen übernehmen kann.&lt;br /&gt;
&lt;br /&gt;
== Anschluss an den Controller ==&lt;br /&gt;
&lt;br /&gt;
Jetzt da wir wissen, welche Anschlüsse das LCDs benötigt, können wir das LCD mit dem Mikrocontroller verbinden: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;table width=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;th align=&amp;quot;left&amp;quot;&amp;gt;Pin #-LCD&amp;lt;/th&amp;gt;&amp;lt;th align=&amp;quot;left&amp;quot;&amp;gt;Bezeichnung-LCD&amp;lt;/th&amp;gt;&amp;lt;th align=&amp;quot;left&amp;quot;&amp;gt;Pin-µC&amp;lt;/th&amp;gt;&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;1&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Vss&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;GND&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;2&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Vcc&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;5V&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;3&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Vee&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;GND oder Poti (siehe oben)&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;4&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;RS&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;PD4 am AVR&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;5&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;RW&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;GND&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;6&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;E&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;PD5 am AVR&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;7&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;DB0&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;offen&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;8&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;DB1&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;offen&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;9&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;DB2&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;offen&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;10&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;DB3&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;offen&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;11&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;DB4&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;PD0 am AVR&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;12&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;DB5&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;PD1 am AVR&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;13&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;DB6&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;PD2 am AVR&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;14&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;DB7&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;PD3 am AVR&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn man die Steuerleitungen EN und RS auf Pins an einem anderen Port legen möchte, kann man so wie in diesem [http://www.mikrocontroller.net/topic/88543#751982 Forumsbeitrag] vorgehen.&lt;br /&gt;
&lt;br /&gt;
Ok, alles ist verbunden, wenn man jetzt den Strom einschaltet sollten ein oder zwei schwarze Balken auf dem Display angezeigt werden. Doch wie bekommt man jetzt die Befehle und Daten in das Display? &lt;br /&gt;
&lt;br /&gt;
== Programmierung ==&lt;br /&gt;
Datei &#039;&#039;&#039;lcd-routines.h&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
// Ansteuerung eines HD44780 kompatiblen LCD im 4-Bit-Interfacemodus&lt;br /&gt;
// http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial&lt;br /&gt;
//&lt;br /&gt;
void lcd_data(unsigned char temp1);&lt;br /&gt;
void lcd_string(char *data);&lt;br /&gt;
void lcd_command(unsigned char temp1);&lt;br /&gt;
void lcd_enable(void);&lt;br /&gt;
void lcd_init(void);&lt;br /&gt;
void lcd_home(void);&lt;br /&gt;
void lcd_clear(void);&lt;br /&gt;
void set_cursor(uint8_t x, uint8_t y);&lt;br /&gt;
&lt;br /&gt;
// Hier die verwendete Taktfrequenz in Hz eintragen, wichtig!&lt;br /&gt;
&lt;br /&gt;
#define F_CPU 8000000&lt;br /&gt;
&lt;br /&gt;
// LCD Befehle&lt;br /&gt;
&lt;br /&gt;
#define CLEAR_DISPLAY 0x01&lt;br /&gt;
#define CURSOR_HOME   0x02&lt;br /&gt;
&lt;br /&gt;
// Pinbelegung für das LCD, an verwendete Pins anpassen&lt;br /&gt;
&lt;br /&gt;
#define LCD_PORT      PORTD&lt;br /&gt;
#define LCD_DDR       DDRD&lt;br /&gt;
#define LCD_RS        PD4&lt;br /&gt;
#define LCD_EN        PD5&lt;br /&gt;
// DB4 bis DB7 des LCD sind mit PD0 bis PD3 des AVR verbunden&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Datei &#039;&#039;&#039;lcd-routines.c&#039;&#039;&#039;:&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
// Ansteuerung eines HD44780 kompatiblen LCD im 4-Bit-Interfacemodus&lt;br /&gt;
// http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial&lt;br /&gt;
//&lt;br /&gt;
// Die Pinbelegung ist über defines in lcd-routines.h einstellbar&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;quot;lcd-routines.h&amp;quot;&lt;br /&gt;
#include &amp;lt;util/delay.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
// sendet ein Datenbyte an das LCD&lt;br /&gt;
&lt;br /&gt;
void lcd_data(unsigned char temp1)&lt;br /&gt;
{&lt;br /&gt;
   unsigned char temp2 = temp1;&lt;br /&gt;
 &lt;br /&gt;
   LCD_PORT |= (1&amp;lt;&amp;lt;LCD_RS);        // RS auf 1 setzen&lt;br /&gt;
&lt;br /&gt;
   temp1 = temp1 &amp;gt;&amp;gt; 4;&lt;br /&gt;
   temp1 = temp1 &amp;amp; 0x0F;&lt;br /&gt;
   LCD_PORT &amp;amp;= 0xF0;&lt;br /&gt;
   LCD_PORT |= temp1;               // setzen&lt;br /&gt;
   lcd_enable();&lt;br /&gt;
 &lt;br /&gt;
   temp2 = temp2 &amp;amp; 0x0F;&lt;br /&gt;
   LCD_PORT &amp;amp;= 0xF0;&lt;br /&gt;
   LCD_PORT |= temp2;               // setzen&lt;br /&gt;
   lcd_enable();&lt;br /&gt;
   &lt;br /&gt;
   _delay_us(42);&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
// sendet einen Befehl an das LCD&lt;br /&gt;
&lt;br /&gt;
void lcd_command(unsigned char temp1)&lt;br /&gt;
{&lt;br /&gt;
   unsigned char temp2 = temp1;&lt;br /&gt;
 &lt;br /&gt;
   LCD_PORT &amp;amp;= ~(1&amp;lt;&amp;lt;LCD_RS);        // RS auf 0 setzen&lt;br /&gt;
&lt;br /&gt;
   temp1 = temp1 &amp;gt;&amp;gt; 4;              // oberes Nibble holen&lt;br /&gt;
   temp1 = temp1 &amp;amp; 0x0F;            // maskieren&lt;br /&gt;
   LCD_PORT &amp;amp;= 0xF0;&lt;br /&gt;
   LCD_PORT |= temp1;               // setzen&lt;br /&gt;
   lcd_enable();&lt;br /&gt;
 &lt;br /&gt;
   temp2 = temp2 &amp;amp; 0x0F;            // unteres Nibble holen und maskieren&lt;br /&gt;
   LCD_PORT &amp;amp;= 0xF0;&lt;br /&gt;
   LCD_PORT |= temp2;               // setzen&lt;br /&gt;
   lcd_enable();&lt;br /&gt;
   &lt;br /&gt;
   _delay_us(42);&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
// erzeugt den Enable-Puls&lt;br /&gt;
void lcd_enable(void)&lt;br /&gt;
{&lt;br /&gt;
   // Bei Problemen ggf. Pause gemäß Datenblatt des LCD Controllers einfügen&lt;br /&gt;
   // http://www.mikrocontroller.net/topic/81974#685882&lt;br /&gt;
   LCD_PORT |= (1&amp;lt;&amp;lt;LCD_EN);&lt;br /&gt;
    _delay_us(1);                   // kurze Pause&lt;br /&gt;
   // Bei Problemen ggf. Pause gemäß Datenblatt des LCD Controllers verlängern&lt;br /&gt;
   // http://www.mikrocontroller.net/topic/80900&lt;br /&gt;
   LCD_PORT &amp;amp;= ~(1&amp;lt;&amp;lt;LCD_EN);&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
// Initialisierung: &lt;br /&gt;
// Muss ganz am Anfang des Programms aufgerufen werden.&lt;br /&gt;
&lt;br /&gt;
void lcd_init(void)&lt;br /&gt;
{&lt;br /&gt;
   LCD_DDR = LCD_DDR | 0x0F | (1&amp;lt;&amp;lt;LCD_RS) | (1&amp;lt;&amp;lt;LCD_EN);   // Port auf Ausgang schalten&lt;br /&gt;
&lt;br /&gt;
   // muss 3mal hintereinander gesendet werden zur Initialisierung&lt;br /&gt;
&lt;br /&gt;
   _delay_ms(15);&lt;br /&gt;
   LCD_PORT &amp;amp;= 0xF0;&lt;br /&gt;
   LCD_PORT |= 0x03;            &lt;br /&gt;
   LCD_PORT &amp;amp;= ~(1&amp;lt;&amp;lt;LCD_RS);      // RS auf 0&lt;br /&gt;
   lcd_enable();&lt;br /&gt;
&lt;br /&gt;
   _delay_ms(5);&lt;br /&gt;
   lcd_enable();&lt;br /&gt;
&lt;br /&gt;
   _delay_ms(1);&lt;br /&gt;
   lcd_enable();&lt;br /&gt;
   _delay_ms(1);&lt;br /&gt;
&lt;br /&gt;
   // 4 Bit Modus aktivieren &lt;br /&gt;
   LCD_PORT &amp;amp;= 0xF0;&lt;br /&gt;
   LCD_PORT |= 0x02;&lt;br /&gt;
   lcd_enable();&lt;br /&gt;
   _delay_ms(1);&lt;br /&gt;
&lt;br /&gt;
   // 4Bit / 2 Zeilen / 5x7&lt;br /&gt;
   lcd_command(0x28);&lt;br /&gt;
    &lt;br /&gt;
   // Display ein / Cursor aus / kein Blinken&lt;br /&gt;
   lcd_command(0x0C); &lt;br /&gt;
 &lt;br /&gt;
   // inkrement / kein Scrollen&lt;br /&gt;
   lcd_command(0x06);&lt;br /&gt;
&lt;br /&gt;
   lcd_clear();&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
// Sendet den Befehl zur Löschung des Displays&lt;br /&gt;
&lt;br /&gt;
void lcd_clear(void)&lt;br /&gt;
{&lt;br /&gt;
   lcd_command(CLEAR_DISPLAY);&lt;br /&gt;
   _delay_ms(5);&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
// Sendet den Befehl: Cursor Home&lt;br /&gt;
&lt;br /&gt;
void lcd_home(void)&lt;br /&gt;
{&lt;br /&gt;
   lcd_command(CURSOR_HOME);&lt;br /&gt;
   _delay_ms(5);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// setzt den Cursor in Zeile y (1..4) Spalte x (0..15)&lt;br /&gt;
&lt;br /&gt;
void set_cursor(uint8_t x, uint8_t y)&lt;br /&gt;
{&lt;br /&gt;
  uint8_t tmp;&lt;br /&gt;
&lt;br /&gt;
  switch (y) {&lt;br /&gt;
    case 1: tmp=0x80+0x00+x; break;    // 1. Zeile&lt;br /&gt;
    case 2: tmp=0x80+0x40+x; break;    // 2. Zeile&lt;br /&gt;
    case 3: tmp=0x80+0x10+x; break;    // 3. Zeile&lt;br /&gt;
    case 4: tmp=0x80+0x50+x; break;    // 4. Zeile&lt;br /&gt;
    default: return;                   // für den Fall einer falschen Zeile&lt;br /&gt;
  }&lt;br /&gt;
  lcd_command(tmp);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Schreibt einen String auf das LCD&lt;br /&gt;
&lt;br /&gt;
void lcd_string(char *data)&lt;br /&gt;
{&lt;br /&gt;
    while(*data) {&lt;br /&gt;
        lcd_data(*data);&lt;br /&gt;
        data++;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein Hauptprogramm, welches die Funktionen benutzt, sieht zb. so aus:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
// &lt;br /&gt;
// Anpassungen im makefile:&lt;br /&gt;
//    ATMega8 =&amp;gt; MCU=atmega8 im makefile einstellen&lt;br /&gt;
//    lcd-routines.c in SRC = ... Zeile anhängen&lt;br /&gt;
// &lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;quot;lcd-routines.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
int main(void)&lt;br /&gt;
{&lt;br /&gt;
    lcd_init();&lt;br /&gt;
&lt;br /&gt;
    lcd_data(&#039;T&#039;);&lt;br /&gt;
    lcd_data(&#039;e&#039;);&lt;br /&gt;
    lcd_data(&#039;s&#039;);&lt;br /&gt;
    lcd_data(&#039;t&#039;);&lt;br /&gt;
&lt;br /&gt;
    set_cursor(0,2);&lt;br /&gt;
&lt;br /&gt;
    lcd_string(&amp;quot;Hello World!&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    while(1)&lt;br /&gt;
    {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wichtig ist dabei, dass die Optimierung bei der Compilierung eingeschaltet ist, sonst stimmen die Zeiten der Funktionen _delay_us() und _delay_ms() nicht und der Code wird wesentlich länger (Siehe Dokumentation der libc im WinAVR).&lt;br /&gt;
&lt;br /&gt;
Ein Hauptprogramm, welches eine Variable ausgibt, sieht zb. so aus.&lt;br /&gt;
Mittels der itoa() Funktion (itoa = &amp;lt;b&amp;gt;I&amp;lt;/b&amp;gt;nteger &amp;lt;b&amp;gt;To&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;A&amp;lt;/b&amp;gt;scii ) wird von einem Zahlenwert eine textuelle Repräsentierung ermittelt (sprich: ein String erzeugt) und dieser String mit der bereits vorhandenen Funktion lcd_string ausgegeben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
// &lt;br /&gt;
// Anpassungen im makefile:&lt;br /&gt;
//    ATMega8 =&amp;gt; MCU=atmega8 im makefile einstellen&lt;br /&gt;
//    lcd-routines.c in SRC = ... Zeile anhängen &lt;br /&gt;
// &lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
#include &amp;quot;lcd-routines.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
// Beispiel&lt;br /&gt;
int variable = 42;&lt;br /&gt;
&lt;br /&gt;
int main(void)&lt;br /&gt;
{&lt;br /&gt;
    lcd_init();&lt;br /&gt;
&lt;br /&gt;
    // Ausgabe des Zeichens dessen ASCII-Code gleich dem Variablenwert ist&lt;br /&gt;
    // (Im Beispiel entspricht der ASCII-Code 42 dem Zeichen *)&lt;br /&gt;
    // http://www.code-knacker.de/ascii.htm&lt;br /&gt;
    lcd_data(variable);&lt;br /&gt;
&lt;br /&gt;
    set_cursor(0,2);&lt;br /&gt;
 &lt;br /&gt;
    // Ausgabe der Variable als Text in dezimaler Schreibweise&lt;br /&gt;
    {&lt;br /&gt;
       // ... umwandeln siehe FAQ Artikel bei www.mikrocontroller.net&lt;br /&gt;
       // WinAVR hat eine itoa()-Funktion, das erfordert obiges #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
       char Buffer[20]; // in diesem {} lokal&lt;br /&gt;
       itoa( variable, Buffer, 10 ); &lt;br /&gt;
&lt;br /&gt;
       // ... ausgeben  &lt;br /&gt;
       lcd_string( Buffer );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    while(1)&lt;br /&gt;
    {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Beim Einrichten eines Projekts muss man zu der Datei mit dem Hauptprogramm auch die Datei lcd-routines.c in das Projekt aufnehmen. Dies geschieht beim AVR Studio unter Source Files im Fenster AVR GCC oder bei WinAVR im Makefile (z.B. durch SRC += lcd-routines.c).&lt;br /&gt;
&lt;br /&gt;
= Die Timer/Counter des AVR =&lt;br /&gt;
&lt;br /&gt;
Die heutigen Mikrocontroller und insbesondere die RISC-AVRs sind für viele Steuerungsaufgaben zu schnell. Wenn wir beispielsweise eine LED oder Lampe blinken lassen wollen, können wir selbstverständlich nicht die CPU-Frequenz verwenden, da ja dann nichts mehr vom Blinken zu bemerken wäre.&lt;br /&gt;
&lt;br /&gt;
Wir brauchen also eine Möglichkeit, Vorgänge in Zeitabständen durchzuführen, die geringer als die Taktfrequenz des Controllers sind. Selbstverständlich sollte die resultierende Frequenz auch noch möglichst genau und stabil sein.&lt;br /&gt;
&lt;br /&gt;
Hier kommen die im AVR vorhandenen Timer/Counter zum Einsatz.&lt;br /&gt;
&lt;br /&gt;
Ein Timer ist ganz einfach ein bestimmtes Register im µC, das völlig ohne Zutun des Programms, also per Hardware, hochgezählt wird. Das alleine wäre noch nicht allzu nützlich, wenn nicht dieses Hardwareregister bei bestimmten Zählerständen einen Interrupt auslösen könnte. Ein solches Ereignis ist der Overflow: Da die Bitbreite des Registers beschränkt ist, kommt es natürlich auch vor, dass der Zähler so hoch zählt, dass der nächste Zählerstand mit dieser Bitbreite nicht mehr darstellbar ist und der Zähler wieder auf 0 zurückgesetzt wird. Dieses Ereignis nennt man den Overflow und es ist möglich an dieses Ereignis einen Interrupt zu koppeln.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- Alternativvorschlag mthomas &lt;br /&gt;
Jeder Timer verfügt über ein Zählerregister im Mikrocontroller, das automatisch und ohne Zutun des Programms von der Hardware weitergezählt wird. In einem einfachen Anwendungsfall stellt man den Timer auf eine Zählgeschwindigkeit (Frequenz) und kann dann anhand des Zählerstands ermitteln, wie viel Zeit vergangen ist. Das eigentlich Nützliche an Timern ist jedoch, dass man  bestimmte Zählerstände mit Interrupts verknüpfen kann, so dass der Controller beim Auftreten automatisch eine vom Anwender geschriebene Routine aufruft. Eines dieser möglichen Ereignis ist der Overflow ((Zähler-)Überlauf), der dann auftritt, wenn der Wert des Zählerregisters (Timer/Counter-Register) den maximal möglichen Wert überschreitet. Der Maximalwert wird durch die Bitbreite des Zählerregisters bestimmt (z.B. 255 bei 8-Bit Timern). Beim Überlauf/Overflow wird der Zähler durch die Hardware auf 0 zurückgesetzt und die Zählung beginnt von neuem. Wurde vorher der Overflow-Interrupt für den Timer aktiviert (im Timer Control Register) unterbricht der Controller automatisch die Ausführung des Hauptprogramms und verzweigt in die Interrupt-Routine des Anwenders.&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein anderes Anwendungsgebiet ist die Zählung von Signalen, welche über einen I/O-Pin zugeführt werden können.&lt;br /&gt;
&lt;br /&gt;
Die folgenden Ausführungen beziehen sich auf den AT90S2313. Für andere Modelltypen müsst ihr euch die allenfalls notwendigen Anpassungen aus den Datenblättern der entsprechenden Controller herauslesen.&lt;br /&gt;
&lt;br /&gt;
Wir unterscheiden grundsätzlich zwischen 8-Bit Timern, welche eine Auflösung von 256 aufweisen und 16-Bit Timern mit (logischerweise) einer Auflösung von 65536. Als Eingangstakt für die Timer/Counter kann entweder die CPU-Taktfrequenz, der Vorteiler-Ausgang oder ein an einen I/O-Pin angelegtes Signal verwendet werden. Wenn ein externes Signal verwendet wird, so darf dessen Frequenz nicht höher sein als die Hälfte des CPU-Taktes.&lt;br /&gt;
&lt;br /&gt;
== Der Vorteiler (Prescaler) ==&lt;br /&gt;
&lt;br /&gt;
Der Vorteiler dient dazu, den CPU-Takt vorerst um einen einstellbaren Faktor zu reduzieren. Die so geteilte Frequenz wird den Eingängen der Timer zugeführt.&lt;br /&gt;
&lt;br /&gt;
Wenn wir mit einem CPU-Takt von 4 MHz arbeiten und den Vorteiler auf 1024 einstellen, wird also der Timer mit einer Frequenz von 4 MHz / 1024, also mit ca. 4 kHz versorgt. Wenn also der Timer läuft, so wird das Daten- bzw. Zählregister (TCNTx) mit dieser Frequenz inkrementiert.&lt;br /&gt;
&lt;br /&gt;
== 8-Bit Timer/Counter ==&lt;br /&gt;
&lt;br /&gt;
Alle AVR-Modelle verfügen über mindestens einen, teilweise sogar zwei, 8-Bit Timer.&lt;br /&gt;
&lt;br /&gt;
Der 8-Bit Timer wird z.B bei AT90S2313 über folgende Register angesprochen (bei anderen Typen weitestgehend analog):&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;TCCR0&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;T&#039;&#039;&#039;imer/&#039;&#039;&#039;C&#039;&#039;&#039;ounter &#039;&#039;&#039;C&#039;&#039;&#039;ontrol &#039;&#039;&#039;R&#039;&#039;&#039;egister&lt;br /&gt;
Timer &#039;&#039;&#039;0&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
In diesem Register stellen wir ein, wie wir den Timer/Counter verwenden möchten.&lt;br /&gt;
&lt;br /&gt;
Das Register ist wie folgt aufgebaut:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Bit&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 7&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 6&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 5&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 4&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 2&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Name&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;CS02&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;CS01&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;CS00&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;R/W&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Initialwert&#039;&#039;&#039;&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;
| 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;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;CS02, CS01, CS00&#039;&#039;&#039; (&#039;&#039;&#039;C&#039;&#039;&#039;lock &#039;&#039;&#039;S&#039;&#039;&#039;elect Bits)&lt;br /&gt;
:Diese 3 Bits bestimmen die Quelle für den Timer/Counter:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | CS02&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | CS01&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | CS00&lt;br /&gt;
| Resultat&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;
| Stopp, Der Timer/Counter wird 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;
| CPU-Takt&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;
| CPU-Takt / 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;
| CPU-Takt / 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;
| CPU-Takt / 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;
| CPU-Takt / 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;
| Externer Pin &#039;&#039;&#039;TO&#039;&#039;&#039;, 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;
| Externer Pin &#039;&#039;&#039;TO&#039;&#039;&#039;, steigende Flanke&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/dd&amp;gt;&lt;br /&gt;
&amp;lt;/dl&amp;gt;&lt;br /&gt;
:Wenn als Quelle der externe Pin &#039;&#039;&#039;TO&#039;&#039;&#039; verwendet wird, so wird ein Flankenwechsel auch erkannt, wenn der Pin &#039;&#039;&#039;TO&#039;&#039;&#039; als Ausgang geschaltet ist.&lt;br /&gt;
&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;TCNT0&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;T&#039;&#039;&#039;imer/&#039;&#039;&#039;C&#039;&#039;&#039;ou&#039;&#039;&#039;nt&#039;&#039;&#039;er Daten Register Timer &#039;&#039;&#039;0&#039;&#039;&#039;&amp;lt;br /&amp;gt;&lt;br /&gt;
Dieses ist als 8-Bit Aufwärtszähler mit Schreib- und Lesezugriff&lt;br /&gt;
realisiert. Wenn der Zähler den Wert 255 erreicht hat beginnt er beim&lt;br /&gt;
nächsten Zyklus wieder bei 0.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Bit&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 7&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 6&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 5&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 4&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 2&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Name&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;MSB&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;LSB&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;R/W&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Initialwert&#039;&#039;&#039;&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;
| 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;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Um nun also den Timer0 in Betrieb zu setzen und ihn mit einer Frequenz von 1/1024-tel des CPU-Taktes zählen zu lassen, schreiben wir die folgende Befehlszeile:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
    TCCR0 |= (1&amp;lt;&amp;lt;CS00)|(1&amp;lt;&amp;lt;CS02);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Zähler zählt nun aufwärts bis 255, um dann wieder bei 0 zu beginnen. Der aktuelle Zählerstand steht in TCNT0. Bei jedem Überlauf von 255 auf 0 wird das Timer Overflow Flag &#039;&#039;&#039;TOV0&#039;&#039;&#039; im Timer Interrupt Flag &#039;&#039;&#039;TIFR&#039;&#039;&#039;-Register gesetzt und, falls so konfiguriert, ein entsprechender Timer-Overflow-Interrupt ausgelöst und die daran gebundene Interrupt-Routine abgearbeitet. Das TOV Flag &lt;br /&gt;
lässt sich durch das Hineinschreiben einer 1 und nicht wie erwartet einer 0 wieder zurücksetzen.&lt;br /&gt;
&lt;br /&gt;
== 16-Bit Timer/Counter ==&lt;br /&gt;
&lt;br /&gt;
Viele AVR-Modelle besitzen außer den 8-Bit Timern auch 16-Bit Timer. Die 16-Bit Timer/Counter sind etwas komplexer aufgebaut als die 8-Bit Timer/Counter, bieten dafür aber auch viel mehr Möglichkeiten, als da sind:&lt;br /&gt;
&lt;br /&gt;
* Die [[PWM]]-Betriebsart Erzeugung eines pulsweitenmodulierten Ausgangssignals. &lt;br /&gt;
* Vergleichswert-Überprüfung mit Erzeugung eines Ausgangssignals (Output Compare Match).&lt;br /&gt;
* Einfangen eines Eingangssignals mit Speicherung des aktuellen Zählerwertes (Input Capturing), mit zuschaltbarer Rauschunterdrückung (Noise Filtering).&lt;br /&gt;
&lt;br /&gt;
Folgende Register sind dem Timer/Counter 1 zugeordnet:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;TCCR1A&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;T&#039;&#039;&#039;imer/&#039;&#039;&#039;C&#039;&#039;&#039;ounter &#039;&#039;&#039;C&#039;&#039;&#039;ontrol &#039;&#039;&#039;R&#039;&#039;&#039;egister &#039;&#039;&#039;A&#039;&#039;&#039; Timer &#039;&#039;&#039;1&#039;&#039;&#039;&amp;lt;br /&amp;gt;&lt;br /&gt;
In diesem und dem folgenden Register stellen wir ein, wie wir den Timer/Counter verwenden möchten.&amp;lt;br /&amp;gt;&lt;br /&gt;
Das Register ist wie folgt aufgebaut:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Bit&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 7&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 6&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 5&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 4&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 2&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Name&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;COM1A1&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;COM1A0&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;PWM11&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;PWM10&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;R/W&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Initialwert&#039;&#039;&#039;&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;
| 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;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;COM1A1&#039;&#039;&#039;, &#039;&#039;&#039;COM1A0&#039;&#039;&#039; (&#039;&#039;&#039;Co&#039;&#039;&#039;mpare &#039;&#039;&#039;M&#039;&#039;&#039;atch Control Bits)&lt;br /&gt;
:Diese 2 Bits bestimmen die Aktion, welche am Output-Pin &#039;&#039;&#039;OC1&#039;&#039;&#039; ausgeführt werden soll, wenn der Wert des Datenregisters des Timer/Counter 1 den Wert des Vergleichsregisters erreicht, also ein so genannter Compare Match auftritt.&lt;br /&gt;
:Der Pin &#039;&#039;&#039;OC1&#039;&#039;&#039; (&#039;&#039;&#039;PB3&#039;&#039;&#039; beim 2313) muss mit dem Datenrichtungsregister als Ausgang konfiguriert werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | COM1A1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | COM1A0&lt;br /&gt;
| Resultat&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;
| Output-Pin &#039;&#039;&#039;OC1&#039;&#039;&#039; wird nicht angesteuert.&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;
| Das Signal am Pin &#039;&#039;&#039;OC1&#039;&#039;&#039; wird invertiert (Toggle).&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;
| Der Output Pin &#039;&#039;&#039;OC1&#039;&#039;&#039; wird auf 0 gesetzt.&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;
| Der Output Pin &#039;&#039;&#039;OC1&#039;&#039;&#039; wird auf 1 gesetzt.&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&lt;br /&gt;
:In der PWM-Betriebsart haben diese Bits eine andere Funktion.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | COM1A1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | COM1A0&lt;br /&gt;
| Resultat&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;
| Output-Pin &#039;&#039;&#039;OC1&#039;&#039;&#039; wird nicht angesteuert.&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;
| Output-Pin &#039;&#039;&#039;OC1&#039;&#039;&#039; wird nicht angesteuert.&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;
| Wird beim Hochzählen der Wert im Vergleichsregister erreicht, so wird der Pin &#039;&#039;&#039;OC1&#039;&#039;&#039; auf 0 gesetzt.&lt;br /&gt;
Wird beim Herunterzählen der Wert im Vergleichsregister erreicht, so wird der Pin auf 1 gesetzt.&lt;br /&gt;
&lt;br /&gt;
Man nennt dies &#039;&#039;nicht invertierende PWM&#039;&#039;.&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;
| Wird beim Hochzählen der Wert im Vergleichsregister erreicht, so wird der Pin &#039;&#039;&#039;OC1&#039;&#039;&#039; auf 1 gesetzt.&lt;br /&gt;
Wird beim Herunterzählen der Wert im Vergleichsregister erreicht, so wird der Pin auf 0 gesetzt.&lt;br /&gt;
&lt;br /&gt;
Man nennt dies &#039;&#039;invertierende PWM&#039;&#039;.&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;PWM11&#039;&#039;&#039;, &#039;&#039;&#039;PWM10&#039;&#039;&#039; (&#039;&#039;&#039;PWM&#039;&#039;&#039; Mode Select Bits)&lt;br /&gt;
:Mit diesen 2 Bits wird die PWM-Betriebsart des Timer/Counter 1 gesteuert.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | PWM11&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | PWM10&lt;br /&gt;
| Resultat&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;
| Die PWM-Betriebsart ist nicht aktiviert. Timer/Counter 1 arbeitet als normaler Timer bzw. Zähler.&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;
| 8-Bit PWM Betriebsart aktivieren.&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;
| 9-Bit PWM Betriebsart aktivieren.&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;
| 10-Bit PWM Betriebsart aktivieren.&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;TCCR1B&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;T&#039;&#039;&#039;imer/&#039;&#039;&#039;C&#039;&#039;&#039;ounter &#039;&#039;&#039;C&#039;&#039;&#039;ontrol &#039;&#039;&#039;R&#039;&#039;&#039;egister &#039;&#039;&#039;B&#039;&#039;&#039; Timer &#039;&#039;&#039;1&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Bit&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 7&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 6&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 5&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 4&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 2&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Name&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ICNC1&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ICES1&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;WGM13&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;WGM12 (CTC1)&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;CS12&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;CS11&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;CS10&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;R/W&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Initialwert&#039;&#039;&#039;&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;
| 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;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ICNC1&#039;&#039;&#039; (&#039;&#039;&#039;I&#039;&#039;&#039;nput &#039;&#039;&#039;C&#039;&#039;&#039;apture &#039;&#039;&#039;N&#039;&#039;&#039;oise &#039;&#039;&#039;C&#039;&#039;&#039;anceler (4 CKs) Timer/Counter 1&lt;br /&gt;
:oder auf Deutsch Rauschunterdrückung des Eingangssignals.&lt;br /&gt;
:Wenn dieses Bit gesetzt ist und mit dem Input Capture Signal gearbeitet wird so werden nach der Triggerung des Signals mit der entsprechenden Flanke (steigend oder fallend) am Input Capture Pin &#039;&#039;&#039;ICP&#039;&#039;&#039; jeweils 4 Messungen mit der CPU-Frequenz des Eingangssignals abgefragt. Nur dann, wenn alle 4 Messungen den gleichen Zustand aufweisen gilt das Signal als erkannt.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ICES1&#039;&#039;&#039; (&#039;&#039;&#039;I&#039;&#039;&#039;nput &#039;&#039;&#039;C&#039;&#039;&#039;apture &#039;&#039;&#039;E&#039;&#039;&#039;dge &#039;&#039;&#039;S&#039;&#039;&#039;elect Timer/Counter &#039;&#039;&#039;1&#039;&#039;&#039;)&lt;br /&gt;
:Mit diesem Bit wird bestimmt, ob die steigende (&#039;&#039;&#039;ICES1&#039;&#039;&#039;=1) oder fallende (&#039;&#039;&#039;ICES1&#039;&#039;&#039;=0) Flanke zur Auswertung des Input Capture Signals an Pin &#039;&#039;&#039;ICP&#039;&#039;&#039; heran gezogen wird.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;CTC1&#039;&#039;&#039; (&#039;&#039;&#039;C&#039;&#039;&#039;lear &#039;&#039;&#039;T&#039;&#039;&#039;imer/&#039;&#039;&#039;C&#039;&#039;&#039;ounter on Compare Match Timer/Counter &#039;&#039;&#039;1&#039;&#039;&#039;)&lt;br /&gt;
:Wenn dieses Bit gesetzt ist, so wird nach einer Übereinstimmung des Datenregisters &#039;&#039;&#039;TCNT1H&#039;&#039;&#039;/&#039;&#039;&#039;TCNT1L&#039;&#039;&#039; mit dem Vergleichswert in &#039;&#039;&#039;OCR1H&#039;&#039;&#039;/&#039;&#039;&#039;OCR1L&#039;&#039;&#039; das Datenregister &#039;&#039;&#039;TCNT1H&#039;&#039;&#039;/&#039;&#039;&#039;TCNT1L&#039;&#039;&#039; auf 0 gesetzt.&lt;br /&gt;
:Da die Übereinstimmung im Takt nach dem Vergleich behandelt wird, ergibt sich je nach eingestelltem Vorteiler ein etwas anderes Zählverhalten:&lt;br /&gt;
:Wenn der Vorteiler auf 1 gestellt, und C der voreingestellte Vergleichswert ist, dann nimmt das Datenregister, im CPU-Takt betrachtet, folgende Werte an:&lt;br /&gt;
:... | C-2 | C-1 | C | 0 | 1 |...&lt;br /&gt;
:Wenn der Vorteiler z.B. auf 8 eingestellt ist, dann nimmt das Datenregister folgende Werte an:&lt;br /&gt;
:... | C-2, C-2, C-2, C-2, C-2, C-2, C-2, C-2 | C-1, C-1, C-1, C-1, C-1, C-1, C-1, C-1 | C, 0, 0, 0, 0, 0, 0, 0 |...&lt;br /&gt;
:In der PWM-Betriebsart hat dieses Bit keine Funktion.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;CS12&#039;&#039;&#039;, &#039;&#039;&#039;CS11&#039;&#039;&#039;, &#039;&#039;&#039;CS10&#039;&#039;&#039; (&#039;&#039;&#039;C&#039;&#039;&#039;lock &#039;&#039;&#039;S&#039;&#039;&#039;elect Bits)&lt;br /&gt;
:Diese 3 Bits bestimmen die Quelle für den Timer/Counter:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | CS12&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | CS11&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | CS10&lt;br /&gt;
| Resultat&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;
| Stopp, Der Timer/Counter wird 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;
| CPU-Takt&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;
| CPU-Takt / 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;
| CPU-Takt / 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;
| CPU-Takt / 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;
| CPU-Takt / 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;
| Externer 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;
| Externer Pin T1, steigende Flanke&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&lt;br /&gt;
:Wenn als Quelle der externe Pin T1 verwendet wird, so wird ein Flankenwechsel auch erkannt, wenn der Pin T1 als Ausgang geschaltet ist.&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;TCNT1H&#039;&#039;&#039;&amp;lt;br /&amp;gt;&#039;&#039;&#039;TCNT1L&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;T&#039;&#039;&#039;imer/&#039;&#039;&#039;C&#039;&#039;&#039;ou&#039;&#039;&#039;nt&#039;&#039;&#039;er Daten Register Timer/Counter &#039;&#039;&#039;1&#039;&#039;&#039;&lt;br /&gt;
Dieses ist als 16-Bit Aufwärtszähler mit Schreib- und Lesezugriff realisiert. Wenn der Zähler den Wert 65535 erreicht hat, beginnt er beim nächsten Zyklus wieder bei 0.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Bit&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 7&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 6&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 5&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 4&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 2&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; | &amp;amp;nbsp;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Name&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;MSB&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;TCNT1H&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Name&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;LSB&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;TCNT1L&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;R/W&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Initialwert&#039;&#039;&#039;&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;
| 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;
| 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; | &amp;amp;nbsp;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
In der PWM-Betriebsart wird das Register als Auf/Ab-Zähler verwendet, d.h. der Wert steigt zuerst von 0, bis er den Überlauf von 65535 auf 0 erreicht hat. Dann zählt das Register rückwärts wiederum bis 0.&lt;br /&gt;
&lt;br /&gt;
Zum Auslesen des Registers wird von der CPU ein internes TEMP-Register verwendet. Das gleiche Register wird auch verwendet, wenn auf &#039;&#039;&#039;OCR1&#039;&#039;&#039; oder &#039;&#039;&#039;ICR1&#039;&#039;&#039; zugegriffen wird.&lt;br /&gt;
&lt;br /&gt;
Deshalb müssen vor dem Zugriff auf eines dieser Register alle Interrupts gesperrt werden, weil sonst die Möglichkeit des gleichzeitigen Zugriffs auf das Temporärregister gegeben ist, was natürlich zu fehlerhaftem Verhalten des Programms führt.. Zudem muss zuerst &#039;&#039;&#039;TCNT1L&#039;&#039;&#039; und erst danach &#039;&#039;&#039;TCNT1H&#039;&#039;&#039; ausgelesen werden.&lt;br /&gt;
&lt;br /&gt;
Wenn in das Register geschrieben werden soll, müssen ebenfalls alle Interrrupts gesperrt werden. Dann muss zuerst das &#039;&#039;&#039;TCNT1H&#039;&#039;&#039;-Register und erst danach das &#039;&#039;&#039;TCNT1L&#039;&#039;&#039;-Register geschrieben werden, also genau die umgekehrte Reihenfolge wie beim Lesen des Registers.&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;OCR1H&#039;&#039;&#039;&amp;lt;br /&amp;gt;&#039;&#039;&#039;OCR1L&#039;&#039;&#039;&lt;br /&gt;
| Timer/Counter &#039;&#039;&#039;O&#039;&#039;&#039;utput &#039;&#039;&#039;C&#039;&#039;&#039;ompare &#039;&#039;&#039;R&#039;&#039;&#039;egister Timer/Counter &#039;&#039;&#039;1&#039;&#039;&#039;&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Bit&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 7&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 6&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 5&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 4&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 2&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; | &amp;amp;nbsp;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Name&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;MSB&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;OCR1H&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Name&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;LSB&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;OCR1L&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;R/W&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Initialwert&#039;&#039;&#039;&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;
| 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;
| 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; | &amp;amp;nbsp;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Der Wert im Output Compare Register wird ständig mit dem aktuellen Wert im Datenregister TCNT1H/TCNT1L verglichen. Stimmen die beiden Werte überein, so wird ein sogenannter Output Compare Match ausgelöst. Die entsprechenden Aktionen werden über die Timer/Counter 1 Control und Status Register eingestellt.&lt;br /&gt;
&lt;br /&gt;
Zum Auslesen des Registers wird von der CPU ein internes TEMP-Register verwendet. Das gleiche Register wird auch verwendet, wenn auf &#039;&#039;&#039;TCNT1&#039;&#039;&#039; oder &#039;&#039;&#039;ICR1&#039;&#039;&#039; zugegriffen wird.&lt;br /&gt;
Deshalb müssen vor dem Zugriff auf eines dieser Register alle Interrupts gesperrt werden, weil sonst die Möglichkeit des gleichzeitigen Zugriffs auf das Temporärregister gegeben ist, was natürlich zu fehlerhaftem Verhalten des Programms führt.. Zudem muss zuerst &#039;&#039;&#039;OCR1L&#039;&#039;&#039; und erst danach &#039;&#039;&#039;OCR1H&#039;&#039;&#039; ausgelesen werden.&lt;br /&gt;
&lt;br /&gt;
Wenn in das Register geschrieben werden soll, müssen ebenfalls alle Interrupts gesperrt werden. Dann muss zuerst das &#039;&#039;&#039;OCR1H&#039;&#039;&#039;-Register und erst danach das &#039;&#039;&#039;OCR1L&#039;&#039;&#039;-Register geschrieben werden, also genau die umgekehrte Reihenfolge wie beim Lesen des Registers.&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;ICR1H&#039;&#039;&#039;&amp;lt;br /&amp;gt;&#039;&#039;&#039;ICR1L&#039;&#039;&#039;&lt;br /&gt;
| Timer/Counter &#039;&#039;&#039;I&#039;&#039;&#039;nput &#039;&#039;&#039;C&#039;&#039;&#039;apture &#039;&#039;&#039;R&#039;&#039;&#039;egister Timer/Counter &#039;&#039;&#039;1&#039;&#039;&#039;&amp;lt;br /&amp;gt;&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Bit&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 7&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 6&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 5&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 4&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 2&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; | &amp;amp;nbsp;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Name&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;MSB&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ICR1&#039;&#039;&#039;&#039;&#039;&#039;H&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Name&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;LSB&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ICR1&#039;&#039;&#039;&#039;&#039;&#039;L&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;R/W&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Initialwert&#039;&#039;&#039;&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;
| 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;
| 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; | &amp;amp;nbsp;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Das Input Capture Register ist ein 16-Bit Register mit Lesezugriff. Es kann nicht beschrieben werden.&lt;br /&gt;
&lt;br /&gt;
Wenn am Input Capture Pin &#039;&#039;&#039;ICP&#039;&#039;&#039; die gemäß Einstellungen im &#039;&#039;&#039;TCCR1B&#039;&#039;&#039; definierte Flanke erkannt wird, so wird der aktuelle Inhalt des Datenregisters &#039;&#039;&#039;TCNT1H&#039;&#039;&#039;/&#039;&#039;&#039;TCNT1L&#039;&#039;&#039; sofort in dieses Register kopiert und das Input Capture Flag &#039;&#039;&#039;ICF1&#039;&#039;&#039; im Timer Interrupt Flag Register &#039;&#039;&#039;TIFR&#039;&#039;&#039; gesetzt.&lt;br /&gt;
&lt;br /&gt;
Wie bereits oben erwähnt, müssen vor dem Zugriff auf dieses Register alle Interrupts gesperrt werden. Zudem müssen Low- und Highbyte des Registers in der richtigen Reihenfolge bearbeitet werden:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;0&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| Lesen:&lt;br /&gt;
| &#039;&#039;&#039;ICR1L&#039;&#039;&#039; -&amp;gt; &#039;&#039;&#039;ICR1H&#039;&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Die PWM-Betriebsart ===&lt;br /&gt;
&lt;br /&gt;
Wenn der Timer/Counter 1 in der PWM-Betriebsart betrieben wird, so bilden das Datenregister &#039;&#039;&#039;TCNT1H&#039;&#039;&#039;/&#039;&#039;&#039;TCNT1L&#039;&#039;&#039; und das Vergleichsregister &#039;&#039;&#039;OCR1H&#039;&#039;&#039;/&#039;&#039;&#039;OCR1L&#039;&#039;&#039; einen 8-, 9- oder 10-Bit, frei laufenden PWM-Modulator, welcher als PWM-Signal am &#039;&#039;&#039;OC1&#039;&#039;&#039;-Pin (&#039;&#039;&#039;PB3&#039;&#039;&#039; beim 2313) abgegriffen werden kann. Das Datenregister &#039;&#039;&#039;TCNT1H&#039;&#039;&#039;/&#039;&#039;&#039;TCNT1L&#039;&#039;&#039; wird dabei als Auf-/Ab-Zähler betrieben, welcher von 0 an aufwärts zählt bis zur Obergrenze und danach wieder zurück auf 0.&lt;br /&gt;
Die Obergrenze ergibt sich daraus, ob 8-, 9- oder 10-Bit PWM verwendet wird, und zwar gemäß folgender Tabelle:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;Auflösung&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;Obergrenze&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Frequenz&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 8&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 255&lt;br /&gt;
| f&amp;lt;sub&amp;gt;TC1&amp;lt;/sub&amp;gt; / 510&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 9&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 511&lt;br /&gt;
| f&amp;lt;sub&amp;gt;TC1&amp;lt;/sub&amp;gt; / 1022&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 10&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1023&lt;br /&gt;
| f&amp;lt;sub&amp;gt;TC1&amp;lt;/sub&amp;gt; / 2046&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Wenn nun der Zählerwert im Datenregister den in &#039;&#039;&#039;OCR1H&#039;&#039;&#039;/&#039;&#039;&#039;OCR1L&#039;&#039;&#039; gespeicherten Wert erreicht, wird der Ausgabepin &#039;&#039;&#039;OC1&#039;&#039;&#039; gesetzt bzw. gelöscht, je nach Einstellung von &#039;&#039;&#039;COM1A1&#039;&#039;&#039; und &#039;&#039;&#039;COM1A0&#039;&#039;&#039; im &#039;&#039;&#039;TCCR1A&#039;&#039;&#039;-Register.&lt;br /&gt;
&lt;br /&gt;
Ich habe versucht, die entsprechenden Signale in der folgenden Grafik zusammenzufassen&lt;br /&gt;
&lt;br /&gt;
[[Image:PWM Theorie 3.gif]] [[Image:PWM Theorie 4.gif]]&lt;br /&gt;
&lt;br /&gt;
=== Vergleichswert-Überprüfung ===&lt;br /&gt;
&lt;br /&gt;
Hier wird in ein spezielles Vergleichswertregister (&#039;&#039;&#039;OCR1H&#039;&#039;&#039;/&#039;&#039;&#039;OCR1L&#039;&#039;&#039;) ein Wert eingeschrieben, welcher ständig mit dem aktuellen Zählerwert verglichen wird.&lt;br /&gt;
Erreicht der Zähler den in diesem Register eingetragenen Wert, so kann ein Signal (0 oder 1) am Pin &#039;&#039;&#039;OC1&#039;&#039;&#039; erzeugt und/oder ein Interrupt ausgelöst werden.&lt;br /&gt;
&lt;br /&gt;
=== Einfangen eines Eingangssignals (Input Capturing) ===&lt;br /&gt;
&lt;br /&gt;
Bei dieser Betriebsart wird an den Input Capturing Pin (ICP) des Controllers eine Signalquelle angeschlossen.&lt;br /&gt;
Nun kann je nach Konfiguration entweder ein Signalwechsel von 0 nach 1 (steigende Flanke) oder von 1 nach 0 (fallende Flanke) erkannt werden und der zu diesem Zeitpunkt aktuelle Zählerstand in ein spezielles Register abgelegt werden. Gleichzeitig kann auch ein entsprechender Interrupt ausgelöst werden.&lt;br /&gt;
Wenn die Signalquelle ein starkes Rauschen beinhaltet, kann die Rauschunterdrückung eingeschaltet werden. Dann wird beim Erkennen der konfigurierten Flanke über 4 Taktzyklen das Signal überwacht und nur dann, wenn alle 4 Messungen gleich sind, wird die entsprechende Aktion ausgelöst.&lt;br /&gt;
&lt;br /&gt;
== Gemeinsame Register ==&lt;br /&gt;
&lt;br /&gt;
Verschiedene Register beinhalten Zustände und Einstellungen, welche sowohl&lt;br /&gt;
für den 8-Bit, als auch für den 16-Bit Timer/Counter in ein und demselben&lt;br /&gt;
Register zu finden sind.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;TIMSK&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;T&#039;&#039;&#039;imer/Counter &#039;&#039;&#039;I&#039;&#039;&#039;nterrupt &#039;&#039;&#039;M&#039;&#039;&#039;a&#039;&#039;&#039;sk&#039;&#039;&#039;&lt;br /&gt;
Register&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Bit&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 7&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 6&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 5&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 4&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 2&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Name&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;TOIE1&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;OCIE1A&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;TICIE&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;TOIE0&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;R/W&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Initialwert&#039;&#039;&#039;&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;
| 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;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;TOIE1&#039;&#039;&#039; (&#039;&#039;&#039;T&#039;&#039;&#039;imer/Counter &#039;&#039;&#039;O&#039;&#039;&#039;verflow &#039;&#039;&#039;I&#039;&#039;&#039;nterrupt &#039;&#039;&#039;E&#039;&#039;&#039;nable Timer/Counter &#039;&#039;&#039;1&#039;&#039;&#039;)&lt;br /&gt;
:Wenn dieses Bit gesetzt ist, wird bei einem Überlauf des Datenregisters des Timer/Counter 1 ein Timer Overflow 1 Interrupt ausgelöst. Das Global Enable Interrupt Flag muss selbstverständlich auch gesetzt sein.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;OCIE1A&#039;&#039;&#039; (&#039;&#039;&#039;O&#039;&#039;&#039;utput &#039;&#039;&#039;C&#039;&#039;&#039;ompare Match &#039;&#039;&#039;I&#039;&#039;&#039;nterrupt &#039;&#039;&#039;E&#039;&#039;&#039;nable Timer/Counter &#039;&#039;&#039;1&#039;&#039;&#039;)&lt;br /&gt;
:Beim Timer/Counter 1 kann zusätzlich zum Überlauf ein Vergleichswert definiert werden.&lt;br /&gt;
&lt;br /&gt;
:Wenn dieses Bit gesetzt ist, wird beim Erreichen des Vergleichswertes ein Compare Match Interrupt ausgelöst. Das Global Enable Interrupt Flag muss selbstverständlich auch gesetzt sein.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;TICIE&#039;&#039;&#039; (&#039;&#039;&#039;T&#039;&#039;&#039;imer/Counter &#039;&#039;&#039;I&#039;&#039;&#039;nput &#039;&#039;&#039;C&#039;&#039;&#039;apture &#039;&#039;&#039;I&#039;&#039;&#039;nterrupt &#039;&#039;&#039;E&#039;&#039;&#039;nable)&lt;br /&gt;
:Wenn dieses Bit gesetzt ist, wird ein Capture Event Interrupt ausgelöst, wenn ein entsprechendes Signalereignis am Pin PD6(ICP) auftritt. Das Global Enable Interrupt Flag muss selbstverständlich auch gesetzt sein, wenn auch ein entsprechender Interrupt ausgelöst werden soll.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;TOIE0&#039;&#039;&#039; (&#039;&#039;&#039;T&#039;&#039;&#039;imer/Counter &#039;&#039;&#039;O&#039;&#039;&#039;verflow &#039;&#039;&#039;I&#039;&#039;&#039;nterrupt &#039;&#039;&#039;E&#039;&#039;&#039;nable Timer/Counter &#039;&#039;&#039;0&#039;&#039;&#039;)&lt;br /&gt;
:Wenn dieses Bit gesetzt ist, wird bei einem Überlauf des Datenregisters des Timer/Counter 0 ein Timer Overflow 0 Interrupt ausgelöst. Das Global Enable Interrupt Flag muss selbstverständlich auch gesetzt sein.&lt;br /&gt;
&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;TIFR&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;T&#039;&#039;&#039;imer/Counter &#039;&#039;&#039;I&#039;&#039;&#039;nterrupt &#039;&#039;&#039;F&#039;&#039;&#039;lag &#039;&#039;&#039;R&#039;&#039;&#039;egister&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Bit&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 7&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 6&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 5&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 4&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 2&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Name&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;TOV1&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;OCF1A&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ICF1&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;TOV0&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;R/W&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Initialwert&#039;&#039;&#039;&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;
| 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;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;TOV1&#039;&#039;&#039; (&#039;&#039;&#039;T&#039;&#039;&#039;imer/Counter &#039;&#039;&#039;O&#039;&#039;&#039;verflow Flag Timer/Counter &#039;&#039;&#039;1&#039;&#039;&#039;)&lt;br /&gt;
:Dieses Bit wird vom Controller gesetzt, wenn beim Timer 1 ein Überlauf des Datenregisters stattfindet.&lt;br /&gt;
&lt;br /&gt;
:In der PWM-Betriebsart wird das Bit gesetzt, wenn die Zählrichtung von auf- zu abwärts und umgekehrt geändert wird (Zählerwert = 0).&lt;br /&gt;
&lt;br /&gt;
:Das Flag wird automatisch gelöscht, wenn der zugehörige Interrupt-Vektor aufgerufen wird. Es kann jedoch auch gelöscht werden, indem eine logische 1 (!) in das entsprechende Bit geschrieben wird.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;OCF1A&#039;&#039;&#039; (&#039;&#039;&#039;O&#039;&#039;&#039;utput &#039;&#039;&#039;C&#039;&#039;&#039;ompare &#039;&#039;&#039;F&#039;&#039;&#039;lag Timer/Counter &#039;&#039;&#039;1&#039;&#039;&#039;)&lt;br /&gt;
:Dieses Bit wird gesetzt, wenn der aktuelle Wert des Datenregisters von Timer/Counter 1 mit demjenigen im Vergleichsregister &#039;&#039;&#039;OCR1&#039;&#039;&#039; übereinstimmt.&lt;br /&gt;
&lt;br /&gt;
:Das Flag wird automatisch gelöscht, wenn der zugehörige Interrupt-Vektor aufgerufen wird. Es kann jedoch auch gelöscht werden, indem eine logische 1 (!) in das entsprechende Bit geschrieben wird.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ICF1&#039;&#039;&#039; (&#039;&#039;&#039;I&#039;&#039;&#039;nput &#039;&#039;&#039;C&#039;&#039;&#039;apture &#039;&#039;&#039;F&#039;&#039;&#039;lag Timer/Counter &#039;&#039;&#039;1&#039;&#039;&#039;)&lt;br /&gt;
:Dieses Bit wird gesetzt, wenn ein Capture-Ereignis aufgetreten ist, welches anzeigt, dass der Wert des Datenregisters des  Timer/Counter 1 in das Input Capture Register ICR1 übertragen wurde.&lt;br /&gt;
&lt;br /&gt;
:Das Flag wird automatisch gelöscht, wenn der zugehörige Interrupt-Vektor aufgerufen wird. Es kann jedoch auch gelöscht werden, indem eine logische 1 (!) in das entsprechende Bit geschrieben wird.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;TOV0&#039;&#039;&#039; (&#039;&#039;&#039;T&#039;&#039;&#039;imer/Counter &#039;&#039;&#039;O&#039;&#039;&#039;verflow Flag Timer/Counter &#039;&#039;&#039;0&#039;&#039;&#039;)&lt;br /&gt;
:Dieses Bit wird vom Controller gesetzt, wenn beim Timer 0 ein Überlauf des Datenregisters stattfindet.&lt;br /&gt;
&lt;br /&gt;
:Das Flag wird automatisch gelöscht, wenn der zugehörige Interrupt-Vektor aufgerufen wird. Es kann jedoch auch gelöscht werden, indem eine logische 1 (!) in das entsprechende Bit geschrieben wird.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;amp;nbsp;&lt;br /&gt;
&lt;br /&gt;
= Warteschleifen (delay.h) =&lt;br /&gt;
&lt;br /&gt;
Der Programmablauf kann verschiedene Arten von Wartefunktionen erfordern:&lt;br /&gt;
&lt;br /&gt;
* Warten im Sinn von Zeitvertrödeln&lt;br /&gt;
* Warten auf einen bestimmten Zustand an den I/O-Pins&lt;br /&gt;
* Warten auf einen bestimmten Zeitpunkt (siehe Timer)&lt;br /&gt;
* Warten auf einen bestimmten Zählerstand (siehe Counter)&lt;br /&gt;
&lt;br /&gt;
Der einfachste Fall, das Zeitvertrödeln, kann in vielen Fällen und mit großer Genauigkeit anhand der avr-libc Bibliotheksfunktionen _delay_ms() und _delay_us() erledigt werden. Die Bibliotheksfunktionen sind einfachen Zählschleifen (Warteschleifen) vorzuziehen, da leere Zählschleifen ohne besondere Vorkehrungen sonst bei eingeschalteter Optimierung vom avr-gcc-Compiler wegoptimiert werden. Weiterhin sind die Bibliotheksfunktionen bereits darauf vorbereitet, die in F_CPU definierte Taktfrequenz zu verwenden. Ausserdem sind die Funktionen der Bibliothek wirklich getestet.&lt;br /&gt;
&lt;br /&gt;
Einfach!? Schon, aber während gewartet wird, macht der µC nichts anderes mehr. Die Wartefunktion blockiert den Programmablauf. Möchte man einerseits warten, um z.B. eine LED blinken zu lassen und gleichzeitig andere Aktionen ausführen z.B. weitere LED bedienen, sollten die Timer/Counter des AVR verwendet werden.&lt;br /&gt;
&lt;br /&gt;
Die Bibliotheksfunktionen funktionieren allerdings nur dann korrekt, wenn sie mit zur Übersetzungszeit (beim Compilieren) bekannten konstanten Werten aufgerufen werden. Der Quellcode muss mit eingeschalteter Optimierung übersetzt werden, sonst wird sehr viel Maschinencode erzeugt und die Wartezeiten stimmen nicht mehr mit dem Parameter überein.&lt;br /&gt;
&lt;br /&gt;
Abhängig von der Version der Bibliothek verhalten sich die Bibliotheksfunktionen etwas unterschiedlich.&lt;br /&gt;
&lt;br /&gt;
== avr-libc Versionen kleiner 1.6 ==&lt;br /&gt;
&lt;br /&gt;
Die Wartezeit der Funktion _delay_ms() ist auf 262,14ms/F_CPU (in MHz) begrenzt, d.h. bei 20 MHz kann man nur max. 13,1ms warten. Die Wartezeit der Funktion _delay_us() ist auf 768us/F_CPU (in MHz) begrenzt, d.h. bei 20 MHz kann man nur max. 38,4us warten. Längere Wartezeiten müssen dann über einen mehrfachen Aufruf in einer Schleife gelöst werden.&lt;br /&gt;
&lt;br /&gt;
Beispiel: Blinken einer LED an PORTB Pin PB0 im ca. 1s Rhythmus&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#ifndef F_CPU&lt;br /&gt;
/* Definiere F_CPU, wenn F_CPU nicht bereits vorher definiert &lt;br /&gt;
   (z.B. durch Übergabe als Parameter zum Compiler innerhalb &lt;br /&gt;
   des Makefiles). Zusätzlich Ausgabe einer Warnung, die auf die&lt;br /&gt;
   &amp;quot;nachträgliche&amp;quot; Definition hinweist */&lt;br /&gt;
#warning &amp;quot;F_CPU war noch nicht definiert, wird nun mit 3686400 definiert&amp;quot;&lt;br /&gt;
#define F_CPU 3686400UL     /* Quarz mit 3.6864 Mhz */&lt;br /&gt;
#endif&lt;br /&gt;
#include &amp;lt;util/delay.h&amp;gt;     /* in älteren avr-libc Versionen &amp;lt;avr/delay.h&amp;gt; */ &lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
 lange, variable Verzögerungszeit, Einheit in Millisekunden&lt;br /&gt;
&lt;br /&gt;
Die maximale Zeit pro Funktionsaufruf ist begrenzt auf &lt;br /&gt;
262.14 ms / F_CPU in MHz (im Beispiel: &lt;br /&gt;
262.1 / 3.6864 = max. 71 ms) &lt;br /&gt;
&lt;br /&gt;
Daher wird die kleine Warteschleife mehrfach aufgerufen,&lt;br /&gt;
um auf eine längere Wartezeit zu kommen. Die zusätzliche &lt;br /&gt;
Prüfung der Schleifenbedingung lässt die Wartezeit geringfügig&lt;br /&gt;
ungenau werden (macht hier vielleicht 2-3ms aus).&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
void long_delay(uint16_t ms) {&lt;br /&gt;
    for(; ms&amp;gt;0; ms--) _delay_ms(1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int main( void )&lt;br /&gt;
{&lt;br /&gt;
    DDRB = ( 1 &amp;lt;&amp;lt; PB0 );        // PB0 an PORTB als Ausgang setzen&lt;br /&gt;
&lt;br /&gt;
    while( 1 ) {                // Endlosschleife&lt;br /&gt;
        PORTB ^= ( 1 &amp;lt;&amp;lt; PB0 );  // Toggle PB0 z.B. angeschlossene LED&lt;br /&gt;
        long_delay(1000);       // Eine Sekunde warten...&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== avr-libc Versionen ab 1.6 ==&lt;br /&gt;
&lt;br /&gt;
_delay_ms() kann mit einem Argument bis 6553,5 ms (= 6,5535 Sekunden) benutzt werden. Wird die früher gültige Grenze von 262,14 ms/F_CPU (in MHz) überschritten, so arbeitet _delay_ms() einfach etwas ungenauer und zählt nur noch mit einer Auflösung von 1/10 ms. Eine Verzögerung von 1000,10 ms ließe sich nicht mehr von einer von 1000,19 ms unterscheiden. Ein Verlust, der sich im Allgemeinen verschmerzen lässt. Dem Programmierer wird keine Rückmeldung gegeben, dass die Funktion ggf. gröber arbeitet, d.h. wenn es darauf ankommt, bitte den Parameter wie bisher geschickt wählen.&lt;br /&gt;
&lt;br /&gt;
Die Funktion _delay_us() wurde ebenfalls erweitert. Wenn deren maximal als genau behandelbares Argument überschritten wird, benutzt diese intern _delay_ms(). Damit gelten in diesem Fall die _delay_ms() Einschränkungen.&lt;br /&gt;
&lt;br /&gt;
Beispiel: Blinken einer LED an PORTB Pin PB0 im ca. 1s Rhythmus, avr-libc ab Version 1.6&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#ifndef F_CPU&lt;br /&gt;
/* Definiere F_CPU, wenn F_CPU nicht bereits vorher definiert &lt;br /&gt;
   (z.B. durch Übergabe als Parameter zum Compiler innerhalb &lt;br /&gt;
   des Makefiles). Zusätzlich Ausgabe einer Warnung, die auf die&lt;br /&gt;
   &amp;quot;nachträgliche&amp;quot; Definition hinweist */&lt;br /&gt;
#warning &amp;quot;F_CPU war noch nicht definiert, wird nun mit 3686400 definiert&amp;quot;&lt;br /&gt;
#define F_CPU 3686400UL     /* Quarz mit 3.6864 Mhz */&lt;br /&gt;
#endif&lt;br /&gt;
#include &amp;lt;util/delay.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
int main( void )&lt;br /&gt;
{&lt;br /&gt;
    DDRB = ( 1 &amp;lt;&amp;lt; PB0 );        // PB0 an PORTB als Ausgang setzen&lt;br /&gt;
&lt;br /&gt;
    while( 1 ) {                // Endlosschleife&lt;br /&gt;
        PORTB ^= ( 1 &amp;lt;&amp;lt; PB0 );  // Toggle PB0 z.B. angeschlossene LED&lt;br /&gt;
        _delay_ms(1000);        // Eine Sekunde +/-1/10000 Sekunde warten...&lt;br /&gt;
                                // funktioniert nicht mit Bibliotheken vor 1.6&lt;br /&gt;
&lt;br /&gt;
    }&lt;br /&gt;
    return 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Der Watchdog =&lt;br /&gt;
&lt;br /&gt;
Und hier kommt das ultimative Mittel gegen die Unvollkommenheit von uns&lt;br /&gt;
Programmierern, der Watchdog.&lt;br /&gt;
&lt;br /&gt;
So sehr wir uns auch anstrengen, es wird uns kaum je gelingen, das absolut&lt;br /&gt;
perfekte und fehlerfreie Programm zu entwickeln.&lt;br /&gt;
&lt;br /&gt;
Der Watchdog kann uns zwar auch nicht zu besseren Programmen verhelfen aber er&lt;br /&gt;
kann dafür sorgen, dass unser Programm, wenn es sich wieder mal in&#039;s Nirwana&lt;br /&gt;
verabschiedet hat, neu gestartet wird, indem ein Reset des Controllers&lt;br /&gt;
ausgelöst wird.&lt;br /&gt;
&lt;br /&gt;
Betrachten wir doch einmal folgende Codesequenz:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
    uint8_t x;&lt;br /&gt;
&lt;br /&gt;
    x = 10;&lt;br /&gt;
&lt;br /&gt;
    while (x &amp;gt;= 0)&lt;br /&gt;
    {&lt;br /&gt;
      // tu was&lt;br /&gt;
&lt;br /&gt;
      x--;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn wir die Schleife mal genau anschauen sollte uns auffallen, dass dieselbe niemals beendet wird. Warum nicht? Ganz einfach, weil eine als &#039;&#039;&#039;&#039;&#039;unsigned&#039;&#039;&#039;&#039;&#039; deklarierte Variable niemals kleiner als Null werden kann (der Compiler sollte jedoch eine ensprechende Warnung ausgeben).&lt;br /&gt;
Das Programm würde sich also hier aufhängen und auf ewig in der Schleife drehen.&lt;br /&gt;
Und hier genau kommt der Watchdog zum Zug.&lt;br /&gt;
&lt;br /&gt;
== Wie funktioniert nun der Watchdog? ==&lt;br /&gt;
&lt;br /&gt;
Der Watchdog enthält einen separaten Timer/Counter, welcher mit einem intern erzeugten Takt von 1 MHz bei 5V Vcc getaktet wird. Einige Controller haben einen eigenen Watchdog Oszillator, z.B. der Tiny2313 mit 128kHz. Nachdem der Watchdog aktiviert und der gewünschte Vorteiler eingestellt wurde, beginnt der Counter von 0 an hochzuzählen. &lt;br /&gt;
Wenn nun die je nach Vorteiler eingestellte Anzahl Zyklen erreicht wurde, löst der Watchdog einen Reset aus. Um nun also im Normalbetrieb den Reset zu verhindern, müssen wir den Watchdog regelmäßig wieder neu starten bzw. rücksetzen (Watchdog Reset). &lt;br /&gt;
Dies sollte innerhalb unserer Hauptschleife passieren.&lt;br /&gt;
&lt;br /&gt;
Um ein unbeabsichtigtes Ausschalten des Watchdogs zu verhindern, muss ein spezielles Prozedere verwendet werden, um den WD auszuschalten. Es müssen zuerst die beiden Bits WDTOE und WDE in einer einzelnen Operation (also nicht mit sbi) auf 1 gesetzt werden. &lt;br /&gt;
Dann muss innerhalb der nächsten 4 Taktzyklen das Bit WDE auf 0 gesetzt werden.&lt;br /&gt;
&lt;br /&gt;
Das Watchdog Control Register:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;WDTCR&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;W&#039;&#039;&#039;atchog &#039;&#039;&#039;T&#039;&#039;&#039;imer&amp;amp;nbsp; &#039;&#039;&#039;C&#039;&#039;&#039;ontrol &#039;&#039;&#039;R&#039;&#039;&#039;egister&lt;br /&gt;
&lt;br /&gt;
In diesem Register stellen wir ein, wie wir den Watchdog verwenden möchten.&lt;br /&gt;
&lt;br /&gt;
Das Register ist wie folgt aufgebaut:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Bit&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 7&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 6&lt;br /&gt;
| align=&amp;amp;quot;center&amp;quot; | 5&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 4&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 2&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Name&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;WDTOE&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;WDE&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;WDP2&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;WDP1&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;WDP0&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;R/W&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Initialwert&#039;&#039;&#039;&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;
| 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;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;WDTOE&#039;&#039;&#039; (&#039;&#039;&#039;W&#039;&#039;&#039;atch&#039;&#039;&#039;d&#039;&#039;&#039;og &#039;&#039;&#039;T&#039;&#039;&#039;urn &#039;&#039;&#039;O&#039;&#039;&#039;ff &#039;&#039;&#039;E&#039;&#039;&#039;nable)&lt;br /&gt;
:Dieses Bit muss gesetzt sein, wenn das Bit &#039;&#039;&#039;WDE&#039;&#039;&#039; gelöscht wird, andernfalls wird der Watchdog nicht ausgeschaltet.&lt;br /&gt;
:Wenn das Bit einmal gesetzt ist, wird es von der Hardware nach 4 Taktzyklen automatisch wieder gelöscht.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;WDE&#039;&#039;&#039; (&#039;&#039;&#039;W&#039;&#039;&#039;atch&#039;&#039;&#039;d&#039;&#039;&#039;og &#039;&#039;&#039;E&#039;&#039;&#039;nable)&lt;br /&gt;
:Wenn dieses Bit gesetzt wird, so wird der Watchdog aktiviert.&lt;br /&gt;
:Das Bit kann nur gelöscht werden, solange das Bit &#039;&#039;&#039;WDTOE&#039;&#039;&#039; auf 1 steht.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;WDP2&#039;&#039;&#039;, &#039;&#039;&#039;WDP1&#039;&#039;&#039;, &#039;&#039;&#039;WDP0&#039;&#039;&#039; (&#039;&#039;&#039;W&#039;&#039;&#039;atch&#039;&#039;&#039;d&#039;&#039;&#039;og Timer &#039;&#039;&#039;P&#039;&#039;&#039;rescaler Bits)&lt;br /&gt;
:Diese 3 Bits bestimmen die Anzahl Oszillatorzyklen für den Watchdog, also, wie lange es dauert, bis ein Reset ausgelöst wird:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | WDP2&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | WDP1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | WDP0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | Anzahl Zyklen&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | Typ. Timeoutzeit bei Vcc = 3V&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | Typ. Timeoutzeit bei Vcc = 5V&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;
| align=&amp;quot;center&amp;quot; | 16K&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 47ms&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 15ms&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;
| align=&amp;quot;center&amp;quot; | 32K&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 94ms&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 30ms&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;
| align=&amp;quot;center&amp;quot; | 64K&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0.19s&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 60ms&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;
| align=&amp;quot;center&amp;quot; | 128K&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0.38s&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0.12s&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;
| align=&amp;quot;center&amp;quot; | 256K&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0.75s&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0.24s&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;
| align=&amp;quot;center&amp;quot; | 512K&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1.5s&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0.49s&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;
| align=&amp;quot;center&amp;quot; | 1024K&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3s&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0.97s&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;
| align=&amp;quot;center&amp;quot; | 2048K&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 6s&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1.9s&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Um den Watchdog mit dem AVR-GCC Compiler zu verwenden, muss die Headerdatei &#039;&#039;wdt.h&#039;&#039; (&#039;&#039;#include &amp;lt;avr/wdt.h&amp;gt;&#039;&#039;) in die Quelldatei eingebunden werden. &lt;br /&gt;
&amp;lt;!-- mt: das stimmt wohl nicht mehr?!:&lt;br /&gt;
Dadurch wird auch der Startup-Code entsprechend angepasst, so dass der Watchdog nach einem Reset automatisch gestartet wird. &lt;br /&gt;
Das WDTCR-Register wird dabei mit dem Wert 0 beschrieben. &lt;br /&gt;
Falls ein anderer Wert gewünscht ist, so kann dies im Makfile in den Linker-Optionen eingetragen werden. &lt;br /&gt;
Dazu muss in der Zeile LDFLAGS folgende Option angefügt werden:&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; --defsym __init_wdtcr__=0x1f&amp;lt;br /&amp;gt;&lt;br /&gt;
wenn beispielsweise der Wert des Registers auf 0x1f gestellt werden soll.&amp;lt;br /&amp;gt; --&amp;gt;&lt;br /&gt;
Danach können die folgenden Funktionen verwendet werden:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;wdt_enable(uint8_t timeout)&#039;&#039;&#039;&lt;br /&gt;
:Aktiviert den Watchdog und stellt den Vorteiler auf den gewünschten Wert ein bzw. der in timeout übergebene Wert wird in das WDTCR-Register eingetragen. Einige Timeout-Werte sind als Konstanten vordefiniert&lt;br /&gt;
:Mögliche Timeoutwerte:&lt;br /&gt;
&amp;lt;div align=&amp;quot;center&amp;quot;&amp;gt;&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
! Konstante&lt;br /&gt;
! Wert&lt;br /&gt;
! TimeOut&lt;br /&gt;
|- &lt;br /&gt;
| WDTO_15MS   &lt;br /&gt;
| 0&lt;br /&gt;
| 15 ms&lt;br /&gt;
|-&lt;br /&gt;
| WDTO_30MS   &lt;br /&gt;
| 1&lt;br /&gt;
| 30 ms&lt;br /&gt;
|-&lt;br /&gt;
| WDTO_60MS   &lt;br /&gt;
| 2&lt;br /&gt;
| 60 ms&lt;br /&gt;
|-&lt;br /&gt;
| WDTO_120MS   &lt;br /&gt;
| 3&lt;br /&gt;
| 120 ms&lt;br /&gt;
|-&lt;br /&gt;
| WDTO_250MS   &lt;br /&gt;
| 4&lt;br /&gt;
| 250 ms&lt;br /&gt;
|-&lt;br /&gt;
| WDTO_500MS   &lt;br /&gt;
| 5&lt;br /&gt;
| 500 ms&lt;br /&gt;
|-&lt;br /&gt;
| WDTO_1S   &lt;br /&gt;
| 6&lt;br /&gt;
| 1 s&lt;br /&gt;
|-&lt;br /&gt;
| WDTO_2S   &lt;br /&gt;
| 7&lt;br /&gt;
| 2 s&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;wdt_disable()&#039;&#039;&#039;&lt;br /&gt;
:Mit dieser Funktion kann der Watchdog ausgeschaltet werden. Dabei wird das notwendige Prozedere, wie oben beschrieben, automatisch ausgeführt.&lt;br /&gt;
* &#039;&#039;&#039;wdt_reset()&#039;&#039;&#039;&lt;br /&gt;
:Dies ist wohl die wichtigste der Watchdog-Funktionen. Sie erzeugt einen Watchdog-Reset, welcher periodisch, und zwar vor Ablauf der Timeoutzeit, ausgeführt werden muss, damit der Watchdog nicht den AVR zurücksetzt.&lt;br /&gt;
&lt;br /&gt;
Selbstverständlich kann das &#039;&#039;&#039;WDTCR&#039;&#039;&#039;-Register auch mit den uns bereits bekannten Funktionen für den Zugriff auf Register programmiert werden.&lt;br /&gt;
&lt;br /&gt;
== Watchdog-Anwendungshinweise ==&lt;br /&gt;
&lt;br /&gt;
Ob nun der Watchdog als Schutzfunktion überhaupt verwendet werden soll, hängt stark von der Anwendung, der genutzten Peripherie und dem Umfang und der Qualitätssicherung des Codes ab. Will man sicher gehen, dass ein Programm sich nicht in einer Endlosschleife verfängt, ist der Wachdog das geeignete Mittel dies zu verhindern. Weiterhin kann bei geschickter Programmierung der Watchdog dazu genutzt werden, bestimmte Stromsparfunktionen zu implementieren. Bei einigen neueren AVRs (z.B. dem ATTiny13) kann der Watchdog auch direkt als Timer genutzt werden, der den Controller aus einem Schlafmodus aufweckt. Auch dies kann im &#039;&#039;&#039;WDTCR&#039;&#039;&#039;-Register eingestellt werden. Außerdem bietet der WD die einzige Möglichkeit einen beabsichtigten System-Reset (ein &amp;quot;richtiger Reset&amp;quot;, kein &amp;quot;jmp 0x0000&amp;quot;) ohne externe Beschaltung auszulösen, was z.B. bei der Implementierung eines Bootloaders nützlich ist. Bei bestimmten Anwendungen kann die Nutzung des WD als &amp;quot;ultimative Deadlock-Sicherung für nicht bedachte Zustände&amp;quot; natürlich immer als zusätzliche Sicherung dienen. &lt;br /&gt;
&lt;br /&gt;
Es besteht die Möglichkeit herauszufinden, ob ein Reset durch den Watchdog ausgelöst wurde (beim ATmega16 z.B. Bit WDRF in MCUCSR). Diese Information sollte auch genutzt werden, falls ein WD-Reset in der Anwendung nicht planmäßig implementiert wurde. Zum Beispiel kann man eine LED an einen freien Pin hängen, die nur bei einem Reset durch den WD aufleuchtet oder aber das &amp;quot;Ereignis WD-Reset&amp;quot; im internen EEPROM des AVR absichern, um die Information später z.B. über UART oder ein Display auszugeben (oder einfach den EEPROM-Inhalt über die ISP/JTAG-Schnittstelle auslesen).&lt;br /&gt;
&lt;br /&gt;
Siehe auch: &lt;br /&gt;
* [http://www.nongnu.org/avr-libc/user-manual/index.html Dokumentation der avr-libc] Abschnitt Modules/Watchdog timer handling&lt;br /&gt;
* [http://www.mikrocontroller.net/topic/77273#642501 Bug in ATtiny2313?]&lt;br /&gt;
&lt;br /&gt;
= Programmieren mit Interrupts =&lt;br /&gt;
&lt;br /&gt;
Nachdem wir nun alles Wissenswerte für die serielle Programmerstellung&lt;br /&gt;
gelernt haben nehmen wir jetzt ein völlig anderes Thema in Angriff, nämlich&lt;br /&gt;
die Programmierung unter Zuhilfenahme der Interrupts des AVR.&lt;br /&gt;
&lt;br /&gt;
Als erstes wollen wir uns noch einmal den allgemeinen Programmablauf bei der&lt;br /&gt;
Interrupt-Programmierung zu Gemüte führen.&lt;br /&gt;
&lt;br /&gt;
[[Image:Interrupt Programme.gif]]&lt;br /&gt;
&lt;br /&gt;
Man sieht, dass die Interruptroutine quasi parallel zum Hauptprogramm&lt;br /&gt;
abläuft. Da wir nur eine CPU haben ist es natürlich keine echte Parallelität,&lt;br /&gt;
sondern das Hauptprogramm wird beim Eintreffen eines Interrupts unterbrochen,&lt;br /&gt;
die Interruptroutine wird ausgeführt und danach erst wieder zum Hauptprogramm&lt;br /&gt;
zurückgekehrt.&lt;br /&gt;
&lt;br /&gt;
[http://www.mikrocontroller.net/forum/read-1-235092.html#new Ausführlicher Thread im Forum]&lt;br /&gt;
&lt;br /&gt;
== Anforderungen an Interrupt-Routinen ==&lt;br /&gt;
&lt;br /&gt;
Um unliebsamen Überraschungen vorzubeugen, sollten einige Grundregeln bei der Implementierung der Interruptroutinen beachtet werden. Interruptroutinen soll möglichst kurz und schnell abarbeitbar sein, daraus folgt:&lt;br /&gt;
&lt;br /&gt;
* Keine umfangreichen Berechnungen innerhalb der Interruptroutine. (*)&lt;br /&gt;
* Keine langen Programmschleifen.&lt;br /&gt;
* Obwohl es möglich ist, während der Abarbeitung einer Interruptroutine andere oder sogar den gleichen Interrupt wieder zuzulassen, wird davon ohne genaue Kenntnis der internen Abläufe dringend abgeraten.&lt;br /&gt;
&lt;br /&gt;
Interruptroutinen (ISRs) sollten also möglichst kurz sein und keine Schleifen mit vielen Durchläufen enthalten. Längere Operationen können meist in einen &amp;quot;Interrupt-Teil&amp;quot; in einer ISR und einen &amp;quot;Arbeitsteil&amp;quot; im Hauptprogramm aufgetrennt werden. Z.B. Speichern des Zustands aller Eingänge im EEPROM in bestimmten Zeitabständen: ISR-Teil: Zeitvergleich (Timer,RTC) mit Logzeit/-intervall. Bei Übereinstimmung ein globales Flag setzen (volatile bei Flag-Deklaration nicht vergessen, s.u.). Dann im Hauptprogramm prüfen, ob das Flag gesetzt ist. Wenn ja: die Daten im EEPROM ablegen und Flag löschen.&lt;br /&gt;
&lt;br /&gt;
(*)&lt;br /&gt;
Hinweis: &lt;br /&gt;
Es gibt allerdings die seltene Situation, dass man gerade eingelesene&lt;br /&gt;
ADC-Werte sofort verarbeiten muss. Besonders dann, wenn man mehrere Werte sehr&lt;br /&gt;
schnell hintereinander bekommt. Dann bleibt einem nichts anderes übrig, als die&lt;br /&gt;
Werte noch in der ISR zu verarbeiten. Kommt aber sehr selten vor und sollte&lt;br /&gt;
durch geeignete Wahl des Systemtaktes bzw. Auswahl des Controllers vermieden werden!&lt;br /&gt;
&lt;br /&gt;
== Interrupt-Quellen ==&lt;br /&gt;
&lt;br /&gt;
Die folgenden Ereignisse können einen Interrupt auf einem AVR AT90S2313 auslösen, wobei die Reihenfolge der Auflistung auch die Priorität der Interrupts aufzeigt.&lt;br /&gt;
&lt;br /&gt;
* Reset&lt;br /&gt;
* Externer Interrupt 0&lt;br /&gt;
* Externer Interrupt 1&lt;br /&gt;
* Timer/Counter 1 Capture Ereignis&lt;br /&gt;
* Timer/Counter 1 Compare Match&lt;br /&gt;
* Timer/Counter 1 Überlauf&lt;br /&gt;
* Timer/Counter 0 Überlauf&lt;br /&gt;
* UART Zeichen empfangen&lt;br /&gt;
* UART Datenregister leer&lt;br /&gt;
* UART Zeichen gesendet&lt;br /&gt;
* Analoger Komparator&lt;br /&gt;
&lt;br /&gt;
Die Anzahl der möglichen Interruptquellen variiert zwischen den verschiedenen Typen. Im Zweifel hilft ein Blick ins Datenblatt (&amp;quot;Interrupt Vectors&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
== Register ==&lt;br /&gt;
&lt;br /&gt;
Der AT90S2313 verfügt über 2 Register die mit den&lt;br /&gt;
Interrupts zusammen hängen.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;GIMSK&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;G&#039;&#039;&#039;eneral &#039;&#039;&#039;I&#039;&#039;&#039;nterrupt &#039;&#039;&#039;M&#039;&#039;&#039;ask &#039;&#039;&#039;R&#039;&#039;&#039;egister.&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Bit&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 7&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 6&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 5&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 4&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 2&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Name&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;INT1&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;INT0&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;R/W&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Initialwert&#039;&#039;&#039;&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;
| 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;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;INT1&#039;&#039;&#039; (External &#039;&#039;&#039;Int&#039;&#039;&#039;errupt Request &#039;&#039;&#039;1&#039;&#039;&#039; Enable)&lt;br /&gt;
:Wenn dieses Bit gesetzt ist, wird ein Interrupt ausgelöst, wenn am &#039;&#039;&#039;INT1&#039;&#039;&#039;-Pin eine steigende oder fallende (je nach Konfiguration im &#039;&#039;&#039;MCUCR&#039;&#039;&#039;) Flanke erkannt wird.&lt;br /&gt;
:Das Global Enable Interrupt Flag muss selbstverständlich auch gesetzt sein.&lt;br /&gt;
:Der Interrupt wird auch ausgelöst, wenn der Pin als Ausgang geschaltet ist. Auf diese Weise bietet sich die Möglichkeit, Software-Interrupts zu realisieren.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;INT0&#039;&#039;&#039; (External &#039;&#039;&#039;Int&#039;&#039;&#039;errupt Request &#039;&#039;&#039;0&#039;&#039;&#039; Enable)&lt;br /&gt;
:Wenn dieses Bit gesetzt ist, wird ein Interrupt ausgelöst, wenn am &#039;&#039;&#039;INT0&#039;&#039;&#039;-Pin eine steigende oder fallende (je nach Konfiguration im &#039;&#039;&#039;MCUCR&#039;&#039;&#039;) Flanke erkannt wird.&lt;br /&gt;
:Das Global Enable Interrupt Flag muss selbstverständlich auch gesetzt sein.&lt;br /&gt;
:Der Interrupt wird auch ausgelöst, wenn der Pin als Ausgang geschaltet ist. Auf diese Weise bietet sich die Möglichkeit, Software-Interrupts zu realisieren.&lt;br /&gt;
&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;GIFR&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;G&#039;&#039;&#039;eneral &#039;&#039;&#039;I&#039;&#039;&#039;nterrupt &#039;&#039;&#039;F&#039;&#039;&#039;lag &#039;&#039;&#039;R&#039;&#039;&#039;egister.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Bit&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 7&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 6&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 5&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 4&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 2&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Name&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;INTF1&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;INTF0&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;R/W&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Initialwert&#039;&#039;&#039;&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;
| 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;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;INTF1&#039;&#039;&#039; (External &#039;&#039;&#039;Int&#039;&#039;&#039;errupt Flag &#039;&#039;&#039;1&#039;&#039;&#039;)&lt;br /&gt;
:Dieses Bit wird gesetzt, wenn am &#039;&#039;&#039;INT1&#039;&#039;&#039;-Pin eine Interrupt-Kondition, entsprechend der Konfiguration, erkannt wird. Wenn das Global Enable Interrupt Flag gesetzt ist, wird die Interruptroutine angesprungen.&lt;br /&gt;
:Das Flag wird automatisch gelöscht, wenn die Interruptroutine beendet ist. Alternativ kann das Flag gelöscht werden, indem der Wert &#039;&#039;&#039;1(!)&#039;&#039;&#039; eingeschrieben wird.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;INTF0&#039;&#039;&#039; (External &#039;&#039;&#039;Int&#039;&#039;&#039;errupt Flag &#039;&#039;&#039;0&#039;&#039;&#039;)&lt;br /&gt;
:Dieses Bit wird gesetzt, wenn am &#039;&#039;&#039;INT0&#039;&#039;&#039;-Pin eine Interrupt-Kondition, entsprechend der Konfiguration, erkannt wird. Wenn das Global Enable Interrupt Flag gesetzt ist, wird die Interruptroutine angesprungen.&lt;br /&gt;
:Das Flag wird automatisch gelöscht, wenn die Interruptroutine beendet ist. Alternativ kann das Flag gelöscht werden, indem der Wert &#039;&#039;&#039;1(!)&#039;&#039;&#039; eingeschrieben wird.&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;MCUCR&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;MCU&#039;&#039;&#039; &#039;&#039;&#039;C&#039;&#039;&#039;ontrol &#039;&#039;&#039;R&#039;&#039;&#039;egister.&lt;br /&gt;
&lt;br /&gt;
Das MCU Control Register enthält Kontrollbits für allgemeine&lt;br /&gt;
MCU-Funktionen.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Bit&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 7&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 6&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 5&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 4&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 2&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Name&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;SE&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;SM&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ISC11&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ISC10&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ISC01&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ISC00&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;R/W&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Initialwert&#039;&#039;&#039;&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;
| 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;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;SE&#039;&#039;&#039; (&#039;&#039;&#039;S&#039;&#039;&#039;leep &#039;&#039;&#039;E&#039;&#039;&#039;nable)&lt;br /&gt;
:Dieses Bit muss gesetzt sein, um den Controller mit dem &#039;&#039;&#039;SLEEP&#039;&#039;&#039;-Befehl in den Schlafzustand versetzen zu können.&lt;br /&gt;
:Um den Schlafmodus nicht irrtümlich einzuschalten, wird empfohlen, das Bit erst unmittelbar vor Ausführung des &#039;&#039;&#039;SLEEP&#039;&#039;&#039;-Befehls zu setzen.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;SM&#039;&#039;&#039; (&#039;&#039;&#039;S&#039;&#039;&#039;leep &#039;&#039;&#039;M&#039;&#039;&#039;ode)&lt;br /&gt;
:Dieses Bit bestimmt der Schlafmodus.&lt;br /&gt;
:Ist das Bit gelöscht, so wird der &#039;&#039;&#039;Idle&#039;&#039;&#039;-Modus ausgeführt. Ist das Bit gesetzt, so wird der &#039;&#039;&#039;Power-Down&#039;&#039;&#039;-Modus ausgeführt. (für andere AVR Controller siehe Abschnitt &amp;quot;Sleep-Mode&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ISC11&#039;&#039;&#039;, &#039;&#039;&#039;ISC10&#039;&#039;&#039; (&#039;&#039;&#039;I&#039;&#039;&#039;nterrupt &#039;&#039;&#039;S&#039;&#039;&#039;ense &#039;&#039;&#039;C&#039;&#039;&#039;ontrol &#039;&#039;&#039;1&#039;&#039;&#039; Bits)&lt;br /&gt;
:Diese beiden Bits bestimmen, ob die steigende oder die fallende Flanke für die Interrupterkennung am &#039;&#039;&#039;INT1&#039;&#039;&#039;-Pin ausgewertet wird.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ISC11&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ISC10&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Bedeutung&#039;&#039;&#039;&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;
| Low Level an &#039;&#039;&#039;INT1&#039;&#039;&#039; erzeugt einen Interrupt.&lt;br /&gt;
&lt;br /&gt;
In der Beschreibung heißt es, der Interrupt wird getriggert, solange der Pin auf 0 bleibt, also eigentlich unbrauchbar.&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;
| Reserviert&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;
| Die fallende Flanke an &#039;&#039;&#039;INT1&#039;&#039;&#039; erzeugt einen Interrupt.&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;
| Die steigende Flanke an &#039;&#039;&#039;INT1&#039;&#039;&#039; erzeugt einen Interrupt.&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;ISC01&#039;&#039;&#039;, &#039;&#039;&#039;ISC00&#039;&#039;&#039; (&#039;&#039;&#039;I&#039;&#039;&#039;nterrupt &#039;&#039;&#039;S&#039;&#039;&#039;ense &#039;&#039;&#039;C&#039;&#039;&#039;ontrol &#039;&#039;&#039;0&#039;&#039;&#039; Bits)&lt;br /&gt;
:Diese beiden Bits bestimmen, ob die steigende oder die fallende Flanke für die Interrupterkennung am &#039;&#039;&#039;INT0&#039;&#039;&#039;-Pin ausgewertet wird.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ISC01&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ISC00&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Bedeutung&#039;&#039;&#039;&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;
| Low Level an &#039;&#039;&#039;INT0&#039;&#039;&#039; erzeugt einen Interrupt.&lt;br /&gt;
&lt;br /&gt;
In der Beschreibung heißt es, der Interrupt wird getriggert, solange der Pin auf 0 bleibt, also eigentlich unbrauchbar.&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;
| Reserviert&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;
| Die fallende Flanke an &#039;&#039;&#039;INT0&#039;&#039;&#039; erzeugt einen Interrupt.&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;
| Die steigende Flanke an &#039;&#039;&#039;INT0&#039;&#039;&#039; erzeugt einen Interrupt.&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Allgemeines über die Interrupt-Abarbeitung ==&lt;br /&gt;
&lt;br /&gt;
Wenn ein Interrupt eintrifft, wird automatisch das &#039;&#039;&#039;Global Interrupt Enable&#039;&#039;&#039; Bit im Status Register &#039;&#039;&#039;SREG&#039;&#039;&#039; gelöscht und alle weiteren Interrupts unterbunden. Obwohl es möglich ist, zu diesem Zeitpunkt bereits wieder das GIE-bit zu setzen, rate ich dringend davon ab. Dieses wird nämlich automatisch gesetzt, wenn die Interruptroutine beendet wird. Wenn in der Zwischenzeit weitere Interrupts eintreffen, werden die zugehörigen Interrupt-Bits gesetzt und die Interrupts bei Beendigung der laufenden Interrupt-Routine in der Reihenfolge ihrer Priorität ausgeführt. Dies kann&lt;br /&gt;
eigentlich nur dann zu Problemen führen, wenn ein hoch priorisierter Interrupt ständig und in kurzer Folge auftritt. Dieser sperrt dann möglicherweise alle anderen Interrupts mit niedrigerer Priorität. Dies ist einer der Gründe, weshalb die Interrupt-Routinen sehr kurz gehalten werden sollen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- === Das Status-Register ===&lt;br /&gt;
&lt;br /&gt;
Es gilt auch zu beachten, dass das Status-Register während der Abarbeitung einer Interruptroutine nicht automatisch gesichert wird. Falls notwendig, muss dies vom Programmierer selber vorgesehen werden. --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Interrupts mit dem AVR GCC Compiler (WinAVR) ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- Selbstverständlich können alle interruptspezifischen Registerzugriffe wie gewohnt über I/O-Adressierung vorgenommen werden. Etwas einfacher geht es jedoch, wenn wir die vom Compiler zur Verfügung gestellten Mittel einsetzen.--&amp;gt;&lt;br /&gt;
Funktionen zur Interrupt-Verarbeitung werden in den Includedateien &#039;&#039;interrupt.h&#039;&#039;  der avr-libc zur Verfügung gestellt (bei älterem Quellcode zusätzlich &#039;&#039;signal.h&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
// fuer sei(), cli() und ISR():&lt;br /&gt;
#include &amp;lt;avr/interrupt.h&amp;gt;&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Makro &#039;&#039;&#039;sei()&#039;&#039;&#039; schaltet die Interrupts ein. Eigentlich wird nichts anderes gemacht, als das &#039;&#039;&#039;Global Interrupt Enable&#039;&#039;&#039; Bit im Status Register gesetzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
    sei();&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Makro &#039;&#039;&#039;cli()&#039;&#039;&#039; schaltet die Interrupts aus, oder anders gesagt, das &#039;&#039;&#039;Global Interrupt Enable&#039;&#039;&#039; Bit im Status Register wird gelöscht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
    cli();&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Oft steht man vor der Aufgabe, dass eine Codesequenz nicht unterbrochen werden darf. Es liegt dann nahe, zu Beginn dieser Sequenz ein cli() und am Ende ein sei() einzufügen. Dies ist jedoch ungünstig, wenn die Interrupts vor Aufruf der Sequenz deaktiviert waren und danach auch weiterhin deaktiviert bleiben sollen. Ein sei() würde ungeachtet des vorherigen  Zustands die Interrups aktivieren, was zu unerwünschten Seiteneffekten führen kann. Die aus dem folgenden Beispiel ersichtliche Vorgehensweise ist in solchen Fällen vorzuziehen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/interrupt.h&amp;gt;&lt;br /&gt;
#include &amp;lt;inttypes.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
void NichtUnterbrechenBitte(void)&lt;br /&gt;
{&lt;br /&gt;
   uint8_t tmp_sreg;  // temporaerer Speicher fuer das Statusregister&lt;br /&gt;
&lt;br /&gt;
   tmp_sreg = SREG;   // Statusregister (also auch das I-Flag darin) sichern&lt;br /&gt;
   cli();             // Interrupts global deaktivieren&lt;br /&gt;
&lt;br /&gt;
   /* hier &amp;quot;unterbrechnungsfreier&amp;quot; Code */&lt;br /&gt;
&lt;br /&gt;
   /* Beispiel Anfang&lt;br /&gt;
     JTAG-Interface eines ATmega16 per Software deaktivieren &lt;br /&gt;
     und damit die JTAG-Pins an PORTC für &amp;quot;general I/O&amp;quot; nutzbar machen&lt;br /&gt;
     ohne die JTAG-Fuse-Bit zu aendern. Dazu ist eine &amp;quot;timed sequence&amp;quot;&lt;br /&gt;
     einzuhalten (vgl Datenblatt ATmega16, Stand 10/04, S. 229): &lt;br /&gt;
     Das JTD-Bit muss zweimal innerhalb von 4 Taktzyklen geschrieben &lt;br /&gt;
     werden. Ein Interrupt zwischen den beiden Schreibzugriffen wuerde &lt;br /&gt;
     die erforderliche Sequenz &amp;quot;brechen&amp;quot;, das JTAG-Interface bliebe&lt;br /&gt;
     weiterhin aktiv und die IO-Pins weiterhin für JTAG reserviert. */&lt;br /&gt;
&lt;br /&gt;
   MCUCSR |= (1&amp;lt;&amp;lt;JTD);&lt;br /&gt;
   MCUCSR |= (1&amp;lt;&amp;lt;JTD); // 2 mal in Folge ,vgl. Datenblatt fuer mehr Information&lt;br /&gt;
&lt;br /&gt;
   /* Beispiel Ende */&lt;br /&gt;
  &lt;br /&gt;
   SREG = tmp_sreg;     // Status-Register wieder herstellen &lt;br /&gt;
                      // somit auch das I-Flag auf gesicherten Zustand setzen&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void NichtSoGut(void)&lt;br /&gt;
{&lt;br /&gt;
   cli();&lt;br /&gt;
   &lt;br /&gt;
   /* hier &amp;quot;unterbrechnungsfreier&amp;quot; Code */&lt;br /&gt;
   &lt;br /&gt;
   sei();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
int main(void)&lt;br /&gt;
{&lt;br /&gt;
   //...&lt;br /&gt;
&lt;br /&gt;
   cli();  &lt;br /&gt;
   // Interrupts global deaktiviert &lt;br /&gt;
&lt;br /&gt;
   NichtUnterbrechenBitte();&lt;br /&gt;
   // auch nach Aufruf der Funktion deaktiviert&lt;br /&gt;
&lt;br /&gt;
   sei();&lt;br /&gt;
   // Interrupts global aktiviert &lt;br /&gt;
&lt;br /&gt;
   NichtUnterbrechenBitte();&lt;br /&gt;
   // weiterhin aktiviert&lt;br /&gt;
   //...&lt;br /&gt;
&lt;br /&gt;
   /* Verdeutlichung der unguenstigen Vorgehensweise mit cli/sei: */&lt;br /&gt;
   cli();  &lt;br /&gt;
   // Interrupts jetzt global deaktiviert &lt;br /&gt;
&lt;br /&gt;
   NichtSoGut();&lt;br /&gt;
   // nach Aufruf der Funktion sind Interrupts global aktiviert &lt;br /&gt;
   // dies ist mglw. ungewollt!&lt;br /&gt;
   //...&lt;br /&gt;
   &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- mt: besser so nicht(?), lieber &amp;quot;datenblattkonform&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;font face=&amp;quot;Courier New&amp;quot;&amp;gt;&#039;&#039;&#039;timer_enable_int (unsigned char ints);&amp;lt;br /&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;/font&amp;gt;Schaltet Timerbezogene Interrupts ein bzw. aus.&amp;lt;br /&amp;gt;&lt;br /&gt;
Wenn als Argument &#039;&#039;&#039;ints&#039;&#039;&#039; der Wert 0 übergeben wird so werden alle&lt;br /&gt;
Timerinterrupts ausgeschaltet, ansonsten muss in &#039;&#039;&#039;ints&#039;&#039;&#039; angegeben werden,&lt;br /&gt;
welche Interrupts zu aktivieren sind. Dabei müssen einfach die entsprechend zu&lt;br /&gt;
setzenden Bits definiert werden.&amp;lt;br /&amp;gt;&lt;br /&gt;
Beispiel: &#039;&#039;&#039;&amp;lt;font face=&amp;quot;Courier New&amp;quot;&amp;gt;timer_enable_int (1 &amp;lt;&amp;lt; TOIE1));&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;/font&amp;gt;&#039;&#039;&#039;Achtung: Wenn ein Timerinterrupt eingeschaltet wird während ein&lt;br /&gt;
anderer Timerinterrupt bereits läuft, dann müssen beide Bits angegeben werden&lt;br /&gt;
sonst wird der andere Timerinterrupt versehentlich ausgeschaltet.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;font face=&amp;quot;Courier New&amp;quot;&amp;gt;&#039;&#039;&#039;enable_external_int (unsigned char ints);&amp;lt;br /&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;/font&amp;gt;Schaltet die externen Interrupts ein bzw. aus.&amp;lt;br /&amp;gt;&lt;br /&gt;
Wenn als Argument &#039;&#039;&#039;ints&#039;&#039;&#039; der Wert 0 übergeben wird so werden alle externen&lt;br /&gt;
Interrrups ausgeschaltet, ansonsten muss in &#039;&#039;&#039;ints&#039;&#039;&#039; angegeben werden, welche&lt;br /&gt;
Interrupts zu aktivieren sind. Dabei müssen einfach die entsprechend zu&lt;br /&gt;
setzenden Bits definiert werden.&amp;lt;br /&amp;gt;&lt;br /&gt;
Beispiel: &#039;&#039;&#039;&amp;lt;font face=&amp;quot;Courier New&amp;quot;&amp;gt;enable_external_int ((1&amp;lt;&lt;br /&gt;
&amp;lt;/font&amp;gt;&#039;&#039;&#039;Schaltet die externen Interrupts 0 und 1 ein.&lt;br /&gt;
&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nachdem nun die Interrupts aktiviert sind, braucht es selbstverständlich noch den auszuführenden Code, der ablaufen soll, wenn ein Interrupt eintrifft. Dazu existiert die Definition (ein Makro) &#039;&#039;&#039;ISR&#039;&#039;&#039;. SIGNAL sollte nicht mehr genutzt werden, zur Portierung von SIGNAL nach ISR siehe Abschnitt (TODO: verlinken) im Anhang.&lt;br /&gt;
&amp;lt;!--Dazu gibt es zwei Definitionen: &#039;&#039;&#039;SIGNAL&#039;&#039;&#039; und &#039;&#039;&#039;INTERRUPT&#039;&#039;&#039;, welche allerdings AVR-GCC spezifisch sind und bei anderen Compilern womöglich anders heissen können.--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== ISR ===&lt;br /&gt;
&lt;br /&gt;
(&#039;&#039;ISR()&#039;&#039; ersetzt bei neueren Versionen der avr-libc &#039;&#039;SIGNAL()&#039;&#039;. vgl. [[AVR-GCC-Tutorial#Anhang|Anhang]])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/signal.h&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
SIGNAL (siglabel)&lt;br /&gt;
{&lt;br /&gt;
    /* Interrupt Code */&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/interrupt.h&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
ISR(Vectorname) /* vormals: SIGNAL(siglabel) dabei Vectorname != siglabel ! */&lt;br /&gt;
{&lt;br /&gt;
    /* Interrupt Code */&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;ISR&#039;&#039; wird eine Funktion für die Bearbeitung eines Interrupts eingeleitet. Als Argument muss dabei die Benennung des entsprechenden Interruptvektors angegeben werden. Diese sind in den jeweiligen Includedateien IOxxxx.h zu finden. Die Bezeichnung entspricht dem Namen aus dem Datenblatt, bei dem die Leerzeichen durch Unterstriche ersetzt sind und ein &#039;&#039;_vect&#039;&#039; angehängt ist.&lt;br /&gt;
&lt;br /&gt;
Als Beispiel ein Ausschnitt aus der Datei für den ATmega8 (bei WinAVR Standardinstallation in C:\WinAVR\avr\include\avr\iom8.h) in der neben den aktuellen Namen für &#039;&#039;ISR&#039;&#039; (*_vect) noch die Bezeichnungen für das inzwischen nicht mehr aktuelle &#039;&#039;SIGNAL&#039;&#039; (SIG_*) enthalten sind.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
/* $Id: iom8.h,v 1.13 2005/10/30 22:11:23 joerg_wunsch Exp $ */&lt;br /&gt;
&lt;br /&gt;
/* avr/iom8.h - definitions for ATmega8 */&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
/* Interrupt vectors */&lt;br /&gt;
&lt;br /&gt;
/* External Interrupt Request 0 */&lt;br /&gt;
#define INT0_vect                       _VECTOR(1)&lt;br /&gt;
#define SIG_INTERRUPT0                  _VECTOR(1)&lt;br /&gt;
&lt;br /&gt;
/* External Interrupt Request 1 */&lt;br /&gt;
#define INT1_vect                       _VECTOR(2)&lt;br /&gt;
#define SIG_INTERRUPT1                  _VECTOR(2)&lt;br /&gt;
&lt;br /&gt;
/* Timer/Counter2 Compare Match */&lt;br /&gt;
#define TIMER2_COMP_vect                _VECTOR(3)&lt;br /&gt;
#define SIG_OUTPUT_COMPARE2             _VECTOR(3)&lt;br /&gt;
&lt;br /&gt;
/* Timer/Counter2 Overflow */&lt;br /&gt;
#define TIMER2_OVF_vect                 _VECTOR(4)&lt;br /&gt;
#define SIG_OVERFLOW2                   _VECTOR(4)&lt;br /&gt;
&lt;br /&gt;
/* Timer/Counter1 Capture Event */&lt;br /&gt;
#define TIMER1_CAPT_vect                _VECTOR(5)&lt;br /&gt;
#define SIG_INPUT_CAPTURE1              _VECTOR(5)&lt;br /&gt;
&lt;br /&gt;
/* Timer/Counter1 Compare Match A */&lt;br /&gt;
#define TIMER1_COMPA_vect               _VECTOR(6)&lt;br /&gt;
#define SIG_OUTPUT_COMPARE1A            _VECTOR(6)&lt;br /&gt;
&lt;br /&gt;
/* Timer/Counter1 Compare Match B */&lt;br /&gt;
#define TIMER1_COMPB_vect               _VECTOR(7)&lt;br /&gt;
#define SIG_OUTPUT_COMPARE1B            _VECTOR(7)&lt;br /&gt;
&lt;br /&gt;
//...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--Vor Nutzung von SIGNAL muss ebenfalls die Header-Datei signal.h eingebunden werden.--&amp;gt; &lt;br /&gt;
Mögliche Funktionsrümpfe für Interruptfunktionen sind zum Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/interrupt.h&amp;gt;&lt;br /&gt;
/* veraltet: #include &amp;lt;avr/signal.h&amp;gt; */&lt;br /&gt;
&lt;br /&gt;
ISR(INT0_vect)       /* veraltet: SIGNAL(SIG_INTERRUPT0) */&lt;br /&gt;
{&lt;br /&gt;
    /* Interrupt Code */&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
ISR(TIMER0_OVF_vect) /* veraltet: SIGNAL(SIG_OVERFLOW0) */&lt;br /&gt;
{&lt;br /&gt;
    /* Interrupt Code */&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
ISR(USART_RXC_vect) /* veraltet: SIGNAL(SIG_UART_RECV) */&lt;br /&gt;
{&lt;br /&gt;
    /* Interrupt Code */&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// und so weiter und so fort...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Auf die korrekte Schreibweise der Vektorbezeichnung ist zu achten. Der gcc-Compiler prüft erst ab Version 4.x, ob ein Signal/Interrupt der angegebenen Bezeichnung tatsächlich in der Includedatei definiert ist und gibt andernfalls eine Warnung aus. Bei WinAVR (ab 2/2005) wurde die Überprüfung auch in den mitgelieferten Compiler der Version 3.x integriert. Aus dem gcc-Quellcode Version 3.x selbst erstellte Compiler enthalten die Prüfung nicht (vgl. [[AVR-GCC]]). &lt;br /&gt;
&lt;br /&gt;
Während der Ausführung der Funktion sind alle weiteren Interrupts automatisch gesperrt. Beim Verlassen der Funktion werden die Interrupts wieder zugelassen.&lt;br /&gt;
&lt;br /&gt;
Sollte während der Abarbeitung der Interruptroutine ein weiterer Interrupt (gleiche oder andere Interruptquelle) auftreten, so wird das entsprechende Bit im zugeordneten Interrupt Flag Register gesetzt und die entsprechende Interruptroutine automatisch nach dem Beenden der aktuellen Funktion aufgerufen.&lt;br /&gt;
&lt;br /&gt;
Ein Problem ergibt sich eigentlich nur dann, wenn während der Abarbeitung der aktuellen Interruptroutine mehrere gleichartige Interrupts auftreten. Die entsprechende Interruptroutine wird im Nachhinein zwar aufgerufen jedoch wissen wir nicht, ob nun der entsprechende Interrupt einmal, zweimal oder gar noch öfter aufgetreten ist. Deshalb soll hier noch einmal betont werden, dass Interruptroutinen so schnell wie nur irgend möglich wieder verlassen werden sollten.&lt;br /&gt;
&lt;br /&gt;
=== Unterbrechbare Interruptroutinen ===&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Faustregel&amp;quot;: im Zweifel &#039;&#039;&#039;ISR&#039;&#039;&#039;. Die nachfolgend beschriebene Methode nur dann verwenden, wenn man sich über die unterschiedliche Funktionsweise im Klaren ist.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/interrupt.h&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
INTERRUPT (signame)&lt;br /&gt;
{&lt;br /&gt;
    /* Interrupt Code */&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/interrupt.h&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
void XXX_vect(void) __attribute__((interrupt));&lt;br /&gt;
void XXX_vect(void) {&lt;br /&gt;
  //...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hierbei steht XXX für den oben beschriebenen Namen des Vektors (also z.B. &#039;&#039;void TIMER0_OVF_vect(void)...&#039;&#039;). Der Unterschied im Vergleich zu ISR ist, dass hier beim Aufrufen der Funktion das &#039;&#039;&#039;Global Enable Interrupt&#039;&#039;&#039; Bit automatisch wieder gesetzt und somit weitere Interrupts zugelassen werden. Dies kann zu nicht unerheblichen Problemen von im einfachsten Fall einem Stack overflow bis zu sonstigen unerwarteten Effekten führen und sollte wirklich &#039;&#039;&#039;nur dann&#039;&#039;&#039; angewendet werden, wenn man sich absolut sicher ist, das Ganze auch im Griff zu haben.  &amp;lt;!--Vor Nutzung von INTERRUPT muss die Header-Datei interrupt.h eingebunden werden.--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
siehe auch: Hinweise in [[AVR-GCC]]&lt;br /&gt;
&lt;br /&gt;
siehe dazu: http://www.nongnu.org/avr-libc/user-manual/group__avr__interrupts.html&lt;br /&gt;
&lt;br /&gt;
== Datenaustausch mit Interrupt-Routinen ==&lt;br /&gt;
&lt;br /&gt;
Variablen die sowohl in Interrupt-Routinen (ISR = Interrupt Service Routine(s)), als auch vom übrigen Programmcode geschrieben oder gelesen werden, müssen mit einem &#039;&#039;&#039;volatile&#039;&#039;&#039; deklariert werden. Damit wird dem Compiler mitgeteilt, dass der Inhalt der Variablen vor jedem Lesezugriff aus dem Speicher gelesen und nach jedem Schreibzugriff in den Speicher geschrieben wird. Ansonsten könnte der Compiler den Code so optimieren, dass der Wert der Variablen nur &lt;br /&gt;
in Prozessorregistern zwischengespeichert wird, die nichts von der Änderung woanders mitbekommen.&lt;br /&gt;
&lt;br /&gt;
Zur Veranschaulichung ein Codefragment für eine Tastenentprellung mit Erkennung einer &amp;quot;lange gedrückten&amp;quot; Taste.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/interrupt.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
// Schwellwerte&lt;br /&gt;
// Entprellung: &lt;br /&gt;
#define CNTDEBOUNCE 10&lt;br /&gt;
// &amp;quot;lange gedrueckt:&amp;quot;&lt;br /&gt;
#define CNTREPEAT 200&lt;br /&gt;
&lt;br /&gt;
// hier z.B. Taste an Pin2 PortA &amp;quot;active low&amp;quot; = 0 wenn gedrueckt&lt;br /&gt;
#define KEY_PIN  PINA&lt;br /&gt;
#define KEY_PINNO PA2&lt;br /&gt;
&lt;br /&gt;
// beachte: volatile! &lt;br /&gt;
volatile uint8_t gKeyCounter;&lt;br /&gt;
&lt;br /&gt;
// Timer-Compare Interrupt ISR, wird z.B. alle 10ms ausgefuehrt&lt;br /&gt;
ISR(TIMER1_COMPA_vect)&lt;br /&gt;
{&lt;br /&gt;
   // hier wird gKeyCounter veraendert. Die übrigen&lt;br /&gt;
   // Programmteile müssen diese Aenderung &amp;quot;sehen&amp;quot;:&lt;br /&gt;
   // volatile -&amp;gt; aktuellen Wert immer in den Speicher schreiben&lt;br /&gt;
   if ( !(KEY_PIN &amp;amp; (1&amp;lt;&amp;lt;KEY_PINNO)) ) {&lt;br /&gt;
      if (gKeyCounter &amp;lt; CNTREPEAT) gKeyCounter++;&lt;br /&gt;
   }&lt;br /&gt;
   else {&lt;br /&gt;
      gKeyCounter = 0;&lt;br /&gt;
   }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
int main(void)&lt;br /&gt;
{&lt;br /&gt;
//...&lt;br /&gt;
    /* hier: Initialisierung der Ports und des Timer-Interrupts */&lt;br /&gt;
//... &lt;br /&gt;
   // hier wird auf gKeyCounter zugegriffen. Dazu muss der in der&lt;br /&gt;
   // ISR geschriebene Wert bekannt sein:&lt;br /&gt;
   // volatile -&amp;gt; aktuellen Wert immer aus dem Speicher lesen&lt;br /&gt;
   if ( gKeyCounter &amp;gt; CNTDEBOUNCE ) { // Taste mind. 10*10 ms &amp;quot;prellfrei&amp;quot;&lt;br /&gt;
       if (gKeyCounter == CNTREPEAT) {&lt;br /&gt;
          /* hier: Code fuer &amp;quot;Taste lange gedrueckt&amp;quot; */&lt;br /&gt;
       }&lt;br /&gt;
       else {&lt;br /&gt;
          /* hier: Code fuer &amp;quot;Taste kurz gedrueckt&amp;quot; */&lt;br /&gt;
       }&lt;br /&gt;
   }&lt;br /&gt;
//...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== volatile und Pointer ===&lt;br /&gt;
&lt;br /&gt;
Bei &#039;&#039;&#039;volatile&#039;&#039;&#039; in Verbindung mit Pointern ist zu beachten, ob der Pointer selbst oder die Variable auf die der Pointer zeigt &#039;&#039;&#039;volatile&#039;&#039;&#039; ist.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
volatile uint8_t *a;   // das Ziel von a ist volatile&lt;br /&gt;
&lt;br /&gt;
uint8_t *volatile a;   // a selbst ist volatile&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Variablen größer 1 Byte ===&lt;br /&gt;
&lt;br /&gt;
Bei Variablen größer ein Byte, auf die in Interrupt-Routinen und im Hauptprogramm zugegriffen wird, muss darauf geachtet werden, dass die Zugriffe auf die einzelnen Bytes außerhalb der ISR nicht durch einen Interrupt unterbrochen werden. (Allgemeinplatz: AVRs sind 8-bit Controller). Zur Veranschaulichung ein Codefragment:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
volatile uint16_t gMyCounter16bit;&lt;br /&gt;
//...&lt;br /&gt;
ISR(...)&lt;br /&gt;
{&lt;br /&gt;
//...&lt;br /&gt;
   gMyCounter16Bit++;&lt;br /&gt;
//...&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int main(void)&lt;br /&gt;
{&lt;br /&gt;
   uint16_t tmpCnt;&lt;br /&gt;
//...&lt;br /&gt;
   // nicht gut: Mglw. hier ein Fehler, wenn ein Byte von MyCounter &lt;br /&gt;
   // schon in tmpCnt kopiert ist aber vor dem Kopieren des zweiten Bytes &lt;br /&gt;
   // ein Interrupt auftritt, der den Inhalt von MyCounter verändert.&lt;br /&gt;
   tmpCnt = gMyCounter16bit; &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
   // besser: Änderungen &amp;quot;außerhalb&amp;quot; verhindern -&amp;gt; alle &amp;quot;Teilbytes&amp;quot;&lt;br /&gt;
   // bleiben konsistent&lt;br /&gt;
   cli();  // Interupts deaktivieren&lt;br /&gt;
   tmpCnt = gMyCounter16Bit;&lt;br /&gt;
   sei();  // wieder aktivieren&lt;br /&gt;
&lt;br /&gt;
   // oder: vorheriger Status des globalen Interrupt-Flags bleibt erhalten&lt;br /&gt;
   uint8_t sreg_tmp;&lt;br /&gt;
   sreg_tmp = SREG;    /* Sichern */&lt;br /&gt;
   cli()&lt;br /&gt;
   tmpCnt = gMyCounter16Bit;&lt;br /&gt;
   SREG = sreg_tmp;    /* Wiederherstellen */&lt;br /&gt;
&lt;br /&gt;
   // oder: mehrfach lesen, bis man konsistente Daten hat&lt;br /&gt;
   uint16_t count1 = gMyCounter16Bit;&lt;br /&gt;
   uint16_t count2 = gMyCounter16Bit;&lt;br /&gt;
   while (count1 != count2) {&lt;br /&gt;
       count1 = count2;&lt;br /&gt;
       count2 = gMyCounter16Bit;&lt;br /&gt;
   }&lt;br /&gt;
   tmpCnt = count1;&lt;br /&gt;
//...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Interrupt-Routinen und Registerzugriffe ==&lt;br /&gt;
&lt;br /&gt;
Falls Register sowohl im Hauptprogramm als auch in Interrupt-Routinen verändert werden, ist darauf zu achten, dass diese Zugriffe sich nicht überlappen. Nur wenige Anweisungen lassen sich in sogenannte &amp;quot;atomare&amp;quot; Zugriffe übersetzen, die nicht von Interrupt-Routinen unterbrochen werden können. &lt;br /&gt;
&lt;br /&gt;
Zur Veranschaulichung eine Anweisung, bei der ein Bit und im Anschluss drei Bits in einem Register gesetzt werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
int main(void)&lt;br /&gt;
{&lt;br /&gt;
//...&lt;br /&gt;
	PORTA |= (1&amp;lt;&amp;lt;PA0);&lt;br /&gt;
	&lt;br /&gt;
	PORTA |= (1&amp;lt;&amp;lt;PA2)|(1&amp;lt;&amp;lt;PA3)|(1&amp;lt;&amp;lt;PA4);&lt;br /&gt;
//...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Compiler übersetzt diese Anweisungen für einen ATmega128 bei Optimierungsstufe &amp;quot;S&amp;quot; nach:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;code&amp;quot;&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
        PORTA |= (1&amp;lt;&amp;lt;PA0);&lt;br /&gt;
  d2:	d8 9a       	sbi	0x1b, 0	; 27 (a)&lt;br /&gt;
	&lt;br /&gt;
        PORTA |= (1&amp;lt;&amp;lt;PA2)|(1&amp;lt;&amp;lt;PA3)|(1&amp;lt;&amp;lt;PA4);&lt;br /&gt;
  d4:	8b b3       	in	r24, 0x1b	; 27 (b)&lt;br /&gt;
  d6:	8c 61       	ori	r24, 0x1C	; 28 (c)&lt;br /&gt;
  d8:	8b bb       	out	0x1b, r24	; 27 (d)&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Setzen des einzelnen Bits wird bei eingeschalteter Optimierung für Register im unteren Speicherbereich in eine einzige Assembler-Anweisung (sbi) übersetzt und ist nicht anfällig für Unterbrechnungen durch Interrupts. Die Anweisung zum Setzen von drei Bits wird jedoch in drei abhängige Assembler-Anweisungen übersetzt und bietet damit zwei &amp;quot;Angriffspunkte&amp;quot; für Unterbrechnungen. Eine Interrupt-Routine könnte nach dem Laden des Ausgangszustands in den Zwischenspeicher (hier Register 24) den Wert des Registers ändern, z.B. ein Bit löschen. Damit würde der Zwischenspeicher nicht mehr mit dem tatsächlichen Zustand übereinstimmen aber dennoch nach der Bitoperation (hier ori) in das Register zurückgeschrieben. &lt;br /&gt;
&lt;br /&gt;
Beispiel: PORTA sei anfangs 0b00000000. Die erste Anweisung (a) setzt Bit 0, PORTA ist danach 0b00000001. Nun wird im ersten Teil der zweiten Anweisung der Portzustand in ein Register eingelesen (b). Unmittelbar darauf (vor (c)) &amp;quot;feuert&amp;quot; ein Interrupt, in dessen Interrupt-Routine Bit 0 von PORTA gelöscht wird. Nach Verlassen der Interrupt-Routine hat PORTA den Wert 0b00000000. In den beiden noch folgenden Anweisungen des Hauptprogramms wird nun der zwischengespeicherte &amp;quot;alte&amp;quot; Zustand 0b00000001 mit 0b00011100 logisch-oder-verknüft (c) und das Ergebnis 0b00011101 in PortA geschrieben (d). Obwohl zwischenzeitlich Bit 0 gelöscht wurde, ist es nach (d) wieder gesetzt. &lt;br /&gt;
&lt;br /&gt;
Lösungsmöglichkeiten:&lt;br /&gt;
* Register ohne besondere Vorkehrungen nicht in Interruptroutinen &#039;&#039;und&#039;&#039; im Hauptprogramm verändern.&lt;br /&gt;
* Interrupts vor Veränderungen in Registern, die auch in ISRs verändert werden, deaktivieren (&amp;quot;cli&amp;quot;).&lt;br /&gt;
* Bits einzeln löschen oder setzen. sbi und cbi können nicht unterbrochen werden. Vorsicht: nur Register im unteren Speicherbereich sind mittels sbi/cbi ansprechbar. Der Compiler kann nur für diese sbi/cbi-Anweisungen generieren. Für Register außerhalb dieses Adressbereichs (&amp;quot;Memory-Mapped&amp;quot;-Register) werden auch zur Manipulation einzelner Bits abhängige Anweisungen erzeugt (lds,...,sts).&lt;br /&gt;
&lt;br /&gt;
* siehe auch: [http://www.nongnu.org/avr-libc/user-manual/index.html Dokumentation der avr-libc] Frequently asked Questions/Fragen Nr. 1 und 8. (Stand: avr-libc Vers. 1.0.4)&lt;br /&gt;
&lt;br /&gt;
== Was macht das Hauptprogramm? ==&lt;br /&gt;
&lt;br /&gt;
Im einfachsten (Ausnahme-)Fall gar nichts mehr. Es ist also durchaus denkbar, ein Programm zu schreiben, welches in der main-Funktion lediglich noch die Interrupts aktiviert und dann in einer Endlosschleife verharrt. Sämtliche Funktionen werden dann in den ISRs abgearbeitet. Diese Vorgehensweise ist jedoch bei den meisten Anwendungen schlecht: man verschenkt eine Verarbeitungsebene und hat außerdem möglicherweise Probleme durch Interruptroutinen, die zu viel Verarbeitungszeit benötigen.&lt;br /&gt;
&lt;br /&gt;
Normalerweise wird man in den Interruptroutinen nur die bei Auftreten des jeweiligen Interruptereignisses unbedingt notwendigen Operationen ausführen lassen. Alle weniger kritischen Aufgaben werden dann im Hauptprogramm abgearbeitet.&lt;br /&gt;
&lt;br /&gt;
* siehe auch: [http://www.nongnu.org/avr-libc/user-manual/index.html Dokumentation der avr-libc] Abschnitt Modules/Interrupts and Signals&lt;br /&gt;
&lt;br /&gt;
= Sleep-Modes =&lt;br /&gt;
&lt;br /&gt;
AVR Controller verfügen über eine Reihe von sogenannten &#039;&#039;Sleep-Modes&#039;&#039; (&amp;quot;Schlaf-Modi&amp;quot;). Diese ermöglichen es, Teile des Controllers abzuschalten. Zum Einen kann damit besonders bei Batteriebetrieb Strom gespart werden, zum Anderen können Komponenten des Controllers deaktiviert werden, die die Genauigkeit des Analog-Digital-Wandlers bzw. des Analog-Comparators negativ beeinflussen. Der Controller wird durch Interrupts aus dem Schlaf geweckt. Welche Interrupts den jeweiligen Schlafmodus beenden, ist einer Tabelle im Datenblatt des jeweiligen Controllers zu entnehmen.&lt;br /&gt;
Die Funktionen (eigentlich Makros) der avr-libc stehen nach Einbinden der header-Datei &#039;&#039;sleep.h&#039;&#039; zur Verfügung.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;set_sleep_mode(uint8_t mode)&#039;&#039;&#039;&lt;br /&gt;
:Setzt den Schlafmodus, der bei Aufruf von sleep() aktiviert wird. In sleep.h sind einige Konstanten definiert (z.B. SLEEP_MODE_PWR_DOWN). Die definierten Modi werden jedoch nicht alle von sämtlichten AVR-Controllern unterstützt.&lt;br /&gt;
* &#039;&#039;&#039;sleep_enable()&#039;&#039;&#039;&lt;br /&gt;
:aktiviert den gesetzten Schlafmodus, versetzt den Controller aber noch nicht in den Schlafmodus&lt;br /&gt;
* &#039;&#039;&#039;sleep_cpu()&#039;&#039;&#039;&lt;br /&gt;
: Versetzt den Controller in den Schlafmodus (sleep_cpu wird im Prinzip durch die Assembler-Anweisung &#039;&#039;sleep&#039;&#039; ersetzt)&lt;br /&gt;
* &#039;&#039;&#039;sleep_disable()&#039;&#039;&#039;&lt;br /&gt;
:deaktiviert den gesetzten Schlafmodus&lt;br /&gt;
* &#039;&#039;&#039;sleep_mode()&#039;&#039;&#039;&lt;br /&gt;
:Versetzt den Controller in den mit set_sleep_mode gewählten Schlafmodus. Das Makro entspricht sleep_enable()+sleep_cpu()+sleep_disable(), beinhaltet also nicht die Aktivierung von Interrupts (besser nicht benutzen).&lt;br /&gt;
&lt;br /&gt;
Bei Anwendung von sleep_cpu() müssen Interrupts also bereits freigeben sein (sei()), da der Controller sonst nicht mehr &amp;quot;aufwachen&amp;quot; kann. sleep_mode() ist nicht geeignet für die Verwendung in ISR Interrupt-Service-Routinen, da bei deren Abarbeitung Interrupts global deaktiviert sind und somit auch die möglichen &amp;quot;Aufwachinterrupts&amp;quot;. Abhilfe: stattdessen sleep_enable(), sei(), sleep_cpu(), sleep_disable() und evtl. cli() verwenden (vgl. Dokumentation der avr-libc).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/sleep.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
int main(void)&lt;br /&gt;
{&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
   while (1) {&lt;br /&gt;
...&lt;br /&gt;
      set_sleep_mode(SLEEP_MODE_PWR_DOWN);&lt;br /&gt;
      sleep_mode();&lt;br /&gt;
   &lt;br /&gt;
      // Code hier wird erst nach Auftreten eines entsprechenden&lt;br /&gt;
      // &amp;quot;Aufwach-Interrupts&amp;quot; verarbeitet&lt;br /&gt;
...&lt;br /&gt;
   }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In älteren Versionenen der avr-libc wurden nicht alle AVR-Controller durch die sleep-Funktionen richtig angesteuert. Mit avr-libc 1.2.0 wurde die Anzahl der unterstützten Typen jedoch deutlich erweitert. Bei nicht-unterstützten Typen erreicht man die gewünschte Funktionalität durch direkte &amp;quot;[[Bitmanipulation]]&amp;quot; der entsprechenden Register (vgl. Datenblatt) und Aufruf des Sleep-Befehls via Inline-Assembler oder sleep_cpu():&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
   // Sleep-Mode &amp;quot;Power-Save&amp;quot; beim ATmega169 &amp;quot;manuell&amp;quot; aktivieren&lt;br /&gt;
   SMCR = (3&amp;lt;&amp;lt;SM0) | (1&amp;lt;&amp;lt;SE);&lt;br /&gt;
   asm volatile (&amp;quot;sleep&amp;quot;::); // alternativ sleep_cpu() aus sleep.h&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* siehe auch: [http://www.nongnu.org/avr-libc/user-manual/index.html Dokumentation der avr-libc] Abschnitt Modules/Power Management and Sleep-Modes&lt;br /&gt;
* [http://www.mikrocontroller.net/topic/96369#832712 Forenbeitrag] zur &amp;quot;Nichtverwendung&amp;quot; von sleep_mode in ISRs.&lt;br /&gt;
&lt;br /&gt;
= Speicherzugriffe =&lt;br /&gt;
&lt;br /&gt;
Atmel AVR-Controller verfügen typisch über drei Speicher:&lt;br /&gt;
&lt;br /&gt;
* [[RAM]]: Im RAM (genauer statisches RAM/SRAM) wird vom gcc-Compiler Platz für Variablen reserviert. Auch der Stack befindet sich im RAM. Dieser Speicher ist &amp;quot;flüchtig&amp;quot;, d.h. der Inhalt der Variablen geht beim Ausschalten oder einem Zusammenbruch der Spannungsversorgung verloren.&lt;br /&gt;
&lt;br /&gt;
* Programmspeicher: Ausgeführt als FLASH-Speicher, seitenweise wiederbeschreibbar. Darin ist das Anwendungsprogramm abgelegt.&lt;br /&gt;
&lt;br /&gt;
* [[EEPROM]]: Nichtflüchtiger Speicher, d.h. der einmal geschriebene Inhalt bleibt auch ohne Stromversorgung erhalten. Byte-weise schreib/lesbar. Im EEPROM werden typischerweise gerätespezifische Werte wie z.B. Kalibrierungswerte von Sensoren abgelegt.&lt;br /&gt;
&lt;br /&gt;
Einige AVRs besitzen keinen RAM-Speicher, lediglich die Register können als &amp;quot;Arbeitsvariablen&amp;quot;&lt;br /&gt;
genutzt werden. Da die Anwendung des avr-gcc auf solch &amp;quot;kleinen&amp;quot; Controllern ohnehin selten sinnvoll ist und auch nur bei einigen RAM-losen Typen nach [http://lightner.net/avr/ATtinyAvrGcc.html &amp;quot;Bastelarbeiten&amp;quot;] möglich ist, werden diese Controller hier nicht weiter berücksichtigt. Auch EEPROM-Speicher ist nicht auf allen Typen verfügbar. Generell sollten die nachfolgenden Erläuterungen auf alle ATmega-Controller und die größeren AT90-Typen übertragbar sein. Für die Typen ATtiny2313, ATtiny26 und viele weitere der &amp;quot;ATtiny-Reihe&amp;quot; gelten die Ausführungen ebenfalls.&lt;br /&gt;
&lt;br /&gt;
== RAM ==&lt;br /&gt;
&lt;br /&gt;
Die Verwaltung des RAM-Speichers erfolgt durch den Compiler, im Regelfall ist beim Zugriff auf Variablen im RAM nichts Besonderes zu beachten. Die Erläuterungen in jedem brauchbaren C-Buch gelten auch für den vom avr-gcc-Compiler erzeugten Code.&lt;br /&gt;
&lt;br /&gt;
Um Speicher dynamisch (während der Laufzeit) zu reservieren, kann &#039;&#039;&#039;malloc()&#039;&#039;&#039; verwendet werden. malloc(size) &amp;quot;allozieren&amp;quot; (~reserviert) einen gewissen Speicherblock mit &#039;&#039;&#039;size&#039;&#039;&#039; Bytes. Ist kein Platz für den neuen Block, wird NULL (0) zurückgegeben.&lt;br /&gt;
&lt;br /&gt;
Wird der angelegte Block zu klein (groß), kann die Größe mit realloc() verändert werden. Den allozierten Speicherbereich kann man mit free() wieder freigeben. Wenn das Freigeben eines Blocks vergessen wird spricht man von einem &amp;quot;Speicherleck&amp;quot; (memory leak).&lt;br /&gt;
&lt;br /&gt;
malloc() legt Speicherblöcke im &#039;&#039;&#039;Heap&#039;&#039;&#039; an, belegt man zuviel Platz, dann wächst der Heap zu weit nach oben und überschreibt den Stack, und der Controller kommt in Teufels Küche. Das kann leider nicht nur passieren wenn man insgesamt zu viel Speicher anfordert, sondern auch wenn man Blöcke unterschiedlicher Größe in ungünstiger Reihenfolge alloziert/freigibt (siehe Artikel [[Heap-Fragmentierung]]). Aus diesem Grund sollte man malloc() auf Mikrocontrollern sehr sparsam (am besten gar nicht) verwenden.&lt;br /&gt;
&lt;br /&gt;
Beispiel zur Verwendung von malloc():&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
void foo(void) {&lt;br /&gt;
  // neuen speicherbereich anlegen,&lt;br /&gt;
  // platz für 10 uint16&lt;br /&gt;
  uint16_t* pBuffer = malloc(10 * sizeof(uint16_t));&lt;br /&gt;
&lt;br /&gt;
  // darauf zugreifen, als wärs ein gewohnter Buffer&lt;br /&gt;
  pBuffer[2] = 5;&lt;br /&gt;
&lt;br /&gt;
  // Speicher (unbedingt!) wieder freigeben&lt;br /&gt;
  free(pBuffer);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn (wie in obigem Beispiel) dynamischer Speicher nur für die Dauer einer Funktion benötigt und am Ende wieder freigegeben wird, bietet es sich an, statt malloc() &#039;&#039;&#039;alloca()&#039;&#039;&#039; zu verwenden. Der Unterschied zu malloc() ist, dass der Speicher auf dem Stack reserviert wird, und beim Verlassen der Funktion automatisch wieder freigegeben wird. Es kann somit kein Speicherleck und keine Fragmentierung entstehen.&lt;br /&gt;
&lt;br /&gt;
siehe auch:&lt;br /&gt;
* http://www.nongnu.org/avr-libc/user-manual/malloc.html&lt;br /&gt;
&lt;br /&gt;
== Programmspeicher (Flash) ==&lt;br /&gt;
&lt;br /&gt;
Ein Zugriff auf Konstanten im Programmspeicher ist mittels avr-gcc nicht &amp;quot;transparent&amp;quot; möglich. D.h. es sind besondere Zugriffsfunktionen erforderlich, um Daten aus diesem Speicher zu lesen. Grundsätzlich basieren alle Zugriffsfunktionen auf der Assembler-Anweisung lpm (load program memory, bei AVR Controllern mit mehr als 64kB Flash auch elpm). Die Standard-Laufzeitbibliothek des avr-gcc (die avr-libc) stellt diese Funktionen nach Einbinden der Header-Datei pgmspace.h zur Verfügung. Mit diesen Funktionen können einzelne Bytes, Datenworte (16bit) und Datenblöcke gelesen werden. &lt;br /&gt;
&lt;br /&gt;
Deklarationen von Variablen im Flash-Speicher werden durch das &amp;quot;Attribut&amp;quot; PROGMEM ergänzt. Lokale Variablen (eigentlich Konstanten) innerhalb von Funktionen können ebenfalls im Programmspeicher abgelegt werden. Dazu ist bei der Definition jedoch ein &#039;&#039;static&#039;&#039; voranzustellen, da solche &amp;quot;Variablen&amp;quot; nicht auf dem Stack bzw. (bei Optimierung) in Registern verwaltet werden können. Der Compiler &amp;quot;wirft&amp;quot; eine Warnung falls static fehlt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/pgmspace.h&amp;gt;&lt;br /&gt;
#include &amp;lt;inttypes.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
/* Byte */&lt;br /&gt;
const uint8_t pgmFooByte PROGMEM = 123;&lt;br /&gt;
&lt;br /&gt;
/* Wort */&lt;br /&gt;
const uint16_t pgmFooWort PROGMEM = 12345;&lt;br /&gt;
&lt;br /&gt;
/* Byte-Feld */&lt;br /&gt;
const uint8_t pgmFooByteArray1[] PROGMEM = { 18, 3 ,70 };&lt;br /&gt;
const uint8_t pgmFooByteArray2[] PROGMEM = { 30, 7 ,79 };&lt;br /&gt;
&lt;br /&gt;
/* Zeiger */&lt;br /&gt;
const uint8_t *pgmPointerToArray1 PROGMEM = pgmFooByteArray1;&lt;br /&gt;
const uint8_t *pgmPointerArray[] PROGMEM = { pgmFooByteArray1, pgmFooByteArray2 };&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
void foo(void)&lt;br /&gt;
{&lt;br /&gt;
  static /*const*/ uint8_t pgmTestByteLocal PROGMEM = 0x55;&lt;br /&gt;
  static /*const*/ char pgmTestStringLocal[] PROGMEM = &amp;quot;im Flash&amp;quot;;&lt;br /&gt;
  // so nicht (static fehlt): char pgmTestStringLocalFalsch [] PROGMEM = &amp;quot;so nicht&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 // ...&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Byte lesen ===&lt;br /&gt;
&lt;br /&gt;
Mit der Funktion pgm_read_byte aus pgmspace.h erfolgt der Zugriff auf die Daten. Parameter der Funktion ist die Adresse des Bytes im Flash-Speicher.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
const uint8_t pgmFooByte PROGMEM = 123;&lt;br /&gt;
const uint8_t pgmFooByteArray1[] PROGMEM = { 18, 3 ,70 };&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    // Wert der Ram-Variablen myByte auf den Wert von pgmFooByte setzen:&lt;br /&gt;
    uint8_t myByte;&lt;br /&gt;
&lt;br /&gt;
    myByte = pgm_read_byte(&amp;amp;pgmFooByte);&lt;br /&gt;
    // myByte hat nun den Wert 123&lt;br /&gt;
&lt;br /&gt;
    //...&lt;br /&gt;
&lt;br /&gt;
    // Schleife ueber ein Array aus Byte-Werten im Flash&lt;br /&gt;
    uint8_t i;&lt;br /&gt;
&lt;br /&gt;
    for (i=0;i&amp;lt;3;i++) {&lt;br /&gt;
        myByte = pgm_read_byte(&amp;amp;pgmFooByteArray1[i]);&lt;br /&gt;
        // mach&#039; was mit myByte....&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Wort lesen ===&lt;br /&gt;
&lt;br /&gt;
Für &amp;quot;einfache&amp;quot; 16-bit breite Variablen erfolgt der Zugriff analog zum Byte-Beispiel, jedoch mit der Funktion pgm_read_word.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
const uint16_t pgmFooWort PROGMEM = 12345;&lt;br /&gt;
&lt;br /&gt;
    uint16_t myWord;&lt;br /&gt;
&lt;br /&gt;
    myWord = pgm_read_word(&amp;amp;pgmFooWort);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zeiger auf Werte im Flash sind ebenfalls 16 Bits &amp;quot;groß&amp;quot; (Stand avr-gcc 3.4.x). Damit ist der mögliche Speicherbereich für &amp;quot;Flash-Konstanten&amp;quot; auf 64kB begrenzt.  &amp;lt;!-- Einige avr-libc/pgmspace-Funktionen ermöglichen den Lesezugriff auf den gesamten Flash-Speicher) (intern via Assembler Anweisung ELPM). Die Initialisierungswerde des Speicherinhalts jenseits der 64kB-Marke müssen dann jedoch auf anderem Weg angelegt werden (nicht PROGMEM, evtl. eigene Section und Linker-Optionen - TODO) /// alt - und nicht ganz korrekt: (Die avr-libc pgmspace-Funktionen unterstützen nur die unteren 64kB Flash bei Controllern mit mehr als 64kB.)--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
    uint8_t *ptrToArray;&lt;br /&gt;
&lt;br /&gt;
    ptrToArray = (uint8_t*)(pgm_read_word(&amp;amp;pgmPointerToArray1));&lt;br /&gt;
    // ptrToArray enthält nun die Startadresse des Byte-Arrays pgmFooByteArray1&lt;br /&gt;
    // Allerdings würde ein direkter Zugriff mit diesem Pointer (z.B. temp=*ptrToArray)&lt;br /&gt;
    // &#039;&#039;&#039;nicht&#039;&#039;&#039; den Inhalt von pgmFooByteArray1[0] liefern, sondern von einer Speicherstelle&lt;br /&gt;
    // im &#039;&#039;&#039;RAM&#039;&#039;&#039;, die die gleiche Adresse hat wie pgmFooByteArray1[0]&lt;br /&gt;
    // Daher muss nun die Funktion pgm_read_byte() benutzt werden, die die in ptrToArray&lt;br /&gt;
    // enthaltene Adresse benutzt und auf das Flash zugreift.&lt;br /&gt;
&lt;br /&gt;
    for (i=0;i&amp;lt;3;i++) {&lt;br /&gt;
        myByte = pgm_read_byte(ptrToArray+i);&lt;br /&gt;
        // mach&#039; was mit myByte... (18, 3, 70)&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    ptrToArray = (uint8_t*)(pgm_read_word(&amp;amp;pgmPointerArray[1]));&lt;br /&gt;
    &lt;br /&gt;
    // ptrToArray enthält nun die Adresse des ersten Elements des Byte-Arrays pgmFooByteArray2&lt;br /&gt;
    // da im zweiten Element des Pointer-Arrays pgmPointerArray die Adresse&lt;br /&gt;
    // von pgmFooByteArray2 abgelegt ist&lt;br /&gt;
&lt;br /&gt;
    for (i=0;i&amp;lt;3;i++) {&lt;br /&gt;
        myByte = pgm_read_byte(ptrToArray+i);&lt;br /&gt;
        // mach&#039; was mit myByte... (30, 7, 79)&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Floats und Structs lesen ===&lt;br /&gt;
&lt;br /&gt;
Um komplexe Datentypen (structs), nicht-integer Datentypen (floats) aus dem Flash auszulesen, sind Hilfsfunktionen erforderlich. Einige Beispiele:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
/* Beispiel float aus Flash */&lt;br /&gt;
&lt;br /&gt;
float pgmFloatArray[3] PROGMEM = {1.1, 2.2, 3.3};&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
/* liest float von Flash-Addresse addr und gibt diese als return-value zurueck */&lt;br /&gt;
inline float pgm_read_float(const float *addr)&lt;br /&gt;
{	&lt;br /&gt;
	union&lt;br /&gt;
	{&lt;br /&gt;
		uint16_t i[2];	// 2 16-bit-Worte&lt;br /&gt;
		float f;&lt;br /&gt;
	} u;&lt;br /&gt;
	&lt;br /&gt;
	u.i[0]=pgm_read_word((PGM_P)addr);&lt;br /&gt;
	u.i[1]=pgm_read_word((PGM_P)addr+2);&lt;br /&gt;
	&lt;br /&gt;
	return u.f;&lt;br /&gt;
} &lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
void egal(void)&lt;br /&gt;
{&lt;br /&gt;
   int i;&lt;br /&gt;
   float f;&lt;br /&gt;
&lt;br /&gt;
   for (i=0;i&amp;lt;3;i++) {&lt;br /&gt;
      f = pgm_read_float(&amp;amp;pgmFloatArray[i]); // entspr. &amp;quot;f = pgmFloatArray[i];&amp;quot;&lt;br /&gt;
      // mach&#039; was mit f &lt;br /&gt;
   }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
TODO: Beispiele fuer structs und pointer aus flash auf struct im flash (menues, state-machines etc.)&lt;br /&gt;
&lt;br /&gt;
=== Array aus Zeichenketten im Flash-Speicher ===&lt;br /&gt;
&lt;br /&gt;
Felder aus Zeichenketten im Flash-Speicher werden in zwei Schritten angelegt: Zuerst die einzelnen Elemente des Arrays und im Anschluss ein Array, in dem die Addressen der Zeichenketten abgelegt werden. Zum Auslesen wird zuerst die Adresse des i-ten Elements aus dem Array im Flash-Speicher gelesen, die im Anschluss dazu genutzt wird, auf das Element (die Zeichenkette) selbst zuzugreifen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/pgmspace.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
const char str1[] PROGMEM = &amp;quot;first_A&amp;quot;;&lt;br /&gt;
const char str2[] PROGMEM = &amp;quot;second_A&amp;quot;;&lt;br /&gt;
const char str3[] PROGMEM = &amp;quot;third_A&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
const char *strarray1[] PROGMEM = {&lt;br /&gt;
	str1,&lt;br /&gt;
	str2,&lt;br /&gt;
	str3&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
int main(void)&lt;br /&gt;
{&lt;br /&gt;
	int i, j, l;&lt;br /&gt;
	const char *pstrflash;&lt;br /&gt;
	char work[20], work2[20];&lt;br /&gt;
	// fuer Simulation: per volatile Optimierung verhindern, &lt;br /&gt;
	//                  da c nicht genutzt&lt;br /&gt;
	volatile char c;&lt;br /&gt;
	&lt;br /&gt;
	for ( i = 0; i &amp;lt; (sizeof(strarray1)/sizeof(strarray1[0]) ); i++ ) {&lt;br /&gt;
&lt;br /&gt;
		// setze Pointer auf die Addresse des i-ten Elements des&lt;br /&gt;
		// &amp;quot;Flash-Arrays&amp;quot; (str1, str2, ...)&lt;br /&gt;
		pstrflash = (const char*)( pgm_read_word( &amp;amp;(strarray1[i]) ) );&lt;br /&gt;
		&lt;br /&gt;
		// kopiere den Inhalt der Zeichenkette von der&lt;br /&gt;
		// in pstrflash abgelegten Adresse in das work-Array&lt;br /&gt;
		// analog zu strcpy( work, strarray1[i]) wenn alles im RAM&lt;br /&gt;
		strcpy_P( work, pstrflash );&lt;br /&gt;
		// verkuerzt:&lt;br /&gt;
		strcpy_P( work2, (const char*)( pgm_read_word( &amp;amp;(strarray1[i]) ) ) );&lt;br /&gt;
		&lt;br /&gt;
&lt;br /&gt;
		// Zeichen-fuer-Zeichen&lt;br /&gt;
		l = strlen_P( pstrflash );&lt;br /&gt;
		for ( j=0; j &amp;lt; l; j++ ) {&lt;br /&gt;
			// analog zu c=strarray[i][j] wenn alles im RAM&lt;br /&gt;
			c = (char)( pgm_read_byte( pstrflash++ ) );&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	while (1) { ; }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Siehe dazu auch die avr-libc FAQ: &amp;quot;How do I put an array of strings completely in ROM?&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=== Vereinfachung für Zeichenketten (Strings) im Flash ===&lt;br /&gt;
&lt;br /&gt;
Zeichenketten können innerhalb des Quellcodes als &amp;quot;Flash-Konstanten&amp;quot; ausgewiesen werden. Dazu dient das Makro PSTR aus pgmspace.h. Dies erspart die getrennte Deklaration mit PROGMEM-Attribut.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/pgmspace.h&amp;gt;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#define MAXLEN 30&lt;br /&gt;
&lt;br /&gt;
char StringImFlash[] PROGMEM = &amp;quot;Erwin Lindemann&amp;quot;; // im &amp;quot;Flash&amp;quot;&lt;br /&gt;
char StringImRam[MAXLEN];&lt;br /&gt;
&lt;br /&gt;
//...&lt;br /&gt;
    strcpy(StringImRam, &amp;quot;Mueller-Luedenscheidt&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (!strncmp_P(StringImRam, StringImFlash, 5)) { &lt;br /&gt;
        // mach&#039; was, wenn die ersten 5 Zeichen identisch - hier nicht&lt;br /&gt;
    }&lt;br /&gt;
    else {&lt;br /&gt;
        // der Code hier wuerde ausgefuehrt &lt;br /&gt;
    } &lt;br /&gt;
&lt;br /&gt;
    if (!strncmp_P(StringImRam, PSTR(&amp;quot;Mueller-Schmitt&amp;quot;), 5)) {&lt;br /&gt;
        // der Code hier wuerde ausgefuehrt, die ersten 5 Zeichen stimmen ueberein&lt;br /&gt;
    }&lt;br /&gt;
    else {&lt;br /&gt;
        // wuerde bei nicht-Uebereinstimmung ausgefuehrt&lt;br /&gt;
    }&lt;br /&gt;
//...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Aber Vorsicht: Ersetzt man zum Beispiel&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
const char textImFlashOK[] PROGMEM = &amp;quot;mit[]&amp;quot;; &lt;br /&gt;
// = Daten im &amp;quot;Flash&amp;quot;, textImFlashOK* zeigt auf Flashadresse&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
durch&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
const char* textImFlashProblem PROGMEM = &amp;quot;mit*&amp;quot;;&lt;br /&gt;
// Konflikt: Daten im BSS (lies: RAM), textImFlashFAIL* zeigt auf Flashadresse&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
dann kann es zu Problemen mit AVR-GCC kommen. Zu erkennen daran, dass der Initialisierungsstring von &amp;quot;textImFlashProblem&amp;quot; zu den Konstanten ans Ende des Programmcodes gelegt wird (BSS), von dem aus er zur Benutzung eigentlich ins RAM kopiert werden sollte (und wird). Da der lesende Code (mittels pgm_read*) trotzdem an einer Stelle vorne im Flash sucht, wird Unsinn gelesen. Dies scheint ein weiters Problem des AVR-GCC (gesehen bei avr-gcc 3.4.1 und 3.4.2) bei der Anpassung an die Harvard-Architektur zu sein (konstanter Pointer auf variable Daten?!). Abhilfe (&amp;quot;Workaround&amp;quot;): Initialisierung bei Zeichenketten mit [] oder gleich im Code PSTR(&amp;quot;...&amp;quot;) nutzen.&lt;br /&gt;
&lt;br /&gt;
Übergibt man Zeichenketten (genauer: die Adresse des ersten Zeichens), die im Flash abglegt sind an eine Funktion, muss diese entsprechend programmiert sein. Die Funktion selbst hat keine Möglichkeit zu unterscheiden, ob es sich um eine Adresse im Flash oder im RAM handelt. Die avr-libc und viele andere avr-gcc-Bibliotheken halten sich an die Konvention, dass Namen von Funktionen die Flash-Adressen erwarten mit dem Suffix _p (oder _P) versehen sind.&lt;br /&gt;
&lt;br /&gt;
Eine Funktion, die einen im Flash abgelegten String z.B. an eine UART ausgibt, würde dann so aussehen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
void uart_puts_p(const char *text)&lt;br /&gt;
{&lt;br /&gt;
    char Zeichen;&lt;br /&gt;
&lt;br /&gt;
    while (Zeichen = pgm_read_byte(text))&lt;br /&gt;
    {   /* so lange, wie mittels pgm_read_byte ein Zeichen vom Flash gelesen&lt;br /&gt;
           werden konnte, welches nicht das &amp;quot;String-Endezeichen&amp;quot; darstellt */&lt;br /&gt;
&lt;br /&gt;
        /* Das gelesene Zeichen über die normalen Kanäle verschicken */&lt;br /&gt;
        uart_putc(Zeichen);&lt;br /&gt;
        text++;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Von einigen Bibliotheken werden Makros definiert, die &amp;quot;automatisch&amp;quot; ein PSTR bei Verwendung einer Funktion einfügen. Ein Blick in den Header-File der Bibliothek zeigt, ob dies der Fall ist. Ein Beispiel aus P. Fleurys lcd-Library:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
// Ausschnitt aus dem Header-File lcd.h der &amp;quot;Fleury-LCD-Lib.&amp;quot;&lt;br /&gt;
//...&lt;br /&gt;
extern void lcd_puts_p(const char *progmem_s);&lt;br /&gt;
#define lcd_puts_P(__s) lcd_puts_p(PSTR(__s))&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
// in einer Anwendung (wieauchimmmer.c)&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/pgmspace.h&amp;gt;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
#include &amp;quot;lcd.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
char StringImFlash[] PROGMEM = &amp;quot;Erwin Lindemann&amp;quot;; // im &amp;quot;Flash&amp;quot;&lt;br /&gt;
&lt;br /&gt;
//...&lt;br /&gt;
    lcd_puts_p(StringImFlash); &lt;br /&gt;
    lcd_puts_P(&amp;quot;Dr. Kloebner&amp;quot;); &lt;br /&gt;
    // daraus wird wg. #define lcd_put_P...:  lcd_puts_p( PSTR(&amp;quot;Dr. Kloebner&amp;quot;) );&lt;br /&gt;
//...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Flash in der Anwendung schreiben ===&lt;br /&gt;
&lt;br /&gt;
Bei AVRs mit &amp;quot;self-programming&amp;quot;-Option (auch bekannt als Bootloader-Support) können Teile des Flash-Speichers auch vom Anwendungsprogramm selbst beschrieben werden. Dies ist nur möglich, wenn die Schreibfunktionen in einem besonderen Speicherbereich (boot-section) des Programmspeichers/Flash abgelegt sind. Bei wenigen &amp;quot;kleinen&amp;quot; AVRs gibt es keine gesonderte Boot-Section, bei diesen kann der Flashspeicher von jeder Stelle des Programms geschrieben werden. Für Details sei hier auf das jeweilige Controller-Datenblatt und die Erläuterungen zum Modul boot.h der avr-libc verwiesen. Es existieren auch Application-Notes dazu bei atmel.com, die auf avr-gcc-Code übertragbar sind.&lt;br /&gt;
&lt;br /&gt;
=== Warum so kompliziert? ===&lt;br /&gt;
&lt;br /&gt;
Zu dem Thema, warum die Verabeitung von Werten aus dem Flash-Speicher so &amp;quot;kompliziert&amp;quot; ist, sei hier nur kurz erläutert: Die Harvard-Architektur des AVR weist getrennte Adressräume für Programm(Flash)- und Datenspeicher(RAM) auf. Der C-Standard und der gcc-Compiler sehen keine unterschiedlichen Adressräume vor. &lt;br /&gt;
Hat man zum Beispiel eine Funktion string_an_uart(const char* s) und übergibt an diese Funktion die Adresse einer Zeichenkette (einen Pointer, z.B. 0x01fe), &amp;quot;weiß&amp;quot; die Funktion nicht, ob die Adresse auf den Flash-Speicher oder den/das RAM zeigt. Allein aus dem Pointer-Wert (der Zahl) kann nicht geschlossen werden, ob ein &amp;quot;einfaches&amp;quot; zeichen_an_uart(s[i]) oder zeichen_an_uart(pgm_read_byte(&amp;amp;s[i]) genutzt werden muss, um das i-te Zeichen auszugeben.&lt;br /&gt;
&lt;br /&gt;
Einige AVR-Compiler &amp;quot;tricksen&amp;quot; etwas, in dem sie für einen Pointer nicht nur die Adresse anlegen, sondern zusätzlich zu jedem Pointer den Ablageort (Flash oder RAM) intern sichern. Bei Aufruf einer Funktion wird dann bei Pointer-Parametern neben der Adresse auch der Speicherbereich, auf den der Pointer zeigt, übergeben. Dies hat jedoch nicht nur Vorteile; Erläuterungen warum dies so ist, führen an dieser Stelle zu weit.&lt;br /&gt;
&lt;br /&gt;
* siehe auch: [http://www.nongnu.org/avr-libc/user-manual/index.html Dokumentation der avr-libc] Abschnitte Modules/Program Space String Utilities und Abschnitt Modules/Bootloader Support Utilities&lt;br /&gt;
&lt;br /&gt;
== EEPROM ==&lt;br /&gt;
&lt;br /&gt;
Man beachte, dass der EEPROM-Speicher nur eine begrenzte Anzahl von Schreibzugriffen zulässt. Beschreibt man eine EEPROM-Zelle öfter als die im Datenblatt zugesicherte Anzahl (typisch 100.000), wird die Funktion der Zelle nicht mehr garantiert. &lt;br /&gt;
Dies gilt für jede einzelne Zelle. Bei geschickter Programmierung (z.B. Ring-Puffer), bei der die zu beschreibenden Zellen regelmäßig gewechselt werden, kann man eine deutlich höhere Anzahl an Schreibzugriffen, bezogen auf den Gesamtspeicher, erreichen.&lt;br /&gt;
&lt;br /&gt;
Schreib- und Lesezugriffe auf den EEPROM-Speicher erfolgen über die im Modul eeprom.h definierten Funktionen. Mit diesen Funktionen können einzelne Bytes, Datenworte (16bit) und Datenblöcke geschrieben und gelesen werden. &lt;br /&gt;
&lt;br /&gt;
Bei Nutzung des EEPROMs ist zu beachten, dass vor dem Zugriff auf diesen Speicher abgefragt wird, ob der Controller die vorherige EEPROM-Operation abgeschlossen hat. Die avr-libc-Funktionen beinhalten diese Prüfung, man muss sie nicht selbst implementieren. Man sollte auch verhindern, dass der Zugriff durch die Abarbeitung einer Interrupt-Routine unterbrochen wird, da bestimme Befehlsabfolgen vorgegeben sind, die innerhalb weniger Taktzyklen aufeinanderfolgen müssen (&amp;quot;timed sequence&amp;quot;). Auch dies muss bei Nutzung der Funktionen aus der avr-libc/eeprom.h-Datei nicht selbst implementiert werden. Innerhalb der Funktionen werden Interrupts vor der &amp;quot;EEPROM-Sequenz&amp;quot; global deaktiviert und im Anschluss, falls vorher auch schon eingeschaltet, wieder aktiviert.&lt;br /&gt;
&lt;br /&gt;
Bei der Deklaration einer Variable im EEPROM, ist das Attribut für die Section &amp;quot;.eeprom&amp;quot; zu ergänzen. Siehe dazu folgendes Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/eeprom.h&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/interrupt.h&amp;gt;&lt;br /&gt;
#include &amp;lt;inttypes.h&amp;gt; // wird in aktuellen Versionen der avr-lib mit xx.h eingebunden&lt;br /&gt;
&lt;br /&gt;
// EEMEM wird bei aktuellen Versionen der avr-lib in eeprom.h definiert&lt;br /&gt;
// hier: definiere falls noch nicht bekannt (&amp;quot;alte&amp;quot; avr-libc)&lt;br /&gt;
#ifndef EEMEM&lt;br /&gt;
// alle Textstellen EEMEM im Quellcode durch __attribute__ ... ersetzen&lt;br /&gt;
#define EEMEM  __attribute__ ((section (&amp;quot;.eeprom&amp;quot;)))&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
/* Byte */&lt;br /&gt;
uint8_t eeFooByte EEMEM = 123;&lt;br /&gt;
&lt;br /&gt;
/* Wort */&lt;br /&gt;
uint16_t eeFooWord EEMEM = 12345;&lt;br /&gt;
&lt;br /&gt;
/* float */&lt;br /&gt;
float eeFooFloat EEMEM;&lt;br /&gt;
&lt;br /&gt;
/* Byte-Feld */&lt;br /&gt;
uint8_t eeFooByteArray1[] EEMEM = { 18, 3 ,70 };&lt;br /&gt;
uint8_t eeFooByteArray2[] EEMEM = { 30, 7 ,79 };&lt;br /&gt;
&lt;br /&gt;
/* 16-bit unsigned short feld */&lt;br /&gt;
uint16_t eeFooWordArray1[4] EEMEM;&lt;br /&gt;
//...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Bytes lesen/schreiben ===&lt;br /&gt;
&lt;br /&gt;
Die avr-libc Funktion zum Lesen eines Bytes heißt eeprom_read_byte. Parameter ist die Adresse des Bytes im EEPROM. Geschrieben wird über die Funktion eeprom_write_byte mit den Parametern Adresse und Inhalt. Anwendungsbeispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
    uint8_t myByte;&lt;br /&gt;
&lt;br /&gt;
    myByte = eeprom_read_byte(&amp;amp;eeFooByte); // lesen&lt;br /&gt;
    // myByte hat nun den Wert 123&lt;br /&gt;
//...&lt;br /&gt;
    myByte = 99;&lt;br /&gt;
    eeprom_write_byte(&amp;amp;eeFooByte, myByte); // schreiben&lt;br /&gt;
    // der Wert 99 wird im EEPROM an die Adresse der&lt;br /&gt;
    // &#039;Variablen&#039; eeFooByte geschrieben&lt;br /&gt;
//...&lt;br /&gt;
    myByte = eeprom_read_byte(&amp;amp;eeFooByteArray1[1]); &lt;br /&gt;
    // myByte hat nun den Wert 3&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
    // Beispiel zur &amp;quot;Sicherung&amp;quot; gegen leeres EEPROM nach &amp;quot;Chip Erase&amp;quot;&lt;br /&gt;
    // (z.B. wenn die .eep-Datei nach Programmierung einer neuen Version&lt;br /&gt;
    // des Programms nicht in den EEPROM uebertragen wurde und EESAVE&lt;br /&gt;
    // deaktiviert ist (unprogrammed/1)&lt;br /&gt;
    // &lt;br /&gt;
    // Vorsicht: wenn EESAVE &amp;quot;programmed&amp;quot; ist, hilft diese Sicherung nicht&lt;br /&gt;
    // weiter, da die Speicheraddressen in einem neuen/erweiterten Programm&lt;br /&gt;
    // moeglicherweise verschoben wurden. An der Stelle &amp;amp;eeFooByte steht&lt;br /&gt;
    // dann u.U. der Wert einer anderen Variable aus einer &amp;quot;alten&amp;quot; Version.&lt;br /&gt;
&lt;br /&gt;
    #define EEPROM_DEF 0xFF&lt;br /&gt;
    uint8_t fooByteDefault = 222;&lt;br /&gt;
    if ( ( myByte = eeprom_read_byte(&amp;amp;eeFooByte) ) == EEPROM_DEF ) {&lt;br /&gt;
        myByte = fooByteDefault;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Wort lesen/schreiben ===&lt;br /&gt;
&lt;br /&gt;
Schreiben und Lesen von Datenworten erfolgt analog zur Vorgehensweise bei Bytes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
    uint16_t myWord;&lt;br /&gt;
&lt;br /&gt;
    myWord = eeprom_read_word(&amp;amp;eeFooWord); // lesen&lt;br /&gt;
    // myWord hat nun den Wert 12345&lt;br /&gt;
//...&lt;br /&gt;
    myWord = 2222;&lt;br /&gt;
    eeprom_write_word(&amp;amp;eeFooWord, myWord); // schreiben&lt;br /&gt;
//...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Block lesen/schreiben ===&lt;br /&gt;
&lt;br /&gt;
Lesen und Schreiben von Datenblöcken erfolgt über die Funktionen &#039;&#039;eeprom_read_block()&#039;&#039; bzw. &#039;&#039;eeprom_write_block()&#039;&#039;. Die Funktionen erwarten drei Parameter: die Adresse der Quell- bzw. Zieldaten im RAM, die EEPROM-Addresse und die Länge des Datenblocks in Bytes (size_t).&lt;br /&gt;
&lt;br /&gt;
TODO: &#039;&#039;&#039;Vorsicht!&#039;&#039;&#039; die folgenden Beispiele sind noch nicht geprüft, erstmal nur als Hinweis auf &amp;quot;das Prinzip&amp;quot;. Evtl. fehlen &amp;quot;casts&amp;quot; und möglicherweise noch mehr.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
    uint8_t  myByteBuffer[3];&lt;br /&gt;
    uint16_t myWordBuffer[4];&lt;br /&gt;
&lt;br /&gt;
    /* Datenblock aus EEPROM LESEN  */&lt;br /&gt;
&lt;br /&gt;
    /* liest 3 Bytes ab der von eeFooByteArray1 definierten EEPROM-Adresse&lt;br /&gt;
       in das RAM-Array myByteBuffer */&lt;br /&gt;
    eeprom_read_block(myByteBuffer,eeFooByteArray1,3);&lt;br /&gt;
&lt;br /&gt;
    /* dito etwas anschaulicher aber &amp;quot;unnütze Tipparbeit&amp;quot;: */&lt;br /&gt;
    eeprom_read_block(&amp;amp;myByteBuffer[0],&amp;amp;eeFooByteArray[0],3);&lt;br /&gt;
&lt;br /&gt;
    /* dito mit etwas Absicherung betr. der Länge */&lt;br /&gt;
    eeprom_read_block(myByteBuffer,eeFooByteArray1,sizeof(myByteBuffer));&lt;br /&gt;
&lt;br /&gt;
    /* und nun mit &amp;quot;16bit&amp;quot; */&lt;br /&gt;
    eeprom_read_block(myWordBuffer,eeFooWordArray1,sizeof(myWordBuffer));&lt;br /&gt;
&lt;br /&gt;
    /* Datenlock in EEPROM SCHREIBEN */&lt;br /&gt;
    eeprom_write_block(eeFooByteArray1,myByteBuffer,sizeof(myByteBuffer));&lt;br /&gt;
    eeprom_write_block(eeFooWordArray1,myWordBuffer,sizeof(myWordBuffer));&lt;br /&gt;
//...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Nicht-Integer&amp;quot;-Datentypen wie z.B. Fließkommazahlen lassen sich recht praktisch über eine &#039;&#039;union&#039;&#039; in &amp;quot;Byte-Arrays&amp;quot; konvertieren und wieder &amp;quot;zurückwandeln&amp;quot;. Dies erweist sich hier (aber nicht nur hier) als nützlich.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
   float myFloat = 12.34;&lt;br /&gt;
&lt;br /&gt;
   union {&lt;br /&gt;
      float r;&lt;br /&gt;
      uint8_t i[sizeof(float)];&lt;br /&gt;
   } u;&lt;br /&gt;
&lt;br /&gt;
   u.r = myFloat;&lt;br /&gt;
   &lt;br /&gt;
   /* float in EEPROM */&lt;br /&gt;
   eeprom_write_block(&amp;amp;eeFooFloat,&amp;amp;(u.i),sizeof(float));&lt;br /&gt;
&lt;br /&gt;
   /* float aus EEPROM */&lt;br /&gt;
   eeprom_read_block(&amp;amp;(u.i),&amp;amp;eeFooFloat,sizeof(float));&lt;br /&gt;
   /* u.r wieder 12.34 */&lt;br /&gt;
//...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Auch zusammengesetzte Typen lassen sich mit den Block-Routinen verarbeiten.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
typedef struct {&lt;br /&gt;
    uint8_t   label[8];&lt;br /&gt;
    uint8_t   rom_code[8];&lt;br /&gt;
} tMyStruct;&lt;br /&gt;
&lt;br /&gt;
#define MAXSENSORS 3&lt;br /&gt;
tMyStruct eeMyStruct[MAXSENSORS] EEMEM;&lt;br /&gt;
&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
void egal(void)&lt;br /&gt;
{&lt;br /&gt;
   tMyStruct work;&lt;br /&gt;
   &lt;br /&gt;
   strcpy(work.label,&amp;quot;Flur&amp;quot;);&lt;br /&gt;
   GetRomCode(work.rom_code);     // Dummy zur Veranschaulichung - setzt rom-code&lt;br /&gt;
&lt;br /&gt;
   /* Sichern von &amp;quot;work&amp;quot; im EEPROM */&lt;br /&gt;
   eeprom_write_block(&amp;amp;eeMyStruct[0],&amp;amp;work,sizeof(tMyStruct)); // f. Index 0&lt;br /&gt;
   strcpy(work.label,&amp;quot;Bad&amp;quot;);&lt;br /&gt;
   GetRomCode(work.rom_code);&lt;br /&gt;
   eeprom_write_block(&amp;amp;eeMyStruct[1],&amp;amp;work,sizeof(tMyStruct)); // f. Index 1&lt;br /&gt;
//...&lt;br /&gt;
   /* Lesen der Daten EEPROM Index 0 in &amp;quot;work&amp;quot; */&lt;br /&gt;
   eeprom_read_block(&amp;amp;work,&amp;amp;eeMyStruct[0],sizeof(tMyStruct));&lt;br /&gt;
   // work.label hat nun den Inhalt &amp;quot;Flur&amp;quot;&lt;br /&gt;
//...&lt;br /&gt;
}&lt;br /&gt;
//...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== EEPROM-Speicherabbild in .eep-Datei ===&lt;br /&gt;
&lt;br /&gt;
Mit den zum Compiler gehörenden Werkzeugen kann der aus den Variablendeklaration abgeleiteten EEPROM-Inhalt in eine Datei geschrieben werden (übliche Dateiendung: .eep, Daten im Intel Hex-Format). Damit können recht elegant Standardwerte für den EEPROM-Inhalt im Quellcode definiert werden. Makefiles nach WinAVR/MFile-Vorlage enthalten bereits die notwendigen Einstellungen (siehe dazu die Erläuterungen im Abschnitt Exkurs: Makefiles). Der Inhalt der eep-Datei muss ebenfalls zum Mikrocontroller übertragen werden (Write EEPROM), wenn die Initialisierungswerte aus der Deklaration vom Programm erwartet werden. Ansonsten enthält der EEPROM-Speicher nach der Übertragung des Programmers mittels ISP abhängig von der Einstellung der EESAVE-Fuse (vgl. Datenblatt Abschnitt Fuse Bits) die vorherigen Daten (EESAVE programmed = 0), deren Position möglicherweise nicht mehr mit der Belegung im aktuellen Programm übereinstimmt oder den Standardwert nach &amp;quot;Chip Erase&amp;quot;: 0xFF (EESAVE unprogrammed = 1). Als Sicherung kann man im Programm nochmals die Standardwerte vorhalten, beim Lesen auf 0xFF prüfen und gegebenfalls einen Standardwert nutzen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--Eine besondere Funktion des avr-gcc ist, dass mit entsprechenden Optionen im Makefile aus den Initialisierungswerten der Variablen im Quellcode eine Datei erzeugt werden kann, die man auf den Controller programmieren kann (.eep-Datei). Damit können sehr elegant Standardwerte für den EEPROM-Inhalt im Quellcode definiert werden. Die Vorgehensweise wird aus dem WinAVR-Beispielmakefile ersichtlich. Siehe dazu die Erläuterungen im Abschnitt Exkurs: Makefiles.--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== EEPROM-Variable auf feste Adressen legen ===&lt;br /&gt;
&lt;br /&gt;
Gleich zu Beginn möchte ich darauf hinweisen, dass dieses Verfahren nur ein Workaround ist, mit dem man das Problem der anscheinend &amp;quot;zufälligen&amp;quot; Verteilung&lt;br /&gt;
der EEPROM-Variablen durch den Compiler etwas in den Griff bekommen kann.&lt;br /&gt;
&lt;br /&gt;
Hilfreich kann dies vor allem dann sein, wenn man z.B. über einen Kommandointerpreter (o.ä. Funktionen) direkt bestimmte EEPROM-Adressen manipulieren möchte. Auch wenn man über einen JTAG-Adapter (mk I oder mkII) den Programmablauf manipulieren möchte, indem man die EEPROM-Werte direkt ändert, kann diese Technik hilfreich sein.&lt;br /&gt;
&lt;br /&gt;
Im folgenden nun zwei Sourcelistings mit einem Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
/////////////////////////////////////////////////&lt;br /&gt;
// Datei &amp;quot;eeprom.h&amp;quot; eines eigenen Projektes&lt;br /&gt;
/////////////////////////////////////////////////&lt;br /&gt;
&lt;br /&gt;
#inlcude &amp;lt;avr/eeprom.h&amp;gt;     // Die EEPROM-Definitionen/Macros der avr-libc einbinden&lt;br /&gt;
&lt;br /&gt;
#define   EESIZE   512      // Maximale Größe des EEPROMS&lt;br /&gt;
&lt;br /&gt;
#define   EE_DUMMY   0x000  // Dummyelement (Adresse 0 sollte nicht genutzt werden)&lt;br /&gt;
#define   EE_VALUE1  0x001  // Eine Bytevariable  &lt;br /&gt;
#define   EE_WORD1L  0x002  // Eine Wordvariable (Lowbyte)&lt;br /&gt;
#define   EE_WORD1H  0x003  // Eine Wordvariable (Highbyte)&lt;br /&gt;
#define   EE_VALUE2  0x004  // Eine weitere Bytevariable&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit den Macros &#039;&#039;&#039;#define EE_VALUE1&#039;&#039;&#039; legt man den Namen und die Adresse der&lt;br /&gt;
&#039;Variablen&#039; fest.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;font color=$FF0000&amp;gt;WICHTIG:&amp;lt;/font&amp;gt;Die Adressen sollten fortlaufend, zumindest aber aufsteigend sortiert sein! Ansonsten besteht die Gefahr, daß man sehr schnell ein Durcheinander im EEPROM Speicher veranstaltet.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;font color=$FF0000&amp;gt;WICHTIG:&amp;lt;/font&amp;gt;Für den Compiler sind das lediglich Speicher-Adressen, über die auf das EEPROM zugegriffen wird. Der Compiler sieht nichts davon als eine echte Variable an und stößt sich daher auch nicht daran, wenn 2 Makros mit der gleichen Speicheradresse, bzw. überlappenden Speicherbereichen definiert werden. Es liegt einzig und alleine in der Hand des Programmierers, hier keinen Fehler zu machen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
/////////////////////////////////////////////////&lt;br /&gt;
// Datei &amp;quot;eeprom.c&amp;quot; eines eigenen Projektes&lt;br /&gt;
/////////////////////////////////////////////////&lt;br /&gt;
&lt;br /&gt;
#include &amp;quot;eeprom.h&amp;quot;          // Eigene EEPROM-Headerdatei einbinden&lt;br /&gt;
&lt;br /&gt;
uint8_t ee_mem[EESIZE] EEMEM =&lt;br /&gt;
{&lt;br /&gt;
   [EE_DUMMY]   = 0x00,&lt;br /&gt;
   [EE_VALUE1]  = 0x05,&lt;br /&gt;
   [EE_WORD1L]  = 0x01,   &lt;br /&gt;
   [EE_WORD1H]  = 0x00,&lt;br /&gt;
   [EE_VALUE2]  = 0xFF&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Durch die Verwendung eines Array, welches das gesammte EEPROM umfasst, bleibt&lt;br /&gt;
dem Compiler nicht anderes übrig, als das Array so zu platzieren, dass Element 0&lt;br /&gt;
des Arrays der Adresse 0 des EEPROMs entspricht. (&#039;&#039;Ich hoffe nur, dass die Compilerbauer daran nichts ändern!&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
Wie man in dem obigen Codelisting auch sehen kann, hat das Verfahren einen kleinen Haken. Variablen die größer sind als 1 Byte, müssen etwas umständlicher&lt;br /&gt;
definiert werden. Benötigt man keine Initialisierung durch das Programm (was der Normalfall sein dürfte), dann kann man das auch so machen:&lt;br /&gt;
&lt;br /&gt;
Möchte man im EEPROM hintereinander beispielsweise Variablen, mit den Namen &#039;&#039;&#039;Wert&#039;&#039;&#039;, &#039;&#039;&#039;Anzahl&#039;&#039;&#039;, &#039;&#039;&#039;Name&#039;&#039;&#039; und &#039;&#039;&#039;Wertigkeit&#039;&#039;&#039; definieren, wobei Wert und Wertigkeit 1 Byte belegen sollen, Anzahl als 1 Wort (also 2 Bytes) und Name mit 10 Bytes reserviert werden soll, so geht auch folgendes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#define EE_DUMMY      0x000&lt;br /&gt;
#define EE_WERT       ( 0x000 + sizeof( uint8_t ) )&lt;br /&gt;
#define EE_ANZAHL     ( EE_WERT + sizeof( uint8_t ) )&lt;br /&gt;
#define EE_NAME       ( EE_ANZAHL + sizeof( uint16_t ) )&lt;br /&gt;
#define EE_WERTIGKEIT ( EE_NAME + 10 * sizeof( uint8_t ) )&lt;br /&gt;
#define EE_LAST       ( EE_WERTIGKEIT + sizeof( uint8_t ) )&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jedes Makro definiert also seine Startadresse durch die Startadresse der unmittelbar vorhergehende &#039;Variablen&#039; plus der Anzahl der Bytes die von der vorhergehenden &#039;Variablen&#039; verbraucht werden. Dadurch ist man zumindest etwas auf der sicheren Seite, dass keine 2 &#039;Variablen&#039; im EEPROM überlappend definiert werden. Möchte man eine weitere &#039;Variable&#039; hinzufügen, so wird deren&lt;br /&gt;
Name, einfach anstelle der EE_LAST eingesetzt und eine neue Zeile für EE_LAST eingefügt, in der dann die Größe der &#039;Variablen&#039; festgelegt wird. Zb.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#define EE_DUMMY      0x000&lt;br /&gt;
#define EE_WERT       ( 0x000 + sizeof( uint8_t ) )&lt;br /&gt;
#define EE_ANZAHL     ( EE_WERT + sizeof( uint8_t ) )&lt;br /&gt;
#define EE_NAME       ( EE_ANZAHL + sizeof( uint16_t ) )&lt;br /&gt;
#define EE_WERTIGKEIT ( EE_NAME + 10 * sizeof( uint8_t ) )&lt;br /&gt;
#define EE_PROZENT    ( EE_WERTIGKEIT + sizeof( uint8_t ) )&lt;br /&gt;
#define EE_LAST       ( EE_WERTIGKEIT + sizeof( double ) )&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
EE_PROZENT legt die Startadresse für eine neue &#039;Variable&#039; des Datentyps double fest.&lt;br /&gt;
&lt;br /&gt;
Der Zugriff auf die EEPROM Werte kann dann z.B.so erfolgen:&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
uint8_t   temp1;&lt;br /&gt;
uint16_t  temp2;&lt;br /&gt;
&lt;br /&gt;
temp1 = eeprom_read_byte(EE_VALUE1);&lt;br /&gt;
temp2 = eeprom_read_word(EE_WORD1L);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ob die in der avr-libc vorhandenen Funktionen dafür verwendet werden können, weiß ich nicht. Aber in einigen Fällen muss man sich sowieso eigene Funktionen&lt;br /&gt;
bauen, welche die spezifischen Anforderungen (Interrupt - Atom Problem, etc.)&lt;br /&gt;
erfüllen.&lt;br /&gt;
&lt;br /&gt;
Die oben beschriebene Möglichkeit ist nur eine Möglichkeit, wie man dies realisieren kann. Sie bietet einem eine relativ einfache Art die EEPROM-Werte&lt;br /&gt;
auf beliebige Adressen zu legen oder Adressen zu ändern. Die Andere Möglichkeit besteht darin, die EEPROM-Werte wie folgt zu belegen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
/////////////////////////////////////////////////&lt;br /&gt;
// Datei &amp;quot;eeprom.c&amp;quot; eines eigenen Projektes&lt;br /&gt;
/////////////////////////////////////////////////&lt;br /&gt;
&lt;br /&gt;
#include &amp;quot;eeprom.h&amp;quot;          // Eigene EEPROM-Headerdatei einbinden&lt;br /&gt;
&lt;br /&gt;
uint8_t ee_mem[EESIZE] EEMEM =&lt;br /&gt;
{&lt;br /&gt;
  0x00,                     //  ee_dummy&lt;br /&gt;
  0x05,                     //  ee_value1&lt;br /&gt;
  0x01,                     //  ee_word1L&lt;br /&gt;
  0x00,                     // (ee_word1H)&lt;br /&gt;
  0xFF                      //  ee_value2&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hierbei kann man Variablen, die größer sind als 1 Byte einfacher definieren und&lt;br /&gt;
man muss nur die Highbyte- oder Lowbyte-Adresse in der &amp;quot;eeprom.h&amp;quot; definieren.&lt;br /&gt;
Allerdings muss man hier höllisch aufpassen, dass man nicht um eine oder mehrere&lt;br /&gt;
Positionen verrutscht!&lt;br /&gt;
&lt;br /&gt;
Welche der beiden Möglichkeiten man einsetzt, hängt vor allem davon ab, wieviele&lt;br /&gt;
Byte, Word und sonstige Variablen man benutzt. Gewöhnen sollte man sich an beide Varianten können ;)&lt;br /&gt;
&lt;br /&gt;
Kleine Schlussbemerkung:&lt;br /&gt;
&lt;br /&gt;
* Der avr-gcc unterstützt die Variante 1 und die Variante 2&lt;br /&gt;
* Der icc-avr Compiler unterstützt nur die Variante 2!&lt;br /&gt;
&lt;br /&gt;
=== Bekannte Probleme bei den EEPROM-Funktionen ===&lt;br /&gt;
&lt;br /&gt;
Vorsicht: Bei alten Versionen der avr-libc wurden nicht alle AVR Controller  untersützt. Z.B. bei der avr-libc Version 1.2.3 insbesondere bei AVRs &amp;quot;der neuen Generation&amp;quot; (ATmega48/88/168/169) funktionieren die Funktionen nicht korrekt (Ursache: unterschiedliche Speicheradressen der EEPROM-Register). In neueren Versionen (z.B. avr-libc 1.4.3 aus WinAVR 20050125) wurde die Zahl der unterstüzten Controller deutlich erweitert und eine Methode zur leichten Anpassung an zukünftige Controller eingeführt.&lt;br /&gt;
&lt;br /&gt;
In jedem Datenblatt zu AVR-Controllern mit EEPROM sind kurze Beispielecodes für den Schreib- und Lesezugriff enthalten. Will oder kann man nicht auf die neue Version aktualisieren, kann der dort gezeigte Code auch mit dem avr-gcc (ohne avr-libc/eeprom.h) genutzt werden (&amp;quot;copy/paste&amp;quot;, gegebenfalls Schutz vor Unterbrechnung/Interrupt ergänzen &#039;&#039;uint8_t sreg; sreg=SREG; cli(); [EEPROM-Code] ; SREG=sreg; return;&#039;&#039;, siehe Abschnitt Interrupts). Im Zweifel hilft ein Blick in den vom Compiler erzeugten Assembler-Code (lst/lss-Dateien).&lt;br /&gt;
&lt;br /&gt;
* siehe auch: [http://www.nongnu.org/avr-libc/user-manual/index.html Dokumentation der avr-libc] Abschnitt Modules/EEPROM handling&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== EEPROM Register ===&lt;br /&gt;
Um das EEPROM anzusteuern sind drei Register von Bedeutung.&amp;lt;BR&amp;gt;&lt;br /&gt;
&amp;lt;LI&amp;gt; EEAR Hier werden die Adressen eingetragen zum Schreiben oder Lesen. Dieses Register unterteilt sich nochmal in EEARH und EEARL da in einem 8 Bit Register keine 512 Adressen adressiert werden können&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
&amp;lt;LI&amp;gt; EEDR Hier werden die Daten eingetragen die geschrieben werden sollen bzw. es enthält die gelesenen Daten&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
&amp;lt;LI&amp;gt; EECR Ist das Kontrollregister für das EEPROM&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das EECR steuert den Zugriff auf das EEPROM und ist wie folgt aufgebaut:&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;TABLE BORDER=1&amp;gt;&lt;br /&gt;
&amp;lt;TR&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;Bit&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;&amp;amp;nbsp;&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;7&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;6&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;5&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;4&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;3&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;2&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;1&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;0&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;/TD&amp;gt;&lt;br /&gt;
&amp;lt;/TR&amp;gt;&lt;br /&gt;
&amp;lt;TR&amp;gt; &lt;br /&gt;
  &amp;lt;TD&amp;gt;Name&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;&amp;amp;nbsp;&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;-&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;-&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;-&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;-&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;EERIE&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;EEMWE&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;EEWE&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;EERE&amp;lt;/TD&amp;gt;&lt;br /&gt;
&amp;lt;/TR&amp;gt;&lt;br /&gt;
&amp;lt;TR&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;Read/Write&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;R&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;R&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;R&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;R&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;R/W&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;R/W&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;R/W&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;R/W&amp;lt;/TD&amp;gt;&lt;br /&gt;
&amp;lt;/TR&amp;gt;&lt;br /&gt;
&amp;lt;TR&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;Init Value&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;0&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;0&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;0&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;0&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;0&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;0&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;0&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;0&amp;lt;/TD&amp;gt;&lt;br /&gt;
&amp;lt;/TR&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/TABLE&amp;gt;&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;U&amp;gt;Bedeutung der Bits:&amp;lt;/U&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
Bit 4-7 nicht belegt.&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;U&amp;gt;Bit 3 (EERIE) - EEPROM Ready Interrupt Enable:&amp;lt;/U&amp;gt; Wenn das Bit gesetzt ist und globale Interrupts erlaubt sind in Register SREG (Bit 7) wird ein Interrupt ausgelöst nach Beendigung des Schreibzyklus (EEPROM Ready Interrupt). Ist einer der beiden Bits 0 wird kein Interrupt ausgelöst.&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;U&amp;gt;Bit 2(EEMWE) - EEPROM Master Write Enable:&amp;lt;/U&amp;gt; Dieses Bit bestimmt, daß wenn EEWE = 1 gesetzt wird (innerhalb von 4 Taktzyklen), das EEPROM beschrieben wird mit den Daten in EEDR bei Adresse EEAR. Wenn EEMWE =0 ist und EEWE = 1 gesetzt wird hat das keine Auswirkungen. Der Schreibvorgang wird dann nicht ausgelöst.&lt;br /&gt;
Nach 4 Taktzyklen wird das Bit EEMWE automatisch wieder auf 0 gesetzt. Dieses Bit löst den Schreibvorgang nicht aus, es dient sozusagen als Sicherungsbit für EEWE.&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;U&amp;gt;Bit 1 (EEWE) - EEPROM Write Enable:&amp;lt;/U&amp;gt; Dieses Bit löst den Schreibvorgang aus wenn es auf 1 gesetzt wird, sofern vorher EEMWE gesetzt wurde und seitdem nicht mehr als 4 Taktzyklen vergangen sind. Wenn der Schreibvorgang abgeschlossen ist wird dieses Bit automatisch wieder auf 0 gesetzt und sofern EERIE gesetzt ist ein Interrupt ausgelöst. &amp;lt;BR&amp;gt;&lt;br /&gt;
Ein Schreibvorgang sieht typischerweise wie folgt aus:&amp;lt;BR&amp;gt;&lt;br /&gt;
1. EEPROM Bereitschaft abwarten (EEWE=0) &lt;br /&gt;
2. Adresse übergeben an EEAR&amp;lt;BR&amp;gt;&lt;br /&gt;
3. Daten übergeben an EEDR&amp;lt;BR&amp;gt;&lt;br /&gt;
4. Schreibvorgang auslösen in EECR mit Bit EEMWE=1 und EEWE=1 &amp;lt;BR&amp;gt;&lt;br /&gt;
5. (Optinal) Warten bis Schreibvorgang abgeschlossen ist.&amp;lt;BR&amp;gt;&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
&amp;lt;U&amp;gt;Bit 0 EERE – EEPROM Read Enable:&amp;lt;/U&amp;gt; Wird dieses Bit auf 1 gesetzt wird das EEPROM an der Adresse in EEAR ausgelesen und die Daten in EEDR gespeichert. Das EEPROM kann nicht ausgelesen werden wenn bereits eine Schreiboperation gestartet wurde. Es ist daher zu empfehlen die Bereitschaft vorher zu prüfen. Das EEPROM ist lesebereit wenn das Bit EEWE=0 ist. ISt der LEsevorgang abgeschlossen wird das Bit wieder auf 0 gesetzt und das EEPROM ist für neue Lese/Schreibbefehle wieder bereit.&amp;lt;BR&amp;gt;&lt;br /&gt;
Ein typischer Lesevorgang kann wie folgt aufgebaut sein:&amp;lt;BR&amp;gt;&lt;br /&gt;
1. Bereitschaft zum lesen prüfen (EEWE=0)&amp;lt;BR&amp;gt;&lt;br /&gt;
2. Adresse übergeben an EEAR&amp;lt;BR&amp;gt;&lt;br /&gt;
3. Lesezyklus auslösen mit EERE = 1&amp;lt;BR&amp;gt;&lt;br /&gt;
4. Warten bis Lesevorgang abgeschlossen EERE = 0&amp;lt;BR&amp;gt;&lt;br /&gt;
5. Daten abholen aus EEDR&amp;lt;BR&amp;gt;&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Die Nutzung von printf =&lt;br /&gt;
&lt;br /&gt;
Um komfortabel Ausgaben auf ein Display oder die serielle Schnittstelle zu tätigen, bietet sich printf/sprintf an. &lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// ...&lt;br /&gt;
// nicht dargestellt: Implementierung von uart_puts (vgl. Abschnitt UART)&lt;br /&gt;
// ...&lt;br /&gt;
&lt;br /&gt;
uint16_t counter;&lt;br /&gt;
&lt;br /&gt;
void uart_puti( uint16_t value )&lt;br /&gt;
{&lt;br /&gt;
    uint8_t s[20];&lt;br /&gt;
&lt;br /&gt;
    sprintf( s, &amp;quot;Zählerstand: %d&amp;quot;, value );&lt;br /&gt;
    uart_puts( s );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int main()&lt;br /&gt;
{&lt;br /&gt;
  counter = 5;&lt;br /&gt;
&lt;br /&gt;
  uart_puti( counter );&lt;br /&gt;
  uart_puti( 42 );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Eine weitere elegante Möglichkeit besteht darin, die Ausgabe stdout auf eigene Ausgabefunktionen umzuleiten. Dazu wird dem Ausgabemechanismus eine neue Ausgabefunktion bekannt gemacht, deren Aufgabe es ist, ein einzelnes Zeichen auszugeben (wie auch immer die Ausgabe stattfindet). Alle anderen, höheren, Funktionen greifen letztendlich auf diese eine Ausgabefunktion zurück, die die Ausgabe eines einzelnen Zeichens vornimmt. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
void uart_init(void);&lt;br /&gt;
int uart_putchar(char c, FILE *stream);&lt;br /&gt;
&lt;br /&gt;
static FILE mystdout = FDEV_SETUP_STREAM( uart_putchar, NULL, _FDEV_SETUP_WRITE );&lt;br /&gt;
&lt;br /&gt;
void uart_init(void)&lt;br /&gt;
{&lt;br /&gt;
    /* hier µC spezifischen Code zur Initialisierung */&lt;br /&gt;
    /* des UART einfügen... s.o. im AVR-GCC-Tutorial */&lt;br /&gt;
&lt;br /&gt;
    // Beispiel: &lt;br /&gt;
    //&lt;br /&gt;
    // myAVR Board 1.5 mit externem Quarz Q1 3,6864 MHz&lt;br /&gt;
    // 9600 Baud 8N1&lt;br /&gt;
&lt;br /&gt;
#ifndef F_CPU&lt;br /&gt;
#define F_CPU 3686400&lt;br /&gt;
#endif&lt;br /&gt;
#define UART_BAUD_RATE 9600&lt;br /&gt;
&lt;br /&gt;
// Hilfsmakro zur UBRR-Berechnung (&amp;quot;Formel&amp;quot; laut Datenblatt)&lt;br /&gt;
#define UART_UBRR_CALC(BAUD_,FREQ_) ((FREQ_)/((BAUD_)*16L)-1)&lt;br /&gt;
&lt;br /&gt;
    UCSRB |= (1&amp;lt;&amp;lt;TXEN) | (1&amp;lt;&amp;lt;RXEN);    // UART TX und RX einschalten&lt;br /&gt;
    UCSRC |= (1&amp;lt;&amp;lt;URSEL)|(3&amp;lt;&amp;lt;UCSZ0);    // Asynchron 8N1 &lt;br /&gt;
 &lt;br /&gt;
    UBRRH = (uint8_t)( UART_UBRR_CALC( UART_BAUD_RATE, F_CPU ) &amp;gt;&amp;gt; 8 );&lt;br /&gt;
    UBRRL = (uint8_t)UART_UBRR_CALC( UART_BAUD_RATE, F_CPU );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int uart_putchar( char c, FILE *stream )&lt;br /&gt;
{&lt;br /&gt;
    if( c == &#039;\n&#039; )&lt;br /&gt;
        uart_putchar( &#039;\r&#039;, stream );&lt;br /&gt;
&lt;br /&gt;
    loop_until_bit_is_set( UCSRA, UDRE );&lt;br /&gt;
    UDR = c;&lt;br /&gt;
    return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int main(void)&lt;br /&gt;
{&lt;br /&gt;
    uart_init();&lt;br /&gt;
    stdout = &amp;amp;mystdout;&lt;br /&gt;
    printf( &amp;quot;Hello, world!\n&amp;quot; );&lt;br /&gt;
    return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Quelle: avr-libc-user-manual-1.4.3.pdf, S.74&lt;br /&gt;
//         + Ergänzungen&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Sollen Fließkommazahlen ausgegeben werden, muss im Makefile eine andere (größere) Version der [[FAQ#Aktivieren_der_Floating_Point_Version_von_sprintf_beim_WinAVR_mit_AVR-Studio|printflib]] eingebunden werden.&lt;br /&gt;
&lt;br /&gt;
Der Nachteil aller printf-Varianten: Sie sind recht speicherintensiv.&lt;br /&gt;
&lt;br /&gt;
= Assembler und Inline-Assembler =&lt;br /&gt;
&lt;br /&gt;
Gelegentlich erweist es sich als nützlich, C- und Assembler-Code in einer Anwendung zu nutzen. Typischerweise wird das Hauptprogramm in C verfasst und wenige, extrem zeitkritische oder hardwarenahe Operationen in Assembler.&lt;br /&gt;
&lt;br /&gt;
Die &amp;quot;gnu-Toolchain&amp;quot; bietet dazu zwei Möglichkeiten:&lt;br /&gt;
&lt;br /&gt;
* Inline-Assembler: Die Assembleranweisungen werden direkt in den C-Code integriert. Eine Quellcode-Datei enthält somit C- und Assembleranweisungen&lt;br /&gt;
* Assembler-Dateien: Der Assemblercode befindet sich in eigenen Quellcodedateien. Diese werden vom gnu-Assembler (avr-as) zu Object-Dateien assembliert (&amp;quot;compiliert&amp;quot;) und mit den aus dem C-Code erstellten Object-Dateien zusammengebunden (gelinkt).&lt;br /&gt;
&lt;br /&gt;
== Inline-Assembler ==&lt;br /&gt;
&lt;br /&gt;
Inline-Assembler bietet sich an, wenn nur wenig Assembleranweisungen benötigt werden. Typische Anwendung sind kurze Codesequenzen für zeitkritische Operationen in Interrupt-Routinen oder sehr präzise Warteschleifen (z.B. 1-Wire). Inline-Assembler wird mit &#039;&#039;&#039;asm volatile&#039;&#039;&#039; eingeleitet, die Assembler-Anweisungen werden in einer Zeichenkette zusammengefasst, die als &amp;quot;Parameter&amp;quot; übergeben wird. Durch Doppelpunkte getrennt werden die Ein- und Ausgaben sowie die &amp;quot;Clobber-Liste&amp;quot; angegeben.&lt;br /&gt;
&lt;br /&gt;
Ein einfaches Beispiel für Inline-Assembler ist das Einfügen einer NOP-Anweisung (NOP steht für No Operation). Dieser Assembler-Befehl benötigt genau einen Taktzyklus, ansonsten &amp;quot;tut sich nichts&amp;quot;. Sinnvolle Anwendungen für NOP sind genaue Delay(=Warte)-Funktionen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
    ...&lt;br /&gt;
   /* Verzögern der weiteren Programmausführung um&lt;br /&gt;
      genau 3 Taktzyklen */&lt;br /&gt;
    asm volatile (&amp;quot;nop&amp;quot;);&lt;br /&gt;
    asm volatile (&amp;quot;nop&amp;quot;);&lt;br /&gt;
    asm volatile (&amp;quot;nop&amp;quot;);&lt;br /&gt;
    ...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Weiterhin kann mit einem NOP verhindert werden, dass leere Schleifen, die als Warteschleifen gedacht sind, wegoptimiert werden. Der Compiler erkennt ansonsten die vermeintlich nutzlose Schleife und erzeugt dafür keinen Code im ausführbaren Programm.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
    ...&lt;br /&gt;
    uint16_t i;&lt;br /&gt;
&lt;br /&gt;
    /* leere Schleife - wird bei eingeschalteter Compiler-Optimierung   wegoptimiert */&lt;br /&gt;
    for (i = 0; i &amp;lt; 1000; i++)&lt;br /&gt;
      ;&lt;br /&gt;
&lt;br /&gt;
    ...&lt;br /&gt;
&lt;br /&gt;
    /* Schleife erzwingen (keine Optimierung): &amp;quot;NOP-Methode&amp;quot; */&lt;br /&gt;
    for (i = 0; i &amp;lt; 1000; i++)&lt;br /&gt;
      asm volatile(&amp;quot;NOP&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    ...&lt;br /&gt;
&lt;br /&gt;
    /* alternative Methode (keine Optimierung): */&lt;br /&gt;
    volatile uint16_t j;&lt;br /&gt;
    for (j = 0; j &amp;lt; 1000; j++)&lt;br /&gt;
      ;&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein weiterer nützlicher &amp;quot;Assembler-Einzeiler&amp;quot; ist der Aufruf von sleep (&#039;&#039;asm volatile (&amp;quot;sleep&amp;quot;);&#039;&#039;), da hierzu in älteren Versionen der avr-libc keine eigene Funktion existiert (in neueren Versionen &#039;&#039;sleep_cpu()&#039;&#039; aus sleep.h).&lt;br /&gt;
&lt;br /&gt;
Als Beispiel für mehrzeiligen Inline-Assembler eine präzise Delay-Funktion. Die Funktion erhält ein 16-bit Wort als Parameter, prüft den Parameter auf 0 und beendet die Funktion in diesem Fall oder durchläuft die folgende Schleife sooft wie im Wert des Parameters angegeben. Inline-Assembler hat hier den Vorteil, dass die Laufzeit unabhängig von der Optimierungsstufe (Parameter -O, vgl. makefile) und der Compiler-Version ist.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
static inline void delayloop16 (uint16_t count)&lt;br /&gt;
{&lt;br /&gt;
    asm volatile (&amp;quot;cp  %A0, __zero_reg__ \n\t&amp;quot;&lt;br /&gt;
                  &amp;quot;cpc %B0, __zero_reg__ \n\t&amp;quot;&lt;br /&gt;
                  &amp;quot;breq 2f               \n\t&amp;quot;&lt;br /&gt;
                  &amp;quot;1:                    \n\t&amp;quot;&lt;br /&gt;
                  &amp;quot;sbiw %0,1             \n\t&amp;quot;&lt;br /&gt;
                  &amp;quot;brne 1b               \n\t&amp;quot;&lt;br /&gt;
                  &amp;quot;2:                    &amp;quot;  &lt;br /&gt;
                  : &amp;quot;=w&amp;quot; (count)&lt;br /&gt;
	          : &amp;quot;0&amp;quot;  (count)&lt;br /&gt;
    );                            &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Jede Anweisung wird mit &#039;&#039;&#039;\n\t&#039;&#039;&#039; abgeschlossen. Der Zeilenumbruch teilt dem Assembler mit, dass ein neuer Befehl beginnt.&lt;br /&gt;
* Als Sprung-Marken (Labels) werden Ziffern verwendet. Diese speziellen Labels sind mehrfach im Code verwendbar. Gesprungen wird jeweils zurück (b) oder vorwärts (f) zum nächsten ausffindbaren Label.&lt;br /&gt;
&lt;br /&gt;
Das Resultat zeigt ein Blick in die Assembler-Datei, die der Compiler mit der option &amp;lt;tt&amp;gt;-save-temps&amp;lt;/tt&amp;gt; nicht löscht:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;avrasm&amp;gt;&lt;br /&gt;
	cp  r24, __zero_reg__ 	 ;  count&lt;br /&gt;
	cpc r25, __zero_reg__ 	 ;  count&lt;br /&gt;
	breq 2f               &lt;br /&gt;
	1:                    &lt;br /&gt;
	sbiw r24,1             	 ;  count&lt;br /&gt;
	brne 1b               &lt;br /&gt;
	2:&lt;br /&gt;
&amp;lt;/avrasm&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Detaillierte Ausführungen zum Thema Inline-Assembler finden sich in der Dokumentation der avr-libc im Abschnitt [http://www.nongnu.org/avr-libc/user-manual/inline_asm.html Related Pages/Inline Asm]. &lt;br /&gt;
&lt;br /&gt;
Siehe auch: &lt;br /&gt;
* [http://www.atmel.com/dyn/resources/prod_documents/doc0856.pdf AVR Assembler-Anweisungsliste]&lt;br /&gt;
* [http://www.roboternetz.de/wissen/index.php/Inline-Assembler_in_avr-gcc Deutsche Einführung in Inline-Assembler]&lt;br /&gt;
&lt;br /&gt;
== Assembler-Dateien ==&lt;br /&gt;
&lt;br /&gt;
Assembler-Dateien erhalten die Endung .S (&#039;&#039;grosses&#039;&#039; S) und werden im makefile nach WinAVR/mfile-Vorlage hinter &#039;&#039;ASRC=&#039;&#039; durch Leerzeichen getrennt aufgelistet.&lt;br /&gt;
&lt;br /&gt;
Wenn man mit dem AVR Studio arbeitet, kann alternativ auch das standardmäßig erstellte Makefile bearbeitet und folgende Zeilen eingefügt werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;code&amp;quot;&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
## Objects that must be built in order to link&lt;br /&gt;
OBJECTS = (alte Dateien...) useful.o&lt;br /&gt;
&lt;br /&gt;
## Compile&lt;br /&gt;
## Hier folgt eine Liste der gelinkten Dateien, darunter einfügen:&lt;br /&gt;
useful.o: ../useful.S&lt;br /&gt;
	$(CC) $(INCLUDES) $(ASMFLAGS) -c  $&amp;lt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
Das war es schon. Allerdings gilt es zu beachten, dass das makefile über &amp;quot;Project -&amp;gt; Configuration options&amp;quot; selbst einzubinden ist, sonst wird es natürlich wieder überschrieben.&lt;br /&gt;
&lt;br /&gt;
Im Beispiel eine Funktion &#039;&#039;superFunc&#039;&#039;, die alle Pins des Ports D auf &amp;quot;Ausgang&amp;quot; schaltet, eine Funktion &#039;&#039;ultraFunc&#039;&#039;, die die Ausgänge entsprechend des übergebenen Parameters schaltet, eine Funktion &#039;&#039;gigaFunc&#039;&#039;, die den Status von Port A zurückgibt und eine Funktion &#039;&#039;addFunc&#039;&#039;, die zwei Bytes zu einem 16-bit-Wort addiert. Die Zuweisungen im C-Code (PORTx = ...) verhindern, dass der Compiler die Aufrufe wegoptimiert und dienen nur zur Veranschaulichung der Parameterübergaben.&lt;br /&gt;
&lt;br /&gt;
Zuerst der Assembler-Code. Der Dateiname sei useful.S:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;avrasm&amp;gt;&lt;br /&gt;
#include &amp;quot;avr/io.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
//; Arbeitsregister (ohne &amp;quot;r&amp;quot;) &lt;br /&gt;
workreg  = 16&lt;br /&gt;
workreg2 = 17&lt;br /&gt;
&lt;br /&gt;
//; Konstante:&lt;br /&gt;
ALLOUT = 0xff&lt;br /&gt;
&lt;br /&gt;
//; ** Setze alle Pins von PortD auf Ausgang **&lt;br /&gt;
//; keine Parameter, keine Rückgabe&lt;br /&gt;
.global superFunc&lt;br /&gt;
.func superFunc&lt;br /&gt;
superFunc:&lt;br /&gt;
   push workreg&lt;br /&gt;
   ldi workreg, ALLOUT&lt;br /&gt;
   out  _SFR_IO_ADDR(DDRD), workreg  // beachte: _SFR_IO_ADDR()&lt;br /&gt;
   pop workreg&lt;br /&gt;
   ret&lt;br /&gt;
.endfunc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
//; ** Setze PORTD auf übergebenen Wert **&lt;br /&gt;
//; Parameter in r24 (LSB immer bei &amp;quot;graden&amp;quot; Nummern)&lt;br /&gt;
.global ultraFunc&lt;br /&gt;
.func ultraFunc&lt;br /&gt;
ultraFunc:&lt;br /&gt;
   out  _SFR_IO_ADDR(PORTD), 24&lt;br /&gt;
   ret&lt;br /&gt;
.endfunc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
//; ** Zustand von PINA zurückgeben **&lt;br /&gt;
//; Rückgabewerte in r24:r25 (LSB:MSB), hier nur LSB genutzt&lt;br /&gt;
.global gigaFunc&lt;br /&gt;
.func gigaFunc&lt;br /&gt;
gigaFunc:&lt;br /&gt;
   in 24, _SFR_IO_ADDR(PINA)&lt;br /&gt;
   ret&lt;br /&gt;
.endfunc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
//; ** Zwei Bytes addieren und 16-bit-Wort zurückgeben **&lt;br /&gt;
//; Parameter in r24 (Summand1) und r22 (Summand2) -&lt;br /&gt;
//;  Parameter sind Word-&amp;quot;aligned&amp;quot; d.h. LSB immer auf &amp;quot;graden&amp;quot;&lt;br /&gt;
//;  Registernummern. Bei 8-Bit und 16-Bit Paramtern somit &lt;br /&gt;
//;  beginnend bei r24 dann r22 dann r20 etc.&lt;br /&gt;
//; Rückgabewert in r24:r25&lt;br /&gt;
.global addFunc&lt;br /&gt;
.func addFunc&lt;br /&gt;
addFunc:&lt;br /&gt;
   push workreg&lt;br /&gt;
   push workreg2&lt;br /&gt;
   clr workreg2&lt;br /&gt;
   mov workreg, 22&lt;br /&gt;
   add workreg, 24&lt;br /&gt;
   adc workreg2, 1    // r1 - assumed to be always zero ...&lt;br /&gt;
   movw r24, workreg&lt;br /&gt;
   pop workreg2&lt;br /&gt;
   pop workreg&lt;br /&gt;
   ret&lt;br /&gt;
.endfunc&lt;br /&gt;
&lt;br /&gt;
//; oh je - sorry - Mein AVR-Assembler ist eingerostet, hoffe das stimmt so...&lt;br /&gt;
&lt;br /&gt;
.end&lt;br /&gt;
&amp;lt;/avrasm&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im Makefile ist der Name der Assembler-Quellcodedatei einzutragen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;code&amp;quot;&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
ASRC = useful.S&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Aufruf erfolgt dann im C-Code so:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
extern void superFunc(void);&lt;br /&gt;
extern void ultraFunc(uint8_t setVal);&lt;br /&gt;
extern uint8_t gigaFunc(void);&lt;br /&gt;
extern uint16_t addFunc(uint8_t w1, uint8_t w2);&lt;br /&gt;
&lt;br /&gt;
int main(void)&lt;br /&gt;
{&lt;br /&gt;
[...]&lt;br /&gt;
  superFunc();&lt;br /&gt;
  &lt;br /&gt;
  ultraFunc(0x55);&lt;br /&gt;
  &lt;br /&gt;
  PORTD = gigaFunc();&lt;br /&gt;
&lt;br /&gt;
  PORTA = (addFunc(0xF0, 0x11) &amp;amp; 0xff);&lt;br /&gt;
  PORTB = (addFunc(0xF0, 0x11) &amp;gt;&amp;gt; 8);&lt;br /&gt;
[...]&lt;br /&gt;
} &lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Ergebnis wird wieder in der lss-Datei ersichtlich:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;code&amp;quot;&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
[...]&lt;br /&gt;
   superFunc();&lt;br /&gt;
 148:	0e 94 f6 00 	call	0x1ec&lt;br /&gt;
  &lt;br /&gt;
  ultraFunc(0x55);&lt;br /&gt;
 14c:	85 e5       	ldi	r24, 0x55	; 85&lt;br /&gt;
 14e:	0e 94 fb 00 	call	0x1f6&lt;br /&gt;
  &lt;br /&gt;
  PORTD = gigaFunc();&lt;br /&gt;
 152:	0e 94 fd 00 	call	0x1fa&lt;br /&gt;
 156:	82 bb       	out	0x12, r24	; 18&lt;br /&gt;
  &lt;br /&gt;
  PORTA = (addFunc(0xF0, 0x11) &amp;amp; 0xff);&lt;br /&gt;
 158:	61 e1       	ldi	r22, 0x11	; 17&lt;br /&gt;
 15a:	80 ef       	ldi	r24, 0xF0	; 240&lt;br /&gt;
 15c:	0e 94 ff 00 	call	0x1fe&lt;br /&gt;
 160:	8b bb       	out	0x1b, r24	; 27&lt;br /&gt;
  PORTB = (addFunc(0xF0, 0x11) &amp;gt;&amp;gt; 8);&lt;br /&gt;
 162:	61 e1       	ldi	r22, 0x11	; 17&lt;br /&gt;
 164:	80 ef       	ldi	r24, 0xF0	; 240&lt;br /&gt;
 166:	0e 94 fc 00 	call	0x1f8&lt;br /&gt;
 16a:	89 2f       	mov	r24, r25&lt;br /&gt;
 16c:	99 27       	eor	r25, r25&lt;br /&gt;
 16e:	88 bb       	out	0x18, r24	; 24&lt;br /&gt;
&lt;br /&gt;
[...]&lt;br /&gt;
000001ec &amp;lt;superFunc&amp;gt;:&lt;br /&gt;
// setze alle Pins von PortD auf Ausgang&lt;br /&gt;
.global superFunc&lt;br /&gt;
.func superFunc&lt;br /&gt;
superFunc:&lt;br /&gt;
   push workreg&lt;br /&gt;
 1ec:	0f 93       	push	r16&lt;br /&gt;
   ldi workreg, ALLOUT&lt;br /&gt;
 1ee:	0f ef       	ldi	r16, 0xFF	; 255&lt;br /&gt;
   out  _SFR_IO_ADDR(DDRD), workreg&lt;br /&gt;
 1f0:	01 bb       	out	0x11, r16	; 17&lt;br /&gt;
   pop workreg&lt;br /&gt;
 1f2:	0f 91       	pop	r16&lt;br /&gt;
   ret&lt;br /&gt;
 1f4:	08 95       	ret&lt;br /&gt;
&lt;br /&gt;
000001f6 &amp;lt;ultraFunc&amp;gt;:&lt;br /&gt;
.endfunc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// setze PORTD auf übergebenen Wert&lt;br /&gt;
.global ultraFunc&lt;br /&gt;
.func ultraFunc&lt;br /&gt;
ultraFunc:&lt;br /&gt;
   out  _SFR_IO_ADDR(PORTD), 24&lt;br /&gt;
 1f6:	82 bb       	out	0x12, r24	; 18&lt;br /&gt;
   ret&lt;br /&gt;
 1f8:	08 95       	ret&lt;br /&gt;
&lt;br /&gt;
000001fa &amp;lt;gigaFunc&amp;gt;:&lt;br /&gt;
.endfunc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// Zustand von PINA zurückgeben&lt;br /&gt;
.global gigaFunc&lt;br /&gt;
.func gigaFunc&lt;br /&gt;
gigaFunc:&lt;br /&gt;
   in 24, _SFR_IO_ADDR(PINA)&lt;br /&gt;
 1fa:	89 b3       	in	r24, 0x19	; 25&lt;br /&gt;
   ret&lt;br /&gt;
 1fc:	08 95       	ret&lt;br /&gt;
&lt;br /&gt;
000001fe &amp;lt;addFunc&amp;gt;:&lt;br /&gt;
.endfunc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// zwei Bytes addieren und 16-bit-Wort zurückgeben&lt;br /&gt;
.global addFunc&lt;br /&gt;
.func addFunc&lt;br /&gt;
addFunc:&lt;br /&gt;
   push workreg&lt;br /&gt;
 1fe:	0f 93       	push	r16&lt;br /&gt;
   push workreg2&lt;br /&gt;
 200:	1f 93       	push	r17&lt;br /&gt;
   clr workreg2&lt;br /&gt;
 202:	11 27       	eor	r17, r17&lt;br /&gt;
   mov workreg, 22&lt;br /&gt;
 204:	06 2f       	mov	r16, r22&lt;br /&gt;
   add workreg, 24&lt;br /&gt;
 206:	08 0f       	add	r16, r24&lt;br /&gt;
   adc workreg2, 1    // r1 - assumed to be always zero ...&lt;br /&gt;
 208:	11 1d       	adc	r17, r1&lt;br /&gt;
   movw r24, workreg&lt;br /&gt;
 20a:	c8 01       	movw	r24, r16&lt;br /&gt;
   pop workreg2&lt;br /&gt;
 20c:	1f 91       	pop	r17&lt;br /&gt;
   pop workreg&lt;br /&gt;
 20e:	0f 91       	pop	r16&lt;br /&gt;
   ret&lt;br /&gt;
 210:	08 95       	ret&lt;br /&gt;
&lt;br /&gt;
[...]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Zuweisung von Registern zu Parameternummer und die Register für die Rückgabewerte sind in den &amp;quot;Register Usage Guidelines&amp;quot; der avr-libc-Dokumentation erläutert.&lt;br /&gt;
&lt;br /&gt;
Siehe auch:&lt;br /&gt;
* [http://www.nongnu.org/avr-libc/user-manual/assembler.html avr-libc-Dokumentation: Related Pages/avr-libc and assembler programs]&lt;br /&gt;
* [http://www.nongnu.org/avr-libc/user-manual/FAQ.html#faq_reg_usage avr-libc-Dokumentation: Related Pages/FAQ/&amp;quot;What registers are used by the C compiler?&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
== Globale Variablen für Datenaustausch ==&lt;br /&gt;
&lt;br /&gt;
Oftmals kommt man um globale Variablen nicht herum, z.B. um den Datenaustausch zwischen Hauptprogramm und Interrupt-Routinen zu realisieren. &lt;br /&gt;
Hierzu muss man im Assembler wissen, wo genau die Variable vom C-Compiler abgespeichert wird.&lt;br /&gt;
&lt;br /&gt;
Hierzu muss die Variable, hier &amp;quot;zaehler&amp;quot; genannt, zuerst im C-Code als Global definiert werden, z.B. so:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
volatile uint8_t zaehler;&lt;br /&gt;
&lt;br /&gt;
int16_t main (void)&lt;br /&gt;
{&lt;br /&gt;
    // irgendein Code, in dem zaehler benutzt werden kann&lt;br /&gt;
    &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im foldenden Assembler-Beispiel wird der Externe Interrupt0  verwendet, um den Zähler hochzuzählen. Es fehlen die Initialisierungen des Interrupts und die Interrupt-Freigabe, so richtig sinnvoll ist der Code auch nicht, aber er zeigt (hoffentlich) wie es geht.&lt;br /&gt;
&lt;br /&gt;
Im Umgang mit Interrupt-Vektoren gilt beim GCC-Assembler das Gleiche, wie bei C: Man muss die exakte Schreibweise beachten, ansonsten wird nicht der Interrupt-Vektor angelegt, sondern eine neue Funktion - und man wundert sich, dass nichts funktionert (vgl. das AVR-GCC-Handbuch).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;avrasm&amp;gt;&lt;br /&gt;
#include &amp;quot;avr/io.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
temp = 16&lt;br /&gt;
&lt;br /&gt;
.extern zaehler&lt;br /&gt;
&lt;br /&gt;
.global INT0_vect&lt;br /&gt;
INT0_vect:&lt;br /&gt;
&lt;br /&gt;
     push temp                      //; wichtig: Benutzte Register und das&lt;br /&gt;
     in temp,_SFR_IO_ADDR(SREG)     //; Status-Register (SREG) sichern!&lt;br /&gt;
     push temp&lt;br /&gt;
&lt;br /&gt;
     lds temp,zaehler               //; Wert aus dem Speicher lesen&lt;br /&gt;
     inc temp                       //; bearbeiten&lt;br /&gt;
     sts zaehler,temp               //; und wieder zurückschreiben&lt;br /&gt;
&lt;br /&gt;
     pop temp                       //; die benutzten Register wiederherstellen&lt;br /&gt;
     out _SFR_IO_ADDR(SREG),temp&lt;br /&gt;
     pop temp&lt;br /&gt;
     reti&lt;br /&gt;
&lt;br /&gt;
.end&lt;br /&gt;
&amp;lt;/avrasm&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Globale Variablen im Assemblerfile anlegen ===&lt;br /&gt;
&lt;br /&gt;
Alternativ können Variablen aber auch im Assemblerfile angelegt werden. Dadurch kann auf eine .c-Datei verzichtet werden. Für das obige Beispiel könnte der Quelltext dann die Dateien zaehl_asm.S und zaehl_asm.h abgelegt werden, so dass nur noch zaehl_asm.S mit kompiliert werden müsste.&lt;br /&gt;
&lt;br /&gt;
Anstatt im Assemblerfile über das Schlüsselwort &#039;&#039;.extern &#039;&#039; auf eine vorhandene Variable zu verweisen, wird dazu mit dem Schlüsselwort &#039;&#039;.comm&#039;&#039; die benötigte Anzahl von Bytes für eine Variable reserviert.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;zaehl_asm.S&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;avrasm&amp;gt;&lt;br /&gt;
#include &amp;quot;avr/io.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
temp = 16&lt;br /&gt;
&lt;br /&gt;
//; 1 Byte im RAM für den Zähler reservieren&lt;br /&gt;
.comm zaehler, 1&lt;br /&gt;
&lt;br /&gt;
.global INT0_vect&lt;br /&gt;
INT0_vect:&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/avrasm&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In der Headerdatei wird dann auf die Variable nur noch verwiesen (Schlüsselwort &#039;&#039;extern&#039;&#039;):&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;zaehl_asm.h&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#ifndef ZAEHL_ASM_H&lt;br /&gt;
#define ZAEHL_ASM_H&lt;br /&gt;
&lt;br /&gt;
extern volatile uint8_t zaehler;&lt;br /&gt;
&lt;br /&gt;
#endif&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im Gegensatz zu globalen Variablen in C werden so angelegte Variablen nicht automatisch mit dem Wert 0 initialisiert. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Variablen größer als 1 Byte ===&lt;br /&gt;
&lt;br /&gt;
Variablen, die größer als &#039;&#039;&#039;ein&#039;&#039;&#039; Byte sind, können in Assembler auf ähnliche Art angesprochen werden. Hierzu müssen nur genug Bytes angefordert werden, um die Variable aufzunehmen. Soll z.B. für den Zähler eine Variable vom Typ &#039;&#039;unsigned long&#039;&#039;, also &#039;&#039;uint32_t&#039;&#039; verwendet werden, so müssen 4 Bytes reserviert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;avrasm&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
// 4 Byte im RAM für den Zähler reservieren&lt;br /&gt;
.comm zaehler, 4&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/avrasm&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die dazugehörige Deklaration im Headerfile wäre dann:&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
extern volatile uint32_t zaehler;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bei Variablen, die größer als ein Byte sind, werden die Werte beginnend mit dem niederwertigsten Byte im RAM abgelegt. Das folgende Codeschnippsel zeigt, wie unter Assembler auf die einzelnen Bytes zugegriffen werden kann. Dazu wird im Interrupt nun ein 32-Bit Zähler erhöht:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;avrasm&amp;gt;&lt;br /&gt;
#include &amp;quot;avr/io.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
temp = 16&lt;br /&gt;
&lt;br /&gt;
// 4 Byte im RAM für den Zähler reservieren&lt;br /&gt;
.comm zaehler, 4&lt;br /&gt;
&lt;br /&gt;
.global INT0_vect&lt;br /&gt;
INT0_vect:&lt;br /&gt;
&lt;br /&gt;
     push temp                      // wichtig: Benutzte Register und das&lt;br /&gt;
     in temp,_SFR_IO_ADDR(SREG)     // Status-Register (SREG) sichern !&lt;br /&gt;
     push temp&lt;br /&gt;
&lt;br /&gt;
     // 32-Bit-Zähler incrementieren&lt;br /&gt;
     lds temp, (zaehler + 0)        // 0. Byte (niederwertigstes Byte)&lt;br /&gt;
     inc temp&lt;br /&gt;
     sts (zaehler + 0), temp&lt;br /&gt;
     brne RAUS&lt;br /&gt;
	&lt;br /&gt;
     lds temp, (zaehler + 1)        // 1. Byte&lt;br /&gt;
     inc temp&lt;br /&gt;
     sts (zaehler + 1), temp&lt;br /&gt;
     brne RAUS&lt;br /&gt;
&lt;br /&gt;
     lds temp, (zaehler + 2)        // 2. Byte&lt;br /&gt;
     inc temp&lt;br /&gt;
     sts (zaehler + 2), temp&lt;br /&gt;
     brne RAUS&lt;br /&gt;
&lt;br /&gt;
     lds temp, (zaehler + 3)        // 3. Byte (höchstwertigstes Byte)&lt;br /&gt;
     inc temp&lt;br /&gt;
     sts (zaehler + 3), temp&lt;br /&gt;
     brne RAUS&lt;br /&gt;
	&lt;br /&gt;
RAUS:&lt;br /&gt;
     pop temp                       // die benutzten Register wiederherstellen&lt;br /&gt;
     out _SFR_IO_ADDR(SREG),temp&lt;br /&gt;
     pop temp&lt;br /&gt;
     reti&lt;br /&gt;
&lt;br /&gt;
.end&lt;br /&gt;
&amp;lt;/avrasm&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;TODO:&#039;&#039;&#039; 16-Bit / 32-Bit Variablen, Zugriff auf Arrays (Strings)&lt;br /&gt;
&lt;br /&gt;
= Anhang =&lt;br /&gt;
&lt;br /&gt;
== Besonderheiten bei der Anpassung bestehenden Quellcodes ==&lt;br /&gt;
&lt;br /&gt;
Einige Funktionen, die in frühren Versionen der avr-libc vorhanden waren, werden inzwischen als veraltet angesehen. Sie sind nicht mehr vorhanden oder als &#039;&#039;deprecated&#039;&#039; (missbilligt) ausgewiesen und Definitionen in &amp;lt;compat/deprecated.h&amp;gt; verschoben. Es empfiehlt sich, vorhandenen Code zu portieren und die alten Funktionen nicht mehr zu nutzen, auch wenn diese noch zur Verfügung stehen.&lt;br /&gt;
&lt;br /&gt;
=== Veraltete Funktionen zur Deklaration von Interrupt-Routinen ===&lt;br /&gt;
&lt;br /&gt;
Die Funktionen (eigentlich Makros) &#039;&#039;SIGNAL&#039;&#039; und &#039;&#039;INTERRUPT&#039;&#039; zur Deklaration von Interruptroutinen sollten nicht mehr genutzt werden. &lt;br /&gt;
&lt;br /&gt;
In aktuellen Versionen der avr-libc (z.B. avr-libc 1.4.3 aus WinAVR 20060125) werden Interruptroutinen, die &#039;&#039;&#039;nicht&#039;&#039;&#039; durch andere Interrupts &#039;&#039;&#039;unterbrechbar&#039;&#039;&#039; sind, mit ISR deklariert (siehe Abschnitt im Hauptteil). Auch die Benennung wurden vereinheitlicht und an die üblichen Bezeichnungen in den AVR Datenblättern angepasst. In der Dokumentation der avr-libc sind alte und neue Bezeichnungen in der Tabelle gegenübergestellt. Die erforderlichen Schritte zur Portierung:&lt;br /&gt;
&lt;br /&gt;
* #include von avr/signal.h entfernen&lt;br /&gt;
* SIGNAL duch ISR ersetzen&lt;br /&gt;
* Name des Interrupt-Vektors anpassen (SIG_* durch entsprechendes *_vect)&lt;br /&gt;
&lt;br /&gt;
Als Beispiel für die Anpassung zuerst ein &amp;quot;alter&amp;quot; Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/interrupt.h&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/signal.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
/* Timer2 Output Compare bei einem ATmega8 */&lt;br /&gt;
SIGNAL(SIG_OUTPUT_COMPARE2)&lt;br /&gt;
{&lt;br /&gt;
   ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im Datenblatt wird der Vektor mit TIMER2 COMP bezeichnet. Die Bezeichnung in der avr-libc entspricht dem Namen im Datenblatt, Leerzeichen werden durch Unterstriche (_) ersetzt und ein _vect angehängt. &lt;br /&gt;
&lt;br /&gt;
Der neue Code sieht dann so aus:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/interrupt.h&amp;gt; &lt;br /&gt;
/* signal.h entfällt */&lt;br /&gt;
&lt;br /&gt;
ISR(TIMER2_COMP_vect)&lt;br /&gt;
{&lt;br /&gt;
   ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bei Unklarheiten bezüglich der neuen Vektorlabels hilft (noch) ein Blick in die Headerdatei des entsprechenden Controllers. Für das vorherige Beispiel also der Blick in die Datei iom8.h für den ATmega8, dort findet man die veraltete Bezeichnung unterhalb der aktuellen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
/* $Id: iom8.h,v 1.13 2005/10/30 22:11:23 joerg_wunsch Exp $ */&lt;br /&gt;
/* avr/iom8.h - definitions for ATmega8 */&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
/* Timer/Counter2 Compare Match */&lt;br /&gt;
#define TIMER2_COMP_vect		_VECTOR(3)&lt;br /&gt;
#define SIG_OUTPUT_COMPARE2		_VECTOR(3)&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- Nachfolgendes mit avr-libc 1.4.5 (in WinAVR 1/2007 behoben - noch eine Weile auskommentiert lassen und dann löschen.&lt;br /&gt;
Konnte in alten Versionen signal.h ohne interrupt.h eingebunden werden, erhält man bei Verwendung der avr-libc Version 1.4.3 (WinAVR 2/2005) beim Compilieren eine Fehlermeldung, da mit signal.h nicht die erforderlichen Definitionen eingebunden werden. Der Lösungsvorschlag in signal.h auch interrupt.h einzubinden, wurde von den avr-libc-Enwicklern akzeptiert und das Problem ist  im Quellcode (CVS) bereits behoben. Es ist aber noch keine avr-libc-&amp;quot;Release&amp;quot; bzw. noch kein WinAVR mit dieser avr-libc-Korrektur verfügbar (Stand 5.2.2006). Will oder kann man den Quellcode nicht aktualisieren, gibt es folgende Alternativen:&lt;br /&gt;
* in Quellcodedateien, in denen nur avr/signal.h eingebunden wird, interrupt.h einbinden (&#039;&#039;#include &amp;amp;lt;avr/interrupt.h&amp;amp;gt;&#039;&#039;). signal.h weiterhin einbinden, falls Kompatibiltät mit alten Versionen gewünscht ist.&lt;br /&gt;
* in der Datei signal.h (bein WinAVR in c:/WinAVR/avr/include/avr/signal.h) ein (&#039;&#039;#include &amp;amp;lt;avr/interrupt.h&amp;amp;gt;&#039;&#039;) ergänzen --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für &#039;&#039;&#039;unterbrechbare&#039;&#039;&#039; Interruptroutinen, die mittels &#039;&#039;INTERRUPT&#039;&#039; deklariert sind, gibt es keinen direkten Ersatz in Form eines Makros. Solche Routinen sind laut Dokumentation der avr-libc in folgender Form zu deklarieren:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
void XXX_vect(void) __attribute__((interrupt));&lt;br /&gt;
void XXX_vect(void) {&lt;br /&gt;
  ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
/* ** alt ** */&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/interrupt.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
INTERRUPT(SIG_OVERFLOW0)&lt;br /&gt;
{&lt;br /&gt;
   ...&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* ** neu: ** */&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
void TIMER0_OVF_vect(void) __attribute__((interrupt));&lt;br /&gt;
void TIMER0_OVF_vect(void) &lt;br /&gt;
{&lt;br /&gt;
   ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Will oder kann man den Code nicht portieren, ist zur weiteren Verwendung von &#039;&#039;INTERRUPT&#039;&#039; die Header-Datei &#039;&#039;compat/deprecated.h&#039;&#039; einzubinden. Man sollte bei dieser Gelegenheit jedoch nochmals überprüfen, ob die Funktionalität von &#039;&#039;INTERRUPT&#039;&#039; tatsächlich gewollt ist. In vielen Fällen wurde &#039;&#039;INTERRUPT&#039;&#039; dort genutzt, wo eigentlich &#039;&#039;SIGNAL&#039;&#039; (nunmehr &#039;&#039;ISR&#039;&#039;) hätte genutzt werden sollen.&lt;br /&gt;
&lt;br /&gt;
=== Veraltete Funktionen zum Portzugriff ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;inp&#039;&#039; und &#039;&#039;outp&#039;&#039; zum Einlesen bzw. Schreiben von Registern sind nicht mehr erforderlich, der Compiler unterstützt dies ohne diesen Umweg.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
unsigned char i, j;&lt;br /&gt;
&lt;br /&gt;
// alt:&lt;br /&gt;
  i = inp(PINA);&lt;br /&gt;
  j = 0xff;&lt;br /&gt;
  outp(PORTB, j);&lt;br /&gt;
&lt;br /&gt;
// neu (nicht mehr wirklich neu...):&lt;br /&gt;
  i = PINA&lt;br /&gt;
  j = 0xff;&lt;br /&gt;
  PORTB = j;&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Will oder kann man den Code nicht portieren, ist zur weiteren Verwendung von inp und outp die Header-Datei &#039;&#039;&#039;compat/deprecated.h&#039;&#039;&#039; einzubinden.&lt;br /&gt;
&lt;br /&gt;
=== Veraltete Funktionen zum Zugriff auf Bits in Registern ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;cbi&#039;&#039; und &#039;&#039;sbi&#039;&#039; zum Löschen und Setzen von Bits sind nicht mehr erforderlich, der Compiler unterstützt dies ohne diesen Umweg. Die Bezeichnung ist ohnehin irreführend da die Funktionen nur für Register mit Adressen im unteren Speicherbereich tatsächlich in die Assembleranweisungen cbi und sbi übersetzt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
// alt:&lt;br /&gt;
  sbi(PORTB, PB2);&lt;br /&gt;
  cbi(PORTC, PC1);&lt;br /&gt;
&lt;br /&gt;
// neu (auch nicht mehr wirklich neu...):&lt;br /&gt;
  PORTB |=  (1&amp;lt;&amp;lt;PB2);&lt;br /&gt;
  PORTC &amp;amp;= ~(1&amp;lt;&amp;lt;PC1);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Will oder kann man den Code nicht portieren, ist zur weiteren Verwendung von sbi und cbi die Header-Datei &#039;&#039;&#039;compat/deprecated.h&#039;&#039;&#039; einzubinden. Wer unbedingt will, kann sich natürlich eigene Makros mit aussagekräftigeren Namen definieren. Zum Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#define SET_BIT(PORT, BITNUM)    ((PORT) |=  (1&amp;lt;&amp;lt;(BITNUM)))&lt;br /&gt;
#define CLEAR_BIT(PORT, BITNUM)  ((PORT) &amp;amp;= ~(1&amp;lt;&amp;lt;(BITNUM)))&lt;br /&gt;
#define TOGGLE_BIT(PORT, BITNUM) ((PORT) ^=  (1&amp;lt;&amp;lt;(BITNUM)))&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Selbstdefinierte (nicht-standardisierte) ganzzahlige Datentypen ===&lt;br /&gt;
&lt;br /&gt;
Bei den im Folgenden genannten Typdefinitionen ist zu beachten, dass die Bezeichnungen für &amp;quot;Worte&amp;quot; teilweise je nach Prozessorplattform unterschiedlich verwendet werden. Die angegebenen Definitionen beziehen sich auf die im Zusammenhang mit AVR/8-bit-Controllern üblichen &amp;quot;Bit-Breiten&amp;quot; (In Erläuterungen zum ARM7TDMI z.B. werden oft 32-bit Integer mit &amp;quot;Wort&amp;quot; ohne weitere Ergänzung bezeichnet). Es empfiehlt sich, bei der Überarbeitung von altem Code die im Abschnitt &#039;&#039;standardisierten ganzzahligen Datentypen&#039;&#039; beschriebenen Datentypen zu nutzen (stdint.h) und damit &amp;quot;Missverständnissen&amp;quot; vorzubeugen, die z.B. bei der Portierung von C-Code zwischen verschiedenen Plattformen auftreten können.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
typedef unsigned char      BYTE;       // besser: uint8_t  aus &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
typedef unsigned short     WORD;       // besser: uint16_t aus &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
typedef unsigned long      DWORD;      // besser: uint32_t aus &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
typedef unsigned long long QWORD;      // besser: uint64_t aus &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; BYTE : Der Datentyp BYTE definiert eine Variable mit 8 Bit Breite zur Darstellung von ganzen Zahlen im Bereich zwischen 0 ... 255. &lt;br /&gt;
&lt;br /&gt;
; WORD : Der Datentyp WORD definiert eine Variable mit 16 Bit Breite zur Darstellung von ganzen Zahlen im Bereich zwischen 0 ... 65535. &lt;br /&gt;
&lt;br /&gt;
; DWORD : Der Datentyp DWORD (gesprochen: Double-Word) definiert eine Variable mit 32 Bit Breite zur Darstellung von ganzen Zahlen im Bereich zwischen 0 ... 4294967295.&lt;br /&gt;
&lt;br /&gt;
; QWORD : Der Datentyp QWORD (gesprochen: Quad-Word) definiert eine Variable mit 64 Bit Breite zur Darstellung von ganzen Zahlen im Bereich zwischen 0 ... 18446744073709551615.&lt;br /&gt;
&lt;br /&gt;
== Zusätzliche Funktionen im Makefile ==&lt;br /&gt;
&lt;br /&gt;
=== Bibliotheken (Libraries/.a-Dateien) hinzufügen ===&lt;br /&gt;
&lt;br /&gt;
Um Funktionen aus Bibliotheken (&amp;quot;echte&amp;quot; Libraries, *.a-Dateien) zu nutzen, sind dem Linker die Namen der Bibliotheken als Parameter zu übergeben. Dazu ist die Option -l (kleines L) vorgesehen, an die der Name der Library angehängt wird. &lt;br /&gt;
&lt;br /&gt;
Dabei ist zu beachten, dass der Name der Library und der Dateiname der Library nicht identisch sind. Der hinter -l angegebene Name entspricht dem Dateinamen der Library ohne die Zeichenfolge &#039;&#039;lib&#039;&#039; am Anfang des Dateinamens und ohne die Endung &#039;&#039;.a&#039;&#039;. Sollen z.B. Funktionen aus einer Library mit dem Dateinamen &#039;&#039;libefsl.a&#039;&#039; eingebunden (gelinkt) werden, lautet der entsprechende Parameter -lefsl (vergl. auch -lm zum Anbinden von libm.a). &lt;br /&gt;
&lt;br /&gt;
In Makefiles wird traditonell eine make-Variable LDLIBS genutzt, in die &amp;quot;l-Parameter&amp;quot; abgelegt werden. Die WinAVR-makefile-Vorlage enthält diese Variable zwar nicht, dies stellt jedoch keine Einschränkung dar, da alle in der make-Variable LDFLAGS abgelegten Parameter an den Linker weitergereicht werden. &lt;br /&gt;
&lt;br /&gt;
Beispiele:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;code&amp;quot;&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
# Einbinden von Funktionen aus einer Library efsl (Dateiname libefsl.a)&lt;br /&gt;
LDFLAGS += -lefsl&lt;br /&gt;
# Einbinden von Funktionen aus einer Library xyz (Dateiname libxyz.a)&lt;br /&gt;
LDFLAGS += -lxyz&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Liegen die Library-Dateien nicht im Standard Library-Suchpfad, sind die Pfade mittels Parameter &#039;&#039;-L&#039;&#039; ebenfalls anzugeben. (Der vordefinierte Suchpfad kann mittels &#039;&#039;avr-gcc --print-search-dirs&#039;&#039; angezeigt werden.)&lt;br /&gt;
&lt;br /&gt;
Als Beispiel ein Projekt (&amp;quot;superapp2&amp;quot;), in dem der Quellcode von zwei Libraries (efsl und xyz) und der Quellcode der eigentlichen Anwendung in verschiedenen Verzeichnissen mit der folgenden &amp;quot;Baumstruktur&amp;quot; abgelegt sind:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;code&amp;quot;&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
superapp2&lt;br /&gt;
|&lt;br /&gt;
+----- efslsource (darin libefsl.a)&lt;br /&gt;
|&lt;br /&gt;
+----- xyzsource (darin libxyz.a)&lt;br /&gt;
|&lt;br /&gt;
+----- firmware (darin Anwendungs-Quellcode und Makefile)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Daraus folgt, dass im Makefile die Verzeichnis efslsource und xyzsource in den Library-Suchpfad aufzunehmen sind:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;code&amp;quot;&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
LDFLAGS += -L../efslsource/ -L../xyzsource/&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Fuse-Bits ===&lt;br /&gt;
&lt;br /&gt;
Zur Berechnung der Fuse-Bits bietet sich neben dem Studium des Datenblattes auch der [http://palmavr.sourceforge.net/cgi-bin/fc.cgi AVR Fuse Calculator] an. Gewarnt werden muss vor der Benutzung von PonyProg, weil dort durch die negierte Darstellung gern Fehler gemacht werden.&lt;br /&gt;
&lt;br /&gt;
Soll die Programmierung von Fuse- und Lockbits automatisiert werden, kann man dies ebenfalls durch Einträge im Makefile vornehmen, die beim Aufruf von &amp;quot;make program&amp;quot; an die genutzte Programmiersoftware übergeben werden. In der makefile-Vorlage von WinAVR (und mfile) gibt es dafuer jedoch keine &amp;quot;Ausfüllhilfe&amp;quot; (Stand 9/2006). Die folgenden Ausführungen gelten für die Programmiersoftware [[AVRDUDE]] (Standard in der WinAVR-Vorlage), können jedoch sinngemäß auf andere Programmiersoftware übertragen werden, die die Angabe der Fuse- und Lockbits-Einstellungen per Kommandozeilenparameter unterstützt (z.B. stk500.exe). Im einfachsten Fall ergänzt man im Makefile einige Variablen, deren Werte natürlich vom verwendeten Controller und den gewünschten Einstellungen abhängen (vgl. Datenblatt Fuse-/Lockbits):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#---------------- Programming Options (avrdude) ----------------&lt;br /&gt;
&lt;br /&gt;
#...&lt;br /&gt;
#Beispiel! f. ATmega16 - nicht einfach uebernehmen! Zahlenwerte anhand&lt;br /&gt;
#--------- des Datenblatts nachvollziehen und gegebenenfalls aendern.&lt;br /&gt;
#&lt;br /&gt;
AVRDUDE_WRITE_LFUSE = -U lfuse:w:0xff:m&lt;br /&gt;
AVRDUDE_WRITE_HFUSE = -U hfuse:w:0xd8:m&lt;br /&gt;
AVRDUDE_WRITE_LOCK  = -U lock:w:0x2f:m&lt;br /&gt;
#...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Damit diese Variablen auch genutzt werden, ist der Aufruf von avrdude im Makefile entsprechend zu ergänzen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
# Program the device.  &lt;br /&gt;
program: $(TARGET).hex $(TARGET).eep&lt;br /&gt;
# ohne Fuse-/Lock-Einstellungen (nach WinAVR Vorlage Stand 4/2006)&lt;br /&gt;
#	$(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH) \&lt;br /&gt;
#        $(AVRDUDE_WRITE_EEPROM)&lt;br /&gt;
# mit Fuse-/Lock-Einstellungen&lt;br /&gt;
        $(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_LFUSE) \&lt;br /&gt;
        $(AVRDUDE_WRITE_HFUSE) $(AVRDUDE_WRITE_FLASH) \&lt;br /&gt;
        $(AVRDUDE_WRITE_EEPROM) $(AVRDUDE_WRITE_LOCK)&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Eine weiter Möglichkeit besteht darin, die Fuse- und Lockbit-Einstellungen vom Preprozessor/Compiler generieren zu lassen. Die Fuse-Bits werden dann bei Verwendung von AVRDUDE in eigene Hex-Files geschrieben. Hierzu kann man z.B. folgendes Konstrukt verwenden:&lt;br /&gt;
&lt;br /&gt;
In eine der C-Sourcen wird eine Variable je Fuse-Byte vom Typ &#039;&#039;unsigned char&#039;&#039; deklariert und in eine extra Section gepackt. Dies kann entweder in einem vorhandenen File passieren oder in ein neues (z.B. fuses.c) geschrieben werden. Das File muss im Makefile aber auf jeden Fall mit kompiliert und gelinkt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
// tiny 2313 fuses low byte&lt;br /&gt;
#define CKDIV8  7&lt;br /&gt;
#define CKOUT   6&lt;br /&gt;
#define SUT1    5&lt;br /&gt;
#define SUT0    4&lt;br /&gt;
#define CKSEL3  3&lt;br /&gt;
#define CKSEL2  2&lt;br /&gt;
#define CKSEL1  1&lt;br /&gt;
#define CKSEL0  0&lt;br /&gt;
&lt;br /&gt;
// tiny2313 fuses high byte&lt;br /&gt;
#define DWEN       7&lt;br /&gt;
#define EESAVE     6&lt;br /&gt;
#define SPIEN      5&lt;br /&gt;
#define WDTON      4&lt;br /&gt;
#define BODLEVEL2  3&lt;br /&gt;
#define BODLEVEL1  2&lt;br /&gt;
#define BODLEVEL0  1&lt;br /&gt;
#define RSTDISBL   0&lt;br /&gt;
&lt;br /&gt;
// tiny2313 fuses extended byte&lt;br /&gt;
#define SELFPRGEN  0&lt;br /&gt;
&lt;br /&gt;
#define LFUSE         __attribute__ ((section (&amp;quot;lfuses&amp;quot;)))&lt;br /&gt;
#define HFUSE         __attribute__ ((section (&amp;quot;hfuses&amp;quot;)))&lt;br /&gt;
#define EFUSE         __attribute__ ((section (&amp;quot;efuses&amp;quot;)))&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// select ext crystal 3-8Mhz&lt;br /&gt;
unsigned char lfuse LFUSE =&lt;br /&gt;
    ( (1&amp;lt;&amp;lt;CKDIV8) | (1&amp;lt;&amp;lt;CKOUT) | (1&amp;lt;&amp;lt;CKSEL3) | (1&amp;lt;&amp;lt;CKSEL2) | &lt;br /&gt;
      (0&amp;lt;&amp;lt;CKSEL1) | (1&amp;lt;&amp;lt;CKSEL0) | (0&amp;lt;&amp;lt;SUT1) | (1&amp;lt;&amp;lt;SUT0) );&lt;br /&gt;
unsigned char hfuse HFUSE =&lt;br /&gt;
    ( (1&amp;lt;&amp;lt;DWEN) | (1&amp;lt;&amp;lt;EESAVE) | (0&amp;lt;&amp;lt;SPIEN) | (1&amp;lt;&amp;lt;WDTON) | &lt;br /&gt;
      (1&amp;lt;&amp;lt;BODLEVEL2) | (1&amp;lt;&amp;lt;BODLEVEL1) | (0&amp;lt;&amp;lt;BODLEVEL0) | (1&amp;lt;&amp;lt;RSTDISBL) );&lt;br /&gt;
unsigned char efuse EFUSE =&lt;br /&gt;
    ((0&amp;lt;&amp;lt;SELFPRGEN));&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ACHTUNG: Die Bitpositionen wurden nicht vollständig getestet!&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Eine &amp;quot;1&amp;quot; bedeutet hier, dass das Fuse-Bit &#039;&#039;nicht&#039;&#039; programmiert wird - die Funktion also i.A. nicht aktiviert ist. Eine &amp;quot;0&amp;quot; hingegen aktiviert die meisten Funktionen. Dies ist wie im Datenblatt (1 = unprogrammed, 0 = programmed).&lt;br /&gt;
&lt;br /&gt;
Das Makefile muss nun noch um folgende Targets erweitert werden (mit Tabulator einrücken - nicht mit Leerzeichen):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;code&amp;quot;&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
lfuses: build&lt;br /&gt;
        -$(OBJCOPY) -j lfuses --change-section-address lfuses=0 \&lt;br /&gt;
          -O ihex $(TARGET).elf $(TARGET)-lfuse.hex&lt;br /&gt;
        @if [ -f $(TARGET)-lfuse.hex ]; then \&lt;br /&gt;
         $(AVRDUDE) $(AVRDUDE_FLAGS) -U lfuse:w:$(TARGET)-lfuse.hex; \&lt;br /&gt;
        fi;&lt;br /&gt;
&lt;br /&gt;
hfuses: build&lt;br /&gt;
        -$(OBJCOPY) -j hfuses --change-section-address hfuses=0 \&lt;br /&gt;
          -O ihex $(TARGET).elf $(TARGET)-hfuse.hex&lt;br /&gt;
        @if [ -f $(TARGET)-hfuse.hex ]; then \&lt;br /&gt;
         $(AVRDUDE) $(AVRDUDE_FLAGS) -U hfuse:w:$(TARGET)-hfuse.hex; \&lt;br /&gt;
        fi;&lt;br /&gt;
&lt;br /&gt;
efuses: build&lt;br /&gt;
        -$(OBJCOPY) -j efuses --change-section-address efuses=0 \&lt;br /&gt;
         -O ihex $(TARGET).elf $(TARGET)-efuse.hex&lt;br /&gt;
        @if [ -f $(TARGET)-efuse.hex ]; then \&lt;br /&gt;
         $(AVRDUDE) $(AVRDUDE_FLAGS) -U efuse:w:$(TARGET)-efuse.hex;&lt;br /&gt;
        fi;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Target &amp;quot;clean&amp;quot; muss noch um die Zeilen&lt;br /&gt;
&amp;lt;div class=&amp;quot;code&amp;quot;&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
        $(REMOVE) $(TARGET)-lfuse.hex&lt;br /&gt;
        $(REMOVE) $(TARGET)-hfuse.hex&lt;br /&gt;
        $(REMOVE) $(TARGET)-efuse.hex&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
erweitert werden, wenn auch die Fuse-Dateien gelöscht werden sollen.&lt;br /&gt;
&lt;br /&gt;
Um nun die Fusebits des angeschlossenen Controllers zu programmieren muss lediglichein &amp;quot;make lfuses&amp;quot;, &amp;quot;make hfuses&amp;quot; oder &amp;quot;make efuses&amp;quot; gestartet werden.&lt;br /&gt;
Bei den Fuse-Bits ist besondere Vorsicht geboten, da diese das Programmieren des Controllers unmöglich machen können. Also erst programmieren, wenn man einen HV-Programmierer hat oder ein paar Reserve-AVRs zur Hand ;-)&lt;br /&gt;
&lt;br /&gt;
Um weiterhin den &amp;quot;normalen&amp;quot; Flash beschreiben zu können, ist es wichtig, für das Target &amp;quot;*.hex&amp;quot; im Makefile nicht nur &amp;quot;-R .eeprom&amp;quot; als Parameter zu übergeben sondern zusätzlich noch &amp;quot;-R lfuses -R efuses -R hfuses&amp;quot;. Sonst bekommt AVRDUDE Probleme diese Sections in den Flash (wo sie ja nicht hingehören) zu schreiben.&lt;br /&gt;
&lt;br /&gt;
Siehe auch: [[AVR_Fuses#Vergleich_der_Fuses_bei_verschiedenen_Programmen|Vergleich der Fuses bei verschiedenen Programmen]]&lt;br /&gt;
&lt;br /&gt;
== Externe Referenzspannung des internen Analog-Digital-Wandlers ==&lt;br /&gt;
&lt;br /&gt;
Die minimale (externe) Referenzspannung des ADC darf nicht beliebig niedrig sein, vgl. dazu das (aktuellste) Datenblatt des verwendeten Controllers. z.B. beim ATMEGA8 darf sie laut Datenblatt (S.245, Tabelle 103, Zeile &amp;quot;VREF&amp;quot;) 2,0V nicht unterschreiten. HINWEIS: diese Information findet sich erst in der letzten Revision (Rev. 2486O-10/04) des Datenblatts.&lt;br /&gt;
&lt;br /&gt;
Meiner &amp;lt;!-- Wer? - es gibt inzwischen x Leute die mehr oder weniger viel in diesem Artikel geschrieben haben --&amp;gt; eigenen Erfahrung nach kann man aber (auf eigene Gefahr und natürlich nicht für Seriengeräte) durchaus noch ein klein wenig weiter heruntergehen, bei dem von mir unter die Lupe genommenen ATMEGA8L (also die Low-Voltage-Variante) funktioniert der ADC bei 5V Betriebsspannung mit bis zu VREF=1,15V hinunter korrekt, ab 1,1V und darunter digitalisiert er jedoch nur noch Blödsinn). Ich würde sicherheitshalber nicht unter 1,5V gehen und bei niedrigeren Betriebsspannungen mag sich die Untergrenze für VREF am Pin AREF ggf. nach oben&#039;&#039;&#039;(!)&#039;&#039;&#039; verschieben.&lt;br /&gt;
&lt;br /&gt;
In der letzten Revision des Datenblatts ist außerdem korrigiert, dass ADC4 und ADC5 sehr wohl 10 Bit Genauigkeit bieten (und nicht bloß 8 Bit, wie in älteren Revisionen irrtümlich angegeben.)&lt;br /&gt;
&lt;br /&gt;
= TODO =&lt;br /&gt;
* Aktualisierung Register- und Bitbeschreibungen an aktuelle AVR&lt;br /&gt;
* stdio.h, malloc() &lt;br /&gt;
* Code-Optimierungen (&amp;quot;tricks&amp;quot;), siehe auch Application Note [http://www.atmel.com/dyn/resources/prod_documents/doc1497.pdf AVR035: Efficient C Coding for AVR]&lt;br /&gt;
* &amp;quot;naked&amp;quot;-Funktionen&lt;br /&gt;
* SPI siehe [http://www.uni-koblenz.de/~physik/informatik/MCU/SPI.pdf SPI Bus mit Atmel AVR]&lt;br /&gt;
* I²C / TWI Bus [http://www.roboternetz.de/wissen/index.php/TWI]&lt;br /&gt;
* Bootloader (bez. auf boot.h)&lt;br /&gt;
* CAN-Bus&lt;br /&gt;
* Einsatz von einfachen Betriebssystemen auf dem AVR&lt;br /&gt;
* Übersicht zu den C bzw. GCC-predefined Makros (__DATE__, __TIME__,...)&lt;br /&gt;
[[Category:AVR]]&lt;br /&gt;
* ADC ; &lt;br /&gt;
* Timer&lt;br /&gt;
* USB ; Steuerung mit USB&lt;br /&gt;
* Multiplexen Siebensegment&lt;br /&gt;
* Sichere vs. effiziente Serialisierung von Datentypen&lt;br /&gt;
* Zustandsautomaten&lt;/div&gt;</summary>
		<author><name>Thymythos</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=RFM12_Protokoll_Stack&amp;diff=32683</id>
		<title>RFM12 Protokoll Stack</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=RFM12_Protokoll_Stack&amp;diff=32683"/>
		<updated>2008-11-23T16:34:45Z</updated>

		<summary type="html">&lt;p&gt;Thymythos: /* Media Access Control (MAC) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Bild:RFM12 Stack.svg|right]]&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel beschreibt einen [http://de.wikipedia.org/wiki/ISO/OSI ISO/OSI] Protokoll [http://de.wikipedia.org/wiki/Protokollstack Stack] für den [[RFM12]] Funkchip.&amp;lt;br/&amp;gt;&lt;br /&gt;
Einige Hardwarebeispiele finden sich in [[AVR RFM12]].&amp;lt;br/&amp;gt;&lt;br /&gt;
Fehler und Anregungen können gerne auf der [[Diskussion:RFM12_Protokoll_Stack|Diskussionsseite]] besprochen werden.&lt;br /&gt;
&lt;br /&gt;
Eine Referenz-Implementierung für den [[AVR]] wird bereitgestellt:&lt;br /&gt;
{| style=&amp;quot;border:1px dashed green&amp;quot;&lt;br /&gt;
|&#039;&#039;svn://mikrocontroller.net/rfm12/trunk/RFM12_Stack&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
;Implementierungskriterien&lt;br /&gt;
* Wo möglich werden [http://de.wikipedia.org/wiki/R%C3%BCckruffunktion Callback]-Funktionen anstatt [http://de.wikipedia.org/wiki/First_In_%E2%80%93_First_Out FIFOs] verwendet um RAM zu sparen.&lt;br /&gt;
* Interruptgesteuerter Ablauf des Stacks&lt;br /&gt;
* Funktionen sollten nicht blockieren&lt;br /&gt;
&lt;br /&gt;
== Layer 1: Physical ==&lt;br /&gt;
&lt;br /&gt;
[[Bild:RFM12 PHY StateMachine.svg|thumb|320px|Layer1 State Diagram]]&lt;br /&gt;
&lt;br /&gt;
Der Physical-Layer kümmert sich um die direkte Ansteuerung des RFM12. Alle Funktionen des Chips werden als Software-API bereitgestellt.&lt;br /&gt;
&lt;br /&gt;
Folgende Eigenschaften sind bereits vom RFM12 vorgegeben:&lt;br /&gt;
&lt;br /&gt;
* [http://de.wikipedia.org/wiki/ISM-Band 70cm Band (433MHz)]&lt;br /&gt;
* [http://de.wikipedia.org/wiki/Frequenzumtastung FSK]-Modulation&lt;br /&gt;
* Sync-Erkennung auf &#039;&#039;0x2D 0xD4&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Definiert werden muss jedoch noch:&lt;br /&gt;
&lt;br /&gt;
* Baudrate (Vorschlag: feste Kanal-Baudraten-Zuordnung)&lt;br /&gt;
* Zuordnung von Frequenzen zu [[#Kanalzuordnung|Kanälen]]&lt;br /&gt;
* Bandbreite der Kanäle&lt;br /&gt;
* Management der Sendeleistung/Empfangsempfindlichkeit&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;API&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
void RFM12_PHY_modeTX(void);&lt;br /&gt;
&lt;br /&gt;
void RFM12_PHY_modeRX(void);&lt;br /&gt;
&lt;br /&gt;
bool RFM12_PHY_busy(void);&lt;br /&gt;
&lt;br /&gt;
void RFM12_setBaudrate(uint32_t baud);&lt;br /&gt;
&lt;br /&gt;
void RFM12_setCenterFrequency(uint16_t freq);&lt;br /&gt;
&lt;br /&gt;
void RFM12_setDataFilter(bool autoLock, bool fastMode, bool analog, uint8_t dqdThres);&lt;br /&gt;
&lt;br /&gt;
void RFM12_setReceiverBandwidth(RFM12_VDI_t vdi, RFM12_RxBW_t bandwidth, RFM12_GAIN_t gain, RFM12_RSSI_t drssi);&lt;br /&gt;
&lt;br /&gt;
void RFM12_setPowerManagement(bool enRX, bool enBB, bool startTX, bool enSynth, bool enOSC, bool enBat, bool enWkT, bool clkOff);&lt;br /&gt;
&lt;br /&gt;
void RFM12_setTransmitPower(RFM12_Power_t power, RFM12_TxDev_t deviation);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Layer 2: Data Link ==&lt;br /&gt;
&lt;br /&gt;
=== Media Access Control (MAC) ===&lt;br /&gt;
&lt;br /&gt;
Hier noch ein paar Anregungen zur Verbesserung des MAC: [http://www.comsoc.org/livepubs/surveys/public/2q00issue/gummalla.html]&lt;br /&gt;
&lt;br /&gt;
Der MAC-Layer ist sehr einfach gehalten und regelt den Zugriff auf das Medium. Hier soll ein [http://de.wikipedia.org/wiki/CSMA-CA CSMA/CA] Verfahren eingesetzt werden.&lt;br /&gt;
&lt;br /&gt;
# Im Grundzustand befindet sich der RFM12 im Empfangsmodus und wartet auf eine SYNC-Sequenz.&lt;br /&gt;
# Kommt eine Sendeanforderung, wird so lange gewartet bis das Medium frei ist, dann darf nach Ablauf einer (pseudo) zufälligen Zeitspanne gesendet werden.&lt;br /&gt;
# Wurde gerade ein Paket empfangen, darf sofort ein ACK gesendet werden.&lt;br /&gt;
# Die maximale Paketlänge beträgt 50ms. Die maximale Anzahl Bytes hängt daher von der Baudrate ab.&lt;br /&gt;
&lt;br /&gt;
Der Frameaufbau ist teilweise vom RFM12 vorgegeben (SYNC-Erkennung). Der Start-Of-Frame (SOF) dient der Synchronisation. Als End-Of-Frame (EOF) wird ebenfalls die Sequenz &#039;&#039;0xAA&#039;&#039; verwendet. Diese darf im Datenteil nicht vorkommen!&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|+ MAC Frameaufbau&lt;br /&gt;
|-&lt;br /&gt;
!&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; bgcolor=&amp;quot;#9fffa8&amp;quot; | SOF&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; bgcolor=&amp;quot;#9fffa8&amp;quot; | Sync&lt;br /&gt;
! bgcolor=&amp;quot;#9fffa8&amp;quot; | &#039;&#039;n Byte Daten&#039;&#039;&lt;br /&gt;
! bgcolor=&amp;quot;#9fffa8&amp;quot; | EOF&lt;br /&gt;
|----&lt;br /&gt;
! Bits&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; bgcolor=&amp;quot;#9fffa8&amp;quot; | 16 || colspan=&amp;quot;2&amp;quot; bgcolor=&amp;quot;#9fffa8&amp;quot; | 16 || bgcolor=&amp;quot;#9fffa8&amp;quot; | 0 - 8*n    || bgcolor=&amp;quot;#9fffa8&amp;quot; | 8&lt;br /&gt;
|----&lt;br /&gt;
! Wert&lt;br /&gt;
| 0xAA || 0xAA     || 0x2D || 0xD4     || &#039;&#039;Daten&#039;&#039;  || 0xAA&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;API&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
void RFM12_MAC_setChannel(uint8_t channel);&lt;br /&gt;
&lt;br /&gt;
bool RFM12_MAC_isReceiving(void);&lt;br /&gt;
&lt;br /&gt;
bool RFM12_MAC_mediaBusy(void);&lt;br /&gt;
&lt;br /&gt;
void RFM12_MAC_startCtrlTransmission(void);&lt;br /&gt;
&lt;br /&gt;
void RFM12_MAC_endCtrlTransmission(void);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Logical Link Control (LLC) ===&lt;br /&gt;
&lt;br /&gt;
Der LLC-Layer kümmert sich um die Sicherung der zu übertragenden Daten.&lt;br /&gt;
Außerdem können Geräte direkt mit ihrer Adresse (7-Bit) angesprochen werden.&lt;br /&gt;
&lt;br /&gt;
;[http://de.wikipedia.org/wiki/Vorw%C3%A4rtsfehlerkorrektur FEC]&lt;br /&gt;
:Alle Bytes werden auf eine [[#Hamming-Tabelle|16-Bit Hamming-Sequenz]] erweitert, wodurch die Datenrate halbiert wird.&lt;br /&gt;
:Dies erlaubt es einzelne Bitfehler zu korrigieren.&lt;br /&gt;
:Bei zu vielen Fehlern können diese jedoch nicht erkannt werden.&lt;br /&gt;
:Im Hamming-Code kommt die Sequenz &#039;&#039;0xAA&#039;&#039; nicht vor (siehe MAC-Layer).&lt;br /&gt;
:Die FEC sorgt außerdem dafür, dass genügend 0-1 Transitionen vorkommen. So kann der Empfänger den Takt auch bei langen Paketen besser halten.&lt;br /&gt;
&lt;br /&gt;
;[http://de.wikipedia.org/wiki/Cyclic_Redundancy_Check CRC]&lt;br /&gt;
:Der gesamte Frame wird nochmals durch eine Checksumme gesichert. (CRC-8: &#039;&#039;x&amp;lt;sup&amp;gt;8&amp;lt;/sup&amp;gt; + x&amp;lt;sup&amp;gt;5&amp;lt;/sup&amp;gt; + x&amp;lt;sup&amp;gt;4&amp;lt;/sup&amp;gt; + 1&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
;Version&lt;br /&gt;
:Das Versionsfeld gibt die verwendete Version an (aktuell ist Version 1 = 0b00).&lt;br /&gt;
:Wenn die Version nicht unterstützt ist, wird der Empfang abgebrochen.&lt;br /&gt;
&lt;br /&gt;
;Adressierung&lt;br /&gt;
:Broadcast (0xff) an alle Geräte (immer ohne ACK)&lt;br /&gt;
:127 Multicast-Gruppen (0x80 - 0xfe)&lt;br /&gt;
:128 Geräteadressen (0x00 - 0x7f) (mit oder ohne ACK)&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|+ LLC Frameaufbau &#039;&#039;(Version 1)&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
!&lt;br /&gt;
! Version&lt;br /&gt;
! need ACK&lt;br /&gt;
! is ACK&lt;br /&gt;
! TypeID&lt;br /&gt;
! Empfänger&lt;br /&gt;
! Sender&lt;br /&gt;
! &#039;&#039;0-m Byte Daten&#039;&#039;&lt;br /&gt;
! CRC-8&lt;br /&gt;
|----&lt;br /&gt;
! Bits (vor FEC)&lt;br /&gt;
| 2 || 1 || 1 || 4 || 8      || 8      || 0 - 8*m || 8&lt;br /&gt;
|-&lt;br /&gt;
! Bits (nach FEC)&lt;br /&gt;
| 4 || 2 || 2 || 8 || 16     || 16     || 0 - 16*m || 16&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039; API &#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
void RFM12_LLC_registerType(RFM12_ProtocolID_t typeID, RFM12_L3_Protocol_t proto);&lt;br /&gt;
&lt;br /&gt;
uint8_t RFM12_LLC_sendFrame(RFM12_ProtocolID_t proto, uint8_t receiver, bool requireACK);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Layer 3: Network ==&lt;br /&gt;
&lt;br /&gt;
Für den Network-Layer werden nur einige Beispiele angeführt. Ab hier können beliebige eigene Protokolle eingesetzt werden. Das verwendete Protokoll wird durch die &#039;&#039;TypeID&#039;&#039; im LLC-Layer angegeben. Die Layer-3-Protokolle sollten nach Möglichkeit nur über die LLC-API mit dem Rest des Stacks kommunizieren.&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;TypeID&#039;&#039;s sind wie folgt definiert:&lt;br /&gt;
&lt;br /&gt;
=== Typ 0: Management ===&lt;br /&gt;
&lt;br /&gt;
Management Protokoll:&lt;br /&gt;
&lt;br /&gt;
* Muss immer implementiert sein&lt;br /&gt;
* Sollte ähnliche Funktionen bieten wie das Service Discovery Protocol (SDP) bei Bluetooth&lt;br /&gt;
* Unterscheidung Request / Response&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot;&lt;br /&gt;
|+ Nachrichten&lt;br /&gt;
|-&lt;br /&gt;
! ID   || Request          || Response&lt;br /&gt;
|-&lt;br /&gt;
| 0x00 || Device Discovery || Device Information&lt;br /&gt;
|-&lt;br /&gt;
| 0x01 || Available Layer 3 Protos || Protocol Information&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot;&lt;br /&gt;
|+ Management Frameaufbau&lt;br /&gt;
|-&lt;br /&gt;
! || Req/Res || ID ||&lt;br /&gt;
|-&lt;br /&gt;
! Bits&lt;br /&gt;
|      1     ||  7 ||&lt;br /&gt;
|}&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Typ 1: Bytestream ===&lt;br /&gt;
&lt;br /&gt;
Die Einteilung in Pakete wird aufgehoben. Daten kommen 1:1 in der Reihenfolge an, wie sie gesendet wurden.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;API&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
void RFM12_Serial_setPeer(uint8_t peer);&lt;br /&gt;
&lt;br /&gt;
bool RFM12_Serial_txAvailable(void);&lt;br /&gt;
&lt;br /&gt;
void RFM12_Serial_txData(uint8_t data);&lt;br /&gt;
&lt;br /&gt;
bool RFM12_Serial_rxAvailable(void);&lt;br /&gt;
&lt;br /&gt;
uint8_t RFM12_Serial_rxData(void);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Typ 3: IPv4 ===&lt;br /&gt;
&lt;br /&gt;
z.B. [http://www.sics.se/~adam/uip/index.php/Main_Page uIP TCP/IP Stack] von Adam Dunkels &amp;lt;adam@dunkels.com&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Anhänge ==&lt;br /&gt;
&lt;br /&gt;
=== Sequenzdiagramme ===&lt;br /&gt;
&lt;br /&gt;
Empfang:&lt;br /&gt;
[[Bild:RFM12 RX Sequence.svg|center|800px|RX Sequenz]]&lt;br /&gt;
&lt;br /&gt;
Senden:&lt;br /&gt;
[[Bild:RFM12 TX Sequence.svg|center|800px|TX Sequenz]]&lt;br /&gt;
&lt;br /&gt;
=== Frames ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Beachte:&#039;&#039;&#039; Durch die Hamming-Codierung sind alle Bytes innerhalb des MAC-Layer doppelt so lang wie angegeben!&lt;br /&gt;
{|&lt;br /&gt;
! bgcolor=&amp;quot;#9fffa8&amp;quot; | MAC || bgcolor=&amp;quot;#a9f3f2&amp;quot; | LLC || bgcolor=&amp;quot;#d28787&amp;quot; | L3&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; align=&amp;quot;center&amp;quot; style=&amp;quot;text-align:center&amp;quot;&lt;br /&gt;
|+ Frameaufbau&lt;br /&gt;
|-&lt;br /&gt;
!&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; bgcolor=&amp;quot;#9fffa8&amp;quot; | SOF&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; bgcolor=&amp;quot;#9fffa8&amp;quot; | Sync&lt;br /&gt;
! bgcolor=&amp;quot;#a9f3f2&amp;quot; | Empfänger&lt;br /&gt;
! bgcolor=&amp;quot;#a9f3f2&amp;quot; | Sender&lt;br /&gt;
! bgcolor=&amp;quot;#a9f3f2&amp;quot; | need ACK | is ACK | | | TypeID&lt;br /&gt;
! bgcolor=&amp;quot;#d28787&amp;quot; | &#039;&#039;0-28 Byte Daten&#039;&#039;&lt;br /&gt;
! bgcolor=&amp;quot;#a9f3f2&amp;quot; | CRC-8&lt;br /&gt;
! bgcolor=&amp;quot;#9fffa8&amp;quot; | EOF&lt;br /&gt;
|----&lt;br /&gt;
! Bits&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; bgcolor=&amp;quot;#9fffa8&amp;quot; | 16 || colspan=&amp;quot;2&amp;quot; bgcolor=&amp;quot;#9fffa8&amp;quot; | 16&lt;br /&gt;
| bgcolor=&amp;quot;#a9f3f2&amp;quot; | 8 || bgcolor=&amp;quot;#a9f3f2&amp;quot; | 8 || bgcolor=&amp;quot;#a9f3f2&amp;quot; | &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; 1 &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; | &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; 1 &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; |1|1| &amp;amp;nbsp;&amp;amp;nbsp; 4 &amp;amp;nbsp;&amp;amp;nbsp;&lt;br /&gt;
| bgcolor=&amp;quot;#d28787&amp;quot; | 0-224&lt;br /&gt;
| bgcolor=&amp;quot;#a9f3f2&amp;quot; | 8&lt;br /&gt;
| bgcolor=&amp;quot;#9fffa8&amp;quot; | 8&lt;br /&gt;
|----&lt;br /&gt;
! Wert&lt;br /&gt;
| bgcolor=&amp;quot;#9fffa8&amp;quot; | 0xAA || bgcolor=&amp;quot;#9fffa8&amp;quot; | 0xAA || bgcolor=&amp;quot;#9fffa8&amp;quot; | 0x2D || bgcolor=&amp;quot;#9fffa8&amp;quot; | 0xD4&lt;br /&gt;
| bgcolor=&amp;quot;#a9f3f2&amp;quot; | || bgcolor=&amp;quot;#a9f3f2&amp;quot; | || bgcolor=&amp;quot;#a9f3f2&amp;quot; | &lt;br /&gt;
| bgcolor=&amp;quot;#d28787&amp;quot; | &lt;br /&gt;
| bgcolor=&amp;quot;#a9f3f2&amp;quot; |&lt;br /&gt;
| bgcolor=&amp;quot;#9fffa8&amp;quot; | 0xAA&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Kanalzuordnung ===&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; align=&amp;quot;center&amp;quot; style=&amp;quot;text-align:right;&amp;quot;&lt;br /&gt;
|+ 433MHz Band&lt;br /&gt;
|-&lt;br /&gt;
! Kanal&lt;br /&gt;
| 0 || 1 || 2 || 3 || 4 || 5 || 6 || 7 || 8 || 9 || 10 || 11 || 12 || 13 || 14 || 15&lt;br /&gt;
|-&lt;br /&gt;
! Mittenfrequenz&lt;br /&gt;
|  431.0 || 431.5 || 432.0 || 432.5 || 433.0 || 433.5 || 434.0 || 434.5 || 435.0 || 435.5 || 436.0 || 436.5 || 437.0 || 437.5 || 438.0 || 438.5&lt;br /&gt;
|-&lt;br /&gt;
! Baudrate&lt;br /&gt;
|   9.6k || 19.2k || 115.2k||  9.6k || 19.2k || 115.2k||  9.6k || 19.2k ||115.2k ||  9.6k || 19.2k || 115.2k||  9.6k || 19.2k || 115.2k||  9.6k&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In der EU sind nur die Kanäle 4-7 möglich. Alle anderen Frequenzen stören andere Funkdienste und können zu nicht unerheblichen Bußgeldern und Kosten für Messeinsätze führen. &#039;&#039;&#039;Achtung: die Module dürfen auf den anderen Kanälen nur von Personen mit Amateurfunkgenehmigung betrieben werden!&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Hamming-Tabelle ===&lt;br /&gt;
&lt;br /&gt;
==== Encodieren ====&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;3&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|&lt;br /&gt;
! colspan=&amp;quot;4&amp;quot; | Algorithmus&lt;br /&gt;
! colspan=&amp;quot;4&amp;quot; | Beispiel&lt;br /&gt;
|-&lt;br /&gt;
| 1:&lt;br /&gt;
| width=&amp;quot;80&amp;quot; |&lt;br /&gt;
| width=&amp;quot;160&amp;quot; colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 8-Bit Wert&lt;br /&gt;
| width=&amp;quot;160&amp;quot; colspan=&amp;quot;2&amp;quot; |&lt;br /&gt;
| width=&amp;quot;160&amp;quot; colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 10010110&lt;br /&gt;
| width=&amp;quot;80&amp;quot; |&lt;br /&gt;
|-&lt;br /&gt;
| 2: || || align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 4-7 ||  align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 0-3 || colspan=&amp;quot;2&amp;quot; | ||  align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 1001 || align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 0110 || &lt;br /&gt;
|-&lt;br /&gt;
| 3:&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | HammingE[(4-7)]&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | HammingE[(0-3)]&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 0xC7&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 0x38&lt;br /&gt;
|-&lt;br /&gt;
| 4:&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | high&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | low&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 11000111&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 00111000&lt;br /&gt;
|-&lt;br /&gt;
| 5:&lt;br /&gt;
| colspan=&amp;quot;4&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 16-Bit Codewort&lt;br /&gt;
| colspan=&amp;quot;4&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 11000111 00111000&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;3&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|+ HammingE&lt;br /&gt;
|-&lt;br /&gt;
!  0 || 1 || 2  || 3 || 4 || 5 || 6 || 7 || 8 || 9 || A || B || C || D || E || F&lt;br /&gt;
|-&lt;br /&gt;
|bgcolor=&amp;quot;#ff0000&amp;quot;|0x15||bgcolor=&amp;quot;#ff1111&amp;quot;|0x02||bgcolor=&amp;quot;#ff2222&amp;quot;|0x49||bgcolor=&amp;quot;#ff3333&amp;quot;|0x5E||bgcolor=&amp;quot;#ff4444&amp;quot;|0x64||bgcolor=&amp;quot;#ff5555&amp;quot;|0x73||bgcolor=&amp;quot;#ff6666&amp;quot;|0x38||bgcolor=&amp;quot;#ff7777&amp;quot;|0x2F||bgcolor=&amp;quot;#ff8888&amp;quot;|0xD0||bgcolor=&amp;quot;#ff9999&amp;quot;|0xC7||bgcolor=&amp;quot;#ffaaaa&amp;quot;|0x8C||bgcolor=&amp;quot;#ffbbbb&amp;quot;|0x9B||bgcolor=&amp;quot;#ffcccc&amp;quot;|0xA1||bgcolor=&amp;quot;#ffdddd&amp;quot;|0xB6||bgcolor=&amp;quot;#ffeeee&amp;quot;|0xFD||bgcolor=&amp;quot;#ffffff&amp;quot;|0xEA&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Die Einträge in der Tabelle sind so gewählt, dass der Code den maximalen [http://de.wikipedia.org/wiki/Hamming-Abstand#Hamming-Abstand_eines_Codes Hamming-Abstand] von 4 Bit hat.&lt;br /&gt;
&lt;br /&gt;
==== Dekodieren ====&lt;br /&gt;
&lt;br /&gt;
In der Tabelle &#039;&#039;HammingD&#039;&#039; stehen nur 4-Bit breite Werte. Um einen 8-Bit Wert zu erhalten müssen also 2 Einträge aus der Tabelle ausgewählt werden.&lt;br /&gt;
&lt;br /&gt;
Wird nun ein 16-Bit Wert empfangen, bestimmt das High-Byte den ersten Eintrag, das Low-Byte den zweiten.&lt;br /&gt;
&lt;br /&gt;
Es können bis zu zwei gekippte Bits im High- und im Low-Byte korrigiert werden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;3&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|&lt;br /&gt;
! colspan=&amp;quot;4&amp;quot; | Algorithmus || colspan=&amp;quot;4&amp;quot; | Beispiel (mit Bitfehlern)&lt;br /&gt;
|-&lt;br /&gt;
| 1:&lt;br /&gt;
| colspan=&amp;quot;4&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 16-Bit Codewort&lt;br /&gt;
| colspan=&amp;quot;4&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 110&#039;&#039;&#039;1&#039;&#039;&#039;0111 001&#039;&#039;&#039;0&#039;&#039;&#039;100&#039;&#039;&#039;1&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 2:&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | high&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | low&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 110&#039;&#039;&#039;1&#039;&#039;&#039;0111&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 001&#039;&#039;&#039;0&#039;&#039;&#039;100&#039;&#039;&#039;1&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 3:&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | HammingD[high]&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | HammingD[low]&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 0x09&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 0x06&lt;br /&gt;
|-&lt;br /&gt;
| 4: || || align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 4-7&lt;br /&gt;
| align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 0-3 || &lt;br /&gt;
| || align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 1001&lt;br /&gt;
| align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 0110 || &lt;br /&gt;
|-&lt;br /&gt;
| 5:&lt;br /&gt;
| width=&amp;quot;80&amp;quot; |&lt;br /&gt;
| width=&amp;quot;160&amp;quot; colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 8-Bit Wert&lt;br /&gt;
| width=&amp;quot;80&amp;quot; | || width=&amp;quot;80&amp;quot; |&lt;br /&gt;
| width=&amp;quot;160&amp;quot; colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 10010110&lt;br /&gt;
| width=&amp;quot;80&amp;quot; |&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;3&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|+ HammingD&lt;br /&gt;
|-&lt;br /&gt;
!  || 0 || 1 || 2  || 3 || 4 || 5 || 6 || 7 || 8 || 9 || A || B || C || D || E || F&lt;br /&gt;
|-&lt;br /&gt;
! 0&lt;br /&gt;
|bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ffaaAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07&lt;br /&gt;
|-&lt;br /&gt;
! 1&lt;br /&gt;
|bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03&lt;br /&gt;
|-&lt;br /&gt;
! 2&lt;br /&gt;
|bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07&lt;br /&gt;
|-&lt;br /&gt;
! 3&lt;br /&gt;
|bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07&lt;br /&gt;
|-&lt;br /&gt;
! 4&lt;br /&gt;
|bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03&lt;br /&gt;
|-&lt;br /&gt;
! 5&lt;br /&gt;
|bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03&lt;br /&gt;
|-&lt;br /&gt;
! 6&lt;br /&gt;
|bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07&lt;br /&gt;
|-&lt;br /&gt;
! 7&lt;br /&gt;
|bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07&lt;br /&gt;
|-&lt;br /&gt;
! 8&lt;br /&gt;
|bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B&lt;br /&gt;
|-&lt;br /&gt;
! 9&lt;br /&gt;
|bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B&lt;br /&gt;
|-&lt;br /&gt;
! A&lt;br /&gt;
|bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07&lt;br /&gt;
|-&lt;br /&gt;
! B&lt;br /&gt;
|bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F&lt;br /&gt;
|-&lt;br /&gt;
! C&lt;br /&gt;
|bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09&lt;br /&gt;
|-&lt;br /&gt;
! D&lt;br /&gt;
|bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B&lt;br /&gt;
|-&lt;br /&gt;
! E&lt;br /&gt;
|bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F&lt;br /&gt;
|-&lt;br /&gt;
! F&lt;br /&gt;
|bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Funk]]&lt;br /&gt;
[[Kategorie:Wettbewerb]]&lt;/div&gt;</summary>
		<author><name>Thymythos</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=RFM12_Protokoll_Stack&amp;diff=32679</id>
		<title>RFM12 Protokoll Stack</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=RFM12_Protokoll_Stack&amp;diff=32679"/>
		<updated>2008-11-23T15:10:17Z</updated>

		<summary type="html">&lt;p&gt;Thymythos: /* Logical Link Control (LLC) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Bild:RFM12 Stack.svg|right]]&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel beschreibt einen [http://de.wikipedia.org/wiki/ISO/OSI ISO/OSI] Protokoll [http://de.wikipedia.org/wiki/Protokollstack Stack] für den [[RFM12]] Funkchip.&amp;lt;br/&amp;gt;&lt;br /&gt;
Einige Hardwarebeispiele finden sich in [[AVR RFM12]].&amp;lt;br/&amp;gt;&lt;br /&gt;
Fehler und Anregungen können gerne auf der [[Diskussion:RFM12_Protokoll_Stack|Diskussionsseite]] besprochen werden.&lt;br /&gt;
&lt;br /&gt;
Eine Referenz-Implementierung für den [[AVR]] wird bereitgestellt:&lt;br /&gt;
{| style=&amp;quot;border:1px dashed green&amp;quot;&lt;br /&gt;
|&#039;&#039;svn://mikrocontroller.net/rfm12/trunk/RFM12_Stack&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
;Implementierungskriterien&lt;br /&gt;
* Wo möglich werden [http://de.wikipedia.org/wiki/R%C3%BCckruffunktion Callback]-Funktionen anstatt [http://de.wikipedia.org/wiki/First_In_%E2%80%93_First_Out FIFOs] verwendet um RAM zu sparen.&lt;br /&gt;
* Interruptgesteuerter Ablauf des Stacks&lt;br /&gt;
* Funktionen sollten nicht blockieren&lt;br /&gt;
&lt;br /&gt;
== Layer 1: Physical ==&lt;br /&gt;
&lt;br /&gt;
[[Bild:RFM12 PHY StateMachine.svg|thumb|320px|Layer1 State Diagram]]&lt;br /&gt;
&lt;br /&gt;
Der Physical-Layer kümmert sich um die direkte Ansteuerung des RFM12. Alle Funktionen des Chips werden als Software-API bereitgestellt.&lt;br /&gt;
&lt;br /&gt;
Folgende Eigenschaften sind bereits vom RFM12 vorgegeben:&lt;br /&gt;
&lt;br /&gt;
* [http://de.wikipedia.org/wiki/ISM-Band 70cm Band (433MHz)]&lt;br /&gt;
* [http://de.wikipedia.org/wiki/Frequenzumtastung FSK]-Modulation&lt;br /&gt;
* Sync-Erkennung auf &#039;&#039;0x2D 0xD4&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Definiert werden muss jedoch noch:&lt;br /&gt;
&lt;br /&gt;
* Baudrate (Vorschlag: feste Kanal-Baudraten-Zuordnung)&lt;br /&gt;
* Zuordnung von Frequenzen zu [[#Kanalzuordnung|Kanälen]]&lt;br /&gt;
* Bandbreite der Kanäle&lt;br /&gt;
* Management der Sendeleistung/Empfangsempfindlichkeit&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;API&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
void RFM12_PHY_modeTX(void);&lt;br /&gt;
&lt;br /&gt;
void RFM12_PHY_modeRX(void);&lt;br /&gt;
&lt;br /&gt;
bool RFM12_PHY_busy(void);&lt;br /&gt;
&lt;br /&gt;
void RFM12_setBaudrate(uint32_t baud);&lt;br /&gt;
&lt;br /&gt;
void RFM12_setCenterFrequency(uint16_t freq);&lt;br /&gt;
&lt;br /&gt;
void RFM12_setDataFilter(bool autoLock, bool fastMode, bool analog, uint8_t dqdThres);&lt;br /&gt;
&lt;br /&gt;
void RFM12_setReceiverBandwidth(RFM12_VDI_t vdi, RFM12_RxBW_t bandwidth, RFM12_GAIN_t gain, RFM12_RSSI_t drssi);&lt;br /&gt;
&lt;br /&gt;
void RFM12_setPowerManagement(bool enRX, bool enBB, bool startTX, bool enSynth, bool enOSC, bool enBat, bool enWkT, bool clkOff);&lt;br /&gt;
&lt;br /&gt;
void RFM12_setTransmitPower(RFM12_Power_t power, RFM12_TxDev_t deviation);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Layer 2: Data Link ==&lt;br /&gt;
&lt;br /&gt;
=== Media Access Control (MAC) ===&lt;br /&gt;
&lt;br /&gt;
Hier noch ein paar Anregungen zur Verbesserung des MAC: [http://www.comsoc.org/livepubs/surveys/public/2q00issue/gummalla.html]&lt;br /&gt;
&lt;br /&gt;
Der MAC-Layer ist sehr einfach gehalten und regelt den Zugriff auf das Medium. Hier soll ein [http://de.wikipedia.org/wiki/CSMA-CA CSMA/CA] Verfahren eingesetzt werden.&lt;br /&gt;
&lt;br /&gt;
# Im Grundzustand befindet sich der RFM12 im Empfangsmodus und wartet auf eine SYNC-Sequenz.&lt;br /&gt;
# Kommt eine Sendeanforderung, wird so lange gewartet bis das Medium frei ist, dann darf nach Ablauf einer (pseudo) zufälligen Zeitspanne gesendet werden.&lt;br /&gt;
# Wurde gerade ein Paket empfangen, darf sofort ein ACK gesendet werden.&lt;br /&gt;
# Die maximale Paketlänge beträgt 50ms. Die maximale Anzahl Bytes hängt daher von der Baudrate ab.&lt;br /&gt;
&lt;br /&gt;
Der Frameaufbau ist teilweise vom RFM12 vorgegeben (SYNC-Erkennung). Der Start-Of-Frame (SOF) dient der Synchronisation. Als End-Of-Frame (EOF) wird ebenfalls die Sequenz &#039;&#039;0xAA&#039;&#039; verwendet. Diese darf im Datenteil nicht vorkommen!&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|+ MAC Frameaufbau&lt;br /&gt;
|-&lt;br /&gt;
!&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; | SOF&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; | Sync&lt;br /&gt;
! &#039;&#039;n Byte Daten&#039;&#039;&lt;br /&gt;
! EOF&lt;br /&gt;
|----&lt;br /&gt;
! Bits&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; | 16 || colspan=&amp;quot;2&amp;quot; | 16 || 0 - 8*n    || 8&lt;br /&gt;
|----&lt;br /&gt;
! Wert&lt;br /&gt;
| 0xAA || 0xAA     || 0x2D || 0xD4     || &#039;&#039;Daten&#039;&#039;  || 0xAA&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;API&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
void RFM12_MAC_setChannel(uint8_t channel);&lt;br /&gt;
&lt;br /&gt;
bool RFM12_MAC_isReceiving(void);&lt;br /&gt;
&lt;br /&gt;
bool RFM12_MAC_mediaBusy(void);&lt;br /&gt;
&lt;br /&gt;
void RFM12_MAC_startCtrlTransmission(void);&lt;br /&gt;
&lt;br /&gt;
void RFM12_MAC_endCtrlTransmission(void);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Logical Link Control (LLC) ===&lt;br /&gt;
&lt;br /&gt;
Der LLC-Layer kümmert sich um die Sicherung der zu übertragenden Daten.&lt;br /&gt;
Außerdem können Geräte direkt mit ihrer Adresse (7-Bit) angesprochen werden.&lt;br /&gt;
&lt;br /&gt;
;[http://de.wikipedia.org/wiki/Vorw%C3%A4rtsfehlerkorrektur FEC]&lt;br /&gt;
:Alle Bytes werden auf eine [[#Hamming-Tabelle|16-Bit Hamming-Sequenz]] erweitert, wodurch die Datenrate halbiert wird.&lt;br /&gt;
:Dies erlaubt es einzelne Bitfehler zu korrigieren.&lt;br /&gt;
:Bei zu vielen Fehlern können diese jedoch nicht erkannt werden.&lt;br /&gt;
:Im Hamming-Code kommt die Sequenz &#039;&#039;0xAA&#039;&#039; nicht vor (siehe MAC-Layer).&lt;br /&gt;
:Die FEC sorgt außerdem dafür, dass genügend 0-1 Transitionen vorkommen. So kann der Empfänger den Takt auch bei langen Paketen besser halten.&lt;br /&gt;
&lt;br /&gt;
;[http://de.wikipedia.org/wiki/Cyclic_Redundancy_Check CRC]&lt;br /&gt;
:Der gesamte Frame wird nochmals durch eine Checksumme gesichert. (CRC-8: &#039;&#039;x&amp;lt;sup&amp;gt;8&amp;lt;/sup&amp;gt; + x&amp;lt;sup&amp;gt;5&amp;lt;/sup&amp;gt; + x&amp;lt;sup&amp;gt;4&amp;lt;/sup&amp;gt; + 1&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
;Version&lt;br /&gt;
:Das Versionsfeld gibt die verwendete Version an (aktuell ist Version 1 = 0b00).&lt;br /&gt;
:Wenn die Version nicht unterstützt ist, wird der Empfang abgebrochen.&lt;br /&gt;
&lt;br /&gt;
;Adressierung&lt;br /&gt;
:Broadcast (0xff) an alle Geräte (immer ohne ACK)&lt;br /&gt;
:127 Multicast-Gruppen (0x80 - 0xfe)&lt;br /&gt;
:128 Geräteadressen (0x00 - 0x7f) (mit oder ohne ACK)&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|+ LLC Frameaufbau &#039;&#039;(Version 1)&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
!&lt;br /&gt;
! Version&lt;br /&gt;
! need ACK&lt;br /&gt;
! is ACK&lt;br /&gt;
! TypeID&lt;br /&gt;
! Empfänger&lt;br /&gt;
! Sender&lt;br /&gt;
! &#039;&#039;0-m Byte Daten&#039;&#039;&lt;br /&gt;
! CRC-8&lt;br /&gt;
|----&lt;br /&gt;
! Bits (vor FEC)&lt;br /&gt;
| 2 || 1 || 1 || 4 || 8      || 8      || 0 - 8*m || 8&lt;br /&gt;
|-&lt;br /&gt;
! Bits (nach FEC)&lt;br /&gt;
| 4 || 2 || 2 || 8 || 16     || 16     || 0 - 16*m || 16&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039; API &#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
void RFM12_LLC_registerType(RFM12_ProtocolID_t typeID, RFM12_L3_Protocol_t proto);&lt;br /&gt;
&lt;br /&gt;
uint8_t RFM12_LLC_sendFrame(RFM12_ProtocolID_t proto, uint8_t receiver, bool requireACK);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Layer 3: Network ==&lt;br /&gt;
&lt;br /&gt;
Für den Network-Layer werden nur einige Beispiele angeführt. Ab hier können beliebige eigene Protokolle eingesetzt werden. Das verwendete Protokoll wird durch die &#039;&#039;TypeID&#039;&#039; im LLC-Layer angegeben. Die Layer-3-Protokolle sollten nach Möglichkeit nur über die LLC-API mit dem Rest des Stacks kommunizieren.&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;TypeID&#039;&#039;s sind wie folgt definiert:&lt;br /&gt;
&lt;br /&gt;
=== Typ 0: Management ===&lt;br /&gt;
&lt;br /&gt;
Management Protokoll:&lt;br /&gt;
&lt;br /&gt;
* Muss immer implementiert sein&lt;br /&gt;
* Sollte ähnliche Funktionen bieten wie das Service Discovery Protocol (SDP) bei Bluetooth&lt;br /&gt;
* Unterscheidung Request / Response&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot;&lt;br /&gt;
|+ Nachrichten&lt;br /&gt;
|-&lt;br /&gt;
! ID   || Request          || Response&lt;br /&gt;
|-&lt;br /&gt;
| 0x00 || Device Discovery || Device Information&lt;br /&gt;
|-&lt;br /&gt;
| 0x01 || Available Layer 3 Protos || Protocol Information&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot;&lt;br /&gt;
|+ Management Frameaufbau&lt;br /&gt;
|-&lt;br /&gt;
! || Req/Res || ID ||&lt;br /&gt;
|-&lt;br /&gt;
! Bits&lt;br /&gt;
|      1     ||  7 ||&lt;br /&gt;
|}&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Typ 1: Bytestream ===&lt;br /&gt;
&lt;br /&gt;
Die Einteilung in Pakete wird aufgehoben. Daten kommen 1:1 in der Reihenfolge an, wie sie gesendet wurden.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;API&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
void RFM12_Serial_setPeer(uint8_t peer);&lt;br /&gt;
&lt;br /&gt;
bool RFM12_Serial_txAvailable(void);&lt;br /&gt;
&lt;br /&gt;
void RFM12_Serial_txData(uint8_t data);&lt;br /&gt;
&lt;br /&gt;
bool RFM12_Serial_rxAvailable(void);&lt;br /&gt;
&lt;br /&gt;
uint8_t RFM12_Serial_rxData(void);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Typ 3: IPv4 ===&lt;br /&gt;
&lt;br /&gt;
z.B. [http://www.sics.se/~adam/uip/index.php/Main_Page uIP TCP/IP Stack] von Adam Dunkels &amp;lt;adam@dunkels.com&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Anhänge ==&lt;br /&gt;
&lt;br /&gt;
=== Sequenzdiagramme ===&lt;br /&gt;
&lt;br /&gt;
Empfang:&lt;br /&gt;
[[Bild:RFM12 RX Sequence.svg|center|800px|RX Sequenz]]&lt;br /&gt;
&lt;br /&gt;
Senden:&lt;br /&gt;
[[Bild:RFM12 TX Sequence.svg|center|800px|TX Sequenz]]&lt;br /&gt;
&lt;br /&gt;
=== Frames ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Beachte:&#039;&#039;&#039; Durch die Hamming-Codierung sind alle Bytes innerhalb des MAC-Layer doppelt so lang wie angegeben!&lt;br /&gt;
{|&lt;br /&gt;
! bgcolor=&amp;quot;#9fffa8&amp;quot; | MAC || bgcolor=&amp;quot;#a9f3f2&amp;quot; | LLC || bgcolor=&amp;quot;#d28787&amp;quot; | L3&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; align=&amp;quot;center&amp;quot; style=&amp;quot;text-align:center&amp;quot;&lt;br /&gt;
|+ Frameaufbau&lt;br /&gt;
|-&lt;br /&gt;
!&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; bgcolor=&amp;quot;#9fffa8&amp;quot; | SOF&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; bgcolor=&amp;quot;#9fffa8&amp;quot; | Sync&lt;br /&gt;
! bgcolor=&amp;quot;#a9f3f2&amp;quot; | Empfänger&lt;br /&gt;
! bgcolor=&amp;quot;#a9f3f2&amp;quot; | Sender&lt;br /&gt;
! bgcolor=&amp;quot;#a9f3f2&amp;quot; | need ACK | is ACK | | | TypeID&lt;br /&gt;
! bgcolor=&amp;quot;#d28787&amp;quot; | &#039;&#039;0-28 Byte Daten&#039;&#039;&lt;br /&gt;
! bgcolor=&amp;quot;#a9f3f2&amp;quot; | CRC-8&lt;br /&gt;
! bgcolor=&amp;quot;#9fffa8&amp;quot; | EOF&lt;br /&gt;
|----&lt;br /&gt;
! Bits&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; bgcolor=&amp;quot;#9fffa8&amp;quot; | 16 || colspan=&amp;quot;2&amp;quot; bgcolor=&amp;quot;#9fffa8&amp;quot; | 16&lt;br /&gt;
| bgcolor=&amp;quot;#a9f3f2&amp;quot; | 8 || bgcolor=&amp;quot;#a9f3f2&amp;quot; | 8 || bgcolor=&amp;quot;#a9f3f2&amp;quot; | &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; 1 &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; | &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; 1 &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; |1|1| &amp;amp;nbsp;&amp;amp;nbsp; 4 &amp;amp;nbsp;&amp;amp;nbsp;&lt;br /&gt;
| bgcolor=&amp;quot;#d28787&amp;quot; | 0-224&lt;br /&gt;
| bgcolor=&amp;quot;#a9f3f2&amp;quot; | 8&lt;br /&gt;
| bgcolor=&amp;quot;#9fffa8&amp;quot; | 8&lt;br /&gt;
|----&lt;br /&gt;
! Wert&lt;br /&gt;
| bgcolor=&amp;quot;#9fffa8&amp;quot; | 0xAA || bgcolor=&amp;quot;#9fffa8&amp;quot; | 0xAA || bgcolor=&amp;quot;#9fffa8&amp;quot; | 0x2D || bgcolor=&amp;quot;#9fffa8&amp;quot; | 0xD4&lt;br /&gt;
| bgcolor=&amp;quot;#a9f3f2&amp;quot; | || bgcolor=&amp;quot;#a9f3f2&amp;quot; | || bgcolor=&amp;quot;#a9f3f2&amp;quot; | &lt;br /&gt;
| bgcolor=&amp;quot;#d28787&amp;quot; | &lt;br /&gt;
| bgcolor=&amp;quot;#a9f3f2&amp;quot; |&lt;br /&gt;
| bgcolor=&amp;quot;#9fffa8&amp;quot; | 0xAA&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Kanalzuordnung ===&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; align=&amp;quot;center&amp;quot; style=&amp;quot;text-align:right;&amp;quot;&lt;br /&gt;
|+ 433MHz Band&lt;br /&gt;
|-&lt;br /&gt;
! Kanal&lt;br /&gt;
| 0 || 1 || 2 || 3 || 4 || 5 || 6 || 7 || 8 || 9 || 10 || 11 || 12 || 13 || 14 || 15&lt;br /&gt;
|-&lt;br /&gt;
! Mittenfrequenz&lt;br /&gt;
|  431.0 || 431.5 || 432.0 || 432.5 || 433.0 || 433.5 || 434.0 || 434.5 || 435.0 || 435.5 || 436.0 || 436.5 || 437.0 || 437.5 || 438.0 || 438.5&lt;br /&gt;
|-&lt;br /&gt;
! Baudrate&lt;br /&gt;
|   9.6k || 19.2k || 115.2k||  9.6k || 19.2k || 115.2k||  9.6k || 19.2k ||115.2k ||  9.6k || 19.2k || 115.2k||  9.6k || 19.2k || 115.2k||  9.6k&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Hamming-Tabelle ===&lt;br /&gt;
&lt;br /&gt;
==== Encodieren ====&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;3&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|&lt;br /&gt;
! colspan=&amp;quot;4&amp;quot; | Algorithmus&lt;br /&gt;
! colspan=&amp;quot;4&amp;quot; | Beispiel&lt;br /&gt;
|-&lt;br /&gt;
| 1:&lt;br /&gt;
| width=&amp;quot;80&amp;quot; |&lt;br /&gt;
| width=&amp;quot;160&amp;quot; colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 8-Bit Wert&lt;br /&gt;
| width=&amp;quot;160&amp;quot; colspan=&amp;quot;2&amp;quot; |&lt;br /&gt;
| width=&amp;quot;160&amp;quot; colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 10010110&lt;br /&gt;
| width=&amp;quot;80&amp;quot; |&lt;br /&gt;
|-&lt;br /&gt;
| 2: || || align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 4-7 ||  align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 0-3 || colspan=&amp;quot;2&amp;quot; | ||  align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 1001 || align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 0110 || &lt;br /&gt;
|-&lt;br /&gt;
| 3:&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | HammingE[(4-7)]&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | HammingE[(0-3)]&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 0xC7&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 0x38&lt;br /&gt;
|-&lt;br /&gt;
| 4:&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | high&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | low&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 11000111&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 00111000&lt;br /&gt;
|-&lt;br /&gt;
| 5:&lt;br /&gt;
| colspan=&amp;quot;4&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 16-Bit Codewort&lt;br /&gt;
| colspan=&amp;quot;4&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 11000111 00111000&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;3&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|+ HammingE&lt;br /&gt;
|-&lt;br /&gt;
!  0 || 1 || 2  || 3 || 4 || 5 || 6 || 7 || 8 || 9 || A || B || C || D || E || F&lt;br /&gt;
|-&lt;br /&gt;
|bgcolor=&amp;quot;#ff0000&amp;quot;|0x15||bgcolor=&amp;quot;#ff1111&amp;quot;|0x02||bgcolor=&amp;quot;#ff2222&amp;quot;|0x49||bgcolor=&amp;quot;#ff3333&amp;quot;|0x5E||bgcolor=&amp;quot;#ff4444&amp;quot;|0x64||bgcolor=&amp;quot;#ff5555&amp;quot;|0x73||bgcolor=&amp;quot;#ff6666&amp;quot;|0x38||bgcolor=&amp;quot;#ff7777&amp;quot;|0x2F||bgcolor=&amp;quot;#ff8888&amp;quot;|0xD0||bgcolor=&amp;quot;#ff9999&amp;quot;|0xC7||bgcolor=&amp;quot;#ffaaaa&amp;quot;|0x8C||bgcolor=&amp;quot;#ffbbbb&amp;quot;|0x9B||bgcolor=&amp;quot;#ffcccc&amp;quot;|0xA1||bgcolor=&amp;quot;#ffdddd&amp;quot;|0xB6||bgcolor=&amp;quot;#ffeeee&amp;quot;|0xFD||bgcolor=&amp;quot;#ffffff&amp;quot;|0xEA&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Die Einträge in der Tabelle sind so gewählt, dass der Code den maximalen [http://de.wikipedia.org/wiki/Hamming-Abstand#Hamming-Abstand_eines_Codes Hamming-Abstand] von 4 Bit hat.&lt;br /&gt;
&lt;br /&gt;
==== Dekodieren ====&lt;br /&gt;
&lt;br /&gt;
In der Tabelle &#039;&#039;HammingD&#039;&#039; stehen nur 4-Bit breite Werte. Um einen 8-Bit Wert zu erhalten müssen also 2 Einträge aus der Tabelle ausgewählt werden.&lt;br /&gt;
&lt;br /&gt;
Wird nun ein 16-Bit Wert empfangen, bestimmt das High-Byte den ersten Eintrag, das Low-Byte den zweiten.&lt;br /&gt;
&lt;br /&gt;
Es können bis zu zwei gekippte Bits im High- und im Low-Byte korrigiert werden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;3&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|&lt;br /&gt;
! colspan=&amp;quot;4&amp;quot; | Algorithmus || colspan=&amp;quot;4&amp;quot; | Beispiel (mit Bitfehlern)&lt;br /&gt;
|-&lt;br /&gt;
| 1:&lt;br /&gt;
| colspan=&amp;quot;4&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 16-Bit Codewort&lt;br /&gt;
| colspan=&amp;quot;4&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 110&#039;&#039;&#039;1&#039;&#039;&#039;0111 001&#039;&#039;&#039;0&#039;&#039;&#039;100&#039;&#039;&#039;1&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 2:&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | high&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | low&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 110&#039;&#039;&#039;1&#039;&#039;&#039;0111&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 001&#039;&#039;&#039;0&#039;&#039;&#039;100&#039;&#039;&#039;1&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 3:&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | HammingD[high]&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | HammingD[low]&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 0x09&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 0x06&lt;br /&gt;
|-&lt;br /&gt;
| 4: || || align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 4-7&lt;br /&gt;
| align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 0-3 || &lt;br /&gt;
| || align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 1001&lt;br /&gt;
| align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 0110 || &lt;br /&gt;
|-&lt;br /&gt;
| 5:&lt;br /&gt;
| width=&amp;quot;80&amp;quot; |&lt;br /&gt;
| width=&amp;quot;160&amp;quot; colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 8-Bit Wert&lt;br /&gt;
| width=&amp;quot;80&amp;quot; | || width=&amp;quot;80&amp;quot; |&lt;br /&gt;
| width=&amp;quot;160&amp;quot; colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 10010110&lt;br /&gt;
| width=&amp;quot;80&amp;quot; |&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;3&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|+ HammingD&lt;br /&gt;
|-&lt;br /&gt;
!  || 0 || 1 || 2  || 3 || 4 || 5 || 6 || 7 || 8 || 9 || A || B || C || D || E || F&lt;br /&gt;
|-&lt;br /&gt;
! 0&lt;br /&gt;
|bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ffaaAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07&lt;br /&gt;
|-&lt;br /&gt;
! 1&lt;br /&gt;
|bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03&lt;br /&gt;
|-&lt;br /&gt;
! 2&lt;br /&gt;
|bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07&lt;br /&gt;
|-&lt;br /&gt;
! 3&lt;br /&gt;
|bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07&lt;br /&gt;
|-&lt;br /&gt;
! 4&lt;br /&gt;
|bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03&lt;br /&gt;
|-&lt;br /&gt;
! 5&lt;br /&gt;
|bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03&lt;br /&gt;
|-&lt;br /&gt;
! 6&lt;br /&gt;
|bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07&lt;br /&gt;
|-&lt;br /&gt;
! 7&lt;br /&gt;
|bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07&lt;br /&gt;
|-&lt;br /&gt;
! 8&lt;br /&gt;
|bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B&lt;br /&gt;
|-&lt;br /&gt;
! 9&lt;br /&gt;
|bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B&lt;br /&gt;
|-&lt;br /&gt;
! A&lt;br /&gt;
|bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07&lt;br /&gt;
|-&lt;br /&gt;
! B&lt;br /&gt;
|bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F&lt;br /&gt;
|-&lt;br /&gt;
! C&lt;br /&gt;
|bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09&lt;br /&gt;
|-&lt;br /&gt;
! D&lt;br /&gt;
|bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B&lt;br /&gt;
|-&lt;br /&gt;
! E&lt;br /&gt;
|bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F&lt;br /&gt;
|-&lt;br /&gt;
! F&lt;br /&gt;
|bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Funk]]&lt;br /&gt;
[[Kategorie:Wettbewerb]]&lt;/div&gt;</summary>
		<author><name>Thymythos</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=RFM12_Protokoll_Stack&amp;diff=32677</id>
		<title>RFM12 Protokoll Stack</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=RFM12_Protokoll_Stack&amp;diff=32677"/>
		<updated>2008-11-23T14:51:15Z</updated>

		<summary type="html">&lt;p&gt;Thymythos: /* Logical Link Control (LLC) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Bild:RFM12 Stack.svg|right]]&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel beschreibt einen [http://de.wikipedia.org/wiki/ISO/OSI ISO/OSI] Protokoll [http://de.wikipedia.org/wiki/Protokollstack Stack] für den [[RFM12]] Funkchip.&amp;lt;br/&amp;gt;&lt;br /&gt;
Einige Hardwarebeispiele finden sich in [[AVR RFM12]].&amp;lt;br/&amp;gt;&lt;br /&gt;
Fehler und Anregungen können gerne auf der [[Diskussion:RFM12_Protokoll_Stack|Diskussionsseite]] besprochen werden.&lt;br /&gt;
&lt;br /&gt;
Eine Referenz-Implementierung für den [[AVR]] wird bereitgestellt:&lt;br /&gt;
{| style=&amp;quot;border:1px dashed green&amp;quot;&lt;br /&gt;
|&#039;&#039;svn://mikrocontroller.net/rfm12/trunk/RFM12_Stack&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
;Implementierungskriterien&lt;br /&gt;
* Wo möglich werden [http://de.wikipedia.org/wiki/R%C3%BCckruffunktion Callback]-Funktionen anstatt [http://de.wikipedia.org/wiki/First_In_%E2%80%93_First_Out FIFOs] verwendet um RAM zu sparen.&lt;br /&gt;
* Interruptgesteuerter Ablauf des Stacks&lt;br /&gt;
* Funktionen sollten nicht blockieren&lt;br /&gt;
&lt;br /&gt;
== Layer 1: Physical ==&lt;br /&gt;
&lt;br /&gt;
[[Bild:RFM12 PHY StateMachine.svg|thumb|320px|Layer1 State Diagram]]&lt;br /&gt;
&lt;br /&gt;
Der Physical-Layer kümmert sich um die direkte Ansteuerung des RFM12. Alle Funktionen des Chips werden als Software-API bereitgestellt.&lt;br /&gt;
&lt;br /&gt;
Folgende Eigenschaften sind bereits vom RFM12 vorgegeben:&lt;br /&gt;
&lt;br /&gt;
* [http://de.wikipedia.org/wiki/ISM-Band 70cm Band (433MHz)]&lt;br /&gt;
* [http://de.wikipedia.org/wiki/Frequenzumtastung FSK]-Modulation&lt;br /&gt;
* Sync-Erkennung auf &#039;&#039;0x2D 0xD4&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Definiert werden muss jedoch noch:&lt;br /&gt;
&lt;br /&gt;
* Baudrate (Vorschlag: feste Kanal-Baudraten-Zuordnung)&lt;br /&gt;
* Zuordnung von Frequenzen zu [[#Kanalzuordnung|Kanälen]]&lt;br /&gt;
* Bandbreite der Kanäle&lt;br /&gt;
* Management der Sendeleistung/Empfangsempfindlichkeit&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;API&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
void RFM12_PHY_modeTX(void);&lt;br /&gt;
&lt;br /&gt;
void RFM12_PHY_modeRX(void);&lt;br /&gt;
&lt;br /&gt;
bool RFM12_PHY_busy(void);&lt;br /&gt;
&lt;br /&gt;
void RFM12_setBaudrate(uint32_t baud);&lt;br /&gt;
&lt;br /&gt;
void RFM12_setCenterFrequency(uint16_t freq);&lt;br /&gt;
&lt;br /&gt;
void RFM12_setDataFilter(bool autoLock, bool fastMode, bool analog, uint8_t dqdThres);&lt;br /&gt;
&lt;br /&gt;
void RFM12_setReceiverBandwidth(RFM12_VDI_t vdi, RFM12_RxBW_t bandwidth, RFM12_GAIN_t gain, RFM12_RSSI_t drssi);&lt;br /&gt;
&lt;br /&gt;
void RFM12_setPowerManagement(bool enRX, bool enBB, bool startTX, bool enSynth, bool enOSC, bool enBat, bool enWkT, bool clkOff);&lt;br /&gt;
&lt;br /&gt;
void RFM12_setTransmitPower(RFM12_Power_t power, RFM12_TxDev_t deviation);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Layer 2: Data Link ==&lt;br /&gt;
&lt;br /&gt;
=== Media Access Control (MAC) ===&lt;br /&gt;
&lt;br /&gt;
Hier noch ein paar Anregungen zur Verbesserung des MAC: [http://www.comsoc.org/livepubs/surveys/public/2q00issue/gummalla.html]&lt;br /&gt;
&lt;br /&gt;
Der MAC-Layer ist sehr einfach gehalten und regelt den Zugriff auf das Medium. Hier soll ein [http://de.wikipedia.org/wiki/CSMA-CA CSMA/CA] Verfahren eingesetzt werden.&lt;br /&gt;
&lt;br /&gt;
# Im Grundzustand befindet sich der RFM12 im Empfangsmodus und wartet auf eine SYNC-Sequenz.&lt;br /&gt;
# Kommt eine Sendeanforderung, wird so lange gewartet bis das Medium frei ist, dann darf nach Ablauf einer (pseudo) zufälligen Zeitspanne gesendet werden.&lt;br /&gt;
# Wurde gerade ein Paket empfangen, darf sofort ein ACK gesendet werden.&lt;br /&gt;
# Die maximale Paketlänge beträgt 50ms. Die maximale Anzahl Bytes hängt daher von der Baudrate ab.&lt;br /&gt;
&lt;br /&gt;
Der Frameaufbau ist teilweise vom RFM12 vorgegeben (SYNC-Erkennung). Der Start-Of-Frame (SOF) dient der Synchronisation. Als End-Of-Frame (EOF) wird ebenfalls die Sequenz &#039;&#039;0xAA&#039;&#039; verwendet. Diese darf im Datenteil nicht vorkommen!&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|+ MAC Frameaufbau&lt;br /&gt;
|-&lt;br /&gt;
!&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; | SOF&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; | Sync&lt;br /&gt;
! &#039;&#039;n Byte Daten&#039;&#039;&lt;br /&gt;
! EOF&lt;br /&gt;
|----&lt;br /&gt;
! Bits&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; | 16 || colspan=&amp;quot;2&amp;quot; | 16 || 0 - 8*n    || 8&lt;br /&gt;
|----&lt;br /&gt;
! Wert&lt;br /&gt;
| 0xAA || 0xAA     || 0x2D || 0xD4     || &#039;&#039;Daten&#039;&#039;  || 0xAA&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;API&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
void RFM12_MAC_setChannel(uint8_t channel);&lt;br /&gt;
&lt;br /&gt;
bool RFM12_MAC_isReceiving(void);&lt;br /&gt;
&lt;br /&gt;
bool RFM12_MAC_mediaBusy(void);&lt;br /&gt;
&lt;br /&gt;
void RFM12_MAC_startCtrlTransmission(void);&lt;br /&gt;
&lt;br /&gt;
void RFM12_MAC_endCtrlTransmission(void);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Logical Link Control (LLC) ===&lt;br /&gt;
&lt;br /&gt;
Der LLC-Layer kümmert sich um die Sicherung der zu übertragenden Daten.&lt;br /&gt;
Außerdem können Geräte direkt mit ihrer Adresse (7-Bit) angesprochen werden.&lt;br /&gt;
&lt;br /&gt;
;[http://de.wikipedia.org/wiki/Vorw%C3%A4rtsfehlerkorrektur FEC]&lt;br /&gt;
:Alle Bytes werden auf eine [[#Hamming-Tabelle|16-Bit Hamming-Sequenz]] erweitert, wodurch die Datenrate halbiert wird.&lt;br /&gt;
:Dies erlaubt es einzelne Bitfehler zu korrigieren.&lt;br /&gt;
:Bei zu vielen Fehlern können diese jedoch nicht erkannt werden.&lt;br /&gt;
:Im Hamming-Code kommt die Sequenz &#039;&#039;0xAA&#039;&#039; nicht vor (siehe MAC-Layer).&lt;br /&gt;
:Die FEC sorgt außerdem dafür, dass genügend 0-1 Transitionen vorkommen. So kann der Empfänger den Takt auch bei langen Paketen besser halten.&lt;br /&gt;
&lt;br /&gt;
;[http://de.wikipedia.org/wiki/Cyclic_Redundancy_Check CRC]&lt;br /&gt;
:Der gesamte Frame wird nochmals durch eine Checksumme gesichert. (CRC-8: &#039;&#039;x&amp;lt;sup&amp;gt;8&amp;lt;/sup&amp;gt; + x&amp;lt;sup&amp;gt;5&amp;lt;/sup&amp;gt; + x&amp;lt;sup&amp;gt;4&amp;lt;/sup&amp;gt; + 1&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
;Adressierung&lt;br /&gt;
:Broadcast (0xff) an alle Geräte (immer ohne ACK)&lt;br /&gt;
:127 Multicast-Gruppen (0x80 - 0xfe)&lt;br /&gt;
:128 Geräteadressen (0x00 - 0x7f) (mit oder ohne ACK)&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|+ LLC Frameaufbau&lt;br /&gt;
|-&lt;br /&gt;
!&lt;br /&gt;
! Empfänger&lt;br /&gt;
! Sender&lt;br /&gt;
! need ACK&lt;br /&gt;
! is ACK&lt;br /&gt;
!&lt;br /&gt;
!&lt;br /&gt;
! TypeID&lt;br /&gt;
! &#039;&#039;0-28 Byte Daten&#039;&#039;&lt;br /&gt;
! CRC-8&lt;br /&gt;
|----&lt;br /&gt;
! Bits (vor FEC)&lt;br /&gt;
| 8      || 8      || 1 || 1 || 1 || 1 || 4 || 0-224 || 8&lt;br /&gt;
|-&lt;br /&gt;
! Bits (nach FEC)&lt;br /&gt;
| 16     || 16     || 2 || 2 || 2 || 2 || 8 || 0-448 || 16&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039; API &#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
void RFM12_LLC_registerType(RFM12_ProtocolID_t typeID, RFM12_L3_Protocol_t proto);&lt;br /&gt;
&lt;br /&gt;
uint8_t RFM12_LLC_sendFrame(RFM12_ProtocolID_t proto, uint8_t receiver, bool requireACK);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Layer 3: Network ==&lt;br /&gt;
&lt;br /&gt;
Für den Network-Layer werden nur einige Beispiele angeführt. Ab hier können beliebige eigene Protokolle eingesetzt werden. Das verwendete Protokoll wird durch die &#039;&#039;TypeID&#039;&#039; im LLC-Layer angegeben. Die Layer-3-Protokolle sollten nach Möglichkeit nur über die LLC-API mit dem Rest des Stacks kommunizieren.&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;TypeID&#039;&#039;s sind wie folgt definiert:&lt;br /&gt;
&lt;br /&gt;
=== Typ 0: Management ===&lt;br /&gt;
&lt;br /&gt;
Management Protokoll:&lt;br /&gt;
&lt;br /&gt;
* Muss immer implementiert sein&lt;br /&gt;
* Sollte ähnliche Funktionen bieten wie das Service Discovery Protocol (SDP) bei Bluetooth&lt;br /&gt;
* Unterscheidung Request / Response&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot;&lt;br /&gt;
|+ Nachrichten&lt;br /&gt;
|-&lt;br /&gt;
! ID   || Request          || Response&lt;br /&gt;
|-&lt;br /&gt;
| 0x00 || Device Discovery || Device Information&lt;br /&gt;
|-&lt;br /&gt;
| 0x01 || Available Layer 3 Protos || Protocol Information&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot;&lt;br /&gt;
|+ Management Frameaufbau&lt;br /&gt;
|-&lt;br /&gt;
! || Req/Res || ID ||&lt;br /&gt;
|-&lt;br /&gt;
! Bits&lt;br /&gt;
|      1     ||  7 ||&lt;br /&gt;
|}&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Typ 1: Bytestream ===&lt;br /&gt;
&lt;br /&gt;
Die Einteilung in Pakete wird aufgehoben. Daten kommen 1:1 in der Reihenfolge an, wie sie gesendet wurden.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;API&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
void RFM12_Serial_setPeer(uint8_t peer);&lt;br /&gt;
&lt;br /&gt;
bool RFM12_Serial_txAvailable(void);&lt;br /&gt;
&lt;br /&gt;
void RFM12_Serial_txData(uint8_t data);&lt;br /&gt;
&lt;br /&gt;
bool RFM12_Serial_rxAvailable(void);&lt;br /&gt;
&lt;br /&gt;
uint8_t RFM12_Serial_rxData(void);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Typ 3: IPv4 ===&lt;br /&gt;
&lt;br /&gt;
z.B. [http://www.sics.se/~adam/uip/index.php/Main_Page uIP TCP/IP Stack] von Adam Dunkels &amp;lt;adam@dunkels.com&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Anhänge ==&lt;br /&gt;
&lt;br /&gt;
=== Sequenzdiagramme ===&lt;br /&gt;
&lt;br /&gt;
Empfang:&lt;br /&gt;
[[Bild:RFM12 RX Sequence.svg|center|800px|RX Sequenz]]&lt;br /&gt;
&lt;br /&gt;
Senden:&lt;br /&gt;
[[Bild:RFM12 TX Sequence.svg|center|800px|TX Sequenz]]&lt;br /&gt;
&lt;br /&gt;
=== Frames ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Beachte:&#039;&#039;&#039; Durch die Hamming-Codierung sind alle Bytes innerhalb des MAC-Layer doppelt so lang wie angegeben!&lt;br /&gt;
{|&lt;br /&gt;
! bgcolor=&amp;quot;#9fffa8&amp;quot; | MAC || bgcolor=&amp;quot;#a9f3f2&amp;quot; | LLC || bgcolor=&amp;quot;#d28787&amp;quot; | L3&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; align=&amp;quot;center&amp;quot; style=&amp;quot;text-align:center&amp;quot;&lt;br /&gt;
|+ Frameaufbau&lt;br /&gt;
|-&lt;br /&gt;
!&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; bgcolor=&amp;quot;#9fffa8&amp;quot; | SOF&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; bgcolor=&amp;quot;#9fffa8&amp;quot; | Sync&lt;br /&gt;
! bgcolor=&amp;quot;#a9f3f2&amp;quot; | Empfänger&lt;br /&gt;
! bgcolor=&amp;quot;#a9f3f2&amp;quot; | Sender&lt;br /&gt;
! bgcolor=&amp;quot;#a9f3f2&amp;quot; | need ACK | is ACK | | | TypeID&lt;br /&gt;
! bgcolor=&amp;quot;#d28787&amp;quot; | &#039;&#039;0-28 Byte Daten&#039;&#039;&lt;br /&gt;
! bgcolor=&amp;quot;#a9f3f2&amp;quot; | CRC-8&lt;br /&gt;
! bgcolor=&amp;quot;#9fffa8&amp;quot; | EOF&lt;br /&gt;
|----&lt;br /&gt;
! Bits&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; bgcolor=&amp;quot;#9fffa8&amp;quot; | 16 || colspan=&amp;quot;2&amp;quot; bgcolor=&amp;quot;#9fffa8&amp;quot; | 16&lt;br /&gt;
| bgcolor=&amp;quot;#a9f3f2&amp;quot; | 8 || bgcolor=&amp;quot;#a9f3f2&amp;quot; | 8 || bgcolor=&amp;quot;#a9f3f2&amp;quot; | &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; 1 &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; | &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; 1 &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; |1|1| &amp;amp;nbsp;&amp;amp;nbsp; 4 &amp;amp;nbsp;&amp;amp;nbsp;&lt;br /&gt;
| bgcolor=&amp;quot;#d28787&amp;quot; | 0-224&lt;br /&gt;
| bgcolor=&amp;quot;#a9f3f2&amp;quot; | 8&lt;br /&gt;
| bgcolor=&amp;quot;#9fffa8&amp;quot; | 8&lt;br /&gt;
|----&lt;br /&gt;
! Wert&lt;br /&gt;
| bgcolor=&amp;quot;#9fffa8&amp;quot; | 0xAA || bgcolor=&amp;quot;#9fffa8&amp;quot; | 0xAA || bgcolor=&amp;quot;#9fffa8&amp;quot; | 0x2D || bgcolor=&amp;quot;#9fffa8&amp;quot; | 0xD4&lt;br /&gt;
| bgcolor=&amp;quot;#a9f3f2&amp;quot; | || bgcolor=&amp;quot;#a9f3f2&amp;quot; | || bgcolor=&amp;quot;#a9f3f2&amp;quot; | &lt;br /&gt;
| bgcolor=&amp;quot;#d28787&amp;quot; | &lt;br /&gt;
| bgcolor=&amp;quot;#a9f3f2&amp;quot; |&lt;br /&gt;
| bgcolor=&amp;quot;#9fffa8&amp;quot; | 0xAA&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Kanalzuordnung ===&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; align=&amp;quot;center&amp;quot; style=&amp;quot;text-align:right;&amp;quot;&lt;br /&gt;
|+ 433MHz Band&lt;br /&gt;
|-&lt;br /&gt;
! Kanal&lt;br /&gt;
| 0 || 1 || 2 || 3 || 4 || 5 || 6 || 7 || 8 || 9 || 10 || 11 || 12 || 13 || 14 || 15&lt;br /&gt;
|-&lt;br /&gt;
! Mittenfrequenz&lt;br /&gt;
|  431.0 || 431.5 || 432.0 || 432.5 || 433.0 || 433.5 || 434.0 || 434.5 || 435.0 || 435.5 || 436.0 || 436.5 || 437.0 || 437.5 || 438.0 || 438.5&lt;br /&gt;
|-&lt;br /&gt;
! Baudrate&lt;br /&gt;
|   9.6k || 19.2k || 115.2k||  9.6k || 19.2k || 115.2k||  9.6k || 19.2k ||115.2k ||  9.6k || 19.2k || 115.2k||  9.6k || 19.2k || 115.2k||  9.6k&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Hamming-Tabelle ===&lt;br /&gt;
&lt;br /&gt;
==== Encodieren ====&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;3&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|&lt;br /&gt;
! colspan=&amp;quot;4&amp;quot; | Algorithmus&lt;br /&gt;
! colspan=&amp;quot;4&amp;quot; | Beispiel&lt;br /&gt;
|-&lt;br /&gt;
| 1:&lt;br /&gt;
| width=&amp;quot;80&amp;quot; |&lt;br /&gt;
| width=&amp;quot;160&amp;quot; colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 8-Bit Wert&lt;br /&gt;
| width=&amp;quot;160&amp;quot; colspan=&amp;quot;2&amp;quot; |&lt;br /&gt;
| width=&amp;quot;160&amp;quot; colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 10010110&lt;br /&gt;
| width=&amp;quot;80&amp;quot; |&lt;br /&gt;
|-&lt;br /&gt;
| 2: || || align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 4-7 ||  align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 0-3 || colspan=&amp;quot;2&amp;quot; | ||  align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 1001 || align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 0110 || &lt;br /&gt;
|-&lt;br /&gt;
| 3:&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | HammingE[(4-7)]&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | HammingE[(0-3)]&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 0xC7&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 0x38&lt;br /&gt;
|-&lt;br /&gt;
| 4:&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | high&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | low&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 11000111&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 00111000&lt;br /&gt;
|-&lt;br /&gt;
| 5:&lt;br /&gt;
| colspan=&amp;quot;4&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 16-Bit Codewort&lt;br /&gt;
| colspan=&amp;quot;4&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 11000111 00111000&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;3&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|+ HammingE&lt;br /&gt;
|-&lt;br /&gt;
!  0 || 1 || 2  || 3 || 4 || 5 || 6 || 7 || 8 || 9 || A || B || C || D || E || F&lt;br /&gt;
|-&lt;br /&gt;
|bgcolor=&amp;quot;#ff0000&amp;quot;|0x15||bgcolor=&amp;quot;#ff1111&amp;quot;|0x02||bgcolor=&amp;quot;#ff2222&amp;quot;|0x49||bgcolor=&amp;quot;#ff3333&amp;quot;|0x5E||bgcolor=&amp;quot;#ff4444&amp;quot;|0x64||bgcolor=&amp;quot;#ff5555&amp;quot;|0x73||bgcolor=&amp;quot;#ff6666&amp;quot;|0x38||bgcolor=&amp;quot;#ff7777&amp;quot;|0x2F||bgcolor=&amp;quot;#ff8888&amp;quot;|0xD0||bgcolor=&amp;quot;#ff9999&amp;quot;|0xC7||bgcolor=&amp;quot;#ffaaaa&amp;quot;|0x8C||bgcolor=&amp;quot;#ffbbbb&amp;quot;|0x9B||bgcolor=&amp;quot;#ffcccc&amp;quot;|0xA1||bgcolor=&amp;quot;#ffdddd&amp;quot;|0xB6||bgcolor=&amp;quot;#ffeeee&amp;quot;|0xFD||bgcolor=&amp;quot;#ffffff&amp;quot;|0xEA&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Die Einträge in der Tabelle sind so gewählt, dass der Code den maximalen [http://de.wikipedia.org/wiki/Hamming-Abstand#Hamming-Abstand_eines_Codes Hamming-Abstand] von 4 Bit hat.&lt;br /&gt;
&lt;br /&gt;
==== Dekodieren ====&lt;br /&gt;
&lt;br /&gt;
In der Tabelle &#039;&#039;HammingD&#039;&#039; stehen nur 4-Bit breite Werte. Um einen 8-Bit Wert zu erhalten müssen also 2 Einträge aus der Tabelle ausgewählt werden.&lt;br /&gt;
&lt;br /&gt;
Wird nun ein 16-Bit Wert empfangen, bestimmt das High-Byte den ersten Eintrag, das Low-Byte den zweiten.&lt;br /&gt;
&lt;br /&gt;
Es können bis zu zwei gekippte Bits im High- und im Low-Byte korrigiert werden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;3&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|&lt;br /&gt;
! colspan=&amp;quot;4&amp;quot; | Algorithmus || colspan=&amp;quot;4&amp;quot; | Beispiel (mit Bitfehlern)&lt;br /&gt;
|-&lt;br /&gt;
| 1:&lt;br /&gt;
| colspan=&amp;quot;4&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 16-Bit Codewort&lt;br /&gt;
| colspan=&amp;quot;4&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 110&#039;&#039;&#039;1&#039;&#039;&#039;0111 001&#039;&#039;&#039;0&#039;&#039;&#039;100&#039;&#039;&#039;1&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 2:&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | high&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | low&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 110&#039;&#039;&#039;1&#039;&#039;&#039;0111&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 001&#039;&#039;&#039;0&#039;&#039;&#039;100&#039;&#039;&#039;1&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 3:&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | HammingD[high]&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | HammingD[low]&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 0x09&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 0x06&lt;br /&gt;
|-&lt;br /&gt;
| 4: || || align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 4-7&lt;br /&gt;
| align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 0-3 || &lt;br /&gt;
| || align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 1001&lt;br /&gt;
| align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 0110 || &lt;br /&gt;
|-&lt;br /&gt;
| 5:&lt;br /&gt;
| width=&amp;quot;80&amp;quot; |&lt;br /&gt;
| width=&amp;quot;160&amp;quot; colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 8-Bit Wert&lt;br /&gt;
| width=&amp;quot;80&amp;quot; | || width=&amp;quot;80&amp;quot; |&lt;br /&gt;
| width=&amp;quot;160&amp;quot; colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 10010110&lt;br /&gt;
| width=&amp;quot;80&amp;quot; |&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;3&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|+ HammingD&lt;br /&gt;
|-&lt;br /&gt;
!  || 0 || 1 || 2  || 3 || 4 || 5 || 6 || 7 || 8 || 9 || A || B || C || D || E || F&lt;br /&gt;
|-&lt;br /&gt;
! 0&lt;br /&gt;
|bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ffaaAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07&lt;br /&gt;
|-&lt;br /&gt;
! 1&lt;br /&gt;
|bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03&lt;br /&gt;
|-&lt;br /&gt;
! 2&lt;br /&gt;
|bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07&lt;br /&gt;
|-&lt;br /&gt;
! 3&lt;br /&gt;
|bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07&lt;br /&gt;
|-&lt;br /&gt;
! 4&lt;br /&gt;
|bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03&lt;br /&gt;
|-&lt;br /&gt;
! 5&lt;br /&gt;
|bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03&lt;br /&gt;
|-&lt;br /&gt;
! 6&lt;br /&gt;
|bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07&lt;br /&gt;
|-&lt;br /&gt;
! 7&lt;br /&gt;
|bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07&lt;br /&gt;
|-&lt;br /&gt;
! 8&lt;br /&gt;
|bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B&lt;br /&gt;
|-&lt;br /&gt;
! 9&lt;br /&gt;
|bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B&lt;br /&gt;
|-&lt;br /&gt;
! A&lt;br /&gt;
|bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07&lt;br /&gt;
|-&lt;br /&gt;
! B&lt;br /&gt;
|bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F&lt;br /&gt;
|-&lt;br /&gt;
! C&lt;br /&gt;
|bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09&lt;br /&gt;
|-&lt;br /&gt;
! D&lt;br /&gt;
|bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B&lt;br /&gt;
|-&lt;br /&gt;
! E&lt;br /&gt;
|bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F&lt;br /&gt;
|-&lt;br /&gt;
! F&lt;br /&gt;
|bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Funk]]&lt;br /&gt;
[[Kategorie:Wettbewerb]]&lt;/div&gt;</summary>
		<author><name>Thymythos</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=RFM12_Protokoll_Stack&amp;diff=32676</id>
		<title>RFM12 Protokoll Stack</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=RFM12_Protokoll_Stack&amp;diff=32676"/>
		<updated>2008-11-23T14:43:02Z</updated>

		<summary type="html">&lt;p&gt;Thymythos: /* Media Access Control (MAC) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Bild:RFM12 Stack.svg|right]]&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel beschreibt einen [http://de.wikipedia.org/wiki/ISO/OSI ISO/OSI] Protokoll [http://de.wikipedia.org/wiki/Protokollstack Stack] für den [[RFM12]] Funkchip.&amp;lt;br/&amp;gt;&lt;br /&gt;
Einige Hardwarebeispiele finden sich in [[AVR RFM12]].&amp;lt;br/&amp;gt;&lt;br /&gt;
Fehler und Anregungen können gerne auf der [[Diskussion:RFM12_Protokoll_Stack|Diskussionsseite]] besprochen werden.&lt;br /&gt;
&lt;br /&gt;
Eine Referenz-Implementierung für den [[AVR]] wird bereitgestellt:&lt;br /&gt;
{| style=&amp;quot;border:1px dashed green&amp;quot;&lt;br /&gt;
|&#039;&#039;svn://mikrocontroller.net/rfm12/trunk/RFM12_Stack&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
;Implementierungskriterien&lt;br /&gt;
* Wo möglich werden [http://de.wikipedia.org/wiki/R%C3%BCckruffunktion Callback]-Funktionen anstatt [http://de.wikipedia.org/wiki/First_In_%E2%80%93_First_Out FIFOs] verwendet um RAM zu sparen.&lt;br /&gt;
* Interruptgesteuerter Ablauf des Stacks&lt;br /&gt;
* Funktionen sollten nicht blockieren&lt;br /&gt;
&lt;br /&gt;
== Layer 1: Physical ==&lt;br /&gt;
&lt;br /&gt;
[[Bild:RFM12 PHY StateMachine.svg|thumb|320px|Layer1 State Diagram]]&lt;br /&gt;
&lt;br /&gt;
Der Physical-Layer kümmert sich um die direkte Ansteuerung des RFM12. Alle Funktionen des Chips werden als Software-API bereitgestellt.&lt;br /&gt;
&lt;br /&gt;
Folgende Eigenschaften sind bereits vom RFM12 vorgegeben:&lt;br /&gt;
&lt;br /&gt;
* [http://de.wikipedia.org/wiki/ISM-Band 70cm Band (433MHz)]&lt;br /&gt;
* [http://de.wikipedia.org/wiki/Frequenzumtastung FSK]-Modulation&lt;br /&gt;
* Sync-Erkennung auf &#039;&#039;0x2D 0xD4&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Definiert werden muss jedoch noch:&lt;br /&gt;
&lt;br /&gt;
* Baudrate (Vorschlag: feste Kanal-Baudraten-Zuordnung)&lt;br /&gt;
* Zuordnung von Frequenzen zu [[#Kanalzuordnung|Kanälen]]&lt;br /&gt;
* Bandbreite der Kanäle&lt;br /&gt;
* Management der Sendeleistung/Empfangsempfindlichkeit&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;API&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
void RFM12_PHY_modeTX(void);&lt;br /&gt;
&lt;br /&gt;
void RFM12_PHY_modeRX(void);&lt;br /&gt;
&lt;br /&gt;
bool RFM12_PHY_busy(void);&lt;br /&gt;
&lt;br /&gt;
void RFM12_setBaudrate(uint32_t baud);&lt;br /&gt;
&lt;br /&gt;
void RFM12_setCenterFrequency(uint16_t freq);&lt;br /&gt;
&lt;br /&gt;
void RFM12_setDataFilter(bool autoLock, bool fastMode, bool analog, uint8_t dqdThres);&lt;br /&gt;
&lt;br /&gt;
void RFM12_setReceiverBandwidth(RFM12_VDI_t vdi, RFM12_RxBW_t bandwidth, RFM12_GAIN_t gain, RFM12_RSSI_t drssi);&lt;br /&gt;
&lt;br /&gt;
void RFM12_setPowerManagement(bool enRX, bool enBB, bool startTX, bool enSynth, bool enOSC, bool enBat, bool enWkT, bool clkOff);&lt;br /&gt;
&lt;br /&gt;
void RFM12_setTransmitPower(RFM12_Power_t power, RFM12_TxDev_t deviation);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Layer 2: Data Link ==&lt;br /&gt;
&lt;br /&gt;
=== Media Access Control (MAC) ===&lt;br /&gt;
&lt;br /&gt;
Hier noch ein paar Anregungen zur Verbesserung des MAC: [http://www.comsoc.org/livepubs/surveys/public/2q00issue/gummalla.html]&lt;br /&gt;
&lt;br /&gt;
Der MAC-Layer ist sehr einfach gehalten und regelt den Zugriff auf das Medium. Hier soll ein [http://de.wikipedia.org/wiki/CSMA-CA CSMA/CA] Verfahren eingesetzt werden.&lt;br /&gt;
&lt;br /&gt;
# Im Grundzustand befindet sich der RFM12 im Empfangsmodus und wartet auf eine SYNC-Sequenz.&lt;br /&gt;
# Kommt eine Sendeanforderung, wird so lange gewartet bis das Medium frei ist, dann darf nach Ablauf einer (pseudo) zufälligen Zeitspanne gesendet werden.&lt;br /&gt;
# Wurde gerade ein Paket empfangen, darf sofort ein ACK gesendet werden.&lt;br /&gt;
# Die maximale Paketlänge beträgt 50ms. Die maximale Anzahl Bytes hängt daher von der Baudrate ab.&lt;br /&gt;
&lt;br /&gt;
Der Frameaufbau ist teilweise vom RFM12 vorgegeben (SYNC-Erkennung). Der Start-Of-Frame (SOF) dient der Synchronisation. Als End-Of-Frame (EOF) wird ebenfalls die Sequenz &#039;&#039;0xAA&#039;&#039; verwendet. Diese darf im Datenteil nicht vorkommen!&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|+ MAC Frameaufbau&lt;br /&gt;
|-&lt;br /&gt;
!&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; | SOF&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; | Sync&lt;br /&gt;
! &#039;&#039;n Byte Daten&#039;&#039;&lt;br /&gt;
! EOF&lt;br /&gt;
|----&lt;br /&gt;
! Bits&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; | 16 || colspan=&amp;quot;2&amp;quot; | 16 || 0 - 8*n    || 8&lt;br /&gt;
|----&lt;br /&gt;
! Wert&lt;br /&gt;
| 0xAA || 0xAA     || 0x2D || 0xD4     || &#039;&#039;Daten&#039;&#039;  || 0xAA&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;API&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
void RFM12_MAC_setChannel(uint8_t channel);&lt;br /&gt;
&lt;br /&gt;
bool RFM12_MAC_isReceiving(void);&lt;br /&gt;
&lt;br /&gt;
bool RFM12_MAC_mediaBusy(void);&lt;br /&gt;
&lt;br /&gt;
void RFM12_MAC_startCtrlTransmission(void);&lt;br /&gt;
&lt;br /&gt;
void RFM12_MAC_endCtrlTransmission(void);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Logical Link Control (LLC) ===&lt;br /&gt;
&lt;br /&gt;
Der LLC-Layer kümmert sich um die Sicherung der zu übertragenden Daten.&lt;br /&gt;
Außerdem können Geräte direkt mit ihrer Adresse (8-Bit) angesprochen werden.&lt;br /&gt;
&lt;br /&gt;
;[http://de.wikipedia.org/wiki/Vorw%C3%A4rtsfehlerkorrektur FEC]&lt;br /&gt;
:Alle Bytes werden auf eine [[#Hamming-Tabelle|16-Bit Hamming-Sequenz]] erweitert, wodurch die Datenrate halbiert wird.&lt;br /&gt;
:Dies erlaubt es einzelne Bitfehler zu korrigieren.&lt;br /&gt;
:Bei zu vielen Fehlern können diese jedoch nicht erkannt werden.&lt;br /&gt;
:Im Hamming-Code kommt die Sequenz &#039;&#039;0xAA&#039;&#039; nicht vor (siehe MAC-Layer).&lt;br /&gt;
:Die FEC sorgt außerdem dafür, dass genügend 0-1 Transitionen vorkommen. So kann der Empfänger den Takt auch bei langen Paketen besser halten.&lt;br /&gt;
&lt;br /&gt;
;[http://de.wikipedia.org/wiki/Cyclic_Redundancy_Check CRC]&lt;br /&gt;
:Der gesamte Frame wird nochmals durch eine Checksumme gesichert. (CRC-8: &#039;&#039;x&amp;lt;sup&amp;gt;8&amp;lt;/sup&amp;gt; + x&amp;lt;sup&amp;gt;5&amp;lt;/sup&amp;gt; + x&amp;lt;sup&amp;gt;4&amp;lt;/sup&amp;gt; + 1&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Es werden mehrere Frame-Typen zur Verfügung gestellt:&lt;br /&gt;
&lt;br /&gt;
* Broadcast an alle Geräte (immer ohne ACK)&lt;br /&gt;
* Nachricht an ein bestimmtes Gerät (mit oder ohne ACK)&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|+ LLC Frameaufbau&lt;br /&gt;
|-&lt;br /&gt;
!&lt;br /&gt;
! Empfänger&lt;br /&gt;
! Sender&lt;br /&gt;
! need ACK&lt;br /&gt;
! is ACK&lt;br /&gt;
!&lt;br /&gt;
!&lt;br /&gt;
! TypeID&lt;br /&gt;
! &#039;&#039;0-28 Byte Daten&#039;&#039;&lt;br /&gt;
! CRC-8&lt;br /&gt;
|----&lt;br /&gt;
! Bits (vor FEC)&lt;br /&gt;
| 8      || 8      || 1 || 1 || 1 || 1 || 4 || 0-224 || 8&lt;br /&gt;
|-&lt;br /&gt;
! Bits (nach FEC)&lt;br /&gt;
| 16     || 16     || 2 || 2 || 2 || 2 || 8 || 0-448 || 16&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039; API &#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
void RFM12_LLC_registerType(RFM12_ProtocolID_t typeID, RFM12_L3_Protocol_t proto);&lt;br /&gt;
&lt;br /&gt;
uint8_t RFM12_LLC_sendFrame(RFM12_ProtocolID_t proto, uint8_t receiver, bool requireACK);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Layer 3: Network ==&lt;br /&gt;
&lt;br /&gt;
Für den Network-Layer werden nur einige Beispiele angeführt. Ab hier können beliebige eigene Protokolle eingesetzt werden. Das verwendete Protokoll wird durch die &#039;&#039;TypeID&#039;&#039; im LLC-Layer angegeben. Die Layer-3-Protokolle sollten nach Möglichkeit nur über die LLC-API mit dem Rest des Stacks kommunizieren.&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;TypeID&#039;&#039;s sind wie folgt definiert:&lt;br /&gt;
&lt;br /&gt;
=== Typ 0: Management ===&lt;br /&gt;
&lt;br /&gt;
Management Protokoll:&lt;br /&gt;
&lt;br /&gt;
* Muss immer implementiert sein&lt;br /&gt;
* Sollte ähnliche Funktionen bieten wie das Service Discovery Protocol (SDP) bei Bluetooth&lt;br /&gt;
* Unterscheidung Request / Response&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot;&lt;br /&gt;
|+ Nachrichten&lt;br /&gt;
|-&lt;br /&gt;
! ID   || Request          || Response&lt;br /&gt;
|-&lt;br /&gt;
| 0x00 || Device Discovery || Device Information&lt;br /&gt;
|-&lt;br /&gt;
| 0x01 || Available Layer 3 Protos || Protocol Information&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot;&lt;br /&gt;
|+ Management Frameaufbau&lt;br /&gt;
|-&lt;br /&gt;
! || Req/Res || ID ||&lt;br /&gt;
|-&lt;br /&gt;
! Bits&lt;br /&gt;
|      1     ||  7 ||&lt;br /&gt;
|}&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Typ 1: Bytestream ===&lt;br /&gt;
&lt;br /&gt;
Die Einteilung in Pakete wird aufgehoben. Daten kommen 1:1 in der Reihenfolge an, wie sie gesendet wurden.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;API&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
void RFM12_Serial_setPeer(uint8_t peer);&lt;br /&gt;
&lt;br /&gt;
bool RFM12_Serial_txAvailable(void);&lt;br /&gt;
&lt;br /&gt;
void RFM12_Serial_txData(uint8_t data);&lt;br /&gt;
&lt;br /&gt;
bool RFM12_Serial_rxAvailable(void);&lt;br /&gt;
&lt;br /&gt;
uint8_t RFM12_Serial_rxData(void);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Typ 3: IPv4 ===&lt;br /&gt;
&lt;br /&gt;
z.B. [http://www.sics.se/~adam/uip/index.php/Main_Page uIP TCP/IP Stack] von Adam Dunkels &amp;lt;adam@dunkels.com&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Anhänge ==&lt;br /&gt;
&lt;br /&gt;
=== Sequenzdiagramme ===&lt;br /&gt;
&lt;br /&gt;
Empfang:&lt;br /&gt;
[[Bild:RFM12 RX Sequence.svg|center|800px|RX Sequenz]]&lt;br /&gt;
&lt;br /&gt;
Senden:&lt;br /&gt;
[[Bild:RFM12 TX Sequence.svg|center|800px|TX Sequenz]]&lt;br /&gt;
&lt;br /&gt;
=== Frames ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Beachte:&#039;&#039;&#039; Durch die Hamming-Codierung sind alle Bytes innerhalb des MAC-Layer doppelt so lang wie angegeben!&lt;br /&gt;
{|&lt;br /&gt;
! bgcolor=&amp;quot;#9fffa8&amp;quot; | MAC || bgcolor=&amp;quot;#a9f3f2&amp;quot; | LLC || bgcolor=&amp;quot;#d28787&amp;quot; | L3&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; align=&amp;quot;center&amp;quot; style=&amp;quot;text-align:center&amp;quot;&lt;br /&gt;
|+ Frameaufbau&lt;br /&gt;
|-&lt;br /&gt;
!&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; bgcolor=&amp;quot;#9fffa8&amp;quot; | SOF&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; bgcolor=&amp;quot;#9fffa8&amp;quot; | Sync&lt;br /&gt;
! bgcolor=&amp;quot;#a9f3f2&amp;quot; | Empfänger&lt;br /&gt;
! bgcolor=&amp;quot;#a9f3f2&amp;quot; | Sender&lt;br /&gt;
! bgcolor=&amp;quot;#a9f3f2&amp;quot; | need ACK | is ACK | | | TypeID&lt;br /&gt;
! bgcolor=&amp;quot;#d28787&amp;quot; | &#039;&#039;0-28 Byte Daten&#039;&#039;&lt;br /&gt;
! bgcolor=&amp;quot;#a9f3f2&amp;quot; | CRC-8&lt;br /&gt;
! bgcolor=&amp;quot;#9fffa8&amp;quot; | EOF&lt;br /&gt;
|----&lt;br /&gt;
! Bits&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; bgcolor=&amp;quot;#9fffa8&amp;quot; | 16 || colspan=&amp;quot;2&amp;quot; bgcolor=&amp;quot;#9fffa8&amp;quot; | 16&lt;br /&gt;
| bgcolor=&amp;quot;#a9f3f2&amp;quot; | 8 || bgcolor=&amp;quot;#a9f3f2&amp;quot; | 8 || bgcolor=&amp;quot;#a9f3f2&amp;quot; | &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; 1 &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; | &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; 1 &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; |1|1| &amp;amp;nbsp;&amp;amp;nbsp; 4 &amp;amp;nbsp;&amp;amp;nbsp;&lt;br /&gt;
| bgcolor=&amp;quot;#d28787&amp;quot; | 0-224&lt;br /&gt;
| bgcolor=&amp;quot;#a9f3f2&amp;quot; | 8&lt;br /&gt;
| bgcolor=&amp;quot;#9fffa8&amp;quot; | 8&lt;br /&gt;
|----&lt;br /&gt;
! Wert&lt;br /&gt;
| bgcolor=&amp;quot;#9fffa8&amp;quot; | 0xAA || bgcolor=&amp;quot;#9fffa8&amp;quot; | 0xAA || bgcolor=&amp;quot;#9fffa8&amp;quot; | 0x2D || bgcolor=&amp;quot;#9fffa8&amp;quot; | 0xD4&lt;br /&gt;
| bgcolor=&amp;quot;#a9f3f2&amp;quot; | || bgcolor=&amp;quot;#a9f3f2&amp;quot; | || bgcolor=&amp;quot;#a9f3f2&amp;quot; | &lt;br /&gt;
| bgcolor=&amp;quot;#d28787&amp;quot; | &lt;br /&gt;
| bgcolor=&amp;quot;#a9f3f2&amp;quot; |&lt;br /&gt;
| bgcolor=&amp;quot;#9fffa8&amp;quot; | 0xAA&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Kanalzuordnung ===&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; align=&amp;quot;center&amp;quot; style=&amp;quot;text-align:right;&amp;quot;&lt;br /&gt;
|+ 433MHz Band&lt;br /&gt;
|-&lt;br /&gt;
! Kanal&lt;br /&gt;
| 0 || 1 || 2 || 3 || 4 || 5 || 6 || 7 || 8 || 9 || 10 || 11 || 12 || 13 || 14 || 15&lt;br /&gt;
|-&lt;br /&gt;
! Mittenfrequenz&lt;br /&gt;
|  431.0 || 431.5 || 432.0 || 432.5 || 433.0 || 433.5 || 434.0 || 434.5 || 435.0 || 435.5 || 436.0 || 436.5 || 437.0 || 437.5 || 438.0 || 438.5&lt;br /&gt;
|-&lt;br /&gt;
! Baudrate&lt;br /&gt;
|   9.6k || 19.2k || 115.2k||  9.6k || 19.2k || 115.2k||  9.6k || 19.2k ||115.2k ||  9.6k || 19.2k || 115.2k||  9.6k || 19.2k || 115.2k||  9.6k&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Hamming-Tabelle ===&lt;br /&gt;
&lt;br /&gt;
==== Encodieren ====&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;3&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|&lt;br /&gt;
! colspan=&amp;quot;4&amp;quot; | Algorithmus&lt;br /&gt;
! colspan=&amp;quot;4&amp;quot; | Beispiel&lt;br /&gt;
|-&lt;br /&gt;
| 1:&lt;br /&gt;
| width=&amp;quot;80&amp;quot; |&lt;br /&gt;
| width=&amp;quot;160&amp;quot; colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 8-Bit Wert&lt;br /&gt;
| width=&amp;quot;160&amp;quot; colspan=&amp;quot;2&amp;quot; |&lt;br /&gt;
| width=&amp;quot;160&amp;quot; colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 10010110&lt;br /&gt;
| width=&amp;quot;80&amp;quot; |&lt;br /&gt;
|-&lt;br /&gt;
| 2: || || align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 4-7 ||  align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 0-3 || colspan=&amp;quot;2&amp;quot; | ||  align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 1001 || align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 0110 || &lt;br /&gt;
|-&lt;br /&gt;
| 3:&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | HammingE[(4-7)]&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | HammingE[(0-3)]&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 0xC7&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 0x38&lt;br /&gt;
|-&lt;br /&gt;
| 4:&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | high&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | low&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 11000111&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 00111000&lt;br /&gt;
|-&lt;br /&gt;
| 5:&lt;br /&gt;
| colspan=&amp;quot;4&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 16-Bit Codewort&lt;br /&gt;
| colspan=&amp;quot;4&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 11000111 00111000&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;3&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|+ HammingE&lt;br /&gt;
|-&lt;br /&gt;
!  0 || 1 || 2  || 3 || 4 || 5 || 6 || 7 || 8 || 9 || A || B || C || D || E || F&lt;br /&gt;
|-&lt;br /&gt;
|bgcolor=&amp;quot;#ff0000&amp;quot;|0x15||bgcolor=&amp;quot;#ff1111&amp;quot;|0x02||bgcolor=&amp;quot;#ff2222&amp;quot;|0x49||bgcolor=&amp;quot;#ff3333&amp;quot;|0x5E||bgcolor=&amp;quot;#ff4444&amp;quot;|0x64||bgcolor=&amp;quot;#ff5555&amp;quot;|0x73||bgcolor=&amp;quot;#ff6666&amp;quot;|0x38||bgcolor=&amp;quot;#ff7777&amp;quot;|0x2F||bgcolor=&amp;quot;#ff8888&amp;quot;|0xD0||bgcolor=&amp;quot;#ff9999&amp;quot;|0xC7||bgcolor=&amp;quot;#ffaaaa&amp;quot;|0x8C||bgcolor=&amp;quot;#ffbbbb&amp;quot;|0x9B||bgcolor=&amp;quot;#ffcccc&amp;quot;|0xA1||bgcolor=&amp;quot;#ffdddd&amp;quot;|0xB6||bgcolor=&amp;quot;#ffeeee&amp;quot;|0xFD||bgcolor=&amp;quot;#ffffff&amp;quot;|0xEA&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Die Einträge in der Tabelle sind so gewählt, dass der Code den maximalen [http://de.wikipedia.org/wiki/Hamming-Abstand#Hamming-Abstand_eines_Codes Hamming-Abstand] von 4 Bit hat.&lt;br /&gt;
&lt;br /&gt;
==== Dekodieren ====&lt;br /&gt;
&lt;br /&gt;
In der Tabelle &#039;&#039;HammingD&#039;&#039; stehen nur 4-Bit breite Werte. Um einen 8-Bit Wert zu erhalten müssen also 2 Einträge aus der Tabelle ausgewählt werden.&lt;br /&gt;
&lt;br /&gt;
Wird nun ein 16-Bit Wert empfangen, bestimmt das High-Byte den ersten Eintrag, das Low-Byte den zweiten.&lt;br /&gt;
&lt;br /&gt;
Es können bis zu zwei gekippte Bits im High- und im Low-Byte korrigiert werden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;3&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|&lt;br /&gt;
! colspan=&amp;quot;4&amp;quot; | Algorithmus || colspan=&amp;quot;4&amp;quot; | Beispiel (mit Bitfehlern)&lt;br /&gt;
|-&lt;br /&gt;
| 1:&lt;br /&gt;
| colspan=&amp;quot;4&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 16-Bit Codewort&lt;br /&gt;
| colspan=&amp;quot;4&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 110&#039;&#039;&#039;1&#039;&#039;&#039;0111 001&#039;&#039;&#039;0&#039;&#039;&#039;100&#039;&#039;&#039;1&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 2:&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | high&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | low&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 110&#039;&#039;&#039;1&#039;&#039;&#039;0111&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 001&#039;&#039;&#039;0&#039;&#039;&#039;100&#039;&#039;&#039;1&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 3:&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | HammingD[high]&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | HammingD[low]&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 0x09&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 0x06&lt;br /&gt;
|-&lt;br /&gt;
| 4: || || align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 4-7&lt;br /&gt;
| align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 0-3 || &lt;br /&gt;
| || align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 1001&lt;br /&gt;
| align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 0110 || &lt;br /&gt;
|-&lt;br /&gt;
| 5:&lt;br /&gt;
| width=&amp;quot;80&amp;quot; |&lt;br /&gt;
| width=&amp;quot;160&amp;quot; colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 8-Bit Wert&lt;br /&gt;
| width=&amp;quot;80&amp;quot; | || width=&amp;quot;80&amp;quot; |&lt;br /&gt;
| width=&amp;quot;160&amp;quot; colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 10010110&lt;br /&gt;
| width=&amp;quot;80&amp;quot; |&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;3&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|+ HammingD&lt;br /&gt;
|-&lt;br /&gt;
!  || 0 || 1 || 2  || 3 || 4 || 5 || 6 || 7 || 8 || 9 || A || B || C || D || E || F&lt;br /&gt;
|-&lt;br /&gt;
! 0&lt;br /&gt;
|bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ffaaAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07&lt;br /&gt;
|-&lt;br /&gt;
! 1&lt;br /&gt;
|bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03&lt;br /&gt;
|-&lt;br /&gt;
! 2&lt;br /&gt;
|bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07&lt;br /&gt;
|-&lt;br /&gt;
! 3&lt;br /&gt;
|bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07&lt;br /&gt;
|-&lt;br /&gt;
! 4&lt;br /&gt;
|bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03&lt;br /&gt;
|-&lt;br /&gt;
! 5&lt;br /&gt;
|bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03&lt;br /&gt;
|-&lt;br /&gt;
! 6&lt;br /&gt;
|bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07&lt;br /&gt;
|-&lt;br /&gt;
! 7&lt;br /&gt;
|bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07&lt;br /&gt;
|-&lt;br /&gt;
! 8&lt;br /&gt;
|bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B&lt;br /&gt;
|-&lt;br /&gt;
! 9&lt;br /&gt;
|bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B&lt;br /&gt;
|-&lt;br /&gt;
! A&lt;br /&gt;
|bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07&lt;br /&gt;
|-&lt;br /&gt;
! B&lt;br /&gt;
|bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F&lt;br /&gt;
|-&lt;br /&gt;
! C&lt;br /&gt;
|bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09&lt;br /&gt;
|-&lt;br /&gt;
! D&lt;br /&gt;
|bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B&lt;br /&gt;
|-&lt;br /&gt;
! E&lt;br /&gt;
|bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F&lt;br /&gt;
|-&lt;br /&gt;
! F&lt;br /&gt;
|bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Funk]]&lt;br /&gt;
[[Kategorie:Wettbewerb]]&lt;/div&gt;</summary>
		<author><name>Thymythos</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=RFM12_Protokoll_Stack&amp;diff=32675</id>
		<title>RFM12 Protokoll Stack</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=RFM12_Protokoll_Stack&amp;diff=32675"/>
		<updated>2008-11-23T14:42:30Z</updated>

		<summary type="html">&lt;p&gt;Thymythos: /* Media Access Control (MAC) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Bild:RFM12 Stack.svg|right]]&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel beschreibt einen [http://de.wikipedia.org/wiki/ISO/OSI ISO/OSI] Protokoll [http://de.wikipedia.org/wiki/Protokollstack Stack] für den [[RFM12]] Funkchip.&amp;lt;br/&amp;gt;&lt;br /&gt;
Einige Hardwarebeispiele finden sich in [[AVR RFM12]].&amp;lt;br/&amp;gt;&lt;br /&gt;
Fehler und Anregungen können gerne auf der [[Diskussion:RFM12_Protokoll_Stack|Diskussionsseite]] besprochen werden.&lt;br /&gt;
&lt;br /&gt;
Eine Referenz-Implementierung für den [[AVR]] wird bereitgestellt:&lt;br /&gt;
{| style=&amp;quot;border:1px dashed green&amp;quot;&lt;br /&gt;
|&#039;&#039;svn://mikrocontroller.net/rfm12/trunk/RFM12_Stack&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
;Implementierungskriterien&lt;br /&gt;
* Wo möglich werden [http://de.wikipedia.org/wiki/R%C3%BCckruffunktion Callback]-Funktionen anstatt [http://de.wikipedia.org/wiki/First_In_%E2%80%93_First_Out FIFOs] verwendet um RAM zu sparen.&lt;br /&gt;
* Interruptgesteuerter Ablauf des Stacks&lt;br /&gt;
* Funktionen sollten nicht blockieren&lt;br /&gt;
&lt;br /&gt;
== Layer 1: Physical ==&lt;br /&gt;
&lt;br /&gt;
[[Bild:RFM12 PHY StateMachine.svg|thumb|320px|Layer1 State Diagram]]&lt;br /&gt;
&lt;br /&gt;
Der Physical-Layer kümmert sich um die direkte Ansteuerung des RFM12. Alle Funktionen des Chips werden als Software-API bereitgestellt.&lt;br /&gt;
&lt;br /&gt;
Folgende Eigenschaften sind bereits vom RFM12 vorgegeben:&lt;br /&gt;
&lt;br /&gt;
* [http://de.wikipedia.org/wiki/ISM-Band 70cm Band (433MHz)]&lt;br /&gt;
* [http://de.wikipedia.org/wiki/Frequenzumtastung FSK]-Modulation&lt;br /&gt;
* Sync-Erkennung auf &#039;&#039;0x2D 0xD4&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Definiert werden muss jedoch noch:&lt;br /&gt;
&lt;br /&gt;
* Baudrate (Vorschlag: feste Kanal-Baudraten-Zuordnung)&lt;br /&gt;
* Zuordnung von Frequenzen zu [[#Kanalzuordnung|Kanälen]]&lt;br /&gt;
* Bandbreite der Kanäle&lt;br /&gt;
* Management der Sendeleistung/Empfangsempfindlichkeit&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;API&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
void RFM12_PHY_modeTX(void);&lt;br /&gt;
&lt;br /&gt;
void RFM12_PHY_modeRX(void);&lt;br /&gt;
&lt;br /&gt;
bool RFM12_PHY_busy(void);&lt;br /&gt;
&lt;br /&gt;
void RFM12_setBaudrate(uint32_t baud);&lt;br /&gt;
&lt;br /&gt;
void RFM12_setCenterFrequency(uint16_t freq);&lt;br /&gt;
&lt;br /&gt;
void RFM12_setDataFilter(bool autoLock, bool fastMode, bool analog, uint8_t dqdThres);&lt;br /&gt;
&lt;br /&gt;
void RFM12_setReceiverBandwidth(RFM12_VDI_t vdi, RFM12_RxBW_t bandwidth, RFM12_GAIN_t gain, RFM12_RSSI_t drssi);&lt;br /&gt;
&lt;br /&gt;
void RFM12_setPowerManagement(bool enRX, bool enBB, bool startTX, bool enSynth, bool enOSC, bool enBat, bool enWkT, bool clkOff);&lt;br /&gt;
&lt;br /&gt;
void RFM12_setTransmitPower(RFM12_Power_t power, RFM12_TxDev_t deviation);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Layer 2: Data Link ==&lt;br /&gt;
&lt;br /&gt;
=== Media Access Control (MAC) ===&lt;br /&gt;
&lt;br /&gt;
Hier noch ein paar Anregungen zur Verbesserung des MAC: [http://www.comsoc.org/livepubs/surveys/public/2q00issue/gummalla.html]&lt;br /&gt;
&lt;br /&gt;
Der MAC-Layer ist sehr einfach gehalten und regelt den Zugriff auf das Medium. Hier soll ein [http://de.wikipedia.org/wiki/CSMA-CA CSMA/CA] Verfahren eingesetzt werden.&lt;br /&gt;
&lt;br /&gt;
# Im Grundzustand befindet sich der RFM12 im Empfangsmodus und wartet auf eine SYNC-Sequenz.&lt;br /&gt;
# Kommt eine Sendeanforderung, wird so lange gewartet bis das Medium frei ist, dann darf nach Ablauf einer (pseudo) zufälligen Zeitspanne gesendet werden.&lt;br /&gt;
# Wurde gerade ein Paket empfangen, darf sofort ein ACK gesendet werden.&lt;br /&gt;
# Die maximale Paketlänge beträgt 50ms. Die maximale Anzahl Bytes hängt daher von der Baudrate ab.&lt;br /&gt;
&lt;br /&gt;
Der Frameaufbau ist teilweise vom RFM12 vorgegeben (SYNC-Erkennung). Der Start-Of-Frame (SOF) dient der Synchronisation. Als End-Of-Frame (EOF) wird ebenfalls die Sequenz &#039;&#039;0xAA&#039;&#039; verwendet. Diese darf im Datenteil nicht vorkommen!&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|+ MAC Frameaufbau&lt;br /&gt;
|-&lt;br /&gt;
!&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; | SOF&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; | Sync&lt;br /&gt;
! &#039;&#039;n Byte Daten&#039;&#039;&lt;br /&gt;
! EOF&lt;br /&gt;
|----&lt;br /&gt;
! Bits&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; | 16 || colspan=&amp;quot;2&amp;quot; | 16 || 0 - 512    || 8&lt;br /&gt;
|----&lt;br /&gt;
! Wert&lt;br /&gt;
| 0xAA || 0xAA     || 0x2D || 0xD4     || &#039;&#039;Daten&#039;&#039;  || 0xAA&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;API&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
void RFM12_MAC_setChannel(uint8_t channel);&lt;br /&gt;
&lt;br /&gt;
bool RFM12_MAC_isReceiving(void);&lt;br /&gt;
&lt;br /&gt;
bool RFM12_MAC_mediaBusy(void);&lt;br /&gt;
&lt;br /&gt;
void RFM12_MAC_startCtrlTransmission(void);&lt;br /&gt;
&lt;br /&gt;
void RFM12_MAC_endCtrlTransmission(void);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Logical Link Control (LLC) ===&lt;br /&gt;
&lt;br /&gt;
Der LLC-Layer kümmert sich um die Sicherung der zu übertragenden Daten.&lt;br /&gt;
Außerdem können Geräte direkt mit ihrer Adresse (8-Bit) angesprochen werden.&lt;br /&gt;
&lt;br /&gt;
;[http://de.wikipedia.org/wiki/Vorw%C3%A4rtsfehlerkorrektur FEC]&lt;br /&gt;
:Alle Bytes werden auf eine [[#Hamming-Tabelle|16-Bit Hamming-Sequenz]] erweitert, wodurch die Datenrate halbiert wird.&lt;br /&gt;
:Dies erlaubt es einzelne Bitfehler zu korrigieren.&lt;br /&gt;
:Bei zu vielen Fehlern können diese jedoch nicht erkannt werden.&lt;br /&gt;
:Im Hamming-Code kommt die Sequenz &#039;&#039;0xAA&#039;&#039; nicht vor (siehe MAC-Layer).&lt;br /&gt;
:Die FEC sorgt außerdem dafür, dass genügend 0-1 Transitionen vorkommen. So kann der Empfänger den Takt auch bei langen Paketen besser halten.&lt;br /&gt;
&lt;br /&gt;
;[http://de.wikipedia.org/wiki/Cyclic_Redundancy_Check CRC]&lt;br /&gt;
:Der gesamte Frame wird nochmals durch eine Checksumme gesichert. (CRC-8: &#039;&#039;x&amp;lt;sup&amp;gt;8&amp;lt;/sup&amp;gt; + x&amp;lt;sup&amp;gt;5&amp;lt;/sup&amp;gt; + x&amp;lt;sup&amp;gt;4&amp;lt;/sup&amp;gt; + 1&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Es werden mehrere Frame-Typen zur Verfügung gestellt:&lt;br /&gt;
&lt;br /&gt;
* Broadcast an alle Geräte (immer ohne ACK)&lt;br /&gt;
* Nachricht an ein bestimmtes Gerät (mit oder ohne ACK)&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|+ LLC Frameaufbau&lt;br /&gt;
|-&lt;br /&gt;
!&lt;br /&gt;
! Empfänger&lt;br /&gt;
! Sender&lt;br /&gt;
! need ACK&lt;br /&gt;
! is ACK&lt;br /&gt;
!&lt;br /&gt;
!&lt;br /&gt;
! TypeID&lt;br /&gt;
! &#039;&#039;0-28 Byte Daten&#039;&#039;&lt;br /&gt;
! CRC-8&lt;br /&gt;
|----&lt;br /&gt;
! Bits (vor FEC)&lt;br /&gt;
| 8      || 8      || 1 || 1 || 1 || 1 || 4 || 0-224 || 8&lt;br /&gt;
|-&lt;br /&gt;
! Bits (nach FEC)&lt;br /&gt;
| 16     || 16     || 2 || 2 || 2 || 2 || 8 || 0-448 || 16&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039; API &#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
void RFM12_LLC_registerType(RFM12_ProtocolID_t typeID, RFM12_L3_Protocol_t proto);&lt;br /&gt;
&lt;br /&gt;
uint8_t RFM12_LLC_sendFrame(RFM12_ProtocolID_t proto, uint8_t receiver, bool requireACK);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Layer 3: Network ==&lt;br /&gt;
&lt;br /&gt;
Für den Network-Layer werden nur einige Beispiele angeführt. Ab hier können beliebige eigene Protokolle eingesetzt werden. Das verwendete Protokoll wird durch die &#039;&#039;TypeID&#039;&#039; im LLC-Layer angegeben. Die Layer-3-Protokolle sollten nach Möglichkeit nur über die LLC-API mit dem Rest des Stacks kommunizieren.&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;TypeID&#039;&#039;s sind wie folgt definiert:&lt;br /&gt;
&lt;br /&gt;
=== Typ 0: Management ===&lt;br /&gt;
&lt;br /&gt;
Management Protokoll:&lt;br /&gt;
&lt;br /&gt;
* Muss immer implementiert sein&lt;br /&gt;
* Sollte ähnliche Funktionen bieten wie das Service Discovery Protocol (SDP) bei Bluetooth&lt;br /&gt;
* Unterscheidung Request / Response&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot;&lt;br /&gt;
|+ Nachrichten&lt;br /&gt;
|-&lt;br /&gt;
! ID   || Request          || Response&lt;br /&gt;
|-&lt;br /&gt;
| 0x00 || Device Discovery || Device Information&lt;br /&gt;
|-&lt;br /&gt;
| 0x01 || Available Layer 3 Protos || Protocol Information&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot;&lt;br /&gt;
|+ Management Frameaufbau&lt;br /&gt;
|-&lt;br /&gt;
! || Req/Res || ID ||&lt;br /&gt;
|-&lt;br /&gt;
! Bits&lt;br /&gt;
|      1     ||  7 ||&lt;br /&gt;
|}&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Typ 1: Bytestream ===&lt;br /&gt;
&lt;br /&gt;
Die Einteilung in Pakete wird aufgehoben. Daten kommen 1:1 in der Reihenfolge an, wie sie gesendet wurden.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;API&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
void RFM12_Serial_setPeer(uint8_t peer);&lt;br /&gt;
&lt;br /&gt;
bool RFM12_Serial_txAvailable(void);&lt;br /&gt;
&lt;br /&gt;
void RFM12_Serial_txData(uint8_t data);&lt;br /&gt;
&lt;br /&gt;
bool RFM12_Serial_rxAvailable(void);&lt;br /&gt;
&lt;br /&gt;
uint8_t RFM12_Serial_rxData(void);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Typ 3: IPv4 ===&lt;br /&gt;
&lt;br /&gt;
z.B. [http://www.sics.se/~adam/uip/index.php/Main_Page uIP TCP/IP Stack] von Adam Dunkels &amp;lt;adam@dunkels.com&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Anhänge ==&lt;br /&gt;
&lt;br /&gt;
=== Sequenzdiagramme ===&lt;br /&gt;
&lt;br /&gt;
Empfang:&lt;br /&gt;
[[Bild:RFM12 RX Sequence.svg|center|800px|RX Sequenz]]&lt;br /&gt;
&lt;br /&gt;
Senden:&lt;br /&gt;
[[Bild:RFM12 TX Sequence.svg|center|800px|TX Sequenz]]&lt;br /&gt;
&lt;br /&gt;
=== Frames ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Beachte:&#039;&#039;&#039; Durch die Hamming-Codierung sind alle Bytes innerhalb des MAC-Layer doppelt so lang wie angegeben!&lt;br /&gt;
{|&lt;br /&gt;
! bgcolor=&amp;quot;#9fffa8&amp;quot; | MAC || bgcolor=&amp;quot;#a9f3f2&amp;quot; | LLC || bgcolor=&amp;quot;#d28787&amp;quot; | L3&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; align=&amp;quot;center&amp;quot; style=&amp;quot;text-align:center&amp;quot;&lt;br /&gt;
|+ Frameaufbau&lt;br /&gt;
|-&lt;br /&gt;
!&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; bgcolor=&amp;quot;#9fffa8&amp;quot; | SOF&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; bgcolor=&amp;quot;#9fffa8&amp;quot; | Sync&lt;br /&gt;
! bgcolor=&amp;quot;#a9f3f2&amp;quot; | Empfänger&lt;br /&gt;
! bgcolor=&amp;quot;#a9f3f2&amp;quot; | Sender&lt;br /&gt;
! bgcolor=&amp;quot;#a9f3f2&amp;quot; | need ACK | is ACK | | | TypeID&lt;br /&gt;
! bgcolor=&amp;quot;#d28787&amp;quot; | &#039;&#039;0-28 Byte Daten&#039;&#039;&lt;br /&gt;
! bgcolor=&amp;quot;#a9f3f2&amp;quot; | CRC-8&lt;br /&gt;
! bgcolor=&amp;quot;#9fffa8&amp;quot; | EOF&lt;br /&gt;
|----&lt;br /&gt;
! Bits&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; bgcolor=&amp;quot;#9fffa8&amp;quot; | 16 || colspan=&amp;quot;2&amp;quot; bgcolor=&amp;quot;#9fffa8&amp;quot; | 16&lt;br /&gt;
| bgcolor=&amp;quot;#a9f3f2&amp;quot; | 8 || bgcolor=&amp;quot;#a9f3f2&amp;quot; | 8 || bgcolor=&amp;quot;#a9f3f2&amp;quot; | &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; 1 &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; | &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; 1 &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; |1|1| &amp;amp;nbsp;&amp;amp;nbsp; 4 &amp;amp;nbsp;&amp;amp;nbsp;&lt;br /&gt;
| bgcolor=&amp;quot;#d28787&amp;quot; | 0-224&lt;br /&gt;
| bgcolor=&amp;quot;#a9f3f2&amp;quot; | 8&lt;br /&gt;
| bgcolor=&amp;quot;#9fffa8&amp;quot; | 8&lt;br /&gt;
|----&lt;br /&gt;
! Wert&lt;br /&gt;
| bgcolor=&amp;quot;#9fffa8&amp;quot; | 0xAA || bgcolor=&amp;quot;#9fffa8&amp;quot; | 0xAA || bgcolor=&amp;quot;#9fffa8&amp;quot; | 0x2D || bgcolor=&amp;quot;#9fffa8&amp;quot; | 0xD4&lt;br /&gt;
| bgcolor=&amp;quot;#a9f3f2&amp;quot; | || bgcolor=&amp;quot;#a9f3f2&amp;quot; | || bgcolor=&amp;quot;#a9f3f2&amp;quot; | &lt;br /&gt;
| bgcolor=&amp;quot;#d28787&amp;quot; | &lt;br /&gt;
| bgcolor=&amp;quot;#a9f3f2&amp;quot; |&lt;br /&gt;
| bgcolor=&amp;quot;#9fffa8&amp;quot; | 0xAA&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Kanalzuordnung ===&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; align=&amp;quot;center&amp;quot; style=&amp;quot;text-align:right;&amp;quot;&lt;br /&gt;
|+ 433MHz Band&lt;br /&gt;
|-&lt;br /&gt;
! Kanal&lt;br /&gt;
| 0 || 1 || 2 || 3 || 4 || 5 || 6 || 7 || 8 || 9 || 10 || 11 || 12 || 13 || 14 || 15&lt;br /&gt;
|-&lt;br /&gt;
! Mittenfrequenz&lt;br /&gt;
|  431.0 || 431.5 || 432.0 || 432.5 || 433.0 || 433.5 || 434.0 || 434.5 || 435.0 || 435.5 || 436.0 || 436.5 || 437.0 || 437.5 || 438.0 || 438.5&lt;br /&gt;
|-&lt;br /&gt;
! Baudrate&lt;br /&gt;
|   9.6k || 19.2k || 115.2k||  9.6k || 19.2k || 115.2k||  9.6k || 19.2k ||115.2k ||  9.6k || 19.2k || 115.2k||  9.6k || 19.2k || 115.2k||  9.6k&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Hamming-Tabelle ===&lt;br /&gt;
&lt;br /&gt;
==== Encodieren ====&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;3&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|&lt;br /&gt;
! colspan=&amp;quot;4&amp;quot; | Algorithmus&lt;br /&gt;
! colspan=&amp;quot;4&amp;quot; | Beispiel&lt;br /&gt;
|-&lt;br /&gt;
| 1:&lt;br /&gt;
| width=&amp;quot;80&amp;quot; |&lt;br /&gt;
| width=&amp;quot;160&amp;quot; colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 8-Bit Wert&lt;br /&gt;
| width=&amp;quot;160&amp;quot; colspan=&amp;quot;2&amp;quot; |&lt;br /&gt;
| width=&amp;quot;160&amp;quot; colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 10010110&lt;br /&gt;
| width=&amp;quot;80&amp;quot; |&lt;br /&gt;
|-&lt;br /&gt;
| 2: || || align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 4-7 ||  align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 0-3 || colspan=&amp;quot;2&amp;quot; | ||  align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 1001 || align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 0110 || &lt;br /&gt;
|-&lt;br /&gt;
| 3:&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | HammingE[(4-7)]&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | HammingE[(0-3)]&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 0xC7&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 0x38&lt;br /&gt;
|-&lt;br /&gt;
| 4:&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | high&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | low&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 11000111&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 00111000&lt;br /&gt;
|-&lt;br /&gt;
| 5:&lt;br /&gt;
| colspan=&amp;quot;4&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 16-Bit Codewort&lt;br /&gt;
| colspan=&amp;quot;4&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 11000111 00111000&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;3&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|+ HammingE&lt;br /&gt;
|-&lt;br /&gt;
!  0 || 1 || 2  || 3 || 4 || 5 || 6 || 7 || 8 || 9 || A || B || C || D || E || F&lt;br /&gt;
|-&lt;br /&gt;
|bgcolor=&amp;quot;#ff0000&amp;quot;|0x15||bgcolor=&amp;quot;#ff1111&amp;quot;|0x02||bgcolor=&amp;quot;#ff2222&amp;quot;|0x49||bgcolor=&amp;quot;#ff3333&amp;quot;|0x5E||bgcolor=&amp;quot;#ff4444&amp;quot;|0x64||bgcolor=&amp;quot;#ff5555&amp;quot;|0x73||bgcolor=&amp;quot;#ff6666&amp;quot;|0x38||bgcolor=&amp;quot;#ff7777&amp;quot;|0x2F||bgcolor=&amp;quot;#ff8888&amp;quot;|0xD0||bgcolor=&amp;quot;#ff9999&amp;quot;|0xC7||bgcolor=&amp;quot;#ffaaaa&amp;quot;|0x8C||bgcolor=&amp;quot;#ffbbbb&amp;quot;|0x9B||bgcolor=&amp;quot;#ffcccc&amp;quot;|0xA1||bgcolor=&amp;quot;#ffdddd&amp;quot;|0xB6||bgcolor=&amp;quot;#ffeeee&amp;quot;|0xFD||bgcolor=&amp;quot;#ffffff&amp;quot;|0xEA&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Die Einträge in der Tabelle sind so gewählt, dass der Code den maximalen [http://de.wikipedia.org/wiki/Hamming-Abstand#Hamming-Abstand_eines_Codes Hamming-Abstand] von 4 Bit hat.&lt;br /&gt;
&lt;br /&gt;
==== Dekodieren ====&lt;br /&gt;
&lt;br /&gt;
In der Tabelle &#039;&#039;HammingD&#039;&#039; stehen nur 4-Bit breite Werte. Um einen 8-Bit Wert zu erhalten müssen also 2 Einträge aus der Tabelle ausgewählt werden.&lt;br /&gt;
&lt;br /&gt;
Wird nun ein 16-Bit Wert empfangen, bestimmt das High-Byte den ersten Eintrag, das Low-Byte den zweiten.&lt;br /&gt;
&lt;br /&gt;
Es können bis zu zwei gekippte Bits im High- und im Low-Byte korrigiert werden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;3&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|&lt;br /&gt;
! colspan=&amp;quot;4&amp;quot; | Algorithmus || colspan=&amp;quot;4&amp;quot; | Beispiel (mit Bitfehlern)&lt;br /&gt;
|-&lt;br /&gt;
| 1:&lt;br /&gt;
| colspan=&amp;quot;4&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 16-Bit Codewort&lt;br /&gt;
| colspan=&amp;quot;4&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 110&#039;&#039;&#039;1&#039;&#039;&#039;0111 001&#039;&#039;&#039;0&#039;&#039;&#039;100&#039;&#039;&#039;1&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 2:&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | high&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | low&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 110&#039;&#039;&#039;1&#039;&#039;&#039;0111&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 001&#039;&#039;&#039;0&#039;&#039;&#039;100&#039;&#039;&#039;1&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 3:&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | HammingD[high]&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | HammingD[low]&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 0x09&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 0x06&lt;br /&gt;
|-&lt;br /&gt;
| 4: || || align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 4-7&lt;br /&gt;
| align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 0-3 || &lt;br /&gt;
| || align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 1001&lt;br /&gt;
| align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 0110 || &lt;br /&gt;
|-&lt;br /&gt;
| 5:&lt;br /&gt;
| width=&amp;quot;80&amp;quot; |&lt;br /&gt;
| width=&amp;quot;160&amp;quot; colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 8-Bit Wert&lt;br /&gt;
| width=&amp;quot;80&amp;quot; | || width=&amp;quot;80&amp;quot; |&lt;br /&gt;
| width=&amp;quot;160&amp;quot; colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 10010110&lt;br /&gt;
| width=&amp;quot;80&amp;quot; |&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;3&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|+ HammingD&lt;br /&gt;
|-&lt;br /&gt;
!  || 0 || 1 || 2  || 3 || 4 || 5 || 6 || 7 || 8 || 9 || A || B || C || D || E || F&lt;br /&gt;
|-&lt;br /&gt;
! 0&lt;br /&gt;
|bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ffaaAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07&lt;br /&gt;
|-&lt;br /&gt;
! 1&lt;br /&gt;
|bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03&lt;br /&gt;
|-&lt;br /&gt;
! 2&lt;br /&gt;
|bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07&lt;br /&gt;
|-&lt;br /&gt;
! 3&lt;br /&gt;
|bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07&lt;br /&gt;
|-&lt;br /&gt;
! 4&lt;br /&gt;
|bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03&lt;br /&gt;
|-&lt;br /&gt;
! 5&lt;br /&gt;
|bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03&lt;br /&gt;
|-&lt;br /&gt;
! 6&lt;br /&gt;
|bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07&lt;br /&gt;
|-&lt;br /&gt;
! 7&lt;br /&gt;
|bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07&lt;br /&gt;
|-&lt;br /&gt;
! 8&lt;br /&gt;
|bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B&lt;br /&gt;
|-&lt;br /&gt;
! 9&lt;br /&gt;
|bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B&lt;br /&gt;
|-&lt;br /&gt;
! A&lt;br /&gt;
|bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07&lt;br /&gt;
|-&lt;br /&gt;
! B&lt;br /&gt;
|bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F&lt;br /&gt;
|-&lt;br /&gt;
! C&lt;br /&gt;
|bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09&lt;br /&gt;
|-&lt;br /&gt;
! D&lt;br /&gt;
|bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B&lt;br /&gt;
|-&lt;br /&gt;
! E&lt;br /&gt;
|bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F&lt;br /&gt;
|-&lt;br /&gt;
! F&lt;br /&gt;
|bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Funk]]&lt;br /&gt;
[[Kategorie:Wettbewerb]]&lt;/div&gt;</summary>
		<author><name>Thymythos</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=RFM12_Protokoll_Stack&amp;diff=32674</id>
		<title>RFM12 Protokoll Stack</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=RFM12_Protokoll_Stack&amp;diff=32674"/>
		<updated>2008-11-23T14:32:56Z</updated>

		<summary type="html">&lt;p&gt;Thymythos: /* Typ 0: Management */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Bild:RFM12 Stack.svg|right]]&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel beschreibt einen [http://de.wikipedia.org/wiki/ISO/OSI ISO/OSI] Protokoll [http://de.wikipedia.org/wiki/Protokollstack Stack] für den [[RFM12]] Funkchip.&amp;lt;br/&amp;gt;&lt;br /&gt;
Einige Hardwarebeispiele finden sich in [[AVR RFM12]].&amp;lt;br/&amp;gt;&lt;br /&gt;
Fehler und Anregungen können gerne auf der [[Diskussion:RFM12_Protokoll_Stack|Diskussionsseite]] besprochen werden.&lt;br /&gt;
&lt;br /&gt;
Eine Referenz-Implementierung für den [[AVR]] wird bereitgestellt:&lt;br /&gt;
{| style=&amp;quot;border:1px dashed green&amp;quot;&lt;br /&gt;
|&#039;&#039;svn://mikrocontroller.net/rfm12/trunk/RFM12_Stack&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
;Implementierungskriterien&lt;br /&gt;
* Wo möglich werden [http://de.wikipedia.org/wiki/R%C3%BCckruffunktion Callback]-Funktionen anstatt [http://de.wikipedia.org/wiki/First_In_%E2%80%93_First_Out FIFOs] verwendet um RAM zu sparen.&lt;br /&gt;
* Interruptgesteuerter Ablauf des Stacks&lt;br /&gt;
* Funktionen sollten nicht blockieren&lt;br /&gt;
&lt;br /&gt;
== Layer 1: Physical ==&lt;br /&gt;
&lt;br /&gt;
[[Bild:RFM12 PHY StateMachine.svg|thumb|320px|Layer1 State Diagram]]&lt;br /&gt;
&lt;br /&gt;
Der Physical-Layer kümmert sich um die direkte Ansteuerung des RFM12. Alle Funktionen des Chips werden als Software-API bereitgestellt.&lt;br /&gt;
&lt;br /&gt;
Folgende Eigenschaften sind bereits vom RFM12 vorgegeben:&lt;br /&gt;
&lt;br /&gt;
* [http://de.wikipedia.org/wiki/ISM-Band 70cm Band (433MHz)]&lt;br /&gt;
* [http://de.wikipedia.org/wiki/Frequenzumtastung FSK]-Modulation&lt;br /&gt;
* Sync-Erkennung auf &#039;&#039;0x2D 0xD4&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Definiert werden muss jedoch noch:&lt;br /&gt;
&lt;br /&gt;
* Baudrate (Vorschlag: feste Kanal-Baudraten-Zuordnung)&lt;br /&gt;
* Zuordnung von Frequenzen zu [[#Kanalzuordnung|Kanälen]]&lt;br /&gt;
* Bandbreite der Kanäle&lt;br /&gt;
* Management der Sendeleistung/Empfangsempfindlichkeit&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;API&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
void RFM12_PHY_modeTX(void);&lt;br /&gt;
&lt;br /&gt;
void RFM12_PHY_modeRX(void);&lt;br /&gt;
&lt;br /&gt;
bool RFM12_PHY_busy(void);&lt;br /&gt;
&lt;br /&gt;
void RFM12_setBaudrate(uint32_t baud);&lt;br /&gt;
&lt;br /&gt;
void RFM12_setCenterFrequency(uint16_t freq);&lt;br /&gt;
&lt;br /&gt;
void RFM12_setDataFilter(bool autoLock, bool fastMode, bool analog, uint8_t dqdThres);&lt;br /&gt;
&lt;br /&gt;
void RFM12_setReceiverBandwidth(RFM12_VDI_t vdi, RFM12_RxBW_t bandwidth, RFM12_GAIN_t gain, RFM12_RSSI_t drssi);&lt;br /&gt;
&lt;br /&gt;
void RFM12_setPowerManagement(bool enRX, bool enBB, bool startTX, bool enSynth, bool enOSC, bool enBat, bool enWkT, bool clkOff);&lt;br /&gt;
&lt;br /&gt;
void RFM12_setTransmitPower(RFM12_Power_t power, RFM12_TxDev_t deviation);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Layer 2: Data Link ==&lt;br /&gt;
&lt;br /&gt;
=== Media Access Control (MAC) ===&lt;br /&gt;
&lt;br /&gt;
Hier noch ein paar Anregungen zur Verbesserung des MAC: [http://www.comsoc.org/livepubs/surveys/public/2q00issue/gummalla.html]&lt;br /&gt;
&lt;br /&gt;
Der MAC-Layer ist sehr einfach gehalten und regelt den Zugriff auf das Medium. Hier soll ein [http://de.wikipedia.org/wiki/CSMA-CA CSMA/CA] Verfahren eingesetzt werden.&lt;br /&gt;
&lt;br /&gt;
# Im Grundzustand befindet sich der RFM12 im Empfangsmodus und wartet auf eine SYNC-Sequenz.&lt;br /&gt;
# Kommt eine Sendeanforderung, wird so lange gewartet bis das Medium frei ist, dann darf nach Ablauf einer (pseudo) zufälligen Zeitspanne gesendet werden.&lt;br /&gt;
# Wurde gerade ein Paket empfangen, darf sofort ein ACK gesendet werden.&lt;br /&gt;
&lt;br /&gt;
Der Frameaufbau ist teilweise vom RFM12 vorgegeben (SYNC-Erkennung). Der Start-Of-Frame (SOF) dient der Synchronisation. Als End-Of-Frame (EOF) wird ebenfalls die Sequenz &#039;&#039;0xAA&#039;&#039; verwendet. Diese darf im Datenteil nicht vorkommen!&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|+ MAC Frameaufbau&lt;br /&gt;
|-&lt;br /&gt;
!&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; | SOF&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; | Sync&lt;br /&gt;
! &#039;&#039;n Byte Daten&#039;&#039;&lt;br /&gt;
! EOF&lt;br /&gt;
|----&lt;br /&gt;
! Bits&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; | 16 || colspan=&amp;quot;2&amp;quot; | 16 || 0 - 512    || 8&lt;br /&gt;
|----&lt;br /&gt;
! Wert&lt;br /&gt;
| 0xAA || 0xAA     || 0x2D || 0xD4     || &#039;&#039;Daten&#039;&#039;  || 0xAA&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;API&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
void RFM12_MAC_setChannel(uint8_t channel);&lt;br /&gt;
&lt;br /&gt;
bool RFM12_MAC_isReceiving(void);&lt;br /&gt;
&lt;br /&gt;
bool RFM12_MAC_mediaBusy(void);&lt;br /&gt;
&lt;br /&gt;
void RFM12_MAC_startCtrlTransmission(void);&lt;br /&gt;
&lt;br /&gt;
void RFM12_MAC_endCtrlTransmission(void);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Logical Link Control (LLC) ===&lt;br /&gt;
&lt;br /&gt;
Der LLC-Layer kümmert sich um die Sicherung der zu übertragenden Daten.&lt;br /&gt;
Außerdem können Geräte direkt mit ihrer Adresse (8-Bit) angesprochen werden.&lt;br /&gt;
&lt;br /&gt;
;[http://de.wikipedia.org/wiki/Vorw%C3%A4rtsfehlerkorrektur FEC]&lt;br /&gt;
:Alle Bytes werden auf eine [[#Hamming-Tabelle|16-Bit Hamming-Sequenz]] erweitert, wodurch die Datenrate halbiert wird.&lt;br /&gt;
:Dies erlaubt es einzelne Bitfehler zu korrigieren.&lt;br /&gt;
:Bei zu vielen Fehlern können diese jedoch nicht erkannt werden.&lt;br /&gt;
:Im Hamming-Code kommt die Sequenz &#039;&#039;0xAA&#039;&#039; nicht vor (siehe MAC-Layer).&lt;br /&gt;
:Die FEC sorgt außerdem dafür, dass genügend 0-1 Transitionen vorkommen. So kann der Empfänger den Takt auch bei langen Paketen besser halten.&lt;br /&gt;
&lt;br /&gt;
;[http://de.wikipedia.org/wiki/Cyclic_Redundancy_Check CRC]&lt;br /&gt;
:Der gesamte Frame wird nochmals durch eine Checksumme gesichert. (CRC-8: &#039;&#039;x&amp;lt;sup&amp;gt;8&amp;lt;/sup&amp;gt; + x&amp;lt;sup&amp;gt;5&amp;lt;/sup&amp;gt; + x&amp;lt;sup&amp;gt;4&amp;lt;/sup&amp;gt; + 1&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Es werden mehrere Frame-Typen zur Verfügung gestellt:&lt;br /&gt;
&lt;br /&gt;
* Broadcast an alle Geräte (immer ohne ACK)&lt;br /&gt;
* Nachricht an ein bestimmtes Gerät (mit oder ohne ACK)&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|+ LLC Frameaufbau&lt;br /&gt;
|-&lt;br /&gt;
!&lt;br /&gt;
! Empfänger&lt;br /&gt;
! Sender&lt;br /&gt;
! need ACK&lt;br /&gt;
! is ACK&lt;br /&gt;
!&lt;br /&gt;
!&lt;br /&gt;
! TypeID&lt;br /&gt;
! &#039;&#039;0-28 Byte Daten&#039;&#039;&lt;br /&gt;
! CRC-8&lt;br /&gt;
|----&lt;br /&gt;
! Bits (vor FEC)&lt;br /&gt;
| 8      || 8      || 1 || 1 || 1 || 1 || 4 || 0-224 || 8&lt;br /&gt;
|-&lt;br /&gt;
! Bits (nach FEC)&lt;br /&gt;
| 16     || 16     || 2 || 2 || 2 || 2 || 8 || 0-448 || 16&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039; API &#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
void RFM12_LLC_registerType(RFM12_ProtocolID_t typeID, RFM12_L3_Protocol_t proto);&lt;br /&gt;
&lt;br /&gt;
uint8_t RFM12_LLC_sendFrame(RFM12_ProtocolID_t proto, uint8_t receiver, bool requireACK);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Layer 3: Network ==&lt;br /&gt;
&lt;br /&gt;
Für den Network-Layer werden nur einige Beispiele angeführt. Ab hier können beliebige eigene Protokolle eingesetzt werden. Das verwendete Protokoll wird durch die &#039;&#039;TypeID&#039;&#039; im LLC-Layer angegeben. Die Layer-3-Protokolle sollten nach Möglichkeit nur über die LLC-API mit dem Rest des Stacks kommunizieren.&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;TypeID&#039;&#039;s sind wie folgt definiert:&lt;br /&gt;
&lt;br /&gt;
=== Typ 0: Management ===&lt;br /&gt;
&lt;br /&gt;
Management Protokoll:&lt;br /&gt;
&lt;br /&gt;
* Muss immer implementiert sein&lt;br /&gt;
* Sollte ähnliche Funktionen bieten wie das Service Discovery Protocol (SDP) bei Bluetooth&lt;br /&gt;
* Unterscheidung Request / Response&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot;&lt;br /&gt;
|+ Nachrichten&lt;br /&gt;
|-&lt;br /&gt;
! ID   || Request          || Response&lt;br /&gt;
|-&lt;br /&gt;
| 0x00 || Device Discovery || Device Information&lt;br /&gt;
|-&lt;br /&gt;
| 0x01 || Available Layer 3 Protos || Protocol Information&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot;&lt;br /&gt;
|+ Management Frameaufbau&lt;br /&gt;
|-&lt;br /&gt;
! || Req/Res || ID ||&lt;br /&gt;
|-&lt;br /&gt;
! Bits&lt;br /&gt;
|      1     ||  7 ||&lt;br /&gt;
|}&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Typ 1: Bytestream ===&lt;br /&gt;
&lt;br /&gt;
Die Einteilung in Pakete wird aufgehoben. Daten kommen 1:1 in der Reihenfolge an, wie sie gesendet wurden.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;API&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
void RFM12_Serial_setPeer(uint8_t peer);&lt;br /&gt;
&lt;br /&gt;
bool RFM12_Serial_txAvailable(void);&lt;br /&gt;
&lt;br /&gt;
void RFM12_Serial_txData(uint8_t data);&lt;br /&gt;
&lt;br /&gt;
bool RFM12_Serial_rxAvailable(void);&lt;br /&gt;
&lt;br /&gt;
uint8_t RFM12_Serial_rxData(void);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Typ 3: IPv4 ===&lt;br /&gt;
&lt;br /&gt;
z.B. [http://www.sics.se/~adam/uip/index.php/Main_Page uIP TCP/IP Stack] von Adam Dunkels &amp;lt;adam@dunkels.com&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Anhänge ==&lt;br /&gt;
&lt;br /&gt;
=== Sequenzdiagramme ===&lt;br /&gt;
&lt;br /&gt;
Empfang:&lt;br /&gt;
[[Bild:RFM12 RX Sequence.svg|center|800px|RX Sequenz]]&lt;br /&gt;
&lt;br /&gt;
Senden:&lt;br /&gt;
[[Bild:RFM12 TX Sequence.svg|center|800px|TX Sequenz]]&lt;br /&gt;
&lt;br /&gt;
=== Frames ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Beachte:&#039;&#039;&#039; Durch die Hamming-Codierung sind alle Bytes innerhalb des MAC-Layer doppelt so lang wie angegeben!&lt;br /&gt;
{|&lt;br /&gt;
! bgcolor=&amp;quot;#9fffa8&amp;quot; | MAC || bgcolor=&amp;quot;#a9f3f2&amp;quot; | LLC || bgcolor=&amp;quot;#d28787&amp;quot; | L3&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; align=&amp;quot;center&amp;quot; style=&amp;quot;text-align:center&amp;quot;&lt;br /&gt;
|+ Frameaufbau&lt;br /&gt;
|-&lt;br /&gt;
!&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; bgcolor=&amp;quot;#9fffa8&amp;quot; | SOF&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; bgcolor=&amp;quot;#9fffa8&amp;quot; | Sync&lt;br /&gt;
! bgcolor=&amp;quot;#a9f3f2&amp;quot; | Empfänger&lt;br /&gt;
! bgcolor=&amp;quot;#a9f3f2&amp;quot; | Sender&lt;br /&gt;
! bgcolor=&amp;quot;#a9f3f2&amp;quot; | need ACK | is ACK | | | TypeID&lt;br /&gt;
! bgcolor=&amp;quot;#d28787&amp;quot; | &#039;&#039;0-28 Byte Daten&#039;&#039;&lt;br /&gt;
! bgcolor=&amp;quot;#a9f3f2&amp;quot; | CRC-8&lt;br /&gt;
! bgcolor=&amp;quot;#9fffa8&amp;quot; | EOF&lt;br /&gt;
|----&lt;br /&gt;
! Bits&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; bgcolor=&amp;quot;#9fffa8&amp;quot; | 16 || colspan=&amp;quot;2&amp;quot; bgcolor=&amp;quot;#9fffa8&amp;quot; | 16&lt;br /&gt;
| bgcolor=&amp;quot;#a9f3f2&amp;quot; | 8 || bgcolor=&amp;quot;#a9f3f2&amp;quot; | 8 || bgcolor=&amp;quot;#a9f3f2&amp;quot; | &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; 1 &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; | &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; 1 &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; |1|1| &amp;amp;nbsp;&amp;amp;nbsp; 4 &amp;amp;nbsp;&amp;amp;nbsp;&lt;br /&gt;
| bgcolor=&amp;quot;#d28787&amp;quot; | 0-224&lt;br /&gt;
| bgcolor=&amp;quot;#a9f3f2&amp;quot; | 8&lt;br /&gt;
| bgcolor=&amp;quot;#9fffa8&amp;quot; | 8&lt;br /&gt;
|----&lt;br /&gt;
! Wert&lt;br /&gt;
| bgcolor=&amp;quot;#9fffa8&amp;quot; | 0xAA || bgcolor=&amp;quot;#9fffa8&amp;quot; | 0xAA || bgcolor=&amp;quot;#9fffa8&amp;quot; | 0x2D || bgcolor=&amp;quot;#9fffa8&amp;quot; | 0xD4&lt;br /&gt;
| bgcolor=&amp;quot;#a9f3f2&amp;quot; | || bgcolor=&amp;quot;#a9f3f2&amp;quot; | || bgcolor=&amp;quot;#a9f3f2&amp;quot; | &lt;br /&gt;
| bgcolor=&amp;quot;#d28787&amp;quot; | &lt;br /&gt;
| bgcolor=&amp;quot;#a9f3f2&amp;quot; |&lt;br /&gt;
| bgcolor=&amp;quot;#9fffa8&amp;quot; | 0xAA&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Kanalzuordnung ===&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; align=&amp;quot;center&amp;quot; style=&amp;quot;text-align:right;&amp;quot;&lt;br /&gt;
|+ 433MHz Band&lt;br /&gt;
|-&lt;br /&gt;
! Kanal&lt;br /&gt;
| 0 || 1 || 2 || 3 || 4 || 5 || 6 || 7 || 8 || 9 || 10 || 11 || 12 || 13 || 14 || 15&lt;br /&gt;
|-&lt;br /&gt;
! Mittenfrequenz&lt;br /&gt;
|  431.0 || 431.5 || 432.0 || 432.5 || 433.0 || 433.5 || 434.0 || 434.5 || 435.0 || 435.5 || 436.0 || 436.5 || 437.0 || 437.5 || 438.0 || 438.5&lt;br /&gt;
|-&lt;br /&gt;
! Baudrate&lt;br /&gt;
|   9.6k || 19.2k || 115.2k||  9.6k || 19.2k || 115.2k||  9.6k || 19.2k ||115.2k ||  9.6k || 19.2k || 115.2k||  9.6k || 19.2k || 115.2k||  9.6k&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Hamming-Tabelle ===&lt;br /&gt;
&lt;br /&gt;
==== Encodieren ====&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;3&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|&lt;br /&gt;
! colspan=&amp;quot;4&amp;quot; | Algorithmus&lt;br /&gt;
! colspan=&amp;quot;4&amp;quot; | Beispiel&lt;br /&gt;
|-&lt;br /&gt;
| 1:&lt;br /&gt;
| width=&amp;quot;80&amp;quot; |&lt;br /&gt;
| width=&amp;quot;160&amp;quot; colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 8-Bit Wert&lt;br /&gt;
| width=&amp;quot;160&amp;quot; colspan=&amp;quot;2&amp;quot; |&lt;br /&gt;
| width=&amp;quot;160&amp;quot; colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 10010110&lt;br /&gt;
| width=&amp;quot;80&amp;quot; |&lt;br /&gt;
|-&lt;br /&gt;
| 2: || || align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 4-7 ||  align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 0-3 || colspan=&amp;quot;2&amp;quot; | ||  align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 1001 || align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 0110 || &lt;br /&gt;
|-&lt;br /&gt;
| 3:&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | HammingE[(4-7)]&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | HammingE[(0-3)]&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 0xC7&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 0x38&lt;br /&gt;
|-&lt;br /&gt;
| 4:&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | high&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | low&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 11000111&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 00111000&lt;br /&gt;
|-&lt;br /&gt;
| 5:&lt;br /&gt;
| colspan=&amp;quot;4&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 16-Bit Codewort&lt;br /&gt;
| colspan=&amp;quot;4&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 11000111 00111000&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;3&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|+ HammingE&lt;br /&gt;
|-&lt;br /&gt;
!  0 || 1 || 2  || 3 || 4 || 5 || 6 || 7 || 8 || 9 || A || B || C || D || E || F&lt;br /&gt;
|-&lt;br /&gt;
|bgcolor=&amp;quot;#ff0000&amp;quot;|0x15||bgcolor=&amp;quot;#ff1111&amp;quot;|0x02||bgcolor=&amp;quot;#ff2222&amp;quot;|0x49||bgcolor=&amp;quot;#ff3333&amp;quot;|0x5E||bgcolor=&amp;quot;#ff4444&amp;quot;|0x64||bgcolor=&amp;quot;#ff5555&amp;quot;|0x73||bgcolor=&amp;quot;#ff6666&amp;quot;|0x38||bgcolor=&amp;quot;#ff7777&amp;quot;|0x2F||bgcolor=&amp;quot;#ff8888&amp;quot;|0xD0||bgcolor=&amp;quot;#ff9999&amp;quot;|0xC7||bgcolor=&amp;quot;#ffaaaa&amp;quot;|0x8C||bgcolor=&amp;quot;#ffbbbb&amp;quot;|0x9B||bgcolor=&amp;quot;#ffcccc&amp;quot;|0xA1||bgcolor=&amp;quot;#ffdddd&amp;quot;|0xB6||bgcolor=&amp;quot;#ffeeee&amp;quot;|0xFD||bgcolor=&amp;quot;#ffffff&amp;quot;|0xEA&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Die Einträge in der Tabelle sind so gewählt, dass der Code den maximalen [http://de.wikipedia.org/wiki/Hamming-Abstand#Hamming-Abstand_eines_Codes Hamming-Abstand] von 4 Bit hat.&lt;br /&gt;
&lt;br /&gt;
==== Dekodieren ====&lt;br /&gt;
&lt;br /&gt;
In der Tabelle &#039;&#039;HammingD&#039;&#039; stehen nur 4-Bit breite Werte. Um einen 8-Bit Wert zu erhalten müssen also 2 Einträge aus der Tabelle ausgewählt werden.&lt;br /&gt;
&lt;br /&gt;
Wird nun ein 16-Bit Wert empfangen, bestimmt das High-Byte den ersten Eintrag, das Low-Byte den zweiten.&lt;br /&gt;
&lt;br /&gt;
Es können bis zu zwei gekippte Bits im High- und im Low-Byte korrigiert werden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;3&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|&lt;br /&gt;
! colspan=&amp;quot;4&amp;quot; | Algorithmus || colspan=&amp;quot;4&amp;quot; | Beispiel (mit Bitfehlern)&lt;br /&gt;
|-&lt;br /&gt;
| 1:&lt;br /&gt;
| colspan=&amp;quot;4&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 16-Bit Codewort&lt;br /&gt;
| colspan=&amp;quot;4&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 110&#039;&#039;&#039;1&#039;&#039;&#039;0111 001&#039;&#039;&#039;0&#039;&#039;&#039;100&#039;&#039;&#039;1&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 2:&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | high&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | low&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 110&#039;&#039;&#039;1&#039;&#039;&#039;0111&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 001&#039;&#039;&#039;0&#039;&#039;&#039;100&#039;&#039;&#039;1&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 3:&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | HammingD[high]&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | HammingD[low]&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 0x09&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 0x06&lt;br /&gt;
|-&lt;br /&gt;
| 4: || || align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 4-7&lt;br /&gt;
| align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 0-3 || &lt;br /&gt;
| || align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 1001&lt;br /&gt;
| align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 0110 || &lt;br /&gt;
|-&lt;br /&gt;
| 5:&lt;br /&gt;
| width=&amp;quot;80&amp;quot; |&lt;br /&gt;
| width=&amp;quot;160&amp;quot; colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 8-Bit Wert&lt;br /&gt;
| width=&amp;quot;80&amp;quot; | || width=&amp;quot;80&amp;quot; |&lt;br /&gt;
| width=&amp;quot;160&amp;quot; colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 10010110&lt;br /&gt;
| width=&amp;quot;80&amp;quot; |&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;3&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|+ HammingD&lt;br /&gt;
|-&lt;br /&gt;
!  || 0 || 1 || 2  || 3 || 4 || 5 || 6 || 7 || 8 || 9 || A || B || C || D || E || F&lt;br /&gt;
|-&lt;br /&gt;
! 0&lt;br /&gt;
|bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ffaaAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07&lt;br /&gt;
|-&lt;br /&gt;
! 1&lt;br /&gt;
|bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03&lt;br /&gt;
|-&lt;br /&gt;
! 2&lt;br /&gt;
|bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07&lt;br /&gt;
|-&lt;br /&gt;
! 3&lt;br /&gt;
|bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07&lt;br /&gt;
|-&lt;br /&gt;
! 4&lt;br /&gt;
|bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03&lt;br /&gt;
|-&lt;br /&gt;
! 5&lt;br /&gt;
|bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03&lt;br /&gt;
|-&lt;br /&gt;
! 6&lt;br /&gt;
|bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07&lt;br /&gt;
|-&lt;br /&gt;
! 7&lt;br /&gt;
|bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07&lt;br /&gt;
|-&lt;br /&gt;
! 8&lt;br /&gt;
|bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B&lt;br /&gt;
|-&lt;br /&gt;
! 9&lt;br /&gt;
|bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B&lt;br /&gt;
|-&lt;br /&gt;
! A&lt;br /&gt;
|bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07&lt;br /&gt;
|-&lt;br /&gt;
! B&lt;br /&gt;
|bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F&lt;br /&gt;
|-&lt;br /&gt;
! C&lt;br /&gt;
|bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09&lt;br /&gt;
|-&lt;br /&gt;
! D&lt;br /&gt;
|bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B&lt;br /&gt;
|-&lt;br /&gt;
! E&lt;br /&gt;
|bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F&lt;br /&gt;
|-&lt;br /&gt;
! F&lt;br /&gt;
|bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Funk]]&lt;br /&gt;
[[Kategorie:Wettbewerb]]&lt;/div&gt;</summary>
		<author><name>Thymythos</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=AVR_RFM12&amp;diff=32664</id>
		<title>AVR RFM12</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=AVR_RFM12&amp;diff=32664"/>
		<updated>2008-11-23T10:50:51Z</updated>

		<summary type="html">&lt;p&gt;Thymythos: /* Hardware */ kompakter&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Schaltungen und Software für AVR und das Funkmodul [[RFM12]].&lt;br /&gt;
&lt;br /&gt;
== SVN ==&lt;br /&gt;
&lt;br /&gt;
svn://mikrocontroller.net/rfm12&lt;br /&gt;
&lt;br /&gt;
Wegen Zugangsdaten bitte bei [http://www.mikrocontroller.net/user/show/andreas Andreas Schwarz] melden.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Software ==&lt;br /&gt;
&lt;br /&gt;
=== Treiber ===&lt;br /&gt;
&lt;br /&gt;
[http://www.mikrocontroller.net/attachment/22473/rfm12_pc.zip Firmware v1.0.0] von Benedikt K.&lt;br /&gt;
&lt;br /&gt;
[http://www.mikrocontroller.net/attachment/23542/RMxx_Driver.tar.bz2 Firmware v2.0.1] von Jürgen Eckert&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot;&lt;br /&gt;
|+ Funktionalität&lt;br /&gt;
|-&lt;br /&gt;
!  || Beschreibung || Software&lt;br /&gt;
|-&lt;br /&gt;
!1. Stufe:&lt;br /&gt;
| Die Daten von der seriellen Schnittstelle werden über die Funkstrecke auf die serielle Schnittstelle der anderen Seite übertragen. (Wir freuen uns über jedes Byte das ankommt)&lt;br /&gt;
| [http://www.mikrocontroller.net/topic/67273#564945 Claude Schwarz], [http://www.mikrocontroller.net/topic/71682#584915 Benedikt K.] oder [http://www.mikrocontroller.net/attachment/36742/RFM12_V3.zip Manuel Stahl]&lt;br /&gt;
|-&lt;br /&gt;
! 2. Stufe:&lt;br /&gt;
| Es findet eine Fehlererkennung (z.B. mit CRC-Summen) statt. Fehlerhafte Daten werden erneut angefordert. Dadurch gehen auf der Funkstrecke keine Daten verloren und es werden keine Daten verfälscht.&lt;br /&gt;
| [http://www.mikrocontroller.net/topic/71682#585851 Benedikt K.]&lt;br /&gt;
|-&lt;br /&gt;
! 3. Stufe:&lt;br /&gt;
| Die Datenübertragung wird individualisiert. Dadurch können zwei Funkstrecken, die im gleichen Empfangsbereich liegen nebeneinander arbeiten, ohne sich zu beeinträchtigen.&lt;br /&gt;
| [[RFM12_Protokoll_Stack]]&lt;br /&gt;
|-&lt;br /&gt;
! 4. Stufe: &lt;br /&gt;
| Die Datenübertragung wird verschlüsselt und damit abhörsicher.&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
!5. Stufe:&lt;br /&gt;
| Neben den Daten der seriellen Schnittstelle werden auch Änderungen der Statusleitungen übertragen. Damit erhält man eine &amp;quot;RS232-Verlängerung&amp;quot; über eine Funkstrecke, die fehlerfrei arbeitet und zu einer Drahtverbindung weitestgehend kompatibel ist.&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== RS232 &amp;lt;-&amp;gt; RFM12 ===&lt;br /&gt;
&lt;br /&gt;
TODO&lt;br /&gt;
&lt;br /&gt;
=== USB &amp;lt;-&amp;gt; RFM12 ===&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;&#039;[http://www.obdev.at/products/avrusb/index.html avrusb]&#039;&#039;&#039; lässt sich ein USB-Slave in Software emulieren.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;[http://www.recursion.jp/avrcdc/ AVR-CDC]&#039;&#039;&#039; läuft mit Anpassung der USB-Pins. &#039;&#039;(Zumindest unter Windows an einem USB2.0-Port)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Adapter für &#039;&#039;&#039;[http://www.embedded-projects.net/?page_id=135 USBprog]:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Funktionierender Code liegt im oben genannten SVN&lt;br /&gt;
* Implementiert die USB-CDC-Klasse (kein Treiber nötig)&lt;br /&gt;
* Sicherung der Übertragung durch Hamming-Code&lt;br /&gt;
* Work in progress... (Manuel Stahl)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Hardware ==&lt;br /&gt;
&lt;br /&gt;
=== Basismodul V1.0 ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Prozessor&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
ATmega8 TQFP32 (kompatibel ATmega48, ATmega88, ATmega168)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Schnittstellen&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* RS232&lt;br /&gt;
* I²C:&lt;br /&gt;
* USB&lt;br /&gt;
* GPIO&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Platine&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[Bild:AVR RFM12 Schematic.png|200px|ATmega48 + USB]]&lt;br /&gt;
[[Bild:AVR RFM12 Board TOP.png|220px|2-lagig top]]&lt;br /&gt;
[[Bild:AVR RFM12 Board BOTTOM.png|240px|2-lagig bottom]]&lt;br /&gt;
[[Bild:AVR_RFM12_Photo.jpg|240px|Photo]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;float:left; border-right:1px solid gray; padding-right:10px;&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Bauteile:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Größe: SMD 0603&lt;br /&gt;
&lt;br /&gt;
* R1, R2: 68R (nur USB)&lt;br /&gt;
* R3, R4: 10k&lt;br /&gt;
* R5: 1k5 (nur USB)&lt;br /&gt;
* C1, C2: 22pF&lt;br /&gt;
* C3 - C9: 100nF&lt;br /&gt;
* Q1: 12Mhz (nur USB)&lt;br /&gt;
* D1, D2: beliebig, Minimelf&lt;br /&gt;
* IC3: MAX3221CUE&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;float:left; border-right:1px solid gray; padding: 0px 0px 10px 10px; width:33%&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Kosten:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* MiniUSB SMD: &#039;&#039;&#039;1,25€&#039;&#039;&#039;&lt;br /&gt;
* HF-Buchse MMCX: &#039;&#039;&#039;4,25€&#039;&#039;&#039;&lt;br /&gt;
* ATmega48: &#039;&#039;&#039;2,85€&#039;&#039;&#039;&lt;br /&gt;
* MAX3221CUE: &#039;&#039;&#039;1,10€&#039;&#039;&#039;&lt;br /&gt;
* Quarz 12Mhz 30ppm: &#039;&#039;&#039;1,19€&#039;&#039;&#039;&lt;br /&gt;
* Kleinkram: &#039;&#039;&#039;&amp;lt; 1,10€&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* habe ein verbindliches Angebot für 24 Stück von http://mme-pcb.de/: &#039;&#039;&#039;4,00€ pro Platine&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;float:left; padding: 0px 0px 10px 10px; width:33%&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039; Bugs / Erweiterungen:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Der 1,5k Widerstand muss direkt an den VCC-Pin angelötet werden (Pad ist nicht verbunden)&lt;br /&gt;
* Beim Fertigen wurde das Polygon, welches das VCC-Signal durch die eine Ecke des ATmega48 leitet, unterbrochen. Hier hilft nur eine Drahtbrücke.&lt;br /&gt;
* Unter den RFM12 und unter das Quarz am Besten Isolierband kleben!&lt;br /&gt;
* Beim Programmieren sollte der SEL des RFM12 (J1 der zweite Pin vom RS232 aus) auf VCC gelegt werden&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear:both&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[http://www.mikrocontroller.net/attachment/24012/RFM12.brd Board (Eagle)]:&lt;br /&gt;
&lt;br /&gt;
[[Bild:AVR RFM12 Board top bestuecken.png|200px|top]]&lt;br /&gt;
[[Bild:Board bottom bestuecken.png|200px|bottom]]&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== Flashcraft Funkboard ===&lt;br /&gt;
&lt;br /&gt;
[http://flashcraft.de/index.php/funkboard-uebersicht Homepage]&lt;br /&gt;
&lt;br /&gt;
# SMA-Antennenanschluss&lt;br /&gt;
# Abmessungen:32x34mm, leichte Montage durch 2 Stiftleisten im 2,54mm Raster&lt;br /&gt;
# ATmega32 onBoard, übernimmt komplette Ansteuerung&lt;br /&gt;
# 3 Schnittstellen zur Ansteuerung sind vorgesehen: I2C, SPI, UART&lt;br /&gt;
# Geringe Stromaufnahme: 10mA im normalen Betrieb, 2 Schlafmodis mit Stromverbrauch bis min. 25µA!&lt;br /&gt;
# Betriebsspannungsbereich von 3,2 - 5,4V&lt;br /&gt;
# 5V oder 3V Spannungsregler onBoard! Direkter Batteriebetrieb möglich; Kann externe Schaltung versorgen! &lt;br /&gt;
# Über 50 Seiten starke Dokumentation&lt;br /&gt;
# Komplettes Projekt online verfügbar!&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== USBprogRFM12 ===&lt;br /&gt;
&lt;br /&gt;
Da der USBprog genau das SPI-Interface des ATmega32 zur Verfügung stellt, eignet er sich perfekt als USB-RFM12-Adapter.&lt;br /&gt;
&lt;br /&gt;
[[Bild:USBprogRFM12_schematic.png|200px|USBprogRFM12]] [[Bild:USBprogRFM12_board.png|200px|USBprogRFM12]]&lt;br /&gt;
&lt;br /&gt;
[[Bild:USBprogRFM12.jpg|400px|USBprogRFM12]]&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
* [http://www.mikrocontroller.net/topic/65984 Allgemeine Diskussion]&lt;br /&gt;
* [http://www.mikrocontroller.net/topic/71682  bidirektionale RS232 Funkbrücke mit RFM12]&lt;br /&gt;
* [http://www.das-labor.org/wiki/Datenfunk_mit_dem_AVR Datenfunk mit dem AVR] bei das-labor.org&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Projekte]]&lt;br /&gt;
[[Kategorie:AVR]]&lt;br /&gt;
[[Kategorie:Funk]]&lt;/div&gt;</summary>
		<author><name>Thymythos</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=AVR_RFM12&amp;diff=32663</id>
		<title>AVR RFM12</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=AVR_RFM12&amp;diff=32663"/>
		<updated>2008-11-23T10:38:18Z</updated>

		<summary type="html">&lt;p&gt;Thymythos: /* Flashcraft Funkboard */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Schaltungen und Software für AVR und das Funkmodul [[RFM12]].&lt;br /&gt;
&lt;br /&gt;
== SVN ==&lt;br /&gt;
&lt;br /&gt;
svn://mikrocontroller.net/rfm12&lt;br /&gt;
&lt;br /&gt;
Wegen Zugangsdaten bitte bei [http://www.mikrocontroller.net/user/show/andreas Andreas Schwarz] melden.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Software ==&lt;br /&gt;
&lt;br /&gt;
=== Treiber ===&lt;br /&gt;
&lt;br /&gt;
[http://www.mikrocontroller.net/attachment/22473/rfm12_pc.zip Firmware v1.0.0] von Benedikt K.&lt;br /&gt;
&lt;br /&gt;
[http://www.mikrocontroller.net/attachment/23542/RMxx_Driver.tar.bz2 Firmware v2.0.1] von Jürgen Eckert&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot;&lt;br /&gt;
|+ Funktionalität&lt;br /&gt;
|-&lt;br /&gt;
!  || Beschreibung || Software&lt;br /&gt;
|-&lt;br /&gt;
!1. Stufe:&lt;br /&gt;
| Die Daten von der seriellen Schnittstelle werden über die Funkstrecke auf die serielle Schnittstelle der anderen Seite übertragen. (Wir freuen uns über jedes Byte das ankommt)&lt;br /&gt;
| [http://www.mikrocontroller.net/topic/67273#564945 Claude Schwarz], [http://www.mikrocontroller.net/topic/71682#584915 Benedikt K.] oder [http://www.mikrocontroller.net/attachment/36742/RFM12_V3.zip Manuel Stahl]&lt;br /&gt;
|-&lt;br /&gt;
! 2. Stufe:&lt;br /&gt;
| Es findet eine Fehlererkennung (z.B. mit CRC-Summen) statt. Fehlerhafte Daten werden erneut angefordert. Dadurch gehen auf der Funkstrecke keine Daten verloren und es werden keine Daten verfälscht.&lt;br /&gt;
| [http://www.mikrocontroller.net/topic/71682#585851 Benedikt K.]&lt;br /&gt;
|-&lt;br /&gt;
! 3. Stufe:&lt;br /&gt;
| Die Datenübertragung wird individualisiert. Dadurch können zwei Funkstrecken, die im gleichen Empfangsbereich liegen nebeneinander arbeiten, ohne sich zu beeinträchtigen.&lt;br /&gt;
| [[RFM12_Protokoll_Stack]]&lt;br /&gt;
|-&lt;br /&gt;
! 4. Stufe: &lt;br /&gt;
| Die Datenübertragung wird verschlüsselt und damit abhörsicher.&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
!5. Stufe:&lt;br /&gt;
| Neben den Daten der seriellen Schnittstelle werden auch Änderungen der Statusleitungen übertragen. Damit erhält man eine &amp;quot;RS232-Verlängerung&amp;quot; über eine Funkstrecke, die fehlerfrei arbeitet und zu einer Drahtverbindung weitestgehend kompatibel ist.&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== RS232 &amp;lt;-&amp;gt; RFM12 ===&lt;br /&gt;
&lt;br /&gt;
TODO&lt;br /&gt;
&lt;br /&gt;
=== USB &amp;lt;-&amp;gt; RFM12 ===&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;&#039;[http://www.obdev.at/products/avrusb/index.html avrusb]&#039;&#039;&#039; lässt sich ein USB-Slave in Software emulieren.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;[http://www.recursion.jp/avrcdc/ AVR-CDC]&#039;&#039;&#039; läuft mit Anpassung der USB-Pins. &#039;&#039;(Zumindest unter Windows an einem USB2.0-Port)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Adapter für &#039;&#039;&#039;[http://www.embedded-projects.net/?page_id=135 USBprog]:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Funktionierender Code liegt im oben genannten SVN&lt;br /&gt;
* Implementiert die USB-CDC-Klasse (kein Treiber nötig)&lt;br /&gt;
* Sicherung der Übertragung durch Hamming-Code&lt;br /&gt;
* Work in progress... (Manuel Stahl)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Hardware ==&lt;br /&gt;
&lt;br /&gt;
=== Basismodul V1.0 ===&lt;br /&gt;
&lt;br /&gt;
==== Prozessor ====&lt;br /&gt;
&lt;br /&gt;
ATmega8 TQFP32 (kompatibel ATmega48, ATmega88, ATmega168)&lt;br /&gt;
&lt;br /&gt;
==== Schnittstellen ====&lt;br /&gt;
&lt;br /&gt;
* RS232&lt;br /&gt;
* I²C:&lt;br /&gt;
* USB&lt;br /&gt;
* GPIO&lt;br /&gt;
&lt;br /&gt;
==== Platine ====&lt;br /&gt;
&lt;br /&gt;
[[Bild:AVR RFM12 Schematic.png|200px|ATmega48 + USB]]&lt;br /&gt;
[[Bild:AVR RFM12 Board TOP.png|220px|2-lagig top]]&lt;br /&gt;
[[Bild:AVR RFM12 Board BOTTOM.png|240px|2-lagig bottom]]&lt;br /&gt;
[[Bild:AVR_RFM12_Photo.jpg|240px|Photo]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Bauteile:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Größe: SMD 0603&lt;br /&gt;
&lt;br /&gt;
* R1, R2: 68R (nur USB)&lt;br /&gt;
* R3, R4: 10k&lt;br /&gt;
* R5: 1k5 (nur USB)&lt;br /&gt;
* C1, C2: 22pF&lt;br /&gt;
* C3 - C9: 100nF&lt;br /&gt;
* Q1: 12Mhz (nur USB)&lt;br /&gt;
* D1, D2: beliebig, Minimelf&lt;br /&gt;
* IC3: MAX3221CUE&lt;br /&gt;
&lt;br /&gt;
==== Bugs / Erweiterungen ====&lt;br /&gt;
&lt;br /&gt;
* Der 1,5k Widerstand muss direkt an den VCC-Pin angelötet werden (Pad ist nicht verbunden)&lt;br /&gt;
* Beim Fertigen wurde das Polygon, welches das VCC-Signal durch die eine Ecke des ATmega48 leitet, unterbrochen. Hier hilft nur eine Drahtbrücke.&lt;br /&gt;
* Unter den RFM12 und unter das Quarz am Besten Isolierband kleben!&lt;br /&gt;
* Beim Programmieren sollte der SEL des RFM12 (J1 der zweite Pin vom RS232 aus) auf VCC gelegt werden&lt;br /&gt;
&lt;br /&gt;
==== Fertigung ====&lt;br /&gt;
&lt;br /&gt;
Kosten:&lt;br /&gt;
&lt;br /&gt;
* MiniUSB SMD: &#039;&#039;&#039;1,25€&#039;&#039;&#039;&lt;br /&gt;
* HF-Buchse MMCX: &#039;&#039;&#039;4,25€&#039;&#039;&#039;&lt;br /&gt;
* ATmega48: &#039;&#039;&#039;2,85€&#039;&#039;&#039;&lt;br /&gt;
* MAX3221CUE: &#039;&#039;&#039;1,10€&#039;&#039;&#039;&lt;br /&gt;
* Quarz 12Mhz 30ppm: &#039;&#039;&#039;1,19€&#039;&#039;&#039;&lt;br /&gt;
* Kleinkram: &#039;&#039;&#039;&amp;lt; 1,10€&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* habe ein verbindliches Angebot für 24 Stück von http://mme-pcb.de/: &#039;&#039;&#039;4,00€ pro Platine&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[http://www.mikrocontroller.net/attachment/24012/RFM12.brd Board]:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Board bottom bestuecken.png|200px|bottom]]&lt;br /&gt;
[[Bild:AVR RFM12 Board top bestuecken.png|200px|top]]&lt;br /&gt;
&lt;br /&gt;
=== Flashcraft Funkboard ===&lt;br /&gt;
&lt;br /&gt;
[http://flashcraft.de/index.php/funkboard-uebersicht Homepage]&lt;br /&gt;
&lt;br /&gt;
# SMA-Antennenanschluss&lt;br /&gt;
# Abmessungen:32x34mm, leichte Montage durch 2 Stiftleisten im 2,54mm Raster&lt;br /&gt;
# ATmega32 onBoard, übernimmt komplette Ansteuerung&lt;br /&gt;
# 3 Schnittstellen zur Ansteuerung sind vorgesehen: I2C, SPI, UART&lt;br /&gt;
# Geringe Stromaufnahme: 10mA im normalen Betrieb, 2 Schlafmodis mit Stromverbrauch bis min. 25µA!&lt;br /&gt;
# Betriebsspannungsbereich von 3,2 - 5,4V&lt;br /&gt;
# 5V oder 3V Spannungsregler onBoard! Direkter Batteriebetrieb möglich; Kann externe Schaltung versorgen! &lt;br /&gt;
# Über 50 Seiten starke Dokumentation&lt;br /&gt;
# Komplettes Projekt online verfügbar!&lt;br /&gt;
&lt;br /&gt;
=== USBprogRFM12 ===&lt;br /&gt;
&lt;br /&gt;
Da der USBprog genau das SPI-Interface des ATmega32 zur Verfügung stellt, eignet er sich perfekt als USB-RFM12-Adapter.&lt;br /&gt;
&lt;br /&gt;
[[Bild:USBprogRFM12_schematic.png|200px|USBprogRFM12]] [[Bild:USBprogRFM12_board.png|200px|USBprogRFM12]]&lt;br /&gt;
&lt;br /&gt;
[[Bild:USBprogRFM12.jpg|400px|USBprogRFM12]]&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
* [http://www.mikrocontroller.net/topic/65984 Allgemeine Diskussion]&lt;br /&gt;
* [http://www.mikrocontroller.net/topic/71682  bidirektionale RS232 Funkbrücke mit RFM12]&lt;br /&gt;
* [http://www.das-labor.org/wiki/Datenfunk_mit_dem_AVR Datenfunk mit dem AVR] bei das-labor.org&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Projekte]]&lt;br /&gt;
[[Kategorie:AVR]]&lt;br /&gt;
[[Kategorie:Funk]]&lt;/div&gt;</summary>
		<author><name>Thymythos</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=AVR-GCC-Tutorial&amp;diff=32658</id>
		<title>AVR-GCC-Tutorial</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=AVR-GCC-Tutorial&amp;diff=32658"/>
		<updated>2008-11-23T09:39:54Z</updated>

		<summary type="html">&lt;p&gt;Thymythos: /* TODO */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Vorwort =&lt;br /&gt;
&lt;br /&gt;
Dieses Tutorial soll den Einstieg in die Programmierung von Atmel [[AVR]]-Mikrocontrollern in der Programmiersprache [[C]] mit dem freien C-Compiler [[AVR-GCC]] erleichtern.&lt;br /&gt;
&lt;br /&gt;
Vorausgesetzt werden Grundkenntnisse der Progammiersprache C. Diese Kenntnisse kann man sich online erarbeiten, z. B. mit dem [http://www.schellong.de/c.htm C Tutorial von Helmut Schellong]. Nicht erforderlich sind Vorkenntnisse in der Programmierung von Mikrocontrollern, weder in Assembler noch in einer anderen Sprache. &lt;br /&gt;
&lt;br /&gt;
In diesem Text wird häufig auf die Standardbibliothek avr-libc verwiesen, für die es eine [http://www.nongnu.org/avr-libc/user-manual/index.html Online-Dokumentation] gibt, in der sich auch viele nützliche Informationen zum Compiler und zur Programmierung von AVR Controllern finden. Bei WinAVR gehört die avr-libc Dokumentation zum Lieferumfang und wird mitinstalliert.&lt;br /&gt;
&lt;br /&gt;
Der Compiler und die Standardbibliothek avr-libc werden stetig weiterentwickelt. Erläuterungen und Beispiele beziehen sich auf den C-Compiler avr-gcc ab Version 3.4 und die avr-libc ab Version 1.4.3. Die Unterschiede zu älteren Versionen werden im Haupttext und Anhang zwar erläutert, Anfängern sei jedoch empfohlen, die aktuellen Versionen zu nutzen (für MS-Windows: aktuelle Version des [[WinAVR]]-Pakets; für Linux gibt es CDK4AVR: http://cdk4avr.sf.net oder auch fertige Pakete bei verschiedenen Distributionen.). &lt;br /&gt;
&lt;br /&gt;
Das ursprüngliche Tutorial stammt von Christian Schifferle, viele neue Abschnitte und aktuelle Anpassungen von Martin Thomas.&lt;br /&gt;
&lt;br /&gt;
Dieses Tutorial ist in PDF-Form erhältlich bei:&lt;br /&gt;
http://www.siwawi.arubi.uni-kl.de/avr_projects/AVR-GCC-Tutorial_-_www_mikrocontroller_net.pdf&lt;br /&gt;
(nicht immer auf aktuellem Stand)&lt;br /&gt;
&lt;br /&gt;
= Benötigte Werkzeuge =&lt;br /&gt;
&lt;br /&gt;
Um eigene Programme für AVRs mittels avr-gcc/avr-libc zu erstellen und zu testen, wird folgende Hard- und Software benötigt:&lt;br /&gt;
&lt;br /&gt;
* Platine oder Versuchsaufbau für die Aufnahme eines AVR Controllers, der vom avr-gcc Compiler unterstützt wird (alle ATmegas und die meisten AT90, siehe Dokumentation der avr-libc für unterstützte Typen). Dieses Testboard kann durchaus auch selbst gelötet oder auf einem Steckbrett aufgebaut werden. Einige Registerbeschreibungen dieses Tutorials beziehen sich auf den inzwischen veralteten AT90S2313. Der weitaus größte Teil des Textes ist aber für alle Controller der AVR-Familie gültig. Brauchbare Testplattformen sind auch das [[STK500]] und der [[AVR Butterfly]] von Atmel. Weitere Infos findet man [[AVR#Starterkits|hier]].&lt;br /&gt;
&lt;br /&gt;
* Der avr-gcc Compiler und die avr-libc. Kostenlos erhältlich für nahezu alle Plattformen und Betriebssysteme. Für MS-Windows im Paket [[WinAVR]]; für Unix/Linux siehe auch Hinweise im Artikel [[AVR-GCC]].&lt;br /&gt;
&lt;br /&gt;
* Programmiersoftware und -[[AVR In System Programmer |hardware]] z. B. PonyProg (siehe auch: [[Pony-Prog Tutorial]]) oder [[AVRDUDE]] mit [[STK200]]-Dongle oder die von Atmel verfügbare Hard- und Software ([[STK500]], Atmel AVRISP, [[AVR-Studio]]).&lt;br /&gt;
&lt;br /&gt;
* Nicht unbedingt erforderlich, aber zur Simulation und zum Debuggen unter MS-Windows recht nützlich: [[AVR-Studio]] (siehe Abschnitt [[AVR-GCC-Tutorial#Exkurs: Makefiles|Exkurs: Makefiles]]).&lt;br /&gt;
&lt;br /&gt;
= Was tun, wenn&#039;s nicht &amp;quot;klappt&amp;quot;? =&lt;br /&gt;
&lt;br /&gt;
* Herausfinden, ob es tatsächlich ein avr(-gcc) spezifisches Problem ist oder nur die eigenen C-Kenntnisse einer Auffrischung bedürfen. Allgemeine C-Fragen kann man eventuell &amp;quot;beim freundlichen Programmierer zwei Büro-, Zimmer- oder Haustüren weiter&amp;quot; loswerden. Ansonsten: [[C]]-Buch (gibt&#039;s auch &amp;quot;gratis&amp;quot; online) lesen.&lt;br /&gt;
&lt;br /&gt;
* Die [[AVR Checkliste]] durcharbeiten.&lt;br /&gt;
&lt;br /&gt;
* Die &#039;&#039;&#039;[http://www.nongnu.org/avr-libc/user-manual/index.html Dokumentation der avr-libc]&#039;&#039;&#039; lesen, vor allem (aber nicht nur) den Abschnitt Related Pages/&#039;&#039;&#039;Frequently Asked Questions&#039;&#039;&#039; = Oft gestellte Fragen (und Antworten dazu). Z.Zt leider nur in englischer Sprache verfügbar.&lt;br /&gt;
&lt;br /&gt;
* Den Artikel [[AVR-GCC]] in diesem Wiki lesen.&lt;br /&gt;
&lt;br /&gt;
* Das [http://www.mikrocontroller.net/forum/2 GCC-Forum auf  www.mikrocontroller.net] nach vergleichbaren Problemen absuchen.&lt;br /&gt;
&lt;br /&gt;
* Das avr-gcc-Forum bei [http://www.avrfreaks.net avrfreaks] nach vergleichbaren Problemen absuchen.&lt;br /&gt;
&lt;br /&gt;
* Das [http://lists.gnu.org/archive/html/avr-gcc-list/ Archiv der avr-gcc Mailing-Liste] nach vergleichbaren Problemen absuchen.&lt;br /&gt;
&lt;br /&gt;
* Nach Beispielcode suchen. Vor allem im &#039;&#039;Projects&#039;&#039;-Bereich von [http://www.avrfreaks.net AVRFREAKS] (anmelden).&lt;br /&gt;
&lt;br /&gt;
* Google oder yahoo befragen schadet nie.&lt;br /&gt;
&lt;br /&gt;
* Bei Problemen mit der Ansteuerung interner AVR-Funktionen mit C-Code: das Datenblatt des Controllers lesen (ganz und am Besten zweimal). Datenblätter sind  auf den [http://www.atmel.com Atmel Webseiten] als pdf-Dateien verfügbar. Das komplette Datenblatt (complete) und nicht die Kurzfassung (summary) verwenden.&lt;br /&gt;
&lt;br /&gt;
* Die Beispieleprogramme im [[AVR-Tutorial]] sind zwar in AVR-Assembler verfasst, Erläuterungen und Vorgehensweisen sind aber auch auf C-Programme übertragbar.&lt;br /&gt;
&lt;br /&gt;
* Einen Beitrag in eines der Foren oder eine Mail an die Mailing-Liste schreiben. Dabei möglichst viel Information geben: Controller, Compilerversion, genutzte Bibliotheken, Ausschnitte aus dem Quellcode oder besser ein [http://www.mikrocontroller.net/topic/72767#598986 Testprojekt] mit allen notwendigen Dateien, um das Problem nachzuvollziehen, sowie genaue Fehlermeldungen bzw. Beschreibung des Fehlverhaltens. Bei Ansteuerung externer Geräte die Beschaltung beschreiben oder skizzieren (z. B. mit [http://www.tech-chat.de/ Andys ASCII Circuit]). Siehe dazu auch: &#039;&#039;&#039;[http://www.lugbz.org/documents/smart-questions_de.html &amp;quot;Wie man Fragen richtig stellt&amp;quot;]&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
= Erzeugen von Maschinencode =&lt;br /&gt;
&lt;br /&gt;
Aus dem C-Quellcode erzeugt der avr-gcc Compiler (zusammen mit Hilfsprogrammen wie z.&amp;amp;nbsp;B. Präprozessor, Assembler und Linker) Maschinencode für den AVR-Controller. Üblicherweise liegt dieser Code dann im Intel Hex-Format vor (&amp;quot;Hex-Datei&amp;quot;). Die Programmiersoftware (z.&amp;amp;nbsp;B. [[AVRDUDE]], PonyProg oder AVRStudio/STK500-plugin) liest diese Datei ein und überträgt die enthaltene Information (den Maschinencode) in den Speicher des Controllers. Im Prinzip sind also &amp;quot;nur&amp;quot; der avr-gcc-Compiler (und wenige Hilfsprogramme) mit den &amp;quot;richtigen&amp;quot; Optionen aufzurufen, um aus C-Code eine &amp;quot;Hex-Datei&amp;quot; zu erzeugen. Grundsätzlich stehen dazu zwei verschiedene Ansätze zur Verfügung:&lt;br /&gt;
&lt;br /&gt;
* Die Verwendung einer integrierten Entwicklungsumgebung (IDE = &#039;&#039;&#039;I&#039;&#039;&#039;ntegrated &#039;&#039;&#039;D&#039;&#039;&#039;evelopment &#039;&#039;&#039;E&#039;&#039;&#039;nvironment), bei der alle Einstellungen z.&amp;amp;nbsp;B. in Dialogboxen durchgeführt werden können. Unter Anderem kann AVRStudio ab Version 4.12 (kostenlos auf [http://www.atmel.com/ atmel.com]) zusammen mit WinAVR als integrierte Entwicklungsumgebung für den Compiler avr-gcc genutzt werden (dazu müssen AVRStudio und WinAVR auf dem Rechner installiert sein). Weitere IDEs für den avr-gcc (ohne Anspruch auf Vollständigkeit): AtmanAvr C (relativ günstig), KamAVR (kostenlos), VMLab (ab Version 3.12 ebenfalls kostenlos). Integrierte Entwicklungsumgebungen unterscheiden sich stark in Ihrer Bedienung und stehen auch nicht für alle Plattformen zur Verfügung, auf denen der Compiler  ausführbar ist (z.&amp;amp;nbsp;B. AVRStudio nur für MS-Windows). Zur Anwendung des avr-gcc Compilers mit IDEs sei hier auf deren Dokumentation verwiesen. &lt;br /&gt;
&lt;br /&gt;
* Die Nutzung des Programms make mit passenden Makefiles. In den folgenden Abschnitten wird die Generierung von Maschinencode für einen AVR (&amp;quot;hex-Datei&amp;quot;) aus C-Quellcode (&amp;quot;c-Dateien&amp;quot;) anhand von &amp;quot;make&amp;quot; und den &amp;quot;Makefiles&amp;quot; näher erläutert. Viele der darin beschriebenen Optionen findet man auch im Konfigurationsdialog des avr-gcc-Plugins von AVRStudio (AVRStudio generiert ein makefile in einem Unterverzeichnis des Projektverzeichnisses). &lt;br /&gt;
&lt;br /&gt;
Beim Wechsel vom makefile-Ansatz nach WinAVR-Vorlage zu AVRStudio ist darauf zu achten, dass AVRStudio (Stand: AVRStudio Version 4.13) bei einem neuen Projekt die Optimierungsoption (vgl. Abschnitt [[AVR-GCC-Tutorial#Exkurs: Makefiles|Exkurs: Makefiles]], typisch: -Os) nicht einstellt und die mathematische Bibliothek der avr-libc (libm.a, Linker-Option -lm) nicht einbindet. Beides ist Standard bei Verwendung von makefiles nach WinAVR-Vorlage und sollte daher auch im Konfigurationsdialog des avr-gcc-Plugins von AVRStudio &amp;quot;manuell&amp;quot; eingestellt werden, um auch mit AVRStudio kompakten Code zu erzeugen.&lt;br /&gt;
&lt;br /&gt;
= Einführungsbeispiel =&lt;br /&gt;
&lt;br /&gt;
Zum Einstieg ein kleines Beispiel, an dem die Nutzung des Compilers und der Hilfsprogramme (der sogenannten &#039;&#039;Toolchain&#039;&#039;) demonstriert wird. Detaillierte Erläuterungen folgen in den weiteren Abschnitten dieses Tutorials.&lt;br /&gt;
&lt;br /&gt;
Das Programm soll auf einem AVR Mikrocontroller einige Ausgänge ein- und andere ausschalten. Das Beispiel ist für einen ATmega16 programmiert ([http://www.atmel.com/dyn/resources/prod_documents/doc2466.pdf Datenblatt]), kann aber sinngemäß für andere Controller der AVR-Familie modifiziert werden. &lt;br /&gt;
&lt;br /&gt;
Zunächst der Quellcode der Anwendung, der in einer Text-Datei mit dem Namen &#039;&#039;main.c&#039;&#039; abgespeichert wird.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
/* Alle Zeichen zwischen Schrägstrich-Stern &lt;br /&gt;
   und Stern-Schrägstrich sind lediglich Kommentare */&lt;br /&gt;
&lt;br /&gt;
// Zeilenkommentare sind ebenfalls möglich&lt;br /&gt;
// alle auf die beiden Schrägstriche folgenden&lt;br /&gt;
// Zeichen einer Zeile sind Kommentar&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;          // (1)&lt;br /&gt;
&lt;br /&gt;
int main (void) {            // (2)&lt;br /&gt;
&lt;br /&gt;
   DDRB  = 0xff;             // (3)&lt;br /&gt;
   PORTB = 0x03;             // (4)&lt;br /&gt;
&lt;br /&gt;
   while(1) {                // (5a)&lt;br /&gt;
     /* &amp;quot;leere&amp;quot; Schleife*/;  // (5b)&lt;br /&gt;
   }                         // (5c)&lt;br /&gt;
&lt;br /&gt;
   /* wird nie erreicht */&lt;br /&gt;
   return 0;                 // (6)&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* In der mit (1) markierten Zeile wird eine so genannte Header-Datei eingebunden. In io.h sind die Registernamen definiert, die im späteren Verlauf genutzt werden.&lt;br /&gt;
&lt;br /&gt;
* Bei (2) beginnt das eigentliche Programm. Jedes C-Programm beginnt mit den Anweisungen in der Funktion main.&lt;br /&gt;
&lt;br /&gt;
* Die Anschlüsse eines AVR (&amp;quot;Beinchen&amp;quot;) werden zu Blöcken zusammengefasst, einen solchen Block bezeichnet man als Port. Beim ATmega16 hat jeder Port 8 Anschlüsse, bei kleineren AVRs können einem Port auch weniger als 8 Anschlüsse zugeordnet sein. Da per Definition (Datenblatt) alle gesetzten Bits in einem Richtungsregister den entsprechenden Anschluss auf Ausgang schalten, werden mit DDRB=0xff alle Anschlüsse des Ports B zu Ausgängen.&lt;br /&gt;
&lt;br /&gt;
* (4) stellt die Werte der Ausgänge ein. Die den ersten beiden Bits des Ports zugeordneten Anschlüsse (PB0 und PB1) werden 1, alle anderen Anschlüsse des Ports B (PB2-PB7) zu 0. Aktivierte Ausgänge (logisch 1 oder &amp;quot;high&amp;quot;) liegen auf Betriebsspannung (VCC, meist 5 Volt), nicht aktivierte Ausgänge führen 0 Volt (GND, Bezugspotential).&lt;br /&gt;
&lt;br /&gt;
* (5) ist die so genannte Hauptschleife (main-loop). Dies ist eine Programmschleife, welche kontinuierlich wiederkehrende Befehle enthält. In diesem Beispiel ist sie leer. Der Controller durchläuft die Schleife immer wieder, ohne dass etwas passiert (außer das Strom verbraucht wird). Eine solche Schleife ist notwendig, da es auf dem Controller kein Betriebssystem gibt, das nach Beendigung des Programmes die Kontrolle übernehmen könnte. Ohne diese Schleife wäre der Zustand des Controllers nach dem Programmende undefiniert.&lt;br /&gt;
&lt;br /&gt;
* (6) wäre das Programmende. Die Zeile ist nur aus Gründen der C-Kompatibilität enthalten: int main(void) besagt, dass die Funktion einen Wert zurückgibt. Die Anweisung wird aber nicht erreicht, da das Programm die Hauptschleife nie verlässt.&lt;br /&gt;
&lt;br /&gt;
Um diesen Quellcode in ein auf dem Controller lauffähiges Programm zu übersetzen, wird hier ein Makefile genutzt. Das verwendete Makefile findet sich auf der Seite [[Beispiel Makefile]] und basiert auf der Vorlage, die in WinAVR mitgeliefert wird und wurde bereits angepasst (Controllertyp ATmega16). Man kann das Makefile bearbeiten und an andere Controller anpassen oder sich mit dem Programm MFile menügesteuert ein Makefile &amp;quot;zusammenklicken&amp;quot;. Das Makefile speichert man unter dem Namen Makefile (ohne Endung) im selben Verzeichnis, in dem auch die Datei main.c mit dem Programmcode abgelegt ist. Detailliertere Erklärungen zur Funktion von Makefiles finden sich im folgenden Abschnitt [[AVR-GCC-Tutorial#Exkurs: Makefiles|Exkurs: Makefiles]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
D:\tmp\gcc_tut\quickstart&amp;gt;dir&lt;br /&gt;
&lt;br /&gt;
 Verzeichnis von D:\tmp\gcc_tut\quickstart&lt;br /&gt;
&lt;br /&gt;
28.11.2006  22:53    &amp;lt;DIR&amp;gt;          .&lt;br /&gt;
28.11.2006  22:53    &amp;lt;DIR&amp;gt;          ..&lt;br /&gt;
28.11.2006  20:06               118 main.c&lt;br /&gt;
28.11.2006  20:03            16.810 Makefile&lt;br /&gt;
               2 Datei(en)         16.928 Bytes&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nun gibt man &#039;&#039;make all&#039;&#039; ein. Falls das mit WinAVR installierte Programmers Notepad genutzt wird, gibt es dazu einen Menüpunkt im Tools Menü. Sind alle Einstellungen korrekt, entsteht eine Datei main.hex, in der der Code für den AVR enthalten ist. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
D:\tmp\gcc_tut\quickstart&amp;gt;make all&lt;br /&gt;
&lt;br /&gt;
-------- begin --------&lt;br /&gt;
avr-gcc (GCC) 3.4.6&lt;br /&gt;
Copyright (C) 2006 Free Software Foundation, Inc.&lt;br /&gt;
This is free software; see the source for copying conditions.  There is NO&lt;br /&gt;
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Compiling C: main.c&lt;br /&gt;
avr-gcc -c -mmcu=atmega16 -I. -gdwarf-2 -DF_CPU=1000000UL -Os -funsigned-char -f&lt;br /&gt;
unsigned-bitfields -fpack-struct -fshort-enums -Wall -Wstrict-prototypes -Wundef&lt;br /&gt;
 -Wa,-adhlns=obj/main.lst  -std=gnu99 -Wundef -MD -MP -MF .dep/main.o.d main.c -&lt;br /&gt;
o obj/main.o&lt;br /&gt;
&lt;br /&gt;
Linking: main.elf&lt;br /&gt;
avr-gcc -mmcu=atmega16 -I. -gdwarf-2 -DF_CPU=1000000UL -Os -funsigned-char -funs&lt;br /&gt;
igned-bitfields -fpack-struct -fshort-enums -Wall -Wstrict-prototypes -Wundef -W&lt;br /&gt;
a,-adhlns=obj/main.o  -std=gnu99 -Wundef -MD -MP -MF .dep/main.elf.d obj/main.o&lt;br /&gt;
--output main.elf -Wl,-Map=main.map,--cref    -lm&lt;br /&gt;
&lt;br /&gt;
Creating load file for Flash: main.hex&lt;br /&gt;
avr-objcopy -O ihex -R .eeprom main.elf main.hex&lt;br /&gt;
&lt;br /&gt;
[...]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Inhalt der hex-Datei kann nun zum Controller übertragen werden. Dies kann z.&amp;amp;nbsp;B. über In-System-Programming (ISP) erfolgen, das im [[AVR-Tutorial: Equipment]] beschrieben ist. Makefiles nach der WinAVR/MFile-Vorlage sind für die Nutzung des Programms [[AVRDUDE]] vorbereitet. Wenn man den Typ und Anschluss des Programmiergerätes richtig eingestellt hat, kann mit &#039;&#039;make program&#039;&#039; die Übertragung mittels AVRDUDE gestartet werden. Jede andere Software, die hex-Dateien lesen und zu einem AVR übertragen kann (z.&amp;amp;nbsp;B. [[Pony-Prog_Tutorial|Ponyprog]], yapp, AVRStudio), kann natürlich ebenfalls genutzt werden.&lt;br /&gt;
&lt;br /&gt;
Startet man nun den Controller (Reset-Taster oder Stromzufuhr aus/an), werden vom Programm die Anschlüsse PB0 und PB1 auf 1 gesetzt. Man kann mit einem Messgerät nun an diesem Anschluss die Betriebsspannung messen oder eine LED leuchten lassen (Anode an den Pin, Vorwiderstand nicht vergessen). An den Anschlüssen PB2-PB7 misst man 0 Volt. Eine mit der Anode mit einem dieser Anschlüsse verbundene LED leuchtet nicht.&lt;br /&gt;
&lt;br /&gt;
= Exkurs: Makefiles =&lt;br /&gt;
&lt;br /&gt;
Wenn man bisher gewohnt ist, mit integrierten Entwicklungsumgebungen à la Visual-C Programme zu erstellen, wirkt das makefile-Konzept auf den ersten Blick etwas kryptisch. Nach kurzer Einarbeitung ist diese Vorgehensweise jedoch sehr praktisch. Diese Dateien (üblicher Name: &#039;Makefile&#039; ohne Dateiendung) dienen der Ablaufsteuerung des Programms make, das auf allen Unix/Linux-Systemen installiert sein sollte, und in einer Fassung fuer MS-Windows auch in [[WinAVR]] (Unterverzeichnis utils/bin) enthalten ist.&lt;br /&gt;
&lt;br /&gt;
Im Unterverzeichnis &#039;&#039;sample&#039;&#039; einer WinAVR-Installation findet man eine sehr brauchbare Vorlage, die sich einfach an das eigene Projekt anpassen lässt ([[Media:Makefile|lokale Kopie Stand Sept. 2004]]). Wahlweise kann man auch [http://www.sax.de/~joerg/mfile/ mfile] von Jörg Wunsch nutzen. mfile erzeugt ein makefile nach Einstellungen in einer grafischen Nutzeroberfläche, wird bei WinAVR mitinstalliert, ist aber als TCL/TK-Programm auf nahezu allen Plattformen lauffähig.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Die folgenden Ausführungen beziehen sich auf das WinAVR Beispiel-Makefile.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Ist im Makefile alles richtig eingestellt, genügt es, sich drei Parameter zu merken, die über die shell bzw. die Windows-Kommandozeile (cmd.exe/command.com) als Parameter an &amp;quot;make&amp;quot; übergeben werden. Das Programm make sucht sich &amp;quot;automatisch&amp;quot; das Makefile im aktuellen Arbeitsverzeichnis und führt die darin definierten Operationen für den entsprechenden Aufrufparameter durch.&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
| &#039;&#039;make all&#039;&#039;&lt;br /&gt;
| Erstellt aus den im Makefile angegebenen Quellcodes eine &#039;&#039;hex&#039;&#039;-Datei (und ggf. auch &#039;&#039;eep&#039;&#039;-Datei).&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;make program&#039;&#039;&lt;br /&gt;
| Überträgt die hex-Datei (und wahlweise auch die eep-Datei für den EEPROM) zum AVR. &lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;make clean&#039;&#039;&lt;br /&gt;
| löscht alle temporären Dateien, also auch die hex-Datei&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Diese Aufrufe können in die allermeisten Editoren in &amp;quot;Tool-Menüs&amp;quot; eingebunden werden. Dies erspart den Kontakt mit der Kommandozeile. Bei WinAVR sind die Aufrufe bereits im Tools-Menü des mitgelieferten Editors Programmers-Notepad eingefügt.&lt;br /&gt;
&lt;br /&gt;
Üblicherweise sind folgende Daten im Makefile anzupassen:&lt;br /&gt;
* Controllertyp&lt;br /&gt;
&lt;br /&gt;
* Quellcode-Dateien (c-Dateien)&lt;br /&gt;
&lt;br /&gt;
* Typ und Anschluss des Programmiergeräts&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Seltener sind folgende Einstellungen durchzuführen:&lt;br /&gt;
* Grad der Optimierung&lt;br /&gt;
&lt;br /&gt;
* Methode zur Erzeugung der Debug-Symbole (Debug-Format)&lt;br /&gt;
&lt;br /&gt;
* Assembler-Quellcode-Dateien (S-Dateien)&lt;br /&gt;
&lt;br /&gt;
Die in den folgenden Unterabschnitten gezeigten Makefile-Ausschnitte sind für ein Programm, das auf einem ATmega8 ausgeführt werden soll. Der Quellcode besteht aus den c-Dateien superprog.c (darin main()), uart.c, lcd.c und 1wire.c. Im Quellcodeverzeichnis befinden sich diese Dateien: superprog.c, uart.h, uart.c, lcd.h, lcd.c, 1wire.h, 1wire.c und das makefile (die angepasste Kopie des WinAVR-Beispiels).&lt;br /&gt;
&lt;br /&gt;
Der Controller wird mittels [[AVRDUDE]] über ein [[STK200]]-Programmierdongle an der Schnittstelle lpt1 (bzw. /dev/lp0) programmiert. Im Quellcode sind auch Daten für die &#039;&#039;section .eeprom&#039;&#039; definiert (siehe Abschnitt [[AVR-GCC-Tutorial#EEPROM|Speicherzugriffe]]), diese sollen beim Programmieren gleich mit ins EEPROM geschrieben werden. &lt;br /&gt;
&lt;br /&gt;
== Controllertyp setzen ==&lt;br /&gt;
&lt;br /&gt;
Dazu wird die &amp;quot;make-Variable&amp;quot; MCU entsprechend dem Namen des verwendeten Controllers gesetzt. Eine Liste der von avr-gcc und der avr-libc unterstützten Typen findet sich in der [http://www.nongnu.org/avr-libc/user-manual/index.html Dokumentation der avr-libc].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;code&amp;quot;&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
# Kommentare in Makefiles beginnen mit einem Doppelkreuz &lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
# ATmega8 at work&lt;br /&gt;
MCU = atmega8&lt;br /&gt;
# oder MCU = atmega16 &lt;br /&gt;
# oder MCU = at90s8535&lt;br /&gt;
# oder ...&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Quellcode-Dateien eintragen ==&lt;br /&gt;
&lt;br /&gt;
Der Name der Quellcodedatei, welche die Funktion main enthält, wird hinter TARGET eingetragen. Dies jedoch ohne die Endung &#039;&#039;.c&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;code&amp;quot;&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
TARGET = superprog&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Besteht das Projekt wie im Beispiel aus mehr als einer Quellcodedatei, sind die weiteren c-Dateien (nicht die Header-Dateien, vgl. [[Include-Files (C)]]) durch Leerzeichen getrennt bei SRC einzutragen. Die bei TARGET definierte Datei ist schon in der SRC-Liste enthalten. Diesen Eintrag nicht löschen!&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;code&amp;quot;&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
SRC = $(TARGET).c uart.c lcd.c 1wire.c &lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Alternativ kann man die Liste der Quellcodedateien auch mit dem Operator += erweitern.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;code&amp;quot;&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
SRC = $(TARGET).c uart.c 1wire.c&lt;br /&gt;
# lcd-Code fuer Controller xyz123 (auskommentiert)&lt;br /&gt;
# SRC += lcd_xyz.c&lt;br /&gt;
# lcd-Code fuer &amp;quot;Standard-Controller&amp;quot; (genutzt)&lt;br /&gt;
SRC += lcd.c&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Programmiergerät einstellen ==&lt;br /&gt;
&lt;br /&gt;
Die Vorlagen sind auf die Programmiersoftware [[AVRDUDE]] angepasst, jedoch lässt sich auch andere Programmiersoftware einbinden, sofern diese über Kommandozeile gesteuert werden kann (z.&amp;amp;nbsp;B. stk500.exe, uisp, sp12).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;code&amp;quot;&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
# Einstellung fuer STK500 an com1 (auskommentiert)&lt;br /&gt;
# AVRDUDE_PROGRAMMER = stk500&lt;br /&gt;
# com1 = serial port. Use lpt1 to connect to parallel port.&lt;br /&gt;
# AVRDUDE_PORT = com1    # programmer connected to serial device&lt;br /&gt;
&lt;br /&gt;
# Einstellung fuer STK200-Dongle an lpt1&lt;br /&gt;
AVRDUDE_PROGRAMMER = stk200&lt;br /&gt;
AVRDUDE_PORT = lpt1&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sollen Flash(=.hex) und EEPROM(=.eep) zusammen auf den Controller programmiert werden, ist das Kommentarzeichen vor AVRDUDE_WRITE_EEPROM zu löschen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;code&amp;quot;&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
# auskommentiert: EERPOM-Inhalt wird nicht mitgeschrieben&lt;br /&gt;
#AVRDUDE_WRITE_EEPROM = -U eeprom:w:$(TARGET).eep&lt;br /&gt;
&lt;br /&gt;
# nicht auskommentiert: EERPOM-Inhalt wird mitgeschrieben&lt;br /&gt;
AVRDUDE_WRITE_EEPROM = -U eeprom:w:$(TARGET).eep&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Anwendung ==&lt;br /&gt;
&lt;br /&gt;
Das erstellte Makefile und der Code müssen im gleichen Ordner sein, auch sollte der Dateiname nicht verändert werden. &lt;br /&gt;
&lt;br /&gt;
Die Eingabe von &#039;&#039;make all&#039;&#039; im Arbeitsverzeichnis mit dem Makefile und den Quellcodedateien erzeugt (unter anderem) die Dateien superprog.hex und superprog.eep. Abhängigkeiten zwischen den einzelnen c-Dateien werden dabei automatisch berücksichtigt. Die &#039;&#039;superprog.hex&#039;&#039; und &#039;&#039;superprog.eep&#039;&#039; werden mit &#039;&#039;make program&#039;&#039; zum Controller  übertragen. Mit &#039;&#039;make clean&#039;&#039; werden alle temporären Dateien gelöscht (=&amp;quot;aufgeräumt&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
== Sonstige Einstellungen ==&lt;br /&gt;
&lt;br /&gt;
=== Optimierungsgrad ===&lt;br /&gt;
&lt;br /&gt;
Der gcc-Compiler kennt verschiedene Stufen der Optimierung. Nur zu Testzwecken sollte die Optimierung ganz deaktiviert werden (&#039;&#039;OPT = 0&#039;&#039;). Die weiteren möglichen Optionen weisen den Compiler an, möglichst kompakten oder möglichst schnellen Code zu erzeugen. In den weitaus meisten Fällen ist &#039;&#039;OPT = s&#039;&#039; die empfohlene Einstellung, damit wird kompakter und oft auch der schnellste Maschinencode erzeugt. Beim Update auf eine neue Compilerversion ist zu beachten, dass diese möglicherweise intern andere Optimierungsalgorithmen verwendet und sich dadurch die Größe des Machinencodes etwas ändert, ohne dass man im Quellcode etwas geändert hat.&lt;br /&gt;
&lt;br /&gt;
Als Orientierungswerte die Größe des Maschinencodes bei verschiedenen Optionen für einen nicht näher spezifizierten relativ kleinen Testcode bei Verwendung einer nicht näher spezifizierten Compilerversion. &lt;br /&gt;
&lt;br /&gt;
* -O0 : 12&#039;217 Byte&lt;br /&gt;
&lt;br /&gt;
* -O1 : 9&#039;128 Byte&lt;br /&gt;
&lt;br /&gt;
* -O2 : 1&#039;670 Byte&lt;br /&gt;
&lt;br /&gt;
* -O3 : 3&#039;004 Byte&lt;br /&gt;
&lt;br /&gt;
* -Os : 1&#039;695 Byte&lt;br /&gt;
&lt;br /&gt;
Im diesem Testfall führt die Option -O2 mit zum kompaktesten Code, dies  allerdings hier nur mit 25 Bytes &amp;quot;Vorsprung&amp;quot;. Es kann durchaus sein, dass nur wenige Programmerweiterungen dazu führen, dass Compilieren mit -Os wieder in kompakteren Code resultiert.&lt;br /&gt;
&lt;br /&gt;
Siehe dazu auch: &lt;br /&gt;
* [http://www.nongnu.org/avr-libc/user-manual/using_tools.html#gcc_optO avr-libc manual Abschnitt Using the gnu-tools/Compiler-Optionen]&lt;br /&gt;
&lt;br /&gt;
* [http://www.nongnu.org/avr-libc/user-manual/FAQ.html#faq_optflags avr-libc Manual FAQ Nr. 16] (Stand avr-libc Version 1.4.5)&lt;br /&gt;
&lt;br /&gt;
=== Debug-Format ===&lt;br /&gt;
&lt;br /&gt;
Unterstützt werden die Formate stabs und dwarf-2. Das Format wird hinter &#039;&#039;DEBUG =&#039;&#039; eingestellt. Siehe dazu Abschnitt &#039;&#039;Eingabedateien zur Simulation&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Assembler-Dateien ===&lt;br /&gt;
&lt;br /&gt;
Die im Projekt genutzten Assembler-Dateien werden hinter ASRC durch Leerzeichen getrennt aufgelistet. Assembler-Dateien haben immer die Endung .S (großes S). Ist zum Beispiel der Assembler-Quellcode eines Software-UARTs in einer Datei softuart.S enthalten, lautet die Zeile: &#039;&#039;ASRC = softuart.S&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Taktfrequenz ===&lt;br /&gt;
&lt;br /&gt;
Neuere Versionen der WinAVR/Mfile Vorlage für Makefiles beinhalten die Definition einer Variablen F_CPU (WinAVR 2/2005). Darin wird die Taktfrequenz des Controllers in Hertz eingetragen. Die Definition steht dann im gesamten Projekt ebenfalls unter der Bezeichnung F_CPU zur Verfügung (z.&amp;amp;nbsp;B. um daraus UART-, SPI- oder ADC-Frequenzeinstellungen abzuleiten).&lt;br /&gt;
&lt;br /&gt;
Die Angabe hat rein &amp;quot;informativen&amp;quot; Charakter, die tatsächliche Taktrate wird über den externen Takt (z.&amp;amp;nbsp;B. Quarz) bzw. die Einstellung des internen R/C-Oszillators  bestimmt. Die Nutzung von F_CPU hat also nur Sinn, wenn die Angabe mit dem tatsächlichen Takt übereinstimmt.&lt;br /&gt;
&lt;br /&gt;
Innerhalb neuerer Versionen der avr-libc (ab Version 1.2) wird die Definition der Taktfrequenz (F_CPU) zur Berechnung der Wartefunktionen in delay.h genutzt. Diese funktionieren nur dann korrekt, wenn F_CPU mit der tatsächlichen Taktfrequenz übereinstimmt.&lt;br /&gt;
F_CPU muss dazu jedoch nicht unbedingt im makefile definiert werden. Es reicht aus, wird aber bei mehrfacher Anwendung unübersichtlich, vor &#039;&#039;#include &amp;lt;util/delay.h&amp;gt;&#039;&#039; (veraltet: &#039;&#039;#include &amp;lt;avr/delay.h&amp;gt;&#039;&#039;) ein &#039;&#039;#define F_CPU [hier Takt in Hz]UL&#039;&#039; einzufügen. Bei Nutzung von delay.h ist darauf zu achten, dass die Optimierung des Compilers nicht ausgeschaltet ist, sonst wird sehr viel Code erzeugt und die Wartezeit stimmt nicht mit der gewünschten Zeitspanne überein. Vgl. dazu den [http://www.nongnu.org/avr-libc/user-manual/group__util__delay.html entsprechenden Abschnitt der Dokumentation].&lt;br /&gt;
&lt;br /&gt;
== Eingabedateien zur Simulation in AVR-Studio ==&lt;br /&gt;
&lt;br /&gt;
Mit älteren AVR-Studio-Versionen kann man nur auf Grundlage so genannter &#039;&#039;coff&#039;&#039;-Dateien simulieren. Neuere Versionen von AVR-Studio (ab 4.10.356) unterstützen zudem das modernere aber noch experimentelle dwarf-2-Format, das ab WinAVR 20040722 (avr-gcc 3.4.1/Binutils inkl. Atmel add-ons) &amp;quot;direkt&amp;quot; vom Compiler erzeugt wird.&lt;br /&gt;
&lt;br /&gt;
; Vorgehensweise bei dwarf-2:&lt;br /&gt;
* Im Makefile bei DEBUG: &amp;lt;div class=&amp;quot;code&amp;quot;&amp;gt;&amp;lt;pre&amp;gt;DEBUG=dwarf-2&amp;lt;/pre&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;make all&#039;&#039; (evtl. vorher &#039;&#039;make clean&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
* Die erzeugte &#039;&#039;elf&#039;&#039;-Datei (im Beispiel oben &#039;&#039;superprog.elf&#039;&#039;) in AVR-Studio laden&lt;br /&gt;
&lt;br /&gt;
* AVR-Simulator und zu simulierenden Controller wählen, &amp;quot;Finish&amp;quot;&lt;br /&gt;
&lt;br /&gt;
* Weiteres siehe AVR-Studio Online-Hilfe&lt;br /&gt;
&lt;br /&gt;
; Vorgehensweise bei extcoff: (sollte nur noch in Ausnahmefällen genutzt werden)&lt;br /&gt;
&lt;br /&gt;
* Im Makefile bei DEBUG: &amp;lt;div class=&amp;quot;code&amp;quot;&amp;gt;&amp;lt;pre&amp;gt;DEBUG=stabs&amp;lt;/pre&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;make extcoff&#039;&#039; (evtl. vorher &#039;&#039;make clean&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
* Die erzeugte &#039;&#039;cof&#039;&#039;-Datei (im Beispiel oben &#039;&#039;superprog.cof&#039;&#039;) in AVR-Studio laden&lt;br /&gt;
&lt;br /&gt;
* AVR-Simulator und zu simulierenden Controller wählen, &amp;quot;Finish&amp;quot;&lt;br /&gt;
&lt;br /&gt;
* Weiteres siehe AVR-Studio Online-Hilfe&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Beim Simulieren scheinen oft &amp;quot;Variablen zu fehlen&amp;quot;. Ursache dafür ist, dass der Compiler diese &amp;quot;Variablen&amp;quot; direkt Registern zuweist. Dies kann vermieden werden, indem die Optimierung abgeschaltet wird (im makefile). Man simuliert dann jedoch ein vom optimierten Code stark abweichendes Programm. Das Abschalten der Optimierung wird nicht empfohlen.&lt;br /&gt;
&lt;br /&gt;
Statt des Software-Simulators kann das AVR-Studio auch genutzt werden, um mit dem ATMEL JTAGICE, einem Nachbau davon (BootICE, Evertool o.&amp;amp;nbsp;ä.) oder dem ATMEL JTAGICE MKII &amp;quot;im System&amp;quot; zu debuggen. Dazu sind keine speziellen Einstellungen im makefile erforderlich. Debugging bzw. &amp;quot;In-System-Emulation&amp;quot; mit dem JTAGICE und JTAGICE MKII sind in der AVR-Studio Online-Hilfe beschrieben.&lt;br /&gt;
&lt;br /&gt;
Die Verwendung von Makefiles bietet noch viele weitere Möglichkeiten, einige davon werden im Anhang [[AVR-GCC-Tutorial#Zus.C3.A4tzliche_Funktionen_im_Makefile|Zusätzliche Funktionen im Makefile]] erläutert.&lt;br /&gt;
&lt;br /&gt;
= Ganzzahlige (Integer) Datentypen =&lt;br /&gt;
&lt;br /&gt;
Bei der Programmierung von Mikrokontrollern ist die Definition einiger ganzzahliger Datentypen sinnvoll, an denen eindeutig die Bit-Länge abgelesen werden kann.&lt;br /&gt;
&lt;br /&gt;
Standardisierte Datentypen werden in der Header-Datei stdint.h definiert. &lt;br /&gt;
Zur Nutzung der standardisierten Typen bindet man die &amp;quot;Definitionsdatei&amp;quot; wie folgt ein:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
// ab avr-libc Version 1.2.0 möglich und empfohlen:&lt;br /&gt;
#include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
// veraltet: #include &amp;lt;inttypes.h&amp;gt;&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Einige der dort definierten Typen (avr-libc Version 1.0.4):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
typedef signed char        int8_t;&lt;br /&gt;
typedef unsigned char      uint8_t;&lt;br /&gt;
&lt;br /&gt;
typedef short              int16_t;&lt;br /&gt;
typedef unsigned short     uint16_t;&lt;br /&gt;
&lt;br /&gt;
typedef long               int32_t;&lt;br /&gt;
typedef unsigned long      uint32_t;&lt;br /&gt;
&lt;br /&gt;
typedef long long          int64_t;&lt;br /&gt;
typedef unsigned long long uint64_t;&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* int8_t steht für einen 8-Bit Integer mit einem Wertebereich -128 bis +127.&lt;br /&gt;
&lt;br /&gt;
* uint8_t steht für einen 8-Bit Integer ohne Vorzeichen (unsigned int) mit einem Wertebereich von 0 bis 255&lt;br /&gt;
&lt;br /&gt;
* int16_t steht für einen 16-Bit Integer mit einem Wertebereich -32768 bis +32767.&lt;br /&gt;
&lt;br /&gt;
* uint16_t steht für einen 16-Bit Integer ohne Vorzeichen (unsigned int) mit einem Wertebereich von 0 bis 65535.&lt;br /&gt;
&lt;br /&gt;
Die Typen ohne vorangestelltes &#039;&#039;u&#039;&#039; werden als vorzeichenbehaftete Zahlen abgespeichert. Typen mit vorgestelltem &#039;&#039;u&#039;&#039; dienen der Ablage von postiven Zahlen (inkl. 0). Siehe dazu auch: [http://www.nongnu.org/avr-libc/user-manual/index.html Dokumentation der avr-libc] Abschnitt Modules/(Standard) Integer Types.&lt;br /&gt;
&lt;br /&gt;
= Bitfelder =&lt;br /&gt;
&lt;br /&gt;
Beim Programmieren von Mikrocontrollern muss auf jedes Byte oder sogar auf&lt;br /&gt;
jedes Bit geachtet werden. Oft müssen wir in einer Variablen lediglich den&lt;br /&gt;
Zustand 0 oder 1 speichern. Wenn wir nun zur Speicherung eines einzelnen Wertes&lt;br /&gt;
den kleinsten bekannten Datentypen, nämlich &#039;&#039;&#039;unsigned char&#039;&#039;&#039;, nehmen, dann&lt;br /&gt;
verschwenden wir 7 Bits, da ein &#039;&#039;&#039;unsigned char&#039;&#039;&#039; ja 8 Bits breit ist.&lt;br /&gt;
&lt;br /&gt;
Hier bietet uns die Programmiersprache C ein mächtiges Werkzeug an, mit dessen&lt;br /&gt;
Hilfe wir 8 Bits in eine einzelne Bytevariable zusammenfassen und (fast) wie&lt;br /&gt;
8 einzelne Variablen ansprechen können. Die Rede ist von so genannten Bitfeldern. Diese werden als Strukturelemente definiert. Sehen wir uns dazu doch am besten gleich ein Beispiel an:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
struct {&lt;br /&gt;
   unsigned bStatus_1:1; // 1 Bit für bStatus_1&lt;br /&gt;
   unsigned bStatus_2:1; // 1 Bit für bStatus_2&lt;br /&gt;
   unsigned bNochNBit:1; // Und hier noch mal ein Bit&lt;br /&gt;
   unsigned b2Bits:2;    // Dieses Feld ist 2 Bits breit&lt;br /&gt;
   // All das hat in einer einzigen Byte-Variable Platz.&lt;br /&gt;
   // die 3 verbleibenden Bits bleiben ungenutzt&lt;br /&gt;
} x;&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Zugriff auf ein solches Feld erfolgt nun wie beim Strukturzugriff bekannt&lt;br /&gt;
über den Punkt- oder den Dereferenzierungs-Operator:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
x.bStatus_1 = 1;&lt;br /&gt;
x.bStatus_2 = 0;&lt;br /&gt;
x.b2Bits = 3;&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bitfelder sparen Platz im RAM, zu Lasten von Platz im Flash, verschlechtern aber unter Umständen die Les- und Wartbarkeit des Codes. Anfängern wird deshalb geraten, ein &amp;quot;ganzes&amp;quot; Byte (uint8_t) zu nutzen, auch wenn nur ein Bitwert gespeichert werden soll.&lt;br /&gt;
&lt;br /&gt;
Wenn man nur ein paar wenige Variablen vom Typ bool verwenden möchte, kann man&lt;br /&gt;
auch die Headerdatei &amp;lt;stdbool.h&amp;gt; einbinden und sich dann wie gewohnt einen Booltyp anlegen. Variablen dieses Typs brauchen dennoch 1 Byte Speicher, ermöglichen aber eine genaue Unterscheidung zwischen Zahlenvariable und boolscher Variable.&lt;br /&gt;
&lt;br /&gt;
= Grundsätzlicher Programmaufbau eines &amp;amp;micro;C-Programms =&lt;br /&gt;
&lt;br /&gt;
Wir unterscheiden zwischen 2 verschiedenen Methoden, um ein&lt;br /&gt;
Mikrocontroller-Programm zu schreiben, und zwar völlig unabhängig davon, in&lt;br /&gt;
welcher Programmiersprache das Programm geschrieben wird.&lt;br /&gt;
&lt;br /&gt;
== Sequentieller Programmablauf ==&lt;br /&gt;
&lt;br /&gt;
Bei dieser Programmiertechnik wird eine Endlosschleife programmiert, welche im&lt;br /&gt;
Wesentlichen immer den gleichen Aufbau hat:&lt;br /&gt;
&lt;br /&gt;
[[Image:Sequentielle Programme.gif]]&lt;br /&gt;
&lt;br /&gt;
== Interruptgesteuerter Programmablauf ==&lt;br /&gt;
&lt;br /&gt;
Bei dieser Methode werden beim Programmstart zuerst die gewünschten Interruptquellen aktiviert und dann in eine Endlosschleife gegangen, in welcher Dinge erledigt werden können, welche nicht zeitkritisch sind. Wenn ein Interrupt ausgelöst wird, so wird automatisch die zugeordnete Interruptfunktion ausgeführt.&lt;br /&gt;
&lt;br /&gt;
[[Image:Interrupt Programme.gif]]&lt;br /&gt;
&lt;br /&gt;
= Zugriff auf Register =&lt;br /&gt;
&lt;br /&gt;
Die AVR-Controller verfügen über eine Vielzahl von Registern. Die meisten&lt;br /&gt;
davon sind sogenannte Schreib-/Leseregister. Das heißt, das Programm kann die&lt;br /&gt;
Inhalte der Register sowohl auslesen als auch beschreiben.&lt;br /&gt;
&lt;br /&gt;
Register haben einen besonderen Stellenwert bei den AVR Controllern. Sie dienen dem Zugriff auf die Ports und die Schnittstellen des Controllers. Wir unterscheiden zwischen 8-Bit und 16-Bit Registern. Vorerst behandeln wir mal&lt;br /&gt;
die 8-Bit Register.&lt;br /&gt;
&lt;br /&gt;
Einzelne Register sind bei allen AVRs vorhanden, andere wiederum nur bei bestimmten Typen. So sind beispielsweise die Register, welche für den Zugriff auf den UART notwendig sind, selbstverständlich nur bei denjenigen Modellen vorhanden, welche über einen integrierten Hardware UART bzw. USART verfügen.&lt;br /&gt;
&lt;br /&gt;
Die Namen der Register sind in den Headerdateien zu den entsprechenden AVR-Typen definiert. Dazu muss man den Namen der controllerspezifischen Headerdatei nicht kennen. Es reicht aus, die allgemeine Headerdatei &#039;&#039;avr/io.h&#039;&#039; einzubinden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ist im Makefile der MCU-Typ z.&amp;amp;nbsp;B. mit dem Inhalt atmega8 definiert (und wird somit per -mmcu=atmega8 an den Compiler übergeben), wird beim Einlesen der io.h-Datei implizit (&amp;quot;automatisch&amp;quot;) auch die iom8.h-Datei mit den Register-Definitionen für den ATmega8 eingelesen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- Wohl besser als Anhang - spaeter... --&amp;gt;&lt;br /&gt;
Intern wird diese &amp;quot;Automatik&amp;quot; wie folgt realisiert: Der Controllertyp wird dem Compiler als Parameter übergeben (vgl. &#039;&#039;avr-gcc -c -mmcu=atmega16 [...]&#039;&#039; im Einführungsbeispiel). Wird ein Makefile nach der WinAVR/mfile-Vorlage verwendet, setzt man die Variable &#039;&#039;MCU&#039;&#039;, der Inhalt dieser Variable wird dann an passender Stelle für die Compilerparameter verwendet. Der Compiler definiert intern eine dem mmcu-Parameter zugeordnete &amp;quot;Variable&amp;quot; (genauer: ein Makro) mit dem Namen des Controllers, vorangestelltem &#039;&#039;__AVR_&#039;&#039; und angehängten Unterstrichen (z.B. wird bei &#039;&#039;-mmcu=atmega16&#039;&#039; das Makro &#039;&#039;__AVR_ATmega16__&#039;&#039; definiert). Beim Einbinden der Header-Datei &#039;&#039;avr/io.h&#039;&#039; wird geprüft, ob das jeweilige Makro definiert ist und die zum Controller passende Definitionsdatei eingelesen. Zur Veranschaulichung einige Ausschnitte aus einem Makefile:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
[...]&lt;br /&gt;
# MCU Type (&amp;quot;name&amp;quot;) setzen:&lt;br /&gt;
MCU = atmega16&lt;br /&gt;
[...]&lt;br /&gt;
&lt;br /&gt;
[...]&lt;br /&gt;
## Verwendung des Inhalts von MCU (hier atmega16) fuer die &lt;br /&gt;
## Compiler- und Assembler-Parameter&lt;br /&gt;
ALL_CFLAGS = -mmcu=$(MCU) -I. $(CFLAGS) $(GENDEPFLAGS)&lt;br /&gt;
ALL_CPPFLAGS = -mmcu=$(MCU) -I. -x c++ $(CPPFLAGS) $(GENDEPFLAGS)&lt;br /&gt;
ALL_ASFLAGS = -mmcu=$(MCU) -I. -x assembler-with-cpp $(ASFLAGS)&lt;br /&gt;
[...]&lt;br /&gt;
&lt;br /&gt;
[...]&lt;br /&gt;
## Aufruf des Compilers:&lt;br /&gt;
## mit den Parametern ($(ALL_CFLAGS) ist -mmcu=$(MCU)[...] = -mmcu=atmega16[...]&lt;br /&gt;
$(OBJDIR)/%.o : %.c&lt;br /&gt;
	@echo&lt;br /&gt;
	@echo $(MSG_COMPILING) $&amp;lt;&lt;br /&gt;
	$(CC) -c $(ALL_CFLAGS) $&amp;lt; -o $@ &lt;br /&gt;
[...]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Da --mmcu=atmega16 übergeben wurde, wird __AVR_ATmega16__ definiert und kann in avr/io.h zur Fallunterscheidung genutzt werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
// avr/io.h &lt;br /&gt;
// (bei WinAVR-Standardinstallation in C:\WinAVR\avr\include\avr)&lt;br /&gt;
[...]&lt;br /&gt;
#if defined (__AVR_AT94K__)&lt;br /&gt;
#  include &amp;lt;avr/ioat94k.h&amp;gt;&lt;br /&gt;
// [...]&lt;br /&gt;
#elif defined (__AVR_ATmega16__)&lt;br /&gt;
// da __AVR_ATmega16__ definiert ist, wird avr/iom16.h eingebunden:&lt;br /&gt;
#  include &amp;lt;avr/iom16.h&amp;gt;&lt;br /&gt;
// [...]&lt;br /&gt;
#else&lt;br /&gt;
#  if !defined(__COMPILING_AVR_LIBC__)&lt;br /&gt;
#    warning &amp;quot;device type not defined&amp;quot;&lt;br /&gt;
#  endif&lt;br /&gt;
#endif&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Schreiben in Register ==&lt;br /&gt;
&lt;br /&gt;
Zum Schreiben kann man Register einfach wie eine Variable setzen. In Quellcodes, die für ältere Versionen des avr-gcc/der avr-libc entwickelt wurden, erfolgt der Schreibzugriff über die Funktion outp(). Aktuelle Versionen des Compilers unterstützen den Zugriff nun direkt und outp() ist nicht mehr erforderlich.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
int main(void)&lt;br /&gt;
{&lt;br /&gt;
    /* Setzt das Richtungsregister des Ports A auf 0xff &lt;br /&gt;
       (alle Pins als Ausgang, vgl. Abschnitt Zugriff auf Ports): */&lt;br /&gt;
    DDRA = 0xff;    &lt;br /&gt;
&lt;br /&gt;
    /* Setzt PortA auf 0x03, Bit 0 und 1 &amp;quot;high&amp;quot;, restliche &amp;quot;low&amp;quot;: */&lt;br /&gt;
    PORTA = 0x03;   &lt;br /&gt;
    ...&lt;br /&gt;
&lt;br /&gt;
    // Setzen der Bits 0,1,2,3 und 4&lt;br /&gt;
    // Binär 00011111 = Hexadezimal 1F&lt;br /&gt;
    DDRB = 0x1F;    /* direkte Zuweisung - unübersichtlich */&lt;br /&gt;
&lt;br /&gt;
    /* Ausführliche Schreibweise: identische Funktionalität, mehr Tipparbeit&lt;br /&gt;
       aber übersichtlicher und selbsterklärend: */&lt;br /&gt;
    DDRB = (1 &amp;lt;&amp;lt; DDB0) | (1 &amp;lt;&amp;lt; DDB1) | (1 &amp;lt;&amp;lt; DDB2) | (1 &amp;lt;&amp;lt; DDB3) | (1 &amp;lt;&amp;lt; DDB4); &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die ausführliche Schreibweise sollte bevorzugt verwendet werden, da dadurch die Zuweisungen selbsterklärend sind und somit der Code leichter nachvollzogen werden kann. Atmel verwendet sie auch bei Beispielen in Datenblätten und in den allermeisten Quellcodes zu Application-Notes.&lt;br /&gt;
&lt;br /&gt;
Der gcc C-Compiler (genauer der Präprozessor) unterstützt ab Version 4.3.0 Konstanten im Binärformat, z.B. DDRB&amp;amp;nbsp;=&amp;amp;nbsp;0b00011111 (für WinAVR wurden schon ältere Versionen des gcc entsprechend angepasst). Diese Schreibweise ist jedoch nicht standardkonform und man sollte sie daher insbesondere dann nicht verwenden, wenn Code mit anderen ausgetauscht oder mit anderen Compilern bzw. älteren Versionen des gcc genutzt werden soll.  &lt;br /&gt;
&lt;br /&gt;
=== Verändern von Registerinhalten ===&lt;br /&gt;
&lt;br /&gt;
Einzelne Bits setzt und löscht man &amp;quot;Standard-C-konform&amp;quot; mittels logischer (Bit-) Operationen. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
 x |= (1 &amp;lt;&amp;lt; Bitnummer);  // Hiermit wird ein Bit in x gesetzt&lt;br /&gt;
 x &amp;amp;= ~(1 &amp;lt;&amp;lt; Bitnummer); // Hiermit wird ein Bit in x geloescht&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Es wird jeweils nur der Zustand des angegebenen Bits geändert, der vorherige Zustand der anderen Bits bleibt erhalten. &lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
#define MEINBIT 2&lt;br /&gt;
...&lt;br /&gt;
PORTA |= (1 &amp;lt;&amp;lt; MEINBIT);    /* setzt Bit 2 an PortA auf 1 */&lt;br /&gt;
PORTA &amp;amp;= ~(1 &amp;lt;&amp;lt; MEINBIT);   /* loescht Bit 2 an PortA */&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit dieser Methode lassen sich auch mehrere Bits eines Registers gleichzeitig setzen und löschen.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
DDRA &amp;amp;= ~( (1&amp;lt;&amp;lt;PA0) | (1&amp;lt;&amp;lt;PA3) );  /* PA0 und PA3 als Eingaenge */&lt;br /&gt;
PORTA |= (1&amp;lt;&amp;lt;PA0) | (1&amp;lt;&amp;lt;PA3);      /* Interne Pull-Up fuer beide einschalten */&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In Quellcodes, die für ältere Version den des avr-gcc/der avr-libc entwickelt wurden, werden einzelne Bits mittels der Funktionen sbi und cbi gesetzt bzw. gelöscht. Beide Funktionen sind nicht mehr erforderlich.&lt;br /&gt;
&lt;br /&gt;
Siehe auch:&lt;br /&gt;
* [[Bitmanipulation]]&lt;br /&gt;
* [http://www.nongnu.org/avr-libc/user-manual/index.html Dokumentation der avr-libc] Abschnitt Modules/Special Function Registers&lt;br /&gt;
&lt;br /&gt;
== Lesen aus Registern ==&lt;br /&gt;
&lt;br /&gt;
Zum Lesen kann man auf Register einfach wie auf eine Variable zugreifen. In Quellcodes, die für ältere Versionen des avr-gcc/der avr-libc entwickelt wurden, erfolgt der Lesezugriff über die Funktion inp(). Aktuelle Versionen des Compilers unterstützen den Zugriff nun direkt und inp() ist nicht mehr erforderlich.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
uint8_t foo;&lt;br /&gt;
&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
int main(void)&lt;br /&gt;
{&lt;br /&gt;
    /* kopiert den Status der Eingabepins an PortB &lt;br /&gt;
       in die Variable foo: */&lt;br /&gt;
    foo = PINB;    &lt;br /&gt;
    //...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Zustände von Bits erfolgt durch Einlesen des gesamten Registerinhalts und ausblenden der Bits deren Zustand nicht von Interesse ist. Einige Beispiele zum Prüfen ob Bits gesetzt oder gelöscht sind:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#define MEINBIT0 0 &lt;br /&gt;
#define MEINBIT2 2&lt;br /&gt;
&lt;br /&gt;
uint8_t i;&lt;br /&gt;
&lt;br /&gt;
extern test1();&lt;br /&gt;
&lt;br /&gt;
// Funkion test1 aufrufen, wenn Bit 0 in Register PINA gesetzt (1) ist&lt;br /&gt;
i = PINA;         // Inhalt in Arbeitsvariable&lt;br /&gt;
i = i &amp;amp; 0x01;     // alle Bits bis auf Bit 0 ausblenden (logisches und)&lt;br /&gt;
                  // falls das Bit gesetzt war, hat i den Inhalt 1&lt;br /&gt;
if ( i != 0 ) {   // Ergebnis ungleich 0 (wahr)? &lt;br /&gt;
  test1()         // dann muss Bit 0 in i gesetzt sein -&amp;gt; Funktion aufrufen&lt;br /&gt;
}&lt;br /&gt;
// verkürzt:&lt;br /&gt;
if ( ( PINA &amp;amp; 0x01 ) != 0 ) {&lt;br /&gt;
  test1();&lt;br /&gt;
}&lt;br /&gt;
// nochmals verkürzt:&lt;br /&gt;
if ( PINA &amp;amp; 0x01 ) {&lt;br /&gt;
  test1();&lt;br /&gt;
}&lt;br /&gt;
// mit definierter Bitnummer:&lt;br /&gt;
if ( PINA &amp;amp; ( 1 &amp;lt;&amp;lt; MEINBIT0 ) ) {&lt;br /&gt;
  test(1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Funktion aufrufen, wenn Bit 0 oder Bit 2 gesetzt ist&lt;br /&gt;
if ( PINA &amp;amp; 0x05 ) {&lt;br /&gt;
  test1();  // Vergleich &amp;lt;&amp;gt; 0 (wahr), also muss Bit 0 oder 2 gesetzt sein&lt;br /&gt;
}&lt;br /&gt;
// mit definierten Bitnummern:&lt;br /&gt;
if ( PINA &amp;amp; ( ( 1 &amp;lt;&amp;lt; MEINBIT0 ) | ( 1 &amp;lt;&amp;lt; MEINBIT2 ) ) ) {&lt;br /&gt;
  test1();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Funktion aufrufen, wenn Bit 0 und Bit 2 gesetzt sind&lt;br /&gt;
if ( ( PINA &amp;amp; 0x05 ) == 0x05 ) {  // nur wahr, wenn beide Bits gesetzt&lt;br /&gt;
  test1();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Funktion test2() aufrufen, wenn Bit 0 gelöscht (0) ist&lt;br /&gt;
i = PINA;        // einlesen in temporäre Variable&lt;br /&gt;
i = i &amp;amp; 0x01;    // maskieren von B&lt;br /&gt;
if ( i == 0 ) {  // Vergleich ist wahr, wenn Bit 0 nicht gesetzt ist&lt;br /&gt;
  test2();&lt;br /&gt;
}&lt;br /&gt;
// analog mit !-Operator (not)&lt;br /&gt;
if ( !i ) {&lt;br /&gt;
  test2();&lt;br /&gt;
}&lt;br /&gt;
// nochmals verkürzt:&lt;br /&gt;
if ( !( PINA &amp;amp; 0x01 ) ) {&lt;br /&gt;
  test2();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die AVR-Bibliothek (avr-libc) stellt auch Funktionen (Makros) zur Abfrage eines einzelnen Bits eines Registers zur Verfügung, diese sind bei anderen Compilern meist nicht verfügbar (können aber dann einfach durch Macros &amp;quot;nachgerüstet&amp;quot; werden).&lt;br /&gt;
&lt;br /&gt;
;bit_is_set (&amp;lt;Register&amp;gt;,&amp;lt;Bitnummer&amp;gt;): Die Funktion &#039;&#039;bit_is_set&#039;&#039; prüft, ob ein Bit gesetzt ist. Wenn das Bit gesetzt ist, wird ein Wert ungleich 0 zurückgegeben. Genau genommen ist es die Wertigkeit des abgefragten Bits, also 1 für Bit0, 2 für Bit1, 4 für Bit2 etc.&lt;br /&gt;
&lt;br /&gt;
;bit_is_clear (&amp;lt;Register&amp;gt;,&amp;lt;Bitnummer&amp;gt;): Die Funktion &#039;&#039;bit_is_clear&#039;&#039; prüft, ob ein Bit gelöscht ist. Wenn das Bit gelöscht ist, also auf 0 ist, wird ein Wert ungleich 0 zurückgegeben.&lt;br /&gt;
&lt;br /&gt;
Die Funktionen (eigentlich Makros) bit_is_clear bzw. bit_is_set sind nicht erforderlich, man kann und sollte C-Syntax verwenden, die universell verwendbar und portabel ist. Siehe auch [[Bitmanipulation]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Warten auf einen bestimmten Zustand ===&lt;br /&gt;
&lt;br /&gt;
Es gibt in der Bibliothek avr-libc Funktionen, die warten, bis ein bestimmter Zustand eines Bits erreicht ist. Es ist allerdings normalerweise eine eher unschöne Programmiertechnik, da in diesen Funktionen &amp;quot;blockierend&amp;quot; gewartet wird. Der Programmablauf bleibt also an dieser Stelle stehen, bis das maskierte Ereignis erfolgt ist. Setzt man den Watchdog ein, muss man darauf achten, dass dieser auch noch getriggert wird (Zurücksetzen des Watchdogtimers). &lt;br /&gt;
&lt;br /&gt;
Die Funktion &#039;&#039;&#039;loop_until_bit_is_set&#039;&#039;&#039; wartet in einer Schleife, bis das definierte Bit gesetzt ist. Wenn das Bit beim Aufruf der Funktion bereits gesetzt ist, wird die Funktion sofort wieder verlassen. Das niederwertigste Bit hat die Bitnummer 0. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
/* Warten bis Bit Nr. 2 (das dritte Bit) in Register PINA gesetzt (1) ist */&lt;br /&gt;
&lt;br /&gt;
#define WARTEPIN PINA&lt;br /&gt;
#define WARTEBIT PA2&lt;br /&gt;
&lt;br /&gt;
// mit der avr-libc Funktion:&lt;br /&gt;
loop_until_bit_is_set(WARTEPIN, WARTEBIT);&lt;br /&gt;
&lt;br /&gt;
// dito in &amp;quot;C-Standard&amp;quot;:&lt;br /&gt;
// Durchlaufe die (leere) Schleife solange das WARTEBIT in Register WARTEPIN&lt;br /&gt;
// _nicht_ ungleich 0 (also 0) ist.&lt;br /&gt;
while ( !(WARTEPIN &amp;amp; (1 &amp;lt;&amp;lt; WARTEBIT)) ) ;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die Funktion &#039;&#039;&#039;loop_until_bit_is_clear&#039;&#039;&#039; wartet in einer Schleife, bis das definierte Bit gelöscht ist. Wenn das Bit beim Aufruf der Funktion bereits gelöscht ist, wird die Funktion sofort wieder verlassen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
/* Warten bis Bit Nr. 4 (das fuenfte Bit) in Register PINB geloescht (0) ist */&lt;br /&gt;
#define WARTEPIN PINB&lt;br /&gt;
#define WARTEBIT PB4&lt;br /&gt;
&lt;br /&gt;
// avr-libc-Funktion:&lt;br /&gt;
loop_until_bit_is_clear(WARTEPIN, WARTEBIT);&lt;br /&gt;
&lt;br /&gt;
// dito in &amp;quot;C-Standard&amp;quot;:&lt;br /&gt;
// Durchlaufe die (leere) Schleife solange das WARTEBIT in Register WARTEPIN&lt;br /&gt;
// gesetzt (1) ist &lt;br /&gt;
while ( WARTEPIN &amp;amp; (1&amp;lt;&amp;lt;WARTEBIT) ) ;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Universeller und auch auf andere Plattformen besser übertragbar ist die Verwendung von C-Standardoperationen.&lt;br /&gt;
&lt;br /&gt;
Siehe auch: &lt;br /&gt;
* [http://www.nongnu.org/avr-libc/user-manual/index.html Dokumentation der avr-libc] Abschnitt Modules/Special Function Registers&lt;br /&gt;
* [[Bitmanipulation]]&lt;br /&gt;
&lt;br /&gt;
= Zugriff auf IO-Ports =&lt;br /&gt;
&lt;br /&gt;
Alle Ports der AVR-Controller werden über Register gesteuert. Dazu sind&lt;br /&gt;
jedem Port 3 Register zugeordnet:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;DDRx&#039;&#039;&#039; &lt;br /&gt;
| Datenrichtungsregister für Port&#039;&#039;&#039;x&#039;&#039;&#039;. &lt;br /&gt;
&#039;&#039;&#039;x&#039;&#039;&#039; entspricht &#039;&#039;&#039;A&#039;&#039;&#039;, &#039;&#039;&#039;B&#039;&#039;&#039;, &#039;&#039;&#039; C&#039;&#039;&#039;, &#039;&#039;&#039;D&#039;&#039;&#039; usw. (abhängig von der Anzahl der Ports des verwendeten AVR). Bit im Register gesetzt (1) für Ausgang, Bit gelöscht (0) für Eingang.&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;PINx&#039;&#039;&#039;&lt;br /&gt;
| Eingangsadresse für Port&#039;&#039;&#039;x&#039;&#039;&#039;. &lt;br /&gt;
Zustand des Ports. Die Bits in PINx entsprechen dem Zustand der als Eingang definierten Portpins. Bit 1 wenn Pin &amp;quot;high&amp;quot;, Bit 0 wenn Portpin low.&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;PORTx&#039;&#039;&#039;&lt;br /&gt;
| Datenregister für Port&#039;&#039;&#039;x&#039;&#039;&#039;. &lt;br /&gt;
Dieses Register wird verwendet, um die Ausgänge eines Ports anzusteuern. Bei Pins, die mittels DDRx auf Eingang geschaltet wurden, können über PORTx&lt;br /&gt;
die internen Pull-Up Widerstände aktiviert oder deaktiviert werden (1 = aktiv).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Jeder AVR implementiert eine unterschiedliche Menge an GPIO-Registern&lt;br /&gt;
(GPIO - General Purpose Input/Output). Die folgenden Beispiele gehen von einem AVR aus, der sowohl Port A als auch Port B besitzt. Sie müssen für andere AVRs (zum Beispiel ATmega8/48/88/168) entsprechend angepasst werden.&lt;br /&gt;
&lt;br /&gt;
== Datenrichtung bestimmen ==&lt;br /&gt;
&lt;br /&gt;
Zuerst muss die Datenrichtung der verwendeten Pins bestimmt werden. Um dies zu erreichen, wird das Datenrichtungsregister des entsprechenden Ports beschrieben.&lt;br /&gt;
&lt;br /&gt;
Für jeden Pin, der als Ausgang verwendet werden soll, muss dabei das&lt;br /&gt;
entsprechende Bit auf dem Port gesetzt werden. Soll der Pin als Eingang&lt;br /&gt;
verwendet werden, muss das entsprechende Bit gelöscht sein.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
Angenommen am Port B sollen die Pins 0 bis 4 als Ausgänge definiert werden, die noch verbleibenden Pins 5 bis 7 sollen als Eingänge fungieren. Dazu ist es daher notwendig, im für das Port B zuständigen Datenrichtungsregister DDRB folgende Bitkonfiguration einzutragen&lt;br /&gt;
&lt;br /&gt;
   +---+---+---+---+---+---+---+---+&lt;br /&gt;
   | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 1 |&lt;br /&gt;
   +---+---+---+---+---+---+---+---+&lt;br /&gt;
     7   6   5   4   3   2   1   0&lt;br /&gt;
&lt;br /&gt;
In C liest sich das dann so:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
// in io.h wird u.a. DDRB definiert:&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
// Setzen der Bits 0,1,2,3 und 4&lt;br /&gt;
// Binär 00011111 = Hexadezimal 1F&lt;br /&gt;
DDRB = 0x1F;    /* direkte Zuweisung - unübersichtlich */&lt;br /&gt;
&lt;br /&gt;
/* Ausführliche Schreibweise: identische Funktionalität, mehr Tipparbeit&lt;br /&gt;
   aber übersichtlicher und selbsterklärend: */&lt;br /&gt;
DDRB = (1 &amp;lt;&amp;lt; DDB0) | (1 &amp;lt;&amp;lt; DDB1) | (1 &amp;lt;&amp;lt; DDB2) | (1 &amp;lt;&amp;lt; DDB3) | (1 &amp;lt;&amp;lt; DDB4); &lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Pins 5 bis 7 werden (da 0) als Eingänge geschaltet. Weitere Beispiele:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
// Alle Pins des Ports B als Ausgang definieren:&lt;br /&gt;
DDRB = 0xff; &lt;br /&gt;
// Pin0 wieder auf Eingang und andere im ursprünglichen Zustand belassen:&lt;br /&gt;
DDRB &amp;amp;= ~( 1 &amp;lt;&amp;lt; DDB0 );&lt;br /&gt;
// Pin 3 und 4 auf Eingang und andere im ursprünglichen Zustand belassen:&lt;br /&gt;
DDRB &amp;amp;= ~( ( 1 &amp;lt;&amp;lt; DDB3 ) | ( 1&amp;lt;&amp;lt;DDB4) );&lt;br /&gt;
// Pin 0 und 3 wieder auf Ausgang und andere im ursprünglichen Zustand belassen:&lt;br /&gt;
DDRB |= ( 1 &amp;lt;&amp;lt; DDB0) | ( 1 &amp;lt;&amp;lt; DDB3 );&lt;br /&gt;
// Alle Pins auf Eingang:&lt;br /&gt;
DDRB = 0x00;&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Vordefinierte Bitnummern für I/O-Register ==&lt;br /&gt;
&lt;br /&gt;
Die Bitnummern (z.B. PCx, PINCx und DDCx für den Port C) sind in den io*.h-Dateien der avr-libc definiert und dienen lediglich der besseren Lesbarkeit. Man muss diese Definitionen nicht verwenden oder kann auch einfach &amp;quot;immer&amp;quot; PAx, PBx, PCx usw. nutzen, auch wenn der Zugriff auf Bits in DDRx- oder PINx-Registern erfolgt. Für den Compiler sind die Ausdrücke (1&amp;lt;&amp;lt;PC7), (1&amp;lt;&amp;lt;DDC7) und (1&amp;lt;&amp;lt;PINC7) identisch zu (1&amp;lt;&amp;lt;7) (genauer: der Präprozessor ersetzt die Ausdrücke (1&amp;lt;&amp;lt;PC7),... zu (1&amp;lt;&amp;lt;7)). Ein Ausschnitt der Definitionen für Port C eines ATmega32 aus der iom32.h-Datei zur Verdeutlichung (analog für die weiteren Ports):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
/* PORTC */&lt;br /&gt;
#define PC7     7&lt;br /&gt;
#define PC6     6&lt;br /&gt;
#define PC5     5&lt;br /&gt;
#define PC4     4&lt;br /&gt;
#define PC3     3&lt;br /&gt;
#define PC2     2&lt;br /&gt;
#define PC1     1&lt;br /&gt;
#define PC0     0&lt;br /&gt;
&lt;br /&gt;
/* DDRC */&lt;br /&gt;
#define DDC7    7&lt;br /&gt;
#define DDC6    6&lt;br /&gt;
#define DDC5    5&lt;br /&gt;
#define DDC4    4&lt;br /&gt;
#define DDC3    3&lt;br /&gt;
#define DDC2    2&lt;br /&gt;
#define DDC1    1&lt;br /&gt;
#define DDC0    0&lt;br /&gt;
&lt;br /&gt;
/* PINC */&lt;br /&gt;
#define PINC7   7&lt;br /&gt;
#define PINC6   6&lt;br /&gt;
#define PINC5   5&lt;br /&gt;
#define PINC4   4&lt;br /&gt;
#define PINC3   3&lt;br /&gt;
#define PINC2   2&lt;br /&gt;
#define PINC1   1&lt;br /&gt;
#define PINC0   0&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Digitale Signale ==&lt;br /&gt;
&lt;br /&gt;
Am einfachsten ist es, digitale Signale mit dem Mikrocontroller zu erfassen bzw. auszugeben.&lt;br /&gt;
&lt;br /&gt;
== Ausgänge ==&lt;br /&gt;
Will man als Ausgang definierte Pins (entsprechende DDRx-Bits = 1) auf Logisch 1 setzen, setzt man die  entsprechenden Bits im Portregister.&lt;br /&gt;
&lt;br /&gt;
Mit dem Befehl&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
    PORTB = 0x04; /* besser PORTB=(1&amp;lt;&amp;lt;PB2) */&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
wird also der Ausgang an Pin PB2 gesetzt (Beachte, dass die Bits immer &#039;&#039;von 0 an&#039;&#039; gezählt werden, das niederwertigste Bit ist also Bitnummer 0 und nicht etwa Bitnummer 1).&lt;br /&gt;
&lt;br /&gt;
Man beachte, dass bei der Zuweisung mittels &#039;&#039;&#039;=&#039;&#039;&#039; immer alle Pins gleichzeitig angegeben werden. Man sollte also, wenn nur bestimmte Ausgänge geschaltet werden sollen, zuerst den aktuellen Wert des Ports einlesen und das Bit des gewünschten Ports in diesen Wert einfließen lassen. Will man also nur den dritten Pin (Bit Nr. 2) an Port B auf &amp;quot;high&amp;quot; setzen und den Status der anderen Ausgänge unverändert lassen, nutze man diese Form:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
    PORTB = PORTB | 0x04; /* besser: PORTB = PORTB | ( 1&amp;lt;&amp;lt;PB2 ) */&lt;br /&gt;
    /* vereinfacht durch Nutzung des |= Operators : */&lt;br /&gt;
    PORTB |= (1&amp;lt;&amp;lt;PB2);&lt;br /&gt;
&lt;br /&gt;
    /* auch mehrere &amp;quot;gleichzeitig&amp;quot;: */&lt;br /&gt;
    PORTB |= (1&amp;lt;&amp;lt;PB4) | (1&amp;lt;&amp;lt;PB5); /* Pins PB4 und PB5 &amp;quot;high&amp;quot; */&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Ausschalten&amp;quot;, also  Ausgänge auf &amp;quot;low&amp;quot; setzen, erfolgt analog:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
    PORTB &amp;amp;= ~(1&amp;lt;&amp;lt;PB2); /* löscht Bit 2 in PORTB und setzt damit Pin PB2 auf low */ &lt;br /&gt;
    PORTB &amp;amp;= ~( (1&amp;lt;&amp;lt;PB4) | (1&amp;lt;&amp;lt;PB5) ); /* Pin PB4 und Pin PB5 &amp;quot;low&amp;quot; */&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In Quellcodes, die für ältere Version den des avr-gcc/der avr-libc entwickelt wurden, werden einzelne Bits mittels der Funktionen sbi und cbi gesetzt bzw. gelöscht. Beide Funktionen sind in aktuellen Versionen der avr-libc nicht mehr enthalten und auch nicht mehr erforderlich.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Falls der Anfangszustand von Ausgängen kritisch ist, muss die Reihenfolge beachtet werden, mit der die Datenrichtung (DDRx) eingestellt und der Ausgabewert (PORTx) gesetzt wird:&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Für Ausgangspins, die mit Anfangswert &amp;quot;high&amp;quot; initialisiert werden sollen:&lt;br /&gt;
* zuerst die Bits im PORTx-Register setzen&lt;br /&gt;
* anschließend die Datenrichtung auf Ausgang stellen&lt;br /&gt;
&lt;br /&gt;
Daraus ergibt sich die Abfolge für einen Pin, der bisher als Eingang mit abgeschaltetem Pull-Up konfiguriert ware:&lt;br /&gt;
* setze PORTx: interner Pull-Up aktiv&lt;br /&gt;
* setze DDRx: Ausgang (&amp;quot;high&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
Bei der Reihenfolge erst DDRx und dann PORTx, kann es zu einem kurzen &amp;quot;low-Puls&amp;quot; kommen, der auch externe Pull-Up-Widerstände &amp;quot;überstimmt&amp;quot;. Die (ungünstige) Abfolge: Eingang -&amp;gt; setze DDRx: Ausgang (auf &amp;quot;low&amp;quot;, da PORTx nach Reset 0) -&amp;gt; setze PORTx: Ausgang auf high. Vergleiche dazu auch das Datenblatt Abschnitt &#039;&#039;Configuring the Pin&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== Eingänge (Wie kommen Signale in den &amp;amp;micro;C) ==&lt;br /&gt;
&lt;br /&gt;
Die digitalen Eingangssignale können auf verschiedene Arten zu unserer Logik gelangen.&lt;br /&gt;
&lt;br /&gt;
=== Signalkopplung ===&lt;br /&gt;
&lt;br /&gt;
Am einfachsten ist es, wenn die Signale direkt aus einer anderen digitalen Schaltung übernommen werden können. Hat der Ausgang der entsprechenden Schaltung TTL-Pegel dann können wir sogar direkt den Ausgang der Schaltung mit einem Eingangspin von unserem Controller verbinden.&lt;br /&gt;
&lt;br /&gt;
Hat der Ausgang der anderen Schaltung keinen TTL-Pegel so müssen wir den Pegel über entsprechende Hardware (z.B. Optokoppler, [[Widerstand#Spannungsteiler|Spannungsteiler]], &amp;quot;Levelshifter&amp;quot; aka [[Pegelwandler]]) anpassen.&lt;br /&gt;
&lt;br /&gt;
Die Masse der beiden Schaltungen muss selbstverständlich miteinander verbunden werden. Der Software selber ist es natürlich letztendlich egal, wie das Signal eingespeist wird. Wir können ja ohnehin lediglich prüfen, ob an einem Pin unseres Controllers eine logische 1 (Spannung größer ca. 0,7*Vcc) oder eine logische 0 (Spannung kleiner ca. 0,2*Vcc) anliegt. Detaillierte Informationen darüber, ab welcher Spannung ein Eingang als 0 (&amp;quot;low&amp;quot;) bzw. 1 (&amp;quot;high&amp;quot;) erkannt wird, liefert die Tabelle DC Characteristics im Datenblatt des genutzten Controllers.&lt;br /&gt;
&lt;br /&gt;
Die Abfrage der Zustände der Portpins erfolgt direkt über den Registernamen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;font color=&amp;quot;#FF0000&amp;quot;&amp;gt;Dabei ist wichtig, zur Abfrage der Eingänge &#039;&#039;&#039;nicht&#039;&#039;&#039; etwa Portregister &#039;&#039;&#039;PORTx&#039;&#039;&#039; zu verwenden, &#039;&#039;&#039;sondern&#039;&#039;&#039; Eingangsregister &#039;&#039;&#039;PINx&#039;&#039;&#039;. Die Abfrage der Pinzustände über PORTx statt PINx ist ein häufiger Fehler beim AVR-&amp;quot;Erstkontakt&amp;quot;.&amp;lt;/font&amp;gt; (Ansonsten liest man nicht den Zustand der Eingänge, sondern den Status der internen Pull-Up-Widerstände.)&lt;br /&gt;
&lt;br /&gt;
Will man also die aktuellen Signalzustände von Port D abfragen und in eine Variable namens bPortD abspeichern, schreibt man folgende Befehlszeilen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
uint8_t bPortD;&lt;br /&gt;
...&lt;br /&gt;
bPortD = PIND;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit den C-Bitoperationen kann man den Status der Bits abfragen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
/* Fuehre Aktion aus, wenn Bit Nr. 1 (das &amp;quot;zweite&amp;quot; Bit) in PINC gesetzt (1) ist */&lt;br /&gt;
if ( PINC &amp;amp; (1&amp;lt;&amp;lt;PINC1) ) {&lt;br /&gt;
  /* Aktion */&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* Fuehre Aktion aus, wenn Bit Nr. 2 (das &amp;quot;dritte&amp;quot; Bit) in PINB geloescht (0) ist */&lt;br /&gt;
if ( !(PINB &amp;amp; (1&amp;lt;&amp;lt;PINB2)) ) {&lt;br /&gt;
  /* Aktion */&lt;br /&gt;
}&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Tasten und Schalter ===&lt;br /&gt;
&lt;br /&gt;
Der Anschluss mechanischer Kontakte an den Mikrocontroller gestaltet sich ebenfalls ganz einfach, wobei wir zwei unterschiedliche Methoden unterscheiden müssen (&#039;&#039;Active Low&#039;&#039; und &#039;&#039;Active High&#039;&#039;):&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Active Low&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Active High&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| [[Image:Active Low.gif]]&lt;br /&gt;
| [[Image:Active High.gif]]&lt;br /&gt;
|- &lt;br /&gt;
| Bei dieser Methode wird der Kontakt zwischen den Eingangspin des Controllers und Masse geschaltet.&lt;br /&gt;
&lt;br /&gt;
Damit bei offenem Schalter der Controller kein undefiniertes Signal bekommt wird zwischen die Versorgungsspannung und den Eingangspin ein sogenannter Pull-Up Widerstand geschaltet. Dieser dient dazu, den Pegel bei geöffnetem Schalter auf logisch 1 zu ziehen.&lt;br /&gt;
&lt;br /&gt;
Der Widerstandswert des Pull-Up Widerstands ist an sich nicht kritisch.  Wird er allerdings zu hoch gewählt, ist die Wirkung eventuell nicht gegeben. Als üblicher Wert haben sich 10 kOhm eingebürgert.&lt;br /&gt;
&lt;br /&gt;
Die AVRs haben sogar an den meisten Pins softwaremäßig zuschaltbare interne Pull-Up Widerstände, welche wir natürlich auch verwenden können.&lt;br /&gt;
&lt;br /&gt;
| Hier wird der Kontakt zwischen die Versorgungsspannung und den Eingangspin geschaltet.&lt;br /&gt;
&lt;br /&gt;
Damit bei offener Schalterstellung kein undefiniertes Signal am Controller ansteht, wird zwischen den Eingangspin und die Masse ein Pull-Down Widerstand geschaltet. Dieser dient dazu, den Pegel bei geöffneter Schalterstellung auf logisch 0 zu halten.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Pull-Up Widerstände aktivieren ====&lt;br /&gt;
&lt;br /&gt;
Die internen Pull-Up Widerstände von Vcc zu den einzelnen Portpins werden über das Register &#039;&#039;&#039; PORTx&#039;&#039;&#039; aktiviert bzw. deaktiviert, wenn ein Pin als &#039;&#039;&#039; Eingang&#039;&#039;&#039; geschaltet ist.&lt;br /&gt;
&lt;br /&gt;
Wird der Wert des entsprechenden Portpins auf 1 gesetzt, so ist der Pull-Up Widerstand aktiviert. Bei einem Wert von 0 ist der Pull-Up Widerstand nicht aktiv. Man sollte jeweils entweder den internen oder einen externen Pull-Up Widerstand verwenden, aber nicht beide zusammen.&lt;br /&gt;
&lt;br /&gt;
Im Beispiel werden alle Pins des Ports D als Eingänge geschaltet und alle Pull-Up Widerstände aktiviert. Weiterhin wird Pin PC7 als Eingang geschaltet und dessen interner Pull-Up Widerstand aktiviert, ohne die Einstellungen für die anderen Portpins (PC0-PC6) zu verändern.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
DDRD  = 0x00; /* alle Pins von Port D als Eingang */&lt;br /&gt;
PORTD = 0xff; /* interne Pull-Ups an allen Port-Pins aktivieren */&lt;br /&gt;
...&lt;br /&gt;
DDRC  &amp;amp;= ~(1&amp;lt;&amp;lt;DDC7);  /* Pin PC7 als Eingang */&lt;br /&gt;
PORTC |= (1&amp;lt;&amp;lt;PC7);    /* internen Pull-Up an PC7 aktivieren */&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== (Tasten-)Entprellung ====&lt;br /&gt;
&lt;br /&gt;
Nun haben alle mechanischen Kontakte, sei es von Schaltern, Tastern oder auch von Relais, die unangenehme Eigenschaft zu prellen. Dies bedeutet, dass beim Schließen des Kontaktes derselbe nicht direkt Kontakt herstellt, sondern mehrfach ein- und ausschaltet bis zum endgültigen Herstellen des Kontaktes.&lt;br /&gt;
&lt;br /&gt;
Soll nun mit einem schnellen Mikrocontroller gezählt werden, wie oft ein solcher Kontakt geschaltet wird, dann haben wir ein Problem, weil das Prellen als mehrfache Impulse gezählt wird. Diesem Phänomen muss beim Schreiben des Programms unbedingt Rechnung getragen werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;lt;inttypes.h&amp;gt;&lt;br /&gt;
#ifndef F_CPU&lt;br /&gt;
#warning &amp;quot;F_CPU war noch nicht definiert, wird nun mit 3686400 definiert&amp;quot;&lt;br /&gt;
#define F_CPU 3686400UL     /* Quarz mit 3.6864 Mhz  */&lt;br /&gt;
#endif&lt;br /&gt;
#include &amp;lt;util/delay.h&amp;gt;     /* bei alter avr-libc: #include &amp;lt;avr/delay.h&amp;gt; */      &lt;br /&gt;
&lt;br /&gt;
/* Einfache Funktion zum Entprellen eines Tasters */&lt;br /&gt;
inline uint8_t debounce(volatile uint8_t *port, uint8_t pin)&lt;br /&gt;
{&lt;br /&gt;
    if ( ! (*port &amp;amp; (1 &amp;lt;&amp;lt; pin)) )&lt;br /&gt;
    {&lt;br /&gt;
        /* Pin wurde auf Masse gezogen, 100ms warten   */&lt;br /&gt;
        _delay_ms(50);  // max. 262.1 ms / F_CPU in MHz&lt;br /&gt;
        _delay_ms(50); &lt;br /&gt;
        if ( *port &amp;amp; (1 &amp;lt;&amp;lt; pin) )&lt;br /&gt;
        {&lt;br /&gt;
            /* Anwender Zeit zum Loslassen des Tasters geben */&lt;br /&gt;
            _delay_ms(50);&lt;br /&gt;
            _delay_ms(50); &lt;br /&gt;
            return 1;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int main(void)&lt;br /&gt;
{&lt;br /&gt;
    DDRB &amp;amp;= ~( 1 &amp;lt;&amp;lt; PB0 );                 /* PIN PB0 auf Eingang (Taster)            */&lt;br /&gt;
    PORTB |= ( 1 &amp;lt;&amp;lt; PB0 );                 /* Pullup-Widerstand aktivieren            */&lt;br /&gt;
    ...&lt;br /&gt;
    if (debounce(&amp;amp;PINB, PB0))             /* Falls Taster an PIN PB0 gedrueckt..    */&lt;br /&gt;
        PORTD = PIND ^ ( 1 &amp;lt;&amp;lt; PD7 );  /* ..LED an Port PD7 an-&lt;br /&gt;
                                   bzw. ausschalten */&lt;br /&gt;
    ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bei diesem Beispiel ist zu beachten, dass der AVR im Falle eines Tastendrucks 200ms wartet, also brach liegt. Bei zeitkritische Anwendungen sollte man ein anderes Verfahren nutzen (z.B. Abfrage der Tastenzustände in einer Timer-Interrupt-Service-Routine).&lt;br /&gt;
&lt;br /&gt;
Zum Thema Entprellen siehe auch:&lt;br /&gt;
* Artikel [[Entprellung]]&lt;br /&gt;
&lt;br /&gt;
== Analog ==&lt;br /&gt;
&lt;br /&gt;
Die Verarbeitung von analogen Eingangswerten und die Ausgabe von Analogwerten wird in Kapitel [[AVR-GCC-Tutorial#Analoge_Ein-_und_Ausgabe|Analoge Ein- und Ausgabe]] behandelt.&lt;br /&gt;
&lt;br /&gt;
== 16-Bit Portregister (ADC, ICR1, OCR1, TCNT1, UBRR) ==&lt;br /&gt;
&lt;br /&gt;
Einige der Portregister in den AVR-Controllern sind 16 Bit breit. Im Datenblatt sind diese Register üblicherweise mit dem Suffix &amp;quot;L&amp;quot; (LSB) und &amp;quot;H&amp;quot; (MSB) versehen. Die avr-libc definiert zusätzlich die meisten dieser Variablen die Bezeichnung ohne &amp;quot;L&amp;quot; oder &amp;quot;H&amp;quot;. Auf diese kann direkt zugewiesen bzw. zugegriffen werden. Die Konvertierung von 16-bit Wort nach 2*8-bit Byte erfolgt intern.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
uint16_t foo;&lt;br /&gt;
&lt;br /&gt;
foo=ADC; /* setzt die Wort-Variable foo auf den Wert der letzten AD-Wandlung */&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Falls ben&amp;amp;ouml;tigt, kann eine 16-Bit Variable auch recht einfach manuell in ihre zwei 8-Bit Bestandteile zerlegt werden. Folgendes Beispiel demonstriert dies anhand des pseudo- 16-Bit Registers UBRR.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
/* Diese Variante ist normal am effizientesten */&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
#ifndef F_CPU&lt;br /&gt;
#define F_CPU 3686400&lt;br /&gt;
#endif&lt;br /&gt;
#define UART_BAUD_RATE 9600&lt;br /&gt;
&lt;br /&gt;
typedef union {&lt;br /&gt;
        uint16_t i16;&lt;br /&gt;
        struct {&lt;br /&gt;
                uint8_t i8l;&lt;br /&gt;
                uint8_t i8h;&lt;br /&gt;
        };&lt;br /&gt;
} convert16to8;&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
convert16to8 baud;&lt;br /&gt;
baud.i16 = F_CPU / (UART_BAUD_RATE * 16L) -1;&lt;br /&gt;
UBRRH = baud.i8h;&lt;br /&gt;
UBRRL = baud.i8l;&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
/* Alternative 1:*/&lt;br /&gt;
#include &amp;lt;inttypes.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
uint16_t wFoo16;&lt;br /&gt;
uint8_t bFooLow, bFooHigh;&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
wFoo16   = 0xAA55;                 /* zu &amp;quot;zerlegende&amp;quot; 16Bit-Integer */&lt;br /&gt;
bFooHigh = (uint8_t)(wFoo16 &amp;gt;&amp;gt; 8); /* MS-Byte */&lt;br /&gt;
bFooLow  = (uint8_t)(wFoo16);      /* LS-Byte */&lt;br /&gt;
&lt;br /&gt;
/* Alternative 2:*/&lt;br /&gt;
&lt;br /&gt;
#define us0(Data) (*((unsigned char *)(&amp;amp;Data)))&lt;br /&gt;
#define us1(Data) (*((unsigned char *)((&amp;amp;Data)+1)))&lt;br /&gt;
bFooHigh = us1(wFoo16);&lt;br /&gt;
bFoolow  = us0(wFoo16);&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bei einigen AVR-Typen (z.B. ATmega8) teilen sich UBRRH und UCSRC die gleiche Memory-Adresse. Damit der AVR trotzdem zwischen den beiden Registern unterscheiden kann, bestimmt das Bit7 (URSEL) welches Register tats&amp;amp;auml;chlich beschrieben werden soll. &#039;&#039;1000 0011&#039;&#039; (0x83) adressiert demnach UCSRC und &amp;amp;uuml;bergibt den Wert &#039;&#039;3&#039;&#039; und &#039;&#039;0000 0011&#039;&#039; (0x3) adressiert UBRRH und &amp;amp;uuml;bergibt ebenfalls den Wert &#039;&#039;3&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
Bei einigen 16-bit Registern (insbesondere die der 16-bit Timer) erfolgen Schreibzugriffe über das sogenannte &#039;&#039;temporary Register&#039;&#039;. Die Reihenfolge der Zugriffe bestimmt, wann der Wert tatsächlich ins Register geschrieben wird. Typisch wird erst das High-Byte beschrieben (xxxH) und intern im temporary Register zwischengespeichert. Nachdem das Low-Byte (xxxL) geschrieben wurde, setzt der Controller mit diesem und dem im temporary Register zwischengespeicherten Wert für das High-Byte das 16-bit Register. Dabei ist zu beachten, dass intern nur ein temporary Register verfügbar ist, welches in Interruptroutinen mglw. mit einem anderen Wert überschrieben wird, wenn dort ebenfalls 16-bit Register beschrieben werden. avr-gcc/avr-libc berücksichtigen die korrekte Reihenfolge automatisch, wenn die Register mit ihrem &amp;quot;16-bit Label&amp;quot; (ohne H bzw. L) angesprochen werden, dabei ist der Schutz des temporary Registers vor Überschreiben durch Interruptroutinen dennoch zu beachten (im Zweifel beim Schreibzugriff die Interrupts kurzzeitig global deaktivieren).&lt;br /&gt;
&lt;br /&gt;
Im Umgang mit 16-Bit Registern siehe auch:&lt;br /&gt;
* [http://www.nongnu.org/avr-libc/user-manual/index.html Dokumentation der avr-libc] Abschnitt Related Pages/Frequently Asked Questions/Nr. 8&lt;br /&gt;
* Datenblatt Abschnitt &#039;&#039;Accessing 16-bit Registers&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== IO-Register als Parameter und Variablen ==&lt;br /&gt;
&lt;br /&gt;
Um Register als Parameter für eigene Funktionen übergeben zu können, muss man sie als einen volatile uint8_t Pointer übergeben. Zum Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
uint8_t key_pressed(const volatile uint8_t *inputreg, uint8_t inputbit)&lt;br /&gt;
{&lt;br /&gt;
  static uint8_t last_state = 0;&lt;br /&gt;
 &lt;br /&gt;
  if ( last_state == ( *inputreg &amp;amp; (1&amp;lt;&amp;lt;inputbit) ) ) {&lt;br /&gt;
     return 0; /* keine Änderung */&lt;br /&gt;
  }&lt;br /&gt;
 &lt;br /&gt;
  /* Wenn doch, warten bis etwaiges Prellen vorbei ist: */&lt;br /&gt;
  _delay_ms(20);&lt;br /&gt;
&lt;br /&gt;
  /* Zustand für nächsten Aufruf merken: */&lt;br /&gt;
  last_state = ( *inputreg &amp;amp; (1&amp;lt;&amp;lt;inputbit) );&lt;br /&gt;
 &lt;br /&gt;
  /* und den entprellten Tastendruck zurückgeben: */&lt;br /&gt;
  return ( *inputreg &amp;amp; (1&amp;lt;&amp;lt;inputbit) );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* Beispiel für einen Funktionsaufruf: */&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
uint8_t i;&lt;br /&gt;
&lt;br /&gt;
//...&lt;br /&gt;
    i = key_pressed( &amp;amp;PINB, PB1 );&lt;br /&gt;
//...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein Aufruf der Funktion mit call by value würde Folgendes bewirken: Beim Funktionseintritt wird nur eine Kopie des momentanen Portzustandes angefertigt, die sich unabhängig vom tatsächlichen Zustand das Ports nicht mehr ändert, womit die Funktion wirkungslos wäre. Die Übergabe eines Zeigers wäre die Lösung, wenn der Compiler nicht optimieren würde. Denn dadurch wird im Programm nicht von der Hardware gelesen, sondern wieder nur von einem Abbild im Speicher. Das Ergebnis wäre das gleiche wie oben. Mit dem Schlüsselwort volatile sagt man nun dem Compiler, dass die entsprechende Variable entweder durch andere Softwareroutinen (Interrupts) oder durch die Hardware verändert werden kann.&lt;br /&gt;
&lt;br /&gt;
Im Übrigen können mit volatile gekennzeichnete Variablen auch als const deklariert werden, um sicherzustellen, dass sie nur noch von der Hardware änderbar sind.&lt;br /&gt;
&lt;br /&gt;
= Der UART =&lt;br /&gt;
&lt;br /&gt;
== Allgemeines zum UART ==&lt;br /&gt;
&lt;br /&gt;
Über den [[UART]] kann ein AVR leicht mit einer [[RS-232]]-Schnittstelle eines PC oder sonstiger Geräte mit &amp;quot;serieller Schnittstelle&amp;quot; verbunden werden. &lt;br /&gt;
&lt;br /&gt;
Mögliche Anwendungen des UART:&lt;br /&gt;
&lt;br /&gt;
* Debug-Schnittstelle: z.B. zur Anzeige von Zwischenergebnissen (&amp;quot;printf-debugging&amp;quot; - hier besser &amp;quot;UART-debugging&amp;quot;) auf einem PC. Auf dem Rechner reicht dazu ein [[RS-232#Terminalprogramme|Terminalprogramm]] (MS-Windows: Hyperterm oder besser [http://braypp.googlepages.com/terminal Bray-Terminal], [http://www.der-hammer.info/terminal/ HTerm]; Unix/Linux z.B. minicom). Ein direkter Anschluss ist aufgrund unterschiedlicher Pegel nicht möglich, jedoch sind entsprechende Schnittstellen-ICs wie z.B. ein MAX232 günstig und leicht zu integrieren. Rechner ohne serielle Schnittstelle können über fertige USB-seriell-Adapter angeschlossen werden. &lt;br /&gt;
* &amp;quot;Mensch-Maschine Schnittstelle&amp;quot;: z.B. Konfiguration und Statusabfrage über eine &amp;quot;Kommandozeile&amp;quot; oder Menüs (siehe z.B. Forumsbeitrag [http://www.mikrocontroller.net/topic/52985 Auswertung RS232-Befehle]) &lt;br /&gt;
* Übertragen von gespeicherten Werten: z.B. bei einem Datenlogger&lt;br /&gt;
* Anschluss von Geräten mit serieller Schnittstelle (z.B. (Funk-)Modems, Mobiltelefone, Drucker, Sensoren, &amp;quot;intelligente&amp;quot; LC-Displays, GPS-Empfänger). &lt;br /&gt;
* &amp;quot;Feldbusse&amp;quot; auf RS485/RS422-Basis mittels entsprechenden Bustreiberbausteinen (z.B. MAX485)&lt;br /&gt;
* DMX, Midi etc.&lt;br /&gt;
* LIN-Bus (&#039;&#039;&#039;L&#039;&#039;&#039;ocal &#039;&#039;&#039;I&#039;&#039;&#039;nterconnect &#039;&#039;&#039;N&#039;&#039;&#039;etwork): Preiswerte Sensoren/Aktoren in der Automobiltechnik und darüber hinaus&lt;br /&gt;
&lt;br /&gt;
Einige AVR-Controller haben ein bis zwei vollduplexfähigen UART (&#039;&#039;&#039;U&#039;&#039;&#039;niversal &#039;&#039;&#039;A&#039;&#039;&#039;synchronous &#039;&#039;&#039;R&#039;&#039;&#039;eceiver and &#039;&#039;&#039;T&#039;&#039;&#039;ransmitter) schon eingebaut (&amp;quot;Hardware-UART&amp;quot;). &lt;br /&gt;
Übrigens: Vollduplex heißt nichts anderes, als dass der Baustein gleichzeitig senden und empfangen kann.&lt;br /&gt;
&lt;br /&gt;
Neuere AVRs (ATmega, ATtiny) verfügen über einen oder zwei U&#039;&#039;&#039;S&#039;&#039;&#039;ART(s), dieser unterscheidet sich vom UART hauptsächlich durch interne FIFO-Puffer für Ein- und Ausgabe und erweiterte Konfigurationsmöglichkeiten. Die Puffergröße ist allerdings nur 1 Byte.&lt;br /&gt;
&lt;br /&gt;
Der UART wird über vier separate Register angesprochen. USARTs der ATMEGAs verfügen über mehrere zusätzliche Konfigurationsregister. Das Datenblatt gibt darüber Auskunft. Die Folgende Tabelle gibt nur die Register für die (veralteten) UARTs wieder.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;UCR&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;U&#039;&#039;&#039;ART &#039;&#039;&#039;C&#039;&#039;&#039;ontrol &#039;&#039;&#039;R&#039;&#039;&#039;egister.&amp;lt;br /&amp;gt;&lt;br /&gt;
In diesem Register stellen wir ein, wie wir den UART verwenden möchten.&amp;lt;br /&amp;gt;&lt;br /&gt;
Das Register ist wie folgt aufgebaut:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Bit&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 7&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 6&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 5&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 4&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 2&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Name&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;RXCIE&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;TXCIE&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;UDRIE&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;RXEN&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;TXEN&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;CHR9&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;RXB8&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;TXB8&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;R/W&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | W&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Initialwert&#039;&#039;&#039;&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;
| 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;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;RXCIE&#039;&#039;&#039; (&#039;&#039;&#039;RX&#039;&#039;&#039; &#039;&#039;&#039;C&#039;&#039;&#039;omplete &#039;&#039;&#039;I&#039;&#039;&#039;nterrupt &#039;&#039;&#039;E&#039;&#039;&#039;nable)&lt;br /&gt;
:Wenn dieses Bit gesetzt ist, wird ein UART RX Complete Interrupt ausgelöst, wenn ein Zeichen vom UART empfangen wurde. Das Global Enable Interrupt Flag muss selbstverständlich auch gesetzt sein.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;TXCIE&#039;&#039;&#039; (&#039;&#039;&#039;TX&#039;&#039;&#039; &#039;&#039;&#039;C&#039;&#039;&#039;omplete &#039;&#039;&#039;I&#039;&#039;&#039;nterrupt &#039;&#039;&#039;E&#039;&#039;&#039;nable)&lt;br /&gt;
:Wenn dieses Bit gesetzt ist, wird ein UART TX Complete Interrupt ausgelöst, wenn ein Zeichen vom UART gesendet wurde. Das Global Enable Interrupt Flag muss selbstverständlich auch gesetzt sein.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;UDRIE&#039;&#039;&#039; (&#039;&#039;&#039;U&#039;&#039;&#039;ART &#039;&#039;&#039;D&#039;&#039;&#039;ata &#039;&#039;&#039;R&#039;&#039;&#039;egister &#039;&#039;&#039;E&#039;&#039;&#039;mpty &#039;&#039;&#039;I&#039;&#039;&#039;nterrupt &#039;&#039;&#039;E&#039;&#039;&#039;nable)&lt;br /&gt;
:Wenn dieses Bit gesetzt ist, wird ein UART Datenregister Leer Interrupt ausgelöst, wenn der UART wieder bereit ist um ein neues zu sendendes Zeichen zu übernehmen. Das Global Enable Interrupt Flag muss selbstverständlich auch gesetzt sein.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;RXEN&#039;&#039;&#039; (&#039;&#039;&#039;R&#039;&#039;&#039;eceiver &#039;&#039;&#039;E&#039;&#039;&#039;nable)&lt;br /&gt;
:Nur wenn dieses Bit gesetzt ist, arbeitet der Empfänger des UART überhaupt. Wenn das Bit nicht gesetzt ist, kann der entsprechende Pin des AVR als normaler I/O-Pin verwendet werden. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;TXEN&#039;&#039;&#039; (&#039;&#039;&#039;T&#039;&#039;&#039;ransmitter &#039;&#039;&#039;E&#039;&#039;&#039;nable)&lt;br /&gt;
:Nur wenn dieses Bit gesetzt ist, arbeitet der Sender des UART überhaupt. Wenn das Bit nicht gesetzt ist, kann der entsprechende Pin des AVR als normaler I/O-Pin verwendet werden.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;CHR9&#039;&#039;&#039; (9 Bit Characters)&lt;br /&gt;
:Wenn dieses Bit gesetzt ist, können 9 Bit lange Zeichen übertragen und empfangen werden. Das 9. Bit kann bei Bedarf als zusätzliches Stopbit oder als Paritätsbit verwendet werden. Man spricht dann von einem 11-Bit Zeichenrahmen:&lt;br /&gt;
:1 Startbit + 8 Datenbits + 1 Stopbit + 1 Paritätsbit = 11 Bits&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;RXB8&#039;&#039;&#039; (Receive Data Bit 8)&lt;br /&gt;
:Wenn das vorher erwähnte CHR9-Bit gesetzt ist, dann enthält dieses Bit das 9. Datenbit eines empfangenen Zeichens.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;TXB8&#039;&#039;&#039; (Transmit Data Bit 8)&lt;br /&gt;
:Wenn das vorher erwähnte CHR9-Bit gesetzt ist, dann muss in dieses Bit das 9. Bit des zu sendenden Zeichens eingeschrieben werden bevor das eigentliche Datenbyte in das Datenregister geschrieben wird.&lt;br /&gt;
&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;USR&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;U&#039;&#039;&#039;ART &#039;&#039;&#039;S&#039;&#039;&#039;tatus &#039;&#039;&#039;R&#039;&#039;&#039;egister.&amp;lt;br /&amp;gt;&lt;br /&gt;
Hier teilt uns der UART mit, was er gerade so macht.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Bit&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 7&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 6&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 5&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 4&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 2&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Name&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;RXC&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;TXC&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;UDRE&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;FE&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;OR&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;R/W&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Initialwert&#039;&#039;&#039;&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;
| 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;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;RXC&#039;&#039;&#039; (UART Receive Complete)&lt;br /&gt;
:Dieses Bit wird vom AVR gesetzt, wenn ein empfangenes Zeichen vom Empfangs-Schieberegister in das Empfangs-Datenregister transferiert wurde.&lt;br /&gt;
:Das Zeichen muss nun schnellstmöglich aus dem Datenregister ausgelesen werden. Falls dies nicht erfolgt bevor ein weiteres Zeichen komplett empfangen wurde wird eine Überlauf-Fehlersituation eintreffen. Mit dem Auslesen des Datenregisters wird das Bit automatisch gelöscht.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;TXC&#039;&#039;&#039; (UART Transmit Complete)&lt;br /&gt;
:Dieses Bit wird vom AVR gesetzt, wenn das im Sende-Schieberegister befindliche Zeichen vollständig ausgegeben wurde und kein weiteres Zeichen im Sendedatenregister ansteht. Dies bedeutet also, wenn die Kommunikation vollumfänglich abgeschlossen ist.&lt;br /&gt;
:Dieses Bit ist wichtig bei Halbduplex-Verbindungen, wenn das Programm nach dem Senden von Daten auf Empfang schalten muss. Im Vollduplexbetrieb brauchen wir dieses Bit nicht zu beachten.&lt;br /&gt;
:Das Bit wird nur dann automatisch gelöscht, wenn der entsprechende Interrupthandler aufgerufen wird, ansonsten müssen wir das Bit selber löschen.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;UDRE&#039;&#039;&#039; (&#039;&#039;&#039;U&#039;&#039;&#039;ART &#039;&#039;&#039;D&#039;&#039;&#039;ata &#039;&#039;&#039;R&#039;&#039;&#039;egister &#039;&#039;&#039;E&#039;&#039;&#039;mpty)&lt;br /&gt;
:Dieses Bit zeigt an, ob der Sendepuffer bereit ist, um ein zu sendendes Zeichen aufzunehmen. Das Bit wird vom AVR gesetzt (1), wenn der Sendepuffer leer ist. Es wird gelöscht (0), wenn ein Zeichen im Sendedatenregister vorhanden ist und noch nicht in das Sendeschieberegister übernommen wurde. Atmel empfiehlt aus Kompatibilitätsgründen mit kommenden µC, UDRE auf 0 zu setzen, wenn das UCSRA Register beschrieben wird.&lt;br /&gt;
:Das Bit wird automatisch gelöscht, wenn ein Zeichen in das Sendedatenregister geschrieben wird.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;FE&#039;&#039;&#039; (&#039;&#039;&#039;F&#039;&#039;&#039;raming &#039;&#039;&#039;E&#039;&#039;&#039;rror)&lt;br /&gt;
:Dieses Bit wird vom AVR gesetzt, wenn der UART einen Zeichenrahmenfehler detektiert, d.h. wenn das Stopbit eines empfangenen Zeichens 0 ist.&lt;br /&gt;
:Das Bit wird automatisch gelöscht, wenn das Stopbit des empfangenen Zeichens 1 ist.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;OR&#039;&#039;&#039; (&#039;&#039;&#039;O&#039;&#039;&#039;ver&#039;&#039;&#039;R&#039;&#039;&#039;un)&amp;lt;br /&amp;gt;&lt;br /&gt;
:Dieses Bit wird vom AVR gesetzt, wenn unser Programm das im Empfangsdatenregister bereit liegende Zeichen nicht abholt bevor das nachfolgende Zeichen komplett empfangen wurde.&lt;br /&gt;
:Das nachfolgende Zeichen wird verworfen.&lt;br /&gt;
:Das Bit wird automatisch gelöscht, wenn das empfangene Zeichen in das Empfangsdatenregister transferiert werden konnte.&lt;br /&gt;
&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;UDR&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;U&#039;&#039;&#039;ART &#039;&#039;&#039;D&#039;&#039;&#039;ata &#039;&#039;&#039;R&#039;&#039;&#039;egister.&amp;lt;br /&amp;gt;&lt;br /&gt;
Hier werden Daten zwischen UART und CPU übertragen. Da der UART im&lt;br /&gt;
Vollduplexbetrieb gleichzeitig empfangen und senden kann, handelt es sich&lt;br /&gt;
hier physikalisch um 2 Register, die aber über die gleiche I/O-Adresse&lt;br /&gt;
angesprochen werden. Je nachdem, ob ein Lese- oder ein Schreibzugriff auf&lt;br /&gt;
den UART erfolgt wird automatisch das richtige UDR angesprochen.&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;UBRR&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;U&#039;&#039;&#039;ART &#039;&#039;&#039;B&#039;&#039;&#039;aud &#039;&#039;&#039;R&#039;&#039;&#039;ate &#039;&#039;&#039;R&#039;&#039;&#039;egister.&amp;lt;br /&amp;gt;&lt;br /&gt;
In diesem Register müssen wir dem UART mitteilen, wie schnell wir gerne&lt;br /&gt;
kommunizieren möchten. Der Wert, der in dieses Register geschrieben&lt;br /&gt;
werden muss, errechnet sich nach folgender Formel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
\begin{matrix}&lt;br /&gt;
\mathrm{UBRR} = \frac{\mathrm{Taktfrequenz}}{\mathrm{Baudrate} \cdot 16} - 1&lt;br /&gt;
\end{matrix}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Es sind Baudraten bis zu 115200 Baud und höher möglich.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Die Hardware ==&lt;br /&gt;
&lt;br /&gt;
Der UART basiert auf normalem TTL-Pegel mit 0V (LOW) und 5V (HIGH). Die&lt;br /&gt;
Schnittstellenspezifikation für RS-232 definiert jedoch -3V ... -12V (LOW) und&lt;br /&gt;
+3 ... +12V (HIGH). Zudem muss der Signalaustausch zwischen AVR und&lt;br /&gt;
Partnergerät invertiert werden. Für die Anpassung der Pegel und das&lt;br /&gt;
Invertieren der Signale gibt es fertige Schnittstellenbausteine. Der bekannteste&lt;br /&gt;
davon ist wohl der MAX232. &lt;br /&gt;
&amp;lt;!-- &amp;quot;Hackerloesung&amp;quot; auskommentiert - nicht so gut in einem &amp;quot;Einsteiger-Tutorial&amp;quot; - mthomas&lt;br /&gt;
Allerdings kostet der auch wieder Geld und benötigt&lt;br /&gt;
zusätzlich immerhin 4 externe Elkos.&lt;br /&gt;
&lt;br /&gt;
Die in den PC eingebauten Schnittstellen vertragen ohne Klagen auch den&lt;br /&gt;
TTL-Pegel vom AVR. Allerdings müssen wir immer noch die Signale invertieren. Im&lt;br /&gt;
einfachtesn Fall verwenden wir dazu jeweils einen einfachen NPN-Transistor und 2&lt;br /&gt;
Widerstände. Näheres dazu erfahrt ihr in den folgenden Übungen.--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Streikt die Kommunikation per UART, so ist oft eine fehlerhafte Einstellung der Baudrate die Ursache. Die Konfiguration auf eine bestimmte Baudrate ist abhängig von der Taktfrequenz des Controllers. Gerade bei neu aufgebauten Schaltungen (bzw. neu gekauften Controllern) sollte man sich daher noch einmal vergewissern, dass der Controller auch tatsächlich mit der vermuteten Taktrate arbeitet und nicht z.B. den bei einigen Modellen werksseitig eingestellten internen [[Oszillator]] statt eines externen Quarzes nutzt. Die Werte der verschiedenen fuse-bits im Fehlerfall also beispielsweise mit &#039;&#039;[[AVRDUDE]]&#039;&#039; kontrollieren und falls nötig anpassen. Grundsätzlich empfiehlt sich auch immer ein Blick in die [[AVR_Checkliste]].&lt;br /&gt;
&lt;br /&gt;
== UART initialisieren ==&lt;br /&gt;
&lt;br /&gt;
Wir wollen nun Daten mit dem UART auf die serielle Schnittstelle ausgeben. Dazu müssen wir den UART zuerst mal initialisieren. Dazu setzen wir je nach gewünschter Funktionsweise die benötigten Bits im &#039;&#039;&#039;U&#039;&#039;&#039;ART &#039;&#039;&#039;C&#039;&#039;&#039;ontrol &#039;&#039;&#039;R&#039;&#039;&#039;egister.&lt;br /&gt;
&lt;br /&gt;
Da wir vorerst nur senden möchten und noch keine Interrupts auswerten wollen, gestaltet sich die Initialisierung wirklich sehr einfach, da wir lediglich das &#039;&#039;&#039;Transmitter Enable&#039;&#039;&#039; Bit setzen müssen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
    UCR |= (1&amp;lt;&amp;lt;TXEN);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Neuere AVRs mit USART haben mehrere Konfigurationsregister und erfordern eine etwas andere Konfiguration. Für einen ATmega16 z.B.:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
    UCSRB |= (1&amp;lt;&amp;lt;TXEN);                            // UART TX einschalten&lt;br /&gt;
    UCSRC |= (1&amp;lt;&amp;lt;URSEL)|(1 &amp;lt;&amp;lt; UCSZ1)|(1 &amp;lt;&amp;lt; UCSZ0); // Asynchron 8N1&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nun ist noch das Baudratenregister &#039;&#039;&#039;UBRR&#039;&#039;&#039; einzustellen. Bei neueren AVRs besteht es aus zwei Registern &#039;&#039;&#039;UBRRL&#039;&#039;&#039; und &#039;&#039;&#039;UBRRH&#039;&#039;&#039;. Der Wert dafür ergibt sich aus der angegebenen Formel durch Einsetzen der Taktfrequenz und der gewünschten Übertragungsrate. Das Berechnen der Formel wird dem [[C-Präprozessor|Präprozessor]] überlassen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
/* UART-Init beim AT90S2313 */&lt;br /&gt;
&lt;br /&gt;
#ifndef F_CPU&lt;br /&gt;
/* In neueren Version der WinAVR/Mfile Makefile-Vorlage kann&lt;br /&gt;
   F_CPU im Makefile definiert werden, eine nochmalige Definition&lt;br /&gt;
   hier wuerde zu einer Compilerwarnung fuehren. Daher &amp;quot;Schutz&amp;quot; durch&lt;br /&gt;
   #ifndef/#endif &lt;br /&gt;
&lt;br /&gt;
   Dieser &amp;quot;Schutz&amp;quot; kann zu Debugsessions führen, wenn AVRStudio &lt;br /&gt;
   verwendet wird und dort eine andere, nicht zur Hardware passende &lt;br /&gt;
   Taktrate eingestellt ist: Dann wird die folgende Definition &lt;br /&gt;
   nicht verwendet, sondern stattdessen der Defaultwert (8 MHz?) &lt;br /&gt;
   von AVRStudio - daher Ausgabe einer Warnung falls F_CPU&lt;br /&gt;
   noch nicht definiert: */&lt;br /&gt;
#warning &amp;quot;F_CPU war noch nicht definiert, wird nun nachgeholt mit 4000000&amp;quot;&lt;br /&gt;
#define F_CPU 4000000UL    // Systemtakt in Hz - Definition als unsigned long beachten &amp;gt;&amp;gt; Ohne ergeben Fehler in der Berechnung&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
#define BAUD 9600UL          // Baudrate&lt;br /&gt;
&lt;br /&gt;
// Berechnungen&lt;br /&gt;
#define UBRR_VAL ((F_CPU+BAUD*8)/(BAUD*16)-1)   // clever runden&lt;br /&gt;
#define BAUD_REAL (F_CPU/(16*(UBRR_VAL+1)))     // Reale Baudrate&lt;br /&gt;
#define BAUD_ERROR ((BAUD_REAL*1000)/BAUD) // Fehler in Promille, 1000 = kein Fehler.&lt;br /&gt;
&lt;br /&gt;
#if ((BAUD_ERROR&amp;lt;990) || (BAUD_ERROR&amp;gt;1010))&lt;br /&gt;
  #error Systematischer Fehler der Baudrate grösser 1% und damit zu hoch! &lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
int main(void)&lt;br /&gt;
{&lt;br /&gt;
    UCR |= (1&amp;lt;&amp;lt;TXEN);&lt;br /&gt;
    UBRR = UBRR_VAL;&lt;br /&gt;
    //...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&amp;lt;!-- mthomas: warum nicht UL?, wird von AVRStudio auch mit UL übergeben --&amp;gt;&lt;br /&gt;
Wieder für den Mega16 mit zwei Registern für die Baudrateneinstellung eine etwas andere Programmierung. Wichtig ist, dass UBRRH &#039;&#039;&#039;vor&#039;&#039;&#039; UBRRL geschrieben wird.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
  /* USART-Init beim ATmega16 */&lt;br /&gt;
&lt;br /&gt;
int main(void)&lt;br /&gt;
{&lt;br /&gt;
    UCSRB |= (1&amp;lt;&amp;lt;TXEN);                // UART TX einschalten&lt;br /&gt;
    UCSRC |= (1&amp;lt;&amp;lt;URSEL)|(3&amp;lt;&amp;lt;UCSZ0);    // Asynchron 8N1 &lt;br /&gt;
&lt;br /&gt;
    UBRRH = UBRR_VAL &amp;gt;&amp;gt; 8;&lt;br /&gt;
    UBRRL = UBRR_VAL &amp;amp; 0xFF;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für einige AVR (z.B. ATmega169, ATmega48/88/168, AT90CAN jedoch nicht für z.B. ATmega16/32, ATmega128, ATtiny2313) wird durch die Registerdefinitionen der avr-libc (io*.h) auch für Controller mit zwei UBRR-Registern (UBRRL/UBRRH) ein UBRR bzw. UBRR0 als &amp;quot;16-bit-Register&amp;quot; definiert und man kann auch Werte direkt per UBRR = UBRR_VAL zuweisen. Intern werden dann zwei Zuweisungen für UBRRH und UBRRL generiert. Dies ist nicht bei allen Controllern möglich, da die beiden Register nicht bei allen aufeinanderfolgende Addressen aufweisen. Die getrennte Zuweisung an UBRRH und UBRRL wie im Beispiel gezeigt ist universeller und portabler und daher vorzuziehen.&lt;br /&gt;
&lt;br /&gt;
Die Makros sind sehr praktisch, da sie sowohl automatisch den Wert für UBRR als auch den Fehler in der generierten Baudrate berechnen und im Falle einer Überschreitung (+/-1%) einen Fehler und somit Abbruch im Compilerablauf generieren. Damit können viele Probleme mit &amp;quot;UART sendet komische Zeichen&amp;quot; vermieden werden. Ausserdem kann man mühelos die Einstellung an eine neue Taktfrequenz bzw. Baudrate anpassen, ohne selber rechnen oder in Tabellen nachschlagen zu müssen.&lt;br /&gt;
&lt;br /&gt;
Siehe auch:&lt;br /&gt;
* [http://www.wormfood.net/avrbaudcalc.php WormFood&#039;s AVR Baud Rate Calculator] online.&lt;br /&gt;
&lt;br /&gt;
== Senden mit dem UART ==&lt;br /&gt;
&lt;br /&gt;
=== Senden einzelner Zeichen ===&lt;br /&gt;
&lt;br /&gt;
Um nun ein Zeichen auf die Schnittstelle auszugeben, müssen wir dasselbe&lt;br /&gt;
lediglich in das &#039;&#039;&#039;U&#039;&#039;&#039;ART &#039;&#039;&#039;D&#039;&#039;&#039;ata &#039;&#039;&#039;R&#039;&#039;&#039;egister schreiben. Vorher ist zu prüfen, ob das UART-Modul bereit ist, das zu sendende Zeichen entgegenzunehmen. Die Bezeichnungen des/der Statusregisters mit dem Bit UDRE ist abhängig vom Controllertypen (vgl. Datenblatt).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
    // bei AVR mit einem UART (&amp;quot;classic AVR&amp;quot; z.B. AT90S8515)&lt;br /&gt;
    while (!(USR &amp;amp; (1&amp;lt;&amp;lt;UDRE)))  /* warten bis Senden moeglich                   */&lt;br /&gt;
    {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    UDR = &#039;x&#039;;                  /* schreibt das Zeichen x auf die Schnittstelle */&lt;br /&gt;
&lt;br /&gt;
    /** ODER **/&lt;br /&gt;
&lt;br /&gt;
    // bei neueren AVRs steht der Status in UCSRA/UCSR0A/UCSR1A, hier z.B. fuer ATmega16:&lt;br /&gt;
    while (!(UCSRA &amp;amp; (1&amp;lt;&amp;lt;UDRE)))  /* warten bis Senden moeglich                   */&lt;br /&gt;
    {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    UDR = &#039;x&#039;;                    /* schreibt das Zeichen x auf die Schnittstelle */&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Schreiben einer Zeichenkette (String) ===&lt;br /&gt;
&lt;br /&gt;
Die Aufgabe &amp;quot;String senden&amp;quot; wird durch zwei Funktionen abgearbeitet. Die universelle/controllerunabhängige Funktion uart_puts übergibt jeweils ein Zeichen der Zeichenkette an eine Funktion uart_putc, die abhängig von der vorhandenen Hardware implementiert werden muss. In der Funktion zum Senden eines Zeichens ist darauf zu achten, dass vor dem Senden geprüft wird, ob der UART bereit ist den &amp;quot;Sendeauftrag&amp;quot; entgegenzunehmen. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
// putc fuer AVR mit einem UART (z.B. AT90S8515)&lt;br /&gt;
int uart_putc(unsigned char c)&lt;br /&gt;
{&lt;br /&gt;
    while(!(USR &amp;amp; (1 &amp;lt;&amp;lt; UDRE)))  /* warte, bis UDR bereit */&lt;br /&gt;
    {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    UDR = c;                     /* sende Zeichen */&lt;br /&gt;
    return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/** ODER **/&lt;br /&gt;
&lt;br /&gt;
// bei neueren AVRs andere Bezeichnung fuer die Statusregister, hier ATmega16:&lt;br /&gt;
int uart_putc(unsigned char c)&lt;br /&gt;
{&lt;br /&gt;
    while (!(UCSRA &amp;amp; (1&amp;lt;&amp;lt;UDRE)))  /* warten bis Senden moeglich */&lt;br /&gt;
    {&lt;br /&gt;
    }                             &lt;br /&gt;
&lt;br /&gt;
    UDR = c;                      /* sende Zeichen */&lt;br /&gt;
    return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* puts ist unabhaengig vom Controllertyp */&lt;br /&gt;
void uart_puts (char *s)&lt;br /&gt;
{&lt;br /&gt;
    while (*s)&lt;br /&gt;
    {   /* so lange *s != &#039;\0&#039; also ungleich dem &amp;quot;String-Endezeichen&amp;quot; */&lt;br /&gt;
        uart_putc(*s);&lt;br /&gt;
        s++;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die in uart_putc verwendeten Schleifen, in denen gewartet wird bis die UART-Hardware zum senden bereit ist, sind insofern etwas kritisch, da während des Sendens eines Strings nicht mehr auf andere Ereignisse reagieren werden kann. Universeller ist die Nutzung von FIFO(first-in first-out)-Puffern, in denen die zu sendenden bzw. empfangenen Zeichen/Bytes zwischengespeichert und in Interruptroutinen an die U(S)ART-Hardware weitergegeben bzw. von ihr ausgelesen werden. Dazu existieren fertige Komponenten (Bibliotheken, Libraries), die man recht einfach in eigene Entwicklungen integrieren kann. Es empfiehlt sich, diese Komponenten zu nutzen und das Rad nicht neu zu erfinden.&lt;br /&gt;
&lt;br /&gt;
=== Schreiben von Variableninhalten ===&lt;br /&gt;
&lt;br /&gt;
Sollen Inhalte von Variablen (Ganzzahlen, Fließkomma) in &amp;quot;menschenlesbarer&amp;quot; Form gesendet werden, ist vor dem Transfer eine Umwandlung in Zeichen (&amp;quot;ASCII&amp;quot;) erforderlich. Bei nur einer Ziffer ist diese Umwandlung relativ einfach: man addiert den ASCII-Wert von Null zur Ziffer und kann diesen Wert direkt senden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
// hier uart_putc (s.o.)&lt;br /&gt;
&lt;br /&gt;
// Ausgabe von 0123456789&lt;br /&gt;
char c;&lt;br /&gt;
&lt;br /&gt;
for (uint8_t i=0; i&amp;lt;=9; ++i) {&lt;br /&gt;
    c = i + &#039;0&#039;;&lt;br /&gt;
    uart_putc( c );&lt;br /&gt;
    // verkuerzt: uart_putc( i + &#039;0&#039; );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Soll mehr als eine Ziffer ausgegeben werden, bedient man sich zweckmäßigerweise vorhandener Funktionen zur Umwandlung von Zahlen in Zeichenketten/Strings. Die Funktion der avr-libc zur Umwandlung von vorzeichenbehafteten 16bit-Ganzzahlen (int16_t) in Zeichenketten heißt &#039;&#039;itoa&#039;&#039; (Integer to ASCII). Man muss der Funktion einen Speicherbereich zur Verarbeitung (buffer) mit Platz für alle Ziffern, das String-Endezeichen (&#039;\0&#039;) und evtl. das Vorzeichen bereitstellen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
// hier uart_init, uart_putc, uart_puts (s.o.)&lt;br /&gt;
&lt;br /&gt;
int main(void)&lt;br /&gt;
{&lt;br /&gt;
   char s[7];&lt;br /&gt;
   int16_t i = -12345;&lt;br /&gt;
   &lt;br /&gt;
   uart_init();&lt;br /&gt;
&lt;br /&gt;
   itoa( i, s, 10 ); // 10 fuer radix -&amp;gt; Dezimalsystem&lt;br /&gt;
   uart_puts( s );&lt;br /&gt;
&lt;br /&gt;
   // da itoa einen Zeiger auf den Beginn von s zurueckgibt verkuerzt auch:&lt;br /&gt;
   uart_puts( itoa( i, s, 10 ) );&lt;br /&gt;
&lt;br /&gt;
   while (1) {&lt;br /&gt;
      ;&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
   return 0; // never reached &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für vorzeichenlose 16bit-Ganzzahlen (uint16_t) exisitert &#039;&#039;utoa&#039;&#039;. Die Funktionen für 32bit-Ganzzahlen (int32_t und uint32_t) heißen &#039;&#039;ltoa&#039;&#039; bzw. &#039;&#039;ultoa&#039;&#039;. Da 32bit-Ganzzahlen mehr Stellen aufweisen können, ist ein entsprechend größerer Pufferspeicher vorzusehen.&lt;br /&gt;
&lt;br /&gt;
Auch Fließkommazahlen (float/double) können mit breits vorhandenen Funktionen in Zeichenfolgen umgewandelt werden, dazu existieren die Funktionen &#039;&#039;dtostre&#039;&#039; und &#039;&#039;dtostrf&#039;&#039;. dtostre nutzt Exponentialschreibweise (&amp;quot;engineering&amp;quot;-Format). (Hinweis: z.Zt. existiert im avr-gcc kein &amp;quot;echtes&amp;quot; double, intern wird immer mit &amp;quot;einfacher Genauigkeit&amp;quot;, entsprechend float, gerechnet.) &lt;br /&gt;
&lt;br /&gt;
dtostrf und dtostre benötigen die libm.a der avr-libc. Bei Nutzung von Makefiles ist der Parameter -lm in in LDFLAGS anzugeben (Standard in den WinAVR/mfile-Makefilevorlagen). Nutzt man AVRStudio als IDE für den GNU-Compiler (gcc-Plugin) ist die libm.a unter Libaries auszuwählen: Project -&amp;gt; Configurations Options -&amp;gt; Libaries -&amp;gt; libm.a mit dem Pfeil nach rechts einbinden. Siehe auch die [[FAQ#Aktivieren_der_Floating_Point_Version_von_sprintf_beim_WinAVR_mit_AVR-Studio|FAQ]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
// hier uart_init, uart_putc, uart_puts (s.o.)&lt;br /&gt;
&lt;br /&gt;
/* lt. avr-libc Dokumentation:&lt;br /&gt;
char* dtostrf(&lt;br /&gt;
  double __val,&lt;br /&gt;
  char   __width,&lt;br /&gt;
  char   __prec,&lt;br /&gt;
  char * __s&lt;br /&gt;
)  &lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
int main(void)&lt;br /&gt;
{&lt;br /&gt;
   // Pufferspeicher ausreichend groß&lt;br /&gt;
   // evtl. Vorzeichen + width + Endezeichen:&lt;br /&gt;
   char s[8]; &lt;br /&gt;
   float f = -12.345;&lt;br /&gt;
   &lt;br /&gt;
   uart_init();&lt;br /&gt;
&lt;br /&gt;
   dtostrf( f, 6, 3, s ); &lt;br /&gt;
   uart_puts( s );&lt;br /&gt;
&lt;br /&gt;
   // verkürzt: uart_puts( dtostrf( f, 7, 3, s ) );&lt;br /&gt;
&lt;br /&gt;
   while (1) {&lt;br /&gt;
      ;&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
   return 0; // never reached &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Empfangen ==&lt;br /&gt;
=== einzelne Zeichen empfangen ===&lt;br /&gt;
&lt;br /&gt;
Zum Empfang von Zeichen muss der Empfangsteil des UART bei der Initialisierung aktiviert werden, indem das RXEN-Bit im jeweiligen Konfigurationsregister (UCSRB bzw UCSR0B/UCSR1B) gesetzt wird. Im einfachsten Fall wird solange gewartet, bis ein Zeichen empfangen wurde, dieses steht dann im UART-Datenregister (UDR bzw. UDR0 und UDR1 bei AVRs mit 2 UARTS) zur Verfügung (sogen. &amp;quot;Polling-Betrieb&amp;quot;). Ein Beispiel für den ATmega16:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;inttypes.h&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/* Zusaetzlich zur Baudrateneinstellung und der weiteren Initialisierung: */&lt;br /&gt;
void Usart_EnableRX(void)&lt;br /&gt;
{&lt;br /&gt;
    UCSRB |= ( 1 &amp;lt;&amp;lt; RXEN );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* Zeichen empfangen */&lt;br /&gt;
uint8_t uart_getc(void)&lt;br /&gt;
{&lt;br /&gt;
    while (!(UCSRA &amp;amp; (1&amp;lt;&amp;lt;RXC)))   // warten bis Zeichen verfuegbar&lt;br /&gt;
        ;&lt;br /&gt;
    return UDR;                   // Zeichen aus UDR an Aufrufer zurueckgeben&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Diese Funktion blockiert den Programmablauf. Alternativ kann das RXC-Bit in einer Programmschleife abgefragt werden und dann nur bei gesetztem RXC-Bit UDR ausgelesen werden. Eleganter und in den meisten Anwendungsfällen &amp;quot;stabiler&amp;quot; ist die Vorgehensweise, die empfangenen Zeichen in einer Interrupt-Routine einzulesen und zur späteren Verarbeitung in einem Eingangsbuffer (FIFO-Buffer) zwischenzuspeichern. Dazu existieren fertige und gut getestete [[Libraries|Bibliotheken]] &amp;lt;!-- &amp;quot;echte Libraries&amp;quot; (.a) wie im Verweis beschrieben sind hier eigentlich nicht gemeint, verwirrt hier etwas, da AVR-&amp;quot;Libraries&amp;quot; meist per #defines anpassbare Source-Codes sind, vielleicht so: --&amp;gt; und Quellcodekomponenten (z.B. UART-Library von P. Fleury, procyon-avrlib und einige in der &amp;quot;Academy&amp;quot; von avrfreaks.net).&lt;br /&gt;
&lt;br /&gt;
siehe auch:&lt;br /&gt;
* [http://www.nongnu.org/avr-libc/user-manual/group__avr__stdlib.html Dokumenation der avr-libc/stdlib.h]&lt;br /&gt;
* [http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Die_Nutzung_von_printf Die Nutzung von printf]&lt;br /&gt;
* [http://homepage.hispeed.ch/peterfleury/ Peter Fleurys] UART-Bibiliothek fuer avr-gcc/avr-libc&lt;br /&gt;
&amp;lt;!-- nimmermehr: * siehe auch: Weiterführende Informationen inkl. Beispielen für die Nutzung von stdio-Funktionen (printf etc.) im [[AVR-Tutorial:_UART]]. --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
TODO: 9bit&lt;br /&gt;
&lt;br /&gt;
=== Empfang von Zeichenketten (Strings) ===&lt;br /&gt;
&lt;br /&gt;
Beim Empfang von Zeichenketten, muß man sich zunächst darüber im klaren sein, daß es ein Kriterium geben muß, an dem der µC erkennen kann, wann ein String zu Ende ist. Sehr oft wird dazu das Zeichen &#039;Return&#039; benutzt, um das Ende eines Strings zu markieren. Dies ist vom Benutzer einfach eingebbar und er ist auch daran gewöhnt, daß er eine Eingabezeile mit einem Druck auf die Return Taste abgeschlossen wird.&lt;br /&gt;
&lt;br /&gt;
Prinzipiell gibt es jedoch keine Einschränkung bezüglich dieses speziellen Zeichens. Es muß nur sichergestellt werden, daß dieses spezielle &#039;Ende eines Strings&#039; - Zeichen nicht mit einem im Text vorkommenden Zeichen verwechselt werden kann. Wenn also im zu übertragenden Text beispielsweise kein &#039;;&#039; vorkommt, dann spricht nichts dagegen, einen String mit einem &#039;;&#039; abschließen zu lassen.&lt;br /&gt;
&lt;br /&gt;
Im Folgenden wird die durchaus übliche Annahme getroffen, daß eine Stringübertragung identisch ist mit der Übertragung einer Textzeile und daher mit einem Return (&#039;\n&#039;) abgeschlossen wird.&lt;br /&gt;
&lt;br /&gt;
Das Problem der Übertragung eines Strings reduziert sich damit auf die Aufgabenstellung: Empfange und Sammle Zeichen in einem char Array, bis entweder das Array voll ist oder das &#039;String Ende Zeichen&#039; empfangen wurde. Danach wird der empfangene Text noch mit einem &#039;\0&#039; Zeichen abgeschlossen um einen Standard C-String daraus zu machen, mit dem dann weiter gearbeitet werden kann.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;C&amp;gt;&lt;br /&gt;
/* Zeichen empfangen */&lt;br /&gt;
uint8_t uart_getc(void)&lt;br /&gt;
{&lt;br /&gt;
    while (!(UCSRA &amp;amp; (1&amp;lt;&amp;lt;RXC)))   // warten bis Zeichen verfuegbar&lt;br /&gt;
        ;&lt;br /&gt;
    return UDR;                   // Zeichen aus UDR an Aufrufer zurueckgeben&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void uart_gets( char* Buffer, uint8_t MaxLen )&lt;br /&gt;
{&lt;br /&gt;
  uint8_t NextChar;&lt;br /&gt;
  uint8_t StringLen = 0;&lt;br /&gt;
&lt;br /&gt;
  NextChar = uart_getc();         // Warte auf und empfange das nächste Zeichen&lt;br /&gt;
&lt;br /&gt;
                                  // Sammle solange Zeichen, bis:&lt;br /&gt;
                                  // * entweder das String Ende Zeichen kam&lt;br /&gt;
                                  // * oder das aufnehmende Array voll ist&lt;br /&gt;
  while( NextChar != &#039;\n&#039; &amp;amp;&amp;amp; StringLen &amp;lt; MaxLen - 1 ) {&lt;br /&gt;
    *Buffer++ = NextChar;&lt;br /&gt;
    StringLen++;&lt;br /&gt;
    NextChar = uart_getc();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
                                  // Noch ein &#039;\0&#039; anhängen um einen Standard&lt;br /&gt;
                                  // C-String daraus zu machen&lt;br /&gt;
  *Buffer = &#039;\0&#039;;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/C&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Beim Aufruf ist darauf zu achten, dass das empfangende Array auch mit einer&lt;br /&gt;
vernünftigen Größe definiert wird.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;C&amp;gt;&lt;br /&gt;
  char Line[40];      // String mit maximal 39 zeichen&lt;br /&gt;
&lt;br /&gt;
  uart_gets( Line, sizeof( Line ) );&lt;br /&gt;
&amp;lt;/C&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bei der Benutzung von sizeof() ist allerdings zu beachten, dass sizeof() nicht die Anzahl der Elemente des Arrays liefert, sondern die Länge in Byte. Da ein char nur ein Byte lang ist, passt der Aufruf &#039;uart_gets(Line, sizeof( Line ) );&#039; in diesem Fall. Falls man - aus welchen Gründen auch immer - andere Datentypen benutzen möchte, sollte man zur korrekten Angabe der Array-Länge folgende Vorgehensweise bevorzugen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;C&amp;gt;&lt;br /&gt;
  int Line[40];      // Array vom Typ int&lt;br /&gt;
&lt;br /&gt;
  uart_gets( Line, sizeof( Line ) / sizeof( Line[0] ) );&lt;br /&gt;
&amp;lt;/C&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Interruptbetrieb==&lt;br /&gt;
&lt;br /&gt;
Beim ATMEGA8 muss das RXCIE Bit im Register UCSRB gesetzt werden, damit ein Interrupt ausgelöst werden kann.&lt;br /&gt;
Der Interrupt wird immer ausgelöst, wenn Daten erfolgreich empfangen wurden.&lt;br /&gt;
&lt;br /&gt;
Zusätzlich braucht man die Routine:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
ISR (USART_RXC_vect) {&lt;br /&gt;
   //irgendein Code&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
natürlich muss &amp;quot;Global Interrupt Enable&amp;quot; Aktiviert sein.&lt;br /&gt;
!! Nur getestet beim ATMEGA8 !!&lt;br /&gt;
&lt;br /&gt;
[BAUSTELLE! Aus Lerngründen eventuell als eigenen UART-Interrupt-Block hinter den grundlegenden Interrupt-Teil im Tutorial und hier eine kurze Einführung und einen Verweis darauf anbieten.]&lt;br /&gt;
&lt;br /&gt;
* Unterschied Polling-Betrieb (bisher, oben) und Interrupt-Betrieb&lt;br /&gt;
* Empfangen (Receive)&lt;br /&gt;
** Verändertes UART-Init, ISR (RXC), ggf. Fallstricke ([http://www.mikrocontroller.net/topic/84256#707214 UDR in der ISR lesen!]), Philosophie einer ISR (kurz und schmerzlos), Datenaustausch ISR zu Restprogramm (volatile)&lt;br /&gt;
** Einfachstbeispiel ([http://www.mikrocontroller.net/topic/84228#707052 Echo] (noch buggy beim Datenzugriff, siehe Lit. 2+3!)), ggf. LED zur ISR-Empfangsanzeige oder Overflow-Anzeige&lt;br /&gt;
* FIFO-Puffer, Ringpuffer&lt;br /&gt;
* Senden (Transmit)&lt;br /&gt;
** Variante &amp;quot;UART Data Register Empty&amp;quot; (UDRE) &lt;br /&gt;
** Variante &amp;quot;UART Transmit Complete&amp;quot; (TXC) &lt;br /&gt;
* Fertige UART-Bibliotheken (-&amp;gt;Fleury, -&amp;gt;Procyon)&lt;br /&gt;
* Literatur: &lt;br /&gt;
** 1/ [http://www.avrfreaks.net/index.php?name=PNphpBB2&amp;amp;file=viewtopic&amp;amp;t=48188 avrfreaks.net Tutorial] inkl. Diskussion (engl.)&lt;br /&gt;
** 2/ avr-libc FAQ: [http://www.nongnu.org/avr-libc/user-manual/FAQ.html#faq_16bitio Why do some 16-bit timer registers sometimes get trashed?]&lt;br /&gt;
** 3/ [[Interrupt]] und atomarer Datenzugriff&lt;br /&gt;
&lt;br /&gt;
==Software-UART==&lt;br /&gt;
&lt;br /&gt;
Falls die Zahl der vorhandenen Hardware-UARTs nicht ausreicht, können weitere Schnittstellen über sogennante Software-UARTs ergänzt werden. Es gibt dazu (mindestens) zwei Ansätze: &lt;br /&gt;
* Der bei AVRs üblichste Ansatz basiert auf dem Prinzip, dass ein externer Interrupt-Pin für den Empfang (&amp;quot;RX&amp;quot;) genutzt wird. Das Startbit löst den Interrupt aus, in der Interrupt-Routine (ISR) wird der externe Interrupt deaktiviert und ein Timer aktiviert. In der Interrupt-Routine des Timers wird der Zustand des Empfangs-Pins entsprechend der Baudrate abgetastet. Nach Empfang des Stop-Bits wird der externe Interrupt wieder aktiviert. Senden kann über einen beliebigen Pin (&amp;quot;TX&amp;quot;) erfolgen, der entsprechend der Baudrate und dem zu sendenden Zeichen auf 0 oder 1 gesetzt wird. Die Implementierung ist nicht ganz einfach, es existieren dazu aber fertige Bibliotheken (z.B. bei [http://www.avrfreaks.net/ avrfreaks] oder in der [http://hubbard.engr.scu.edu/embedded/avr/avrlib/ Procyon avrlib]).&lt;br /&gt;
* Ein weiterer Ansatz erfordert keinen Pin mit &amp;quot;Interrupt-Funktion&amp;quot; aber benötigt mehr Rechenzeit. Jeder Input-Pin kann als Empfangspin (RX) dienen. Über einen Timer wird der Zustand des RX-Pins mit einem vielfachen der Baudrate abgetastet (dreifach scheint üblich) und High- bzw. Lowbits anhand einer Mindestanzahl identifiziert. (Beispiel: &amp;quot;Generic Software Uart&amp;quot; Application-Note von IAR)&lt;br /&gt;
&lt;br /&gt;
Neuere AVRs (z.B. ATtiny26 oder ATmega48,88,168,169) verfügen über ein Universal Serial Interface (USI), das teilweise UART-Funktion übernehmen kann. Atmel stellt eine Application-Note bereit, in der die Nutzung des USI als UART erläutert wird (im Prinzip &amp;quot;Hardware-unterstützter Software-UART&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
==Handshaking==&lt;br /&gt;
Wenn der Sender ständig sendet, wird irgendwann der Fall eintreten, daß der Empfänger nicht bereit ist, neue Zeichen zu empfangen. In diesem Fall muß durch ein &#039;&#039;&#039;Handshake-Verfahren&#039;&#039;&#039; die Situation bereinigt werden. Handshake bedeutet nichts anderes, als daß der Empfänger dem Sender mitteilt, daß er zur Zeit keine Daten annehmen kann und der Sender die Übertragung der nächsten Zeichen solange einstellen soll, bis der Empfänger signalisiert, daß er wieder Zeichen aufnehmen kann.&lt;br /&gt;
===Hardwarehandshake (RTS/CTS)===&lt;br /&gt;
Beim Hardwarehandshake werden zusätzlich zu den beiden Daten-Übertragungsleitungen noch 2 weitere Leitungen benötigt: &#039;&#039;&#039;RTS&#039;&#039;&#039; (&#039;&#039;&#039;R&#039;&#039;&#039;equest &#039;&#039;&#039;T&#039;&#039;&#039;o &#039;&#039;&#039;S&#039;&#039;&#039;end) und &#039;&#039;&#039;CTS&#039;&#039;&#039; (&#039;&#039;&#039;C&#039;&#039;&#039;lear &#039;&#039;&#039;T&#039;&#039;&#039;o &#039;&#039;&#039;S&#039;&#039;&#039;end). Jeder der beiden Kommunikationspartner ist verpflichtet, bevor ein Zeichen gesendet wird, den Zustand der &#039;&#039;&#039;RTS&#039;&#039;&#039; Leitung zu überprüfen. Nur wenn die Gegenstelle darauf Empfangsbereitschaft signalisiert, darf das Zeichen gesendet werden. Um der Gegenstelle zu signalisieren, daß sie zur Zeit keine Zeichen schicken soll, wird die Leitung &#039;&#039;&#039;CTS&#039;&#039;&#039; benutzt.&lt;br /&gt;
&lt;br /&gt;
===Softwarehandshake (XON/XOFF)===&lt;br /&gt;
Beim Softwarehandshake sind keine speziellen Leitungen notwendig. Statt dessen werden besondere ASCII-Zeichen benutzt, die der Gegenstelle signalisieren, daß Senden einzustellen bzw. wieder aufzunehmen.&amp;lt;br /&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;XOFF&#039;&#039;&#039; Aufforderung das Senden einzustellen&lt;br /&gt;
* &#039;&#039;&#039;XON&#039;&#039;&#039;  Gegenstelle darf wieder senden&lt;br /&gt;
&lt;br /&gt;
Nachteilig bei einem Softwarehandshake ist es, dass dadurch keine direkte binäre Datenübertragung mehr möglich ist. Von den möglichen 256 Bytewerten werden ja 2 (nämlich &#039;&#039;&#039;XON&#039;&#039;&#039; und &#039;&#039;&#039;XOFF&#039;&#039;&#039;) für besondere Zwecke benutzt und fallen daher aus.&lt;br /&gt;
&lt;br /&gt;
==Fehlersuche==&lt;br /&gt;
Erstaunlich oft wird im Forum der Hilferuf laut: &amp;quot;Meine UART funktioniert nicht, was mache ich falsch&amp;quot;. In der überwiegenden Mehrzahl der Fälle stellt sich dann heraus, daß es sich um ein Hardwareproblem handelt, wobei da wiederrum der Löwenanteil auf das Konto einer nicht korrekt eingestellten Taktrate geht: Der µC benutzt nicht einen angeschlossenen Quarz, so wie er auch im Programm eingetragen ist, sondern läuft immer noch mit dem internen RC-Takt. Daraus resultiert aber auch, daß der Baudraten Konfigurationswert falsch berechnet wird.&lt;br /&gt;
&lt;br /&gt;
Eine Checkliste zum Aufspüren solcher Fehler findet sich [[AVR_Checkliste#UART.2FUSART|hier]].&lt;br /&gt;
&lt;br /&gt;
= Analoge Ein- und Ausgabe =&lt;br /&gt;
&lt;br /&gt;
Analoge Eingangswerte werden in der Regel über den AVR Analog-Digital-Converter (AD-Wandler, ADC) eingelesen, der in vielen Typen verfügbar ist (typisch 10bit Auflösung). Durch diesen werden analogen Signale (Spannungen) in digitale Zahlenwerte gewandelt. Bei AVRs, die über keinen internen AD-Wandler verfügen (z.B. ATmega162), kann durch externe Beschaltung (R/C-Netzwerk und &amp;quot;Zeitmessung&amp;quot;) die Funktion des AD-Wandlers &amp;quot;emuliert&amp;quot; werden.&lt;br /&gt;
&lt;br /&gt;
Es existieren keine AVRs mit eingebautem Digital-Analog-Konverter (DAC). Diese Funktion muss durch externe Komponenten nachgebildet werden (z.B. PWM und &amp;quot;Glättung&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Unabhängig davon besteht natürlich immer die Möglichkeit, spezielle Bausteine zur Analog-Digital- bzw. Digital-Analog-Wandlung zu nutzen und diese über eine digitale Schnittstelle (z.b. SPI oder I2C) mit einem AVR anzusteuern.&lt;br /&gt;
&lt;br /&gt;
== AC (Analog Comparator) ==&lt;br /&gt;
&lt;br /&gt;
Der Comparator vergleicht 2 Spannungen an den Pins AIN0 und AIN1 und gibt einen Status aus welche der beiden Spannungen größer ist. AIN0 Dient dabei als Referenzspannung (Sollwert) und AIN1 als Vergleichsspannung (Istwert). Als Referenzspannung kann auch alternativ eine interne Referenzspannung ausgewählt werden.&amp;lt;BR&amp;gt;&lt;br /&gt;
&amp;lt;BR&amp;gt;&lt;br /&gt;
Liegt die Vergleichsspannung (IST) unter der der Referenzspannung (SOLL) gibt der Comperator eine logische 1 aus. Ist die Vergleichsspannung hingegen größer als die Referenzspannung wird eine logische 0 ausgegeben.&amp;lt;BR&amp;gt;&lt;br /&gt;
&amp;lt;BR&amp;gt;&lt;br /&gt;
Der Comperator arbeitet völlig autark bzw. parallel zum Prozessor. Für mobile Anwendungen empfiehlt es sich ihn abzuschalten sofern er nicht benötigt wird, da er ansonsten Strom benötigt. Der Comparator kann Interruptgesteuert abgefragt werden oder im Pollingbetrieb.&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Steuer- bzw. Statusregister ist wie folgt aufgebaut:&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ACSR (0x28) - Analog Comparator Status Register&amp;lt;BR&amp;gt;&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Bit&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 7&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 6&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 5&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 4&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 2&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Name&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ACD&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ACBG&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ACO&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ACI&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ACIE&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ACIC&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ACIS1&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ACIS0&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;R/W&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Initialwert&#039;&#039;&#039;&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; | n/a&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;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
Bit 7 ACD - Analog Comparator Disable: 0 = Comparator ein, 1 = Comparator aus. Wird dieses Bit geändert kann ein Interrupt ausgelöst werden. Soll dies vermieden werden muß das Bit 3 ACIE ggf. abgeschaltet werden.&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
Bit 6 ACBG - Analog Comparator Bandgap Select: Ermöglicht das umschalten zwischen interner und externer Referenzspannung. 1 = interne (~1,3 Volt), 0 = externe Referenzspannung (an Pin AIN0)&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
Bit 5 ACO - Analog Comparator Output: Hier wird das Ergebnis des Vergleichs angezeigt. Es liegt typischerweise nach 1-2 Taktzyklen vor. &amp;lt;BR&amp;gt;&lt;br /&gt;
Ergebnis: &amp;lt;BR&amp;gt;IST &amp;lt; SOLL --&amp;gt; 1&amp;lt;BR&amp;gt;&lt;br /&gt;
IST &amp;gt; SOLL --&amp;gt; 0&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
Bit 4 ACI - Analog Comparator Interrupt Flag: Dieses Bit wird von der Hardware gesetzt wenn ein Interruptereignis das in Bit 0 und 1 definiert ist eintritt. Dieses Bit löst noch keinen Interrupt aus! Die Interruptroutine wird nur dann ausgeführt wenn das Bit 3 ACIE gesetzt ist und global Interrupts erlaubt sind (I-Bit in SREG=1). Das Bit 4 ACI wird wieder gelöscht wenn die Interruptroutine ausgeführt wurde oder wenn manuell das Bit auf 1 gesetzt wird. Das Bit kann für Abfragen genutzt werden, steuert oder konfuguriert aber nicht den Comparator.&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
Bit 3 ACIE - Analog Comparator Interrupt Enable: Ist das Bit auf 1 gesetzt wird immer ein Interrupt ausgelöst wenn das Ereignis das in Bit 1 und 0 definiert ist eintritt.&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
Bit 2 ACIC - Analog Comparator Input Capture Enable: Wird das Bit gesetzt wird der Comparatorausgang intern mit dem Counter 1 verbunden. Es könnten damit z.b. die Anzahl der Vergleiche im Counter1 gezählt werden. Um den Comparator an den Timer1 Input Capture Interrupt zu verbinden muß im Timerregister das TICIE1 Bit auf 1 gesetzt werden. Der Trigger wird immer dann ausgelöst wenn das in Bit 1 und 0 definierte Ereignis eintritt.&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
Bit 1,0 ACIS1,ACIS0 - Analog Comparator Interrupt select: Hier wird definiert welche Ereignisse einen Interrupt auslösen sollen:&amp;lt;BR&amp;gt;&lt;br /&gt;
00 = Interrupt auslösen bei jedem Flankenwechsel&amp;lt;BR&amp;gt;&lt;br /&gt;
10 = Interrupt auslösen bei fallender Flanke&amp;lt;BR&amp;gt;&lt;br /&gt;
11 = Interrupt auslösen bei steigender Flanke&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
Werden diese Bit geändert kann ein Interrupt ausgelöst werden. Soll dies vermieden werden muß das Bit 3 gelöscht werden.&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== ADC (Analog Digital Converter) ==&lt;br /&gt;
&lt;br /&gt;
Der Analog-Digital-Konverter (ADC) wandelt analoge Signale in digitale Werte um, welche vom Controller interpretiert werden können. Einige AVR-Typen haben bereits einen mehrkanaligen Analog-Digital-Konverter eingebaut. Die Genauigkeit, mit welcher ein analoges Signal aufgelöst werden kann, wird durch die Auflösung des ADC in Anzahl Bits angegeben, man hört bzw. liest jeweils von 8-Bit-ADC oder 10-Bit-ADC oder noch höher. ADCs die in AVRs enthalten sind haben zur Zeit eine maximale Auflösung von 10-Bit.&lt;br /&gt;
&lt;br /&gt;
Ein ADC mit 8 Bit Auflösung kann somit das analoge Signal mit einer Genauigkeit von 1/256 des Maximalwertes darstellen. Wenn wir nun mal annehmen, wir hätten eine Spannung zwischen 0 und 5 Volt und eine Auflösung von 3 Bit, dann könnten&lt;br /&gt;
die Werte 0V, 0.625V, 1.25, 1.875V, 2.5V, 3.125V, 3.75, 4.375, 5V&lt;br /&gt;
daherkommen, siehe dazu folgende Tabelle:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div align=&amp;quot;center&amp;quot;&amp;gt;&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;Eingangsspannung am ADC&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;Entsprechender Messwert&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0...&amp;lt;0.625V&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0.625...&amp;lt;1.25V&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1.25...&amp;lt;1.875V&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 2&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1.875...&amp;lt;2.5V&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 2.5...&amp;lt;3.125V&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 4&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3.125...&amp;lt;3.75V&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 5&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3.75...&amp;lt;4.375V&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 6&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 4.375...5V&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 7&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Angaben sind natürlich nur ungefähr. Je höher nun die Auflösung des Analog-Digital-Konverters ist, also je mehr Bits er hat, um so genauer kann der Wert erfasst werden.&lt;br /&gt;
&lt;br /&gt;
=== Der interne ADC im AVR ===&lt;br /&gt;
&lt;br /&gt;
Wenn es einmal etwas genauer sein soll, dann müssen wir auf einen AVR mit eingebautem Analog-Digital-Wandler (ADC) zurückgreifen, die über mehrere Kanäle verfügen. Kanäle heißt in diesem Zusammenhang, dass zwar bis zu zehn analoge Eingänge am AVR verfügbar sind, aber nur ein &amp;quot;echter&amp;quot; Analog-Digital-Wandler zur Verfügung steht, vor der eigentlichen Messung ist also einzustellen, welcher Kanal (&amp;quot;Pin&amp;quot;) mit dem Wandler verbunden und gemessen wird.&lt;br /&gt;
&lt;br /&gt;
Die Umwandlung innerhalb des AVR basiert auf der schrittweisen Näherung. Beim AVR müssen die Pins &#039;&#039;&#039;AGND&#039;&#039;&#039; und &#039;&#039;&#039;AVCC&#039;&#039;&#039; beschaltet werden. Für genaue Messungen sollte AVCC über ein L-C Netzwerk mit VCC verbunden werden, um Spannungsspitzen und -einbrüche vom Analog-Digital-Wandler fernzuhalten. Im Datenblatt findet sich dazu eine Schaltung, die 10uH und 100nF vorsieht.&lt;br /&gt;
&lt;br /&gt;
Das Ergebnis der Analog-Digital-Wandlung wird auf eine Referenzspannung bezogen. Aktuelle AVRs bieten drei Möglichkeiten zur Wahl dieser Spannung:&lt;br /&gt;
&lt;br /&gt;
* Eine externe Referenzspannung von maximal &#039;&#039;&#039;Vcc&#039;&#039;&#039; am Anschlusspin &#039;&#039;&#039;AREF&#039;&#039;&#039;. Die minimale (externe) Referenzspannung darf jedoch nicht beliebig niedrig sein, vgl. dazu das (aktuellste) Datenblatt des verwendeten Controllers. &lt;br /&gt;
&lt;br /&gt;
* Verfügt der AVR über eine interne Referenzspannung, kann diese genutzt werden. Alle aktuellen AVRs mit internem AD-Wandler sollten damit ausgestattet sein (vgl. Datenblatt: 2,56V oder 1,1V je nach Typ). Das Datenblatt gibt auch über die Genauigkeit dieser Spannung Auskunft.&lt;br /&gt;
&lt;br /&gt;
* Die &#039;&#039;&#039;interne&#039;&#039;&#039; Referenzspannung wird auf &#039;&#039;&#039;Vcc&#039;&#039;&#039; bezogen, eine externe Referenzspannung auf &#039;&#039;&#039;GND (Masse)&#039;&#039;&#039;. Davon unabhängig werden digitalisierte Spannungen &#039;&#039;&#039;immer&#039;&#039;&#039; auf GND bezogen. Beim ATMEGA8 z.B. ist der Pin AREF über 32kOhm mit GND verbunden, d.h. man muss diese doch extrem niedrige Eingangsimpedanz mit in die Berechnung für einen Spannungsteiler einbeziehen, bzw. kann diesen Widerstand als R2 gleich mit benutzen. Formel für Spannungsteiler: Udiv = U / ((R1 + R2) / R2)&lt;br /&gt;
&lt;br /&gt;
Bei Nutzung von Vcc oder der internen Referenz wird empfohlen, einen Kondensator zwischen dem AREF-Pin und GND anzuordnen. Die Festlegung, welche Spannungsreferenz genutzt wird, erfolgt z.B. beim ATmega16 mit den Bits REFS1/REFS0 im ADMUX-Register. Die zu messende Spannung muss im Bereich zwischen &#039;&#039;&#039;AGND&#039;&#039;&#039; und &#039;&#039;&#039;AREF&#039;&#039;&#039; (egal ob intern oder extern) liegen. &lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;&#039;ADC&#039;&#039;&#039; kann in zwei verschiedenen Betriebsarten verwendet werden:&lt;br /&gt;
&lt;br /&gt;
; Einfache Wandlung (Single Conversion) : In dieser Betriebsart wird der Wandler bei Bedarf vom Programm angestoßen für jeweils eine Messung.&lt;br /&gt;
&lt;br /&gt;
; Frei laufend (Free Running) : In dieser Betriebsart erfasst der Wandler permanent die anliegende Spannung und schreibt diese in das &#039;&#039;&#039;ADC Data Register&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==== Die Register des ADC ====&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;&#039;ADC&#039;&#039;&#039; verfügt über eigene Register. Im Folgenden die Registerbeschreibung eines  ATMega16, welcher über 8 ADC-Kanäle verfügt. Die Register unterscheiden sich jedoch nicht erheblich von denen anderer AVRs (vgl. Datenblatt).&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;ADCSRA&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;ADC&#039;&#039;&#039; &#039;&#039;&#039;C&#039;&#039;&#039;ontrol and &#039;&#039;&#039;S&#039;&#039;&#039;tatus &#039;&#039;&#039;R&#039;&#039;&#039;egister A.&amp;lt;br /&amp;gt;&lt;br /&gt;
In diesem Register stellen wir ein, wie wir den &#039;&#039;&#039;ADC&#039;&#039;&#039; verwenden möchten.&amp;lt;br /&amp;gt;&lt;br /&gt;
Das Register ist wie folgt aufgebaut:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Bit&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 7&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 6&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 5&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 4&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 2&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Name&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ADEN&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ADSC&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ADFR&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ADIF&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ADIE&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ADPS2&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ADPS1&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ADPS0&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;R/W&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Initialwert&#039;&#039;&#039;&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;
| 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;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ADEN&#039;&#039;&#039; (&#039;&#039;&#039;AD&#039;&#039;&#039;C &#039;&#039;&#039;En&#039;&#039;&#039;able)&lt;br /&gt;
:Dieses Bit muss gesetzt werden, um den &#039;&#039;&#039; ADC&#039;&#039;&#039; überhaupt zu aktivieren. Wenn das Bit nicht gesetzt ist, können die Pins wie normale I/O-Pins verwendet werden.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ADSC&#039;&#039;&#039; (&#039;&#039;&#039;AD&#039;&#039;&#039;C &#039;&#039;&#039;S&#039;&#039;&#039;tart &#039;&#039;&#039;C&#039;&#039;&#039;onversion)&lt;br /&gt;
:Mit diesem Bit wird ein Messvorgang gestartet. In der frei laufenden Betriebsart muss das Bit gesetzt werden, um die kontinuierliche Messung zu aktivieren.&lt;br /&gt;
:Wenn das Bit nach dem Setzen des &#039;&#039;&#039;ADEN&#039;&#039;&#039;-Bits zum ersten Mal gesetzt wird, führt der Controller zuerst eine zusätzliche Wandlung und erst dann die eigentliche Wandlung aus. Diese zusätzliche Wandlung wird zu Initialisierungszwecken durchgeführt.&lt;br /&gt;
:Das Bit bleibt nun so lange auf 1, bis die Umwandlung abgeschlossen ist, im Initialisierungsfall entsprechend bis die zweite Umwandlung erfolgt ist und geht danach auf 0.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ADFR&#039;&#039;&#039; (&#039;&#039;&#039;AD&#039;&#039;&#039;C &#039;&#039;&#039;F&#039;&#039;&#039;ree &#039;&#039;&#039;R&#039;&#039;&#039;un select)&lt;br /&gt;
:Mit diesem Bit wird die Betriebsart eingestellt.&lt;br /&gt;
:Ist das Bit auf 1 gesetzt arbeitet der ADC im Freerunning Modus. Dabei wird das Datenregister permanent aktualisiert. Ist das Bit hingegen auf 0 gesetzt macht der ADC nur eine Single Conversion. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ADIF&#039;&#039;&#039; (&#039;&#039;&#039;AD&#039;&#039;&#039;C &#039;&#039;&#039;I&#039;&#039;&#039;nterrupt &#039;&#039;&#039;F&#039;&#039;&#039;lag)&lt;br /&gt;
:Dieses Bit wird vom &#039;&#039;&#039; ADC&#039;&#039;&#039; gesetzt, sobald eine Umwandlung erfolgt ist und das &#039;&#039;&#039;ADC Data Register&#039;&#039;&#039; aktualisiert wurde. Das Bit wird bei lesendem Zugriff auf &#039;&#039;&#039;ADC(L,H)&#039;&#039;&#039; automatisch (d.h. durch die Hardware) gelöscht.&lt;br /&gt;
:Wenn das &#039;&#039;&#039;ADIE&#039;&#039;&#039; Bit sowie das &#039;&#039;&#039;I-Bit&#039;&#039;&#039; im AVR &#039;&#039;&#039;Statusregister&#039;&#039;&#039; gesetzt ist, wird der &#039;&#039;&#039;ADC Interrupt&#039;&#039;&#039; ausgelöst und die Interrupt-Behandlungsroutine aufgerufen.&lt;br /&gt;
:Das Bit wird automatisch gelöscht, wenn die Interrupt-Behandlungsroutine aufgerufen wird. Es kann jedoch auch gelöscht werden, indem eine logische 1 in das Register geschrieben wird.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ADIE&#039;&#039;&#039; (&#039;&#039;&#039;AD&#039;&#039;&#039;C &#039;&#039;&#039;I&#039;&#039;&#039;nterrupt &#039;&#039;&#039;E&#039;&#039;&#039;nable)&lt;br /&gt;
:Wenn dieses Bit gesetzt ist und ebenso das &#039;&#039;&#039; I-Bit&#039;&#039;&#039; im Statusregister &#039;&#039;&#039;SREG&#039;&#039;&#039;, dann wird der &#039;&#039;&#039; ADC-Interrupt&#039;&#039;&#039; aktiviert.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ADPS2...ADPS0&#039;&#039;&#039; (&#039;&#039;&#039;AD&#039;&#039;&#039;C &#039;&#039;&#039;P&#039;&#039;&#039;rescaler &#039;&#039;&#039;S&#039;&#039;&#039;elect Bits)&lt;br /&gt;
:Diese Bits bestimmen den Teilungsfaktor zwischen der Taktfrequenz und dem Eingangstakt des &#039;&#039;&#039;ADC&#039;&#039;&#039;.&lt;br /&gt;
:Der &#039;&#039;&#039;ADC&#039;&#039;&#039; benötigt einen eigenen Takt, welchen er sich selber aus der CPU-Taktfreqenz erzeugt. Der &#039;&#039;&#039;ADC&#039;&#039;&#039;-Takt sollte zwischen 50 und 200kHz sein.&lt;br /&gt;
:Der Vorteiler muss also so eingestellt werden, dass die CPU-Taktfrequenz dividiert durch den Teilungsfaktor einen Wert zwischen 50-200kHz ergibt.&lt;br /&gt;
:Bei einer CPU-Taktfrequenz von 4MHz beispielsweise rechnen wir&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;&lt;br /&gt;
\begin{matrix}&lt;br /&gt;
TF_{min}=\frac{CLK}{200\,\mathrm{kHz}}=\frac{4000000}{200000}=\mathbf{20}&lt;br /&gt;
\\&lt;br /&gt;
\\&lt;br /&gt;
TF_{max}=\frac{CLK}{50\,\mathrm{kHz}}=\frac{4000000}{50000}=\mathbf{80}&lt;br /&gt;
\end{matrix}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Somit kann hier der Teilungsfaktor 32 oder 64 verwendet werden. Im Interesse der schnelleren Wandlungszeit werden wir hier den Faktor 32 einstellen.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&lt;br /&gt;
{| style=&amp;quot;&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ADPS2&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ADPS1&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ADPS0&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;Teilungsfaktor&#039;&#039;&#039;&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;
| align=&amp;quot;center&amp;quot; | 2&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;
| align=&amp;quot;center&amp;quot; | 2&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;
| align=&amp;quot;center&amp;quot; | 4&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;
| align=&amp;quot;center&amp;quot; | 8&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;
| align=&amp;quot;center&amp;quot; | 16&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;
| align=&amp;quot;center&amp;quot; | 32&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;
| align=&amp;quot;center&amp;quot; | 64&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;
| align=&amp;quot;center&amp;quot; | 128&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;ADCL&#039;&#039;&#039;&amp;lt;br /&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;ADCH&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;ADC &#039;&#039;&#039; Data Register&amp;lt;br /&amp;gt;&lt;br /&gt;
Wenn eine Umwandlung abgeschlossen ist, befindet sich der gemessene Wert in&lt;br /&gt;
diesen beiden Registern. Von &#039;&#039;&#039;ADCH&#039;&#039;&#039; werden nur die beiden niederwertigsten Bits verwendet. Es müssen immer beide Register ausgelesen werden, und zwar immer &#039;&#039;&#039;in der Reihenfolge: ADCL, ADCH&#039;&#039;&#039;. &lt;br /&gt;
Der effektive Messwert ergibt sich dann zu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
x = ADCL;       // mit uint16_t x&lt;br /&gt;
x += (ADCH&amp;lt;&amp;lt;8); // in zwei Zeilen (LSB/MSB-Reihenfolge und&lt;br /&gt;
                // C-Operatorpriorität sichergestellt)&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
oder &lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
x = ADCW; // je nach AVR auch x = ADC (siehe avr/ioxxx.h)&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;ADMUX&amp;amp;nbsp;&amp;amp;nbsp;&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;AD&#039;&#039;&#039;C &#039;&#039;&#039;Mu&#039;&#039;&#039;ltiple&#039;&#039;&#039;x&#039;&#039;&#039;er Select Register&amp;lt;br /&amp;gt;&lt;br /&gt;
Mit diesem Register wird der zu messende Kanal ausgewählt. Beim 90S8535&lt;br /&gt;
kann jeder Pin von Port A als &#039;&#039;&#039;ADC&#039;&#039;&#039;-Eingang verwendet werden (=8 Kanäle).&amp;lt;br /&amp;gt;&lt;br /&gt;
Das Register ist wie folgt aufgebaut:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Bit&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 7&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 6&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 5&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 4&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 2&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Name&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;REFS1&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;REFS0&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ADLAR&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;MUX4&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;MUX3&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;MUX2&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;MUX1&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;MUX0&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;R/W&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Initialwert&#039;&#039;&#039;&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;
| 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;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;REFS1...REFS0&#039;&#039;&#039; (&#039;&#039;&#039;Ref&#039;&#039;&#039;erence&#039;&#039;&#039;S&#039;&#039;&#039;election Bits)&lt;br /&gt;
:Mit diesen Bits kann die Referenzspannung eingestellt werden:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&lt;br /&gt;
{| style=&amp;quot;&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;REFS1&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;REFS0&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;Referenzspanung&#039;&#039;&#039;&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; | Externes AREF&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; | AVCC als Referenz&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; | Reserviert&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; | Interne 2,56 Volt&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ADLAR&#039;&#039;&#039; (&#039;&#039;&#039;ADC &#039;&#039;&#039; &#039;&#039;&#039;L&#039;&#039;&#039;eft &#039;&#039;&#039;A&#039;&#039;&#039;djust &#039;&#039;&#039;R&#039;&#039;&#039;esult)&lt;br /&gt;
:Das ADLAR Bit verändert das Aussehen des Ergebnisses der AD-Wandlung. Bei einer logischen 1 wird das Ergebnis linksbündig ausgegeben, bei einer 0 rechtsündig. Eine Änderung in diesem Bit beeinflusst das Ergebnis sofort, ganz egal ob bereits eine Wandlung läuft.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;MUX4...MUX0&#039;&#039;&#039;&lt;br /&gt;
:Mit diesen 5 Bits wird der zu messende Kanal bestimmt. Wenn man einen einfachen 1-kanaligen ADC verwendet wird einfach die entsprechende Pinnummer des Ports in die Bits 0...2 eingeschrieben.&lt;br /&gt;
:Wenn das Register beschrieben wird, während dem eine Umwandlung läuft, so wird zuerst die aktuelle Umwandlung auf dem bisherigen Kanal beendet. Dies ist vor allem beim frei laufenden Betrieb zu berücksichtigen.&lt;br /&gt;
&lt;br /&gt;
:Eine Empfehlung ist deswegen diese, dass der frei laufende Betrieb nur bei einem einzelnen zu verwendenden Analogeingang verwendet werden sollte, wenn man sich Probleme bei der Umschalterei ersparen will.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Aktivieren des ADC ====&lt;br /&gt;
&lt;br /&gt;
Um den &#039;&#039;&#039; ADC&#039;&#039;&#039; zu aktivieren, müssen wir das &#039;&#039;&#039;ADEN&#039;&#039;&#039;-Bit im &#039;&#039;&#039;ADCSR&#039;&#039;&#039;-Register&lt;br /&gt;
setzen. Im gleichen Schritt legen wir auch gleich die Betriebsart fest. &lt;br /&gt;
&lt;br /&gt;
Ein kleines Beispiel für den &amp;quot;single conversion&amp;quot;-Mode bei einem ATmega169 und Nutzung der internen Referenzspannung (beim &#039;169 1,1V bei anderen AVRs auch 2,56V). D.h. das Eingangssignal darf diese Spannung nicht überschreiten, gegebenenfalls mit Spannungsteiler einstellen. Ergebnis der Routine ist der ADC-Wert, also 0 für 0-Volt und 1023 für V_ref-Volt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
uint16_t ReadChannel(uint8_t mux)&lt;br /&gt;
{&lt;br /&gt;
  uint8_t i;&lt;br /&gt;
  uint16_t result;&lt;br /&gt;
&lt;br /&gt;
  ADMUX = mux;                      // Kanal waehlen&lt;br /&gt;
  ADMUX |= (1&amp;lt;&amp;lt;REFS1) | (1&amp;lt;&amp;lt;REFS0); // interne Referenzspannung nutzen&lt;br /&gt;
&lt;br /&gt;
  ADCSRA = (1&amp;lt;&amp;lt;ADEN) | (1&amp;lt;&amp;lt;ADPS1) | (1&amp;lt;&amp;lt;ADPS0);    // Frequenzvorteiler &lt;br /&gt;
                               // setzen auf 8 (1) und ADC aktivieren (1)&lt;br /&gt;
&lt;br /&gt;
  /* nach Aktivieren des ADC wird ein &amp;quot;Dummy-Readout&amp;quot; empfohlen, man liest&lt;br /&gt;
     also einen Wert und verwirft diesen, um den ADC &amp;quot;warmlaufen zu lassen&amp;quot; */&lt;br /&gt;
  ADCSRA |= (1&amp;lt;&amp;lt;ADSC);              // eine ADC-Wandlung &lt;br /&gt;
  while ( ADCSRA &amp;amp; (1&amp;lt;&amp;lt;ADSC) ) {&lt;br /&gt;
     ;     // auf Abschluss der Konvertierung warten &lt;br /&gt;
  }&lt;br /&gt;
  result = ADCW;  // ADCW muss einmal gelesen werden,&lt;br /&gt;
                  // sonst wird Ergebnis der nächsten Wandlung&lt;br /&gt;
                  // nicht übernommen.&lt;br /&gt;
&lt;br /&gt;
  /* Eigentliche Messung - Mittelwert aus 4 aufeinanderfolgenden Wandlungen */&lt;br /&gt;
  result = 0; &lt;br /&gt;
  for( i=0; i&amp;lt;4; i++ )&lt;br /&gt;
  {&lt;br /&gt;
    ADCSRA |= (1&amp;lt;&amp;lt;ADSC);            // eine Wandlung &amp;quot;single conversion&amp;quot;&lt;br /&gt;
    while ( ADCSRA &amp;amp; (1&amp;lt;&amp;lt;ADSC) ) {&lt;br /&gt;
      ;   // auf Abschluss der Konvertierung warten&lt;br /&gt;
    }&lt;br /&gt;
    result += ADCW;		    // Wandlungsergebnisse aufaddieren&lt;br /&gt;
  }&lt;br /&gt;
  ADCSRA &amp;amp;= ~(1&amp;lt;&amp;lt;ADEN);             // ADC deaktivieren (2)&lt;br /&gt;
&lt;br /&gt;
  result /= 4;                     // Summe durch vier teilen = arithm. Mittelwert&lt;br /&gt;
&lt;br /&gt;
  return result;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
/* Beispielaufrufe: */&lt;br /&gt;
&lt;br /&gt;
void foo(void)&lt;br /&gt;
{&lt;br /&gt;
  uint16_t adcval;&lt;br /&gt;
&lt;br /&gt;
  adcval = ReadChannel(0); /* MUX-Bits auf 0b0000 -&amp;gt; Channel 0 */&lt;br /&gt;
  ...&lt;br /&gt;
  adcval = ReadChannel(2); /* MUX-Bits auf 0b0010 -&amp;gt; Channel 2 */&lt;br /&gt;
  ...&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im Beispiel wird bei jedem Aufruf der ADC aktiviert und nach der Wandlung wieder abgeschaltet, das spart Strom. Will man dies nicht, verschiebt man die mit (1) gekennzeichneten Zeilen in eine Funktion adc_init() o.ä. und löscht die mit (2) markierten Zeilen. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- &lt;br /&gt;
Das Löschen des ADIF-Flags sollte, &#039;&#039;&#039;entgegen&#039;&#039;&#039; der [http://www.nongnu.org/avr-libc/user-manual/FAQ.html#faq_intbits FAQ], mit&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  ADCSRA |= (1&amp;lt;&amp;lt;ADIF);&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
erfolgen. Die Methode in der FAQ eignet sich nur für Register in denen &#039;&#039;&#039;nur&#039;&#039;&#039; Interrupt-Flags stehen.&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Analog-Digital-Wandlung ohne internen ADC ===&lt;br /&gt;
&lt;br /&gt;
==== Messen eines Widerstandes ====&lt;br /&gt;
&lt;br /&gt;
Analoge Werte lassen sich ohne Analog-Digital-Wandler auch indirekt ermitteln. Im Folgenden wird die Messung des an einem Potentiometer eingestellten Widerstands anhand der Ladekurve eines Kondensators erläutert. Bei dieser Methode wird nur ein Portpin benötigt, ein Analog-Digital-Wandler oder Analog-Comparator ist nicht erforderlich. Es wird dazu ein Kondensator und der Widerstand (das Potentiometer) in Reihe zwischen Vorsorgungsspannung und Masse/GND geschaltet (sogen. RC-Netzwerk). Zusätzlich wird eine Verbindung der Leitung zwischen Kondensator und Potentiometer zu einem Portpin des Controllers hergestellt. Die folgende Abbildung verdeutlicht die erforderliche Schaltung. &lt;br /&gt;
&lt;br /&gt;
[[Image:Poti.gif]]&lt;br /&gt;
&lt;br /&gt;
Wird der Portpin des Controllers auf Ausgang konfiguriert (im Beispiel &#039;&#039;DDRD&amp;amp;nbsp;|=&amp;amp;nbsp;(1&amp;lt;&amp;lt;PD2)&#039;&#039;) und dieser Ausgang auf Logisch 1 (&amp;quot;High&amp;quot;, &#039;&#039;PORTD&amp;amp;nbsp;|=&amp;amp;nbsp;(1&amp;lt;&amp;lt;PD2)&#039;&#039;) geschaltet, liegt an beiden &amp;quot;Platten&amp;quot; des Kondensators das gleiche Potential &#039;&#039;&#039;VCC&#039;&#039;&#039; an und der Kondensator somit entladen. (Klingt komisch, mit &#039;&#039;&#039; Vcc&#039;&#039;&#039; entladen, ist aber so, da an beiden Seiten des Kondensators das gleiche Potential anliegt und somit eine Potentialdifferenz von 0V besteht =&amp;gt; Kondensator ist entladen).&lt;br /&gt;
&lt;br /&gt;
Nach einer gewissen Zeit ist der Kondensator entladen und der Portpin wird als Eingang konfiguriert (&#039;&#039;DDRD&amp;amp;nbsp;&amp;amp;=&amp;amp;nbsp;~(1&amp;lt;&amp;lt;PD2); PORTD&amp;amp;nbsp;&amp;amp;=&amp;amp;nbsp;~(1&amp;lt;&amp;lt;PD2)&#039;&#039;), wodurch dieser hochohmig wird. Der Status des Eingangspin (in PIND) ist Logisch 1 (High). Der Kondensator lädt sich jetzt über das Poti auf, dabei steigt der Spannungsabfall über dem Kondensator und derjenige über dem Poti sinkt. Fällt nun der Spannungsabfall über dem Poti unter die Thresholdspannung des Eingangspins (2/5 Vcc, also ca. 2V), wird das Eingangssignal als LOW erkannt (Bit in PIND wird 0). Die Zeitspanne zwischen der Umschaltung von Entladung auf Aufladung und dem Wechsel des Eingangssignals von High auf Low ist ein Maß für den am Potentiometer eingestellten Widerstand. Zur Zeitmessung kann einer der im Controller vorhandenen Timer genutzt werden. Der 220 Ohm Widerstand dient dem Schutz des Controllers. Es würde sonst bei Maximaleinstellung des Potentionmeters (hier 0 Ohm) ein zu hoher Strom fließen, der die Ausgangsstufe des Controllers zerstört. &lt;br /&gt;
&lt;br /&gt;
Mit einem weiteren Eingangspin und ein wenig Software können wir auch eine Kalibrierung realisieren, um den Messwert in einen vernünftigen Bereich (z.B: 0...100 % oder so) umzurechnen. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- Link 404 =&amp;gt; auskommentiert, mthomas 9.2.2008 &lt;br /&gt;
Ein Beispielprogramm findet sich auf [http://www.mypage.bluewin.ch/ch_schifferle/ Christian Schifferles Web-Seite] im Archiv &#039;&#039;ATMEL.ZIP&#039;&#039;, welches unter den Titel &#039;&#039;Tutorial &amp;quot;Programmieren mit C für Atmel Mikrocontroller&#039;&#039; heruntergeladen werden kann. --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== ADC über Komparator ====&lt;br /&gt;
&lt;br /&gt;
Es gibt einen weiteren Weg, eine analoge Spannung mit Hilfe des&lt;br /&gt;
Komparators, welcher in fast jedem AVR integriert ist, zu messen. Siehe dazu&lt;br /&gt;
auch die Application Note AVR400 von Atmel.&lt;br /&gt;
&lt;br /&gt;
Dabei wird das zu messende Signal auf den invertierenden Eingang&lt;br /&gt;
des Komparators geführt. Zusätzlich wird ein Referenzsignal an den nicht&lt;br /&gt;
invertierenden Eingang des Komparators angeschlossen. Das Referenzsignal wird&lt;br /&gt;
hier auch wieder über ein RC-Glied erzeugt, allerdings mit festen Werten für R&lt;br /&gt;
und C.&lt;br /&gt;
&lt;br /&gt;
[[Image:ADC ueber Komparator.gif]]&lt;br /&gt;
&lt;br /&gt;
Das Prinzip der Messung ist nun dem vorhergehenden recht&lt;br /&gt;
ähnlich. Durch Anlegen eines LOW-Pegels an Pin 2 wird der Kondensator zuerst&lt;br /&gt;
einmal entladen. Auch hier muss darauf geachtet werden, dass der Entladevorgang&lt;br /&gt;
genügend lang dauert.&amp;lt;br /&amp;gt;&lt;br /&gt;
Nun wird Pin 2 auf HIGH gelegt. Der Kondensator wird geladen. Wenn die Spannung&lt;br /&gt;
über dem Kondensator die am Eingangspin anliegende Spannung erreicht hat&lt;br /&gt;
schaltet der Komparator durch. Die Zeit, welche benötigt wird, um den&lt;br /&gt;
Kondensator zu laden kann nun auch wieder als Maß für die Spannung an Pin 1&lt;br /&gt;
herangezogen werden.&lt;br /&gt;
&lt;br /&gt;
Ich habe es mir gespart, diese Schaltung auch aufzubauen und&lt;br /&gt;
zwar aus mehreren Gründen:&lt;br /&gt;
&lt;br /&gt;
# 3 Pins notwendig.&lt;br /&gt;
# Genauigkeit vergleichbar mit einfacherer Lösung.&lt;br /&gt;
# War einfach zu faul.&lt;br /&gt;
&lt;br /&gt;
Der Vorteil dieser Schaltung liegt allerdings darin, dass damit&lt;br /&gt;
direkt Spannungen gemessen werden können.&lt;br /&gt;
&lt;br /&gt;
== DAC (Digital Analog Converter) ==&lt;br /&gt;
&lt;br /&gt;
Mit Hilfe eines Digital-Analog-Konverters (&#039;&#039;&#039;DAC&#039;&#039;&#039;) können wir nun auch Analogsignale ausgeben. Es gibt hier mehrere Verfahren. &amp;lt;!-- Wenn wir beim ADC die Möglichkeit haben, mit externen Komponenten zu operieren, müssen wir bei der DAC-Wandlung mit dem auskommen, was der Controller selber zu bieten hat. --mt: hmm, richtig? verstaendlich? redundant? --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== DAC über mehrere digitale Ausgänge ===&lt;br /&gt;
&lt;br /&gt;
Wenn wir an den Ausgängen des Controllers ein entsprechendes&lt;br /&gt;
Widerstandsnetzwerk aufbauen haben wir die Möglichkeit, durch die Ansteuerung&lt;br /&gt;
der Ausgänge über den Widerständen einen Addierer aufzubauen, mit dessen&lt;br /&gt;
Hilfe wir eine dem Zahlenwert proportionale Spannung erzeugen können. Das&lt;br /&gt;
Schaltbild dazu kann etwa so aussehen:&lt;br /&gt;
&lt;br /&gt;
[[Image:DAC R2R.gif]]&lt;br /&gt;
&lt;br /&gt;
Es sollten selbstverständlich möglichst genaue Widerstände verwendet&lt;br /&gt;
werden, also nicht unbedingt solche mit einer Toleranz von 10% oder mehr.&lt;br /&gt;
Weiterhin empfiehlt es sich, je nach Anwendung den Ausgangsstrom über einen&lt;br /&gt;
Operationsverstärker zu verstärken.&lt;br /&gt;
&lt;br /&gt;
=== PWM (Pulsweitenmodulation) ===&lt;br /&gt;
&lt;br /&gt;
Wir kommen nun zu einem Thema, welches in aller Munde ist, aber viele&lt;br /&gt;
Anwender verstehen nicht ganz, wie &#039;&#039;&#039;[[PWM]]&#039;&#039;&#039; eigentlich funktioniert.&lt;br /&gt;
&lt;br /&gt;
Wie wir alle wissen, ist ein Mikrocontroller ein rein digitales Bauteil.&lt;br /&gt;
Definieren wir einen Pin als Ausgang, dann können wir diesen Ausgang entweder&lt;br /&gt;
auf HIGH setzen, worauf am Ausgang die Versorgungsspannung &#039;&#039;&#039; Vcc&#039;&#039;&#039; anliegt, oder aber wir setzen den Ausgang auf LOW, wonach dann &#039;&#039;&#039; 0V&#039;&#039;&#039; am Ausgang liegt. Was passiert aber nun, wenn wir periodisch mit einer festen Frequenz zwischen HIGH und LOW umschalten? - Richtig, wir erhalten eine Rechteckspannung, wie die folgende Abbildung zeigt:&lt;br /&gt;
&lt;br /&gt;
[[Image:PWM Theorie 1.gif]]&lt;br /&gt;
&lt;br /&gt;
Diese Rechteckspannung hat nun einen arithmetischen Mittelwert, &lt;br /&gt;
der je nach Pulsbreite kleiner oder größer ist.&lt;br /&gt;
&lt;br /&gt;
[[Image:PWM Theorie 2.gif]]&lt;br /&gt;
&lt;br /&gt;
Wenn wir nun diese pulsierende Ausgangsspannung noch über ein RC-Glied filtern/&amp;quot;glätten&amp;quot;, dann haben wir schon eine entsprechende Gleichspannung erzeugt.&lt;br /&gt;
&lt;br /&gt;
Mit den AVRs können wir direkt &#039;&#039;&#039;PWM&#039;&#039;&#039;-Signale erzeugen. &lt;br /&gt;
Dazu dient der 16-Bit Zähler, welcher im sogenannten &#039;&#039;&#039;PWM&#039;&#039;&#039;-Modus betrieben werden kann.&lt;br /&gt;
&lt;br /&gt;
Hinweis:&lt;br /&gt;
:In den folgenden Überlegungen wird als Controller der 90S2313 vorausgesetzt. Die Theorie ist bei anderen AVR-Controllern vergleichbar, die Pinbelegung allerdings nicht unbedingt, weshalb ein Blick ins entsprechende Datenblatt dringend angeraten wird.&lt;br /&gt;
&lt;br /&gt;
Um den &#039;&#039;&#039;PWM&#039;&#039;&#039;-Modus zu aktivieren, müssen im Timer/Counter1 Control&lt;br /&gt;
Register A &#039;&#039;&#039;TCCR1A&#039;&#039;&#039; die Pulsweiten-Modulatorbits &#039;&#039;&#039;PWM10&#039;&#039;&#039; bzw. &#039;&#039;&#039;PWM11&#039;&#039;&#039; entsprechend nachfolgender Tabelle gesetzt werden:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;PWM11&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;PWM10&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Bedeutung&#039;&#039;&#039;&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;
| PWM-Modus des Timers ist nicht aktiv.&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;
| 8-Bit PWM.&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;
| 9-Bit PWM.&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;
| 10-Bit PWM.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Der Timer/Counter zählt nun permanent von 0 bis zur Obergrenze&lt;br /&gt;
und wieder zurück, er wird also als sogenannter Auf-/Ab Zähler betrieben. &lt;br /&gt;
Die Obergrenze hängt davon ab, ob wir mit 8, 9 oder 10-Bit PWM arbeiten wollen:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;Auflösung&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;Obergrenze&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Frequenz&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 8&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 255&lt;br /&gt;
| f&amp;lt;sub&amp;gt;TC1&amp;lt;/sub&amp;gt; / 510&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 9&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 511&lt;br /&gt;
| f&amp;lt;sub&amp;gt;TC1&amp;lt;/sub&amp;gt; / 1022&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 10&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1023&lt;br /&gt;
| f&amp;lt;sub&amp;gt;TC1&amp;lt;/sub&amp;gt; / 2046&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Zusätzlich muss mit den Bits &#039;&#039;&#039;COM1A1&#039;&#039;&#039; und &#039;&#039;&#039;COM1A0&#039;&#039;&#039; desselben&lt;br /&gt;
Registers die gewünschte Ausgabeart des Signals definiert werden:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;COM1A1&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;COM1A0&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Bedeutung&#039;&#039;&#039;&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;
| Keine Wirkung, Pin wird nicht geschaltet.&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;
| Keine Wirkung, Pin wird nicht geschaltet.&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;
| Nicht invertierende PWM.&amp;lt;br /&amp;gt;&lt;br /&gt;
Der Ausgangspin wird gelöscht beim Hochzählen und gesetzt beim&lt;br /&gt;
Herunterzählen.&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;
| Invertierende PWM.&amp;lt;br /&amp;gt;&lt;br /&gt;
Der Ausgangspin wird gelöscht beim Herunterzählen und gesetzt beim&lt;br /&gt;
Hochzählen.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Der entsprechende Befehl, um beispielsweise den Timer/Counter als&lt;br /&gt;
nicht invertierenden 10-Bit PWM zu verwenden, heißt dann:&lt;br /&gt;
&lt;br /&gt;
alte Schreibweise (PWMxx wird nicht mehr akzeptiert)&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
TCCR1A = (1&amp;lt;&amp;lt;PWM11)|(1&amp;lt;&amp;lt;PWM10)|(1&amp;lt;&amp;lt;COM1A1);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
neue Schreibweise&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
TCCR1A = (1&amp;lt;&amp;lt;WGM11)|(1&amp;lt;&amp;lt;WGM10)|(1&amp;lt;&amp;lt;COM1A1);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Damit der Timer/Counter überhaupt läuft, müssen wir im Control&lt;br /&gt;
Register B &#039;&#039;&#039;TCCR1B&#039;&#039;&#039; noch den gewünschten Takt (Vorteiler) einstellen und&lt;br /&gt;
somit auch die Frequenz des &#039;&#039;&#039;PWM&#039;&#039;&#039;-Signals bestimmen.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;CS12&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;CS11&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;CS10&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Bedeutung&#039;&#039;&#039;&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;
| Stop. Der Timer/Counter wird gestoppt.&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;
| CK&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;
| CK / 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;
| CK / 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;
| CK / 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;
| CK / 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;
| Externer Pin 1, negative 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;
| Externer Pin 1, positive Flanke&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Also um einen Takt von CK / 1024 zu generieren, verwenden wir&lt;br /&gt;
folgenden Befehl:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
TCCR1B = (1&amp;lt;&amp;lt;CS12) | (1&amp;lt;&amp;lt;CS10);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jetzt muss nur noch der Vergleichswert festgelegt werden. Diesen&lt;br /&gt;
schreiben wir in das 16-Bit Timer/Counter Output Compare Register &#039;&#039;&#039;OCR1A&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
OCR1A = xxx;&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die folgende Grafik soll den Zusammenhang zwischen dem Vergleichswert und dem generierten &#039;&#039;&#039;PWM&#039;&#039;&#039;-Signal aufzeigen.&lt;br /&gt;
&lt;br /&gt;
[[Image:PWM Theorie 3.gif]]&lt;br /&gt;
&lt;br /&gt;
[[Image:PWM Theorie 4.gif]]&lt;br /&gt;
&lt;br /&gt;
Ach ja, fast hätte ich&#039;s vergessen. Das generierte &#039;&#039;&#039;PWM&#039;&#039;&#039;-Signal&lt;br /&gt;
wird am Output Compare Pin &#039;&#039;&#039;OC1&#039;&#039;&#039; des Timers ausgegeben und leider können wir&lt;br /&gt;
deshalb auch beim AT90S2313 nur ein einzelnes &#039;&#039;&#039;PWM&#039;&#039;&#039;-Signal mit dieser Methode generieren. Andere AVR-Typen verfügen über bis zu vier PWM-Ausgänge. Zu beachten ist außerdem, das wenn der OC Pin aktiviert ist, er nichtmehr wie üblich funktioniert und z.B. nicht einfach über PINx ausgelesen werden kann.&lt;br /&gt;
&lt;br /&gt;
Ein Programm, welches an einem ATMega8 den Fast-PWM Modus verwendet, den Modus 14, könnte so aussehen&lt;br /&gt;
&amp;lt;C&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
int main()&lt;br /&gt;
{&lt;br /&gt;
  // OC1A auf Ausgang&lt;br /&gt;
  DDRB = (1 &amp;lt;&amp;lt; PB1 );&lt;br /&gt;
&lt;br /&gt;
  //&lt;br /&gt;
  // Timer 1 einstellen&lt;br /&gt;
  //  &lt;br /&gt;
  // Modus 14:&lt;br /&gt;
  //    Fast PWM, Top von ICR1&lt;br /&gt;
  //&lt;br /&gt;
  //     WGM13    WGM12   WGM11    WGM10&lt;br /&gt;
  //      1        1       1        0&lt;br /&gt;
  //&lt;br /&gt;
  //    Timer Vorteiler: 1&lt;br /&gt;
  //     CS12     CS11    CS10&lt;br /&gt;
  //       0        0       1&lt;br /&gt;
  //&lt;br /&gt;
  //  Steuerung des Ausgangsport: Set at BOTTOM, Clear at match&lt;br /&gt;
  //     COM1A1   COM1A0&lt;br /&gt;
  //       1        0&lt;br /&gt;
 &lt;br /&gt;
  TCCR1A = (1&amp;lt;&amp;lt;COM1A1) | (1&amp;lt;&amp;lt;WGM11);&lt;br /&gt;
  TCCR1B = (1&amp;lt;&amp;lt;WGM13) | (1&amp;lt;&amp;lt;WGM12) | (1&amp;lt;&amp;lt;CS10);&lt;br /&gt;
 &lt;br /&gt;
  //&lt;br /&gt;
  //  den Endwert (TOP) für den Zähler setzen&lt;br /&gt;
  //  der Zähler zählt bis zu diesem Wert&lt;br /&gt;
&lt;br /&gt;
  ICR1 = 0x6FFF;&lt;br /&gt;
 &lt;br /&gt;
  //&lt;br /&gt;
  // der Compare Wert&lt;br /&gt;
  // Wenn der Zähler diesen Wert erreicht, wird mit&lt;br /&gt;
  // obiger Konfiguration der OC1A Ausgang abgeschaltet&lt;br /&gt;
  // Sobald der Zähler wieder bei 0 startet, wird der&lt;br /&gt;
  // Ausgang wieder auf 1 gesetzt&lt;br /&gt;
  //&lt;br /&gt;
  // Durch Verändern dieses Wertes, werden die unterschiedlichen&lt;br /&gt;
  // PWM Werte eingestellt.&lt;br /&gt;
&lt;br /&gt;
  OCR1A = 0x3FFF;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  while( 1 )&lt;br /&gt;
    ;  &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/C&amp;gt;&lt;br /&gt;
&lt;br /&gt;
PWM Mode Tabelle aus dem Datenblatt des Atmega 8515:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;Mode&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;WGM13&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;WGM12&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;WGM11&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;WGM10&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;Timer/Counter Mode of Operation&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;TOP&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;Update of OCR1x at&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;TOV1 Flag set on&#039;&#039;&#039;&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;
| 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; | Normal&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0xFFFF&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | Immediate&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | MAX&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;
| 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; | PWM, Phase Correct, 8-Bit&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0x00FF&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | TOP&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | BOTTOM&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 2&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;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | PWM, Phase Correct, 9-Bit&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0x01FF&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | TOP&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | BOTTOM&lt;br /&gt;
|-&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3&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;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | PWM, Phase Correct, 10-Bit&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0x03FF&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | TOP&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | BOTTOM&lt;br /&gt;
|-&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 4&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;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | CTC&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | OCR1A&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | Immediate&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | MAX&lt;br /&gt;
|-&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 5&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;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | Fast PWM, 8-Bit&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0x00FF&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | BOTTOM&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | TOP&lt;br /&gt;
|-&lt;br /&gt;
&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 6&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;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | Fast PWM, 9-Bit&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0x01FF&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | BOTTOM&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | TOP&lt;br /&gt;
|-&lt;br /&gt;
&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 7&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;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | Fast PWM, 10-Bit&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0x03FF&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | BOTTOM&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | TOP&lt;br /&gt;
|-&lt;br /&gt;
&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 8&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;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | PWM, Phase an Frequency Correct&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | ICR1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | BOTTOM&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | BOTTOM&lt;br /&gt;
|-    &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 9&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;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | PWM, Phase an Frequency Correct&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | OCR1A&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | BOTTOM&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | BOTTOM&lt;br /&gt;
|-&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 10&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;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | PWM, Phase Correct&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | ICR1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | TOP&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | BOTTOM&lt;br /&gt;
|-&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 11&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;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | PWM, Phase an Frequency Correct&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | OCR1A&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | TOP&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | BOTTOM&lt;br /&gt;
|-&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 12&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;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | CTC&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | ICR1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | Immediate&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | MAX&lt;br /&gt;
|-&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 13&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;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | Reserved&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | -&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | -&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | -&lt;br /&gt;
|-&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 14&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;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | Fast PWM&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | ICR1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | BOTTOM&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | TOP&lt;br /&gt;
|-&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 15&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;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | Fast PWM&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | OCR1A&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | BOTTOM&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | TOP&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Für Details der PWM Möglichkeiten, muß immer das jeweilge Datenblatt des Prozessors konsultiert werden, da sich die unterschiedlichen Prozessoren in ihren Möglichkeiten doch stark unterscheiden. Auch muß man aufpassen, welches zu setzende Bit in welchem Register sind. Auch hier kann es sein, dass gleichnamige Konfigurationsbits in unterschiedlichen Konfigurationsregistern (je nach konkretem Prozessortyp) sitzen.&lt;br /&gt;
&lt;br /&gt;
= LCD-Ansteuerung =&lt;br /&gt;
&lt;br /&gt;
==Das LCD und sein Controller==&lt;br /&gt;
&lt;br /&gt;
Die meisten Text-LCDs verwenden den Controller [[HD44780|&#039;&#039;&#039;HD44780&#039;&#039;&#039;]] oder einen kompatiblen (z.B. KS0070) und haben 14 oder 16 Pins. Die Pinbelegung an der LCD-Controller-Platine ist praktisch immer gleich: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;table width=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;th width=&amp;quot;50&amp;quot; align=&amp;quot;left&amp;quot;&amp;gt;Pin #&amp;lt;/th&amp;gt;&amp;lt;th  width=&amp;quot;70&amp;quot; align=&amp;quot;left&amp;quot;&amp;gt;Bezeichnung&amp;lt;/th&amp;gt;&amp;lt;th align=&amp;quot;left&amp;quot;&amp;gt;Funktion&amp;lt;/th&amp;gt;&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;1&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Vss&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;GND&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;2&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Vcc&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;5V&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;3&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Vee&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Kontrastspannung (0V bis 5V)&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;4&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;RS&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Register Select (Befehle/Daten)&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;5&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;RW&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Read/Write&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;6&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;E&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Enable&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;7&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;DB0&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Datenbit 0&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;8&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;DB1&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Datenbit 1&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;9&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;DB2&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Datenbit 2&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;10&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;DB3&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Datenbit 3&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;11&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;DB4&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Datenbit 4&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;12&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;DB5&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Datenbit 5&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;13&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;DB6&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Datenbit 6&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;14&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;DB7&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Datenbit 7&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;15&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;A&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;LED-Beleuchtung, Anode&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;16&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;K&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;LED-Beleuchtung, Kathode&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Achtung: Unbedingt von der richtigen Seite zu zählen anfangen! Meistens ist neben Pin 1 eine kleine 1 auf der LCD-Platine, ansonsten im Datenblatt nachschauen. &lt;br /&gt;
&lt;br /&gt;
Bei LCDs mit 16-poligem Anschluss sind die beiden letzten Pins für die Hintergrundbeleuchtung reserviert. Hier unbedingt das Datenblatt zu Rate ziehen, die beiden Anschlüsse sind je nach Hersteller verdreht beschaltet. Falls kein Datenblatt vorliegt, kann man mit einem Durchgangsprüfer feststellen, welcher Anschluss mit Masse (GND) verbunden ist.&lt;br /&gt;
&lt;br /&gt;
Vss wird ganz einfach an GND angeschlossen und Vcc an 5V. Vee kann man testweise auch an GND legen. Wenn das LCD dann zu dunkel sein sollte muss man ein 10k-Potentiometer zwischen GND und 5V schalten, mit dem Schleifer an Vee: &lt;br /&gt;
&lt;br /&gt;
[[Bild:LCD_Vee.gif]]&lt;br /&gt;
&lt;br /&gt;
Es gibt zwei verschiedene Möglichkeiten zur Ansteuerung eines solchen Displays: den &#039;&#039;&#039;8-bit-&#039;&#039;&#039; und den &#039;&#039;&#039;4-bit-&#039;&#039;&#039;Modus.&lt;br /&gt;
* Für den &#039;&#039;&#039;8-bit-Modus&#039;&#039;&#039; werden (wie der Name schon sagt) alle acht Datenleitungen zur Ansteuerung verwendet, somit kann durch einen Zugriff immer ein ganzes Byte übertragen werden.&lt;br /&gt;
* Der &#039;&#039;&#039;4-bit-Modus&#039;&#039;&#039; verwendet nur die oberen vier Datenleitungen (&#039;&#039;&#039;DB4-DB7&#039;&#039;&#039;). Um ein Byte zu übertragen braucht man somit zwei Zugriffe, wobei zuerst das höherwertige &#039;&#039;&#039;&amp;quot;Nibble&amp;quot;&#039;&#039;&#039; (= 4 Bits), also Bit 4 bis Bit 7 übertragen wird und dann das niederwertige, also Bit 0 bis Bit 3. Die unteren Datenleitungen des LCDs, die beim Lesezyklus Ausgänge sind, lässt man offen (siehe Datasheets, z.B. vom KS0070).&lt;br /&gt;
&lt;br /&gt;
Der 4-bit-Modus hat den Vorteil, dass man 4 IO-Pins weniger benötigt als beim 8-bit-Modus, weshalb ich mich hier für eine Ansteuerung mit 4bit entschieden habe. &lt;br /&gt;
&lt;br /&gt;
Neben den vier Datenleitungen (DB4, DB5, DB6 und DB7) werden noch die Anschlüsse &#039;&#039;&#039;RS&#039;&#039;&#039;, &#039;&#039;&#039;RW&#039;&#039;&#039; und &#039;&#039;&#039;E&#039;&#039;&#039; (ist in manchen Unterlagen auch &#039;&#039;&#039;EN&#039;&#039;&#039;  für &#039;&#039;Enable&#039;&#039; abgekürzt) benötigt. &lt;br /&gt;
&lt;br /&gt;
* Über &#039;&#039;&#039;RS&#039;&#039;&#039; wird ausgewählt, ob man einen Befehl oder ein Datenbyte an das LCD schicken möchte. Ist RS Low, dann wird das ankommende Byte als Befehl interpretiert, ist RS high, dann wird das Byte auf dem LCD angezeigt. &lt;br /&gt;
* &#039;&#039;&#039;RW&#039;&#039;&#039; legt fest, ob geschrieben oder gelesen werden soll. High bedeutet lesen, low bedeutet schreiben. Wenn man RW auf lesen einstellt und RS auf Befehl, dann kann man das &#039;&#039;&#039;Busy-Flag&#039;&#039;&#039; an DB7 lesen, das anzeigt, ob das LCD den vorhergehenden Befehl fertig verarbeitetet hat (diese Methode u.a. in der LCD-Library von Peter Fleury verwendet). Ist RS auf Daten eingestellt, dann kann man z.B. den Inhalt des Displays lesen - was jedoch nur in den wenigsten Fällen Sinn macht. Deshalb kann man RW dauerhaft auf low lassen (= an GND anschließen), so dass man noch ein IO-Pin am Controller einspart. Der Nachteil ist, dass man dann das Busy-Flag nicht lesen kann, weswegen man nach jedem Befehl vorsichtshalber ein paar Mikrosekunden warten sollte, um dem LCD Zeit zum Ausführen des Befehls zu geben. Dummerweise schwankt die Ausführungszeit von Display zu Display und ist auch von der Betriebsspannung abhängig. Für professionellere Sachen also lieber den IO-Pin opfern und Busy abfragen.&lt;br /&gt;
* Der &#039;&#039;&#039;E&#039;&#039;&#039; Anschluss schließlich signalisiert dem LCD, dass die übrigen Datenleitungen jetzt korrekte Pegel angenommen haben und es die gewünschten Daten von den Datenleitungen bzw. Kommandos von den Datenleitungen übernehmen kann.&lt;br /&gt;
&lt;br /&gt;
== Anschluss an den Controller ==&lt;br /&gt;
&lt;br /&gt;
Jetzt da wir wissen, welche Anschlüsse das LCDs benötigt, können wir das LCD mit dem Mikrocontroller verbinden: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;table width=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;th align=&amp;quot;left&amp;quot;&amp;gt;Pin #-LCD&amp;lt;/th&amp;gt;&amp;lt;th align=&amp;quot;left&amp;quot;&amp;gt;Bezeichnung-LCD&amp;lt;/th&amp;gt;&amp;lt;th align=&amp;quot;left&amp;quot;&amp;gt;Pin-µC&amp;lt;/th&amp;gt;&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;1&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Vss&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;GND&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;2&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Vcc&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;5V&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;3&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Vee&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;GND oder Poti (siehe oben)&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;4&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;RS&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;PD4 am AVR&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;5&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;RW&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;GND&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;6&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;E&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;PD5 am AVR&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;7&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;DB0&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;offen&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;8&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;DB1&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;offen&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;9&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;DB2&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;offen&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;10&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;DB3&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;offen&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;11&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;DB4&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;PD0 am AVR&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;12&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;DB5&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;PD1 am AVR&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;13&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;DB6&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;PD2 am AVR&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;14&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;DB7&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;PD3 am AVR&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn man die Steuerleitungen EN und RS auf Pins an einem anderen Port legen möchte, kann man so wie in diesem [http://www.mikrocontroller.net/topic/88543#751982 Forumsbeitrag] vorgehen.&lt;br /&gt;
&lt;br /&gt;
Ok, alles ist verbunden, wenn man jetzt den Strom einschaltet sollten ein oder zwei schwarze Balken auf dem Display angezeigt werden. Doch wie bekommt man jetzt die Befehle und Daten in das Display? &lt;br /&gt;
&lt;br /&gt;
== Programmierung ==&lt;br /&gt;
Datei &#039;&#039;&#039;lcd-routines.h&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
// Ansteuerung eines HD44780 kompatiblen LCD im 4-Bit-Interfacemodus&lt;br /&gt;
// http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial&lt;br /&gt;
//&lt;br /&gt;
void lcd_data(unsigned char temp1);&lt;br /&gt;
void lcd_string(char *data);&lt;br /&gt;
void lcd_command(unsigned char temp1);&lt;br /&gt;
void lcd_enable(void);&lt;br /&gt;
void lcd_init(void);&lt;br /&gt;
void lcd_home(void);&lt;br /&gt;
void lcd_clear(void);&lt;br /&gt;
void set_cursor(uint8_t x, uint8_t y);&lt;br /&gt;
&lt;br /&gt;
// Hier die verwendete Taktfrequenz in Hz eintragen, wichtig!&lt;br /&gt;
&lt;br /&gt;
#define F_CPU 8000000&lt;br /&gt;
&lt;br /&gt;
// LCD Befehle&lt;br /&gt;
&lt;br /&gt;
#define CLEAR_DISPLAY 0x01&lt;br /&gt;
#define CURSOR_HOME   0x02&lt;br /&gt;
&lt;br /&gt;
// Pinbelegung für das LCD, an verwendete Pins anpassen&lt;br /&gt;
&lt;br /&gt;
#define LCD_PORT      PORTD&lt;br /&gt;
#define LCD_DDR       DDRD&lt;br /&gt;
#define LCD_RS        PD4&lt;br /&gt;
#define LCD_EN        PD5&lt;br /&gt;
// DB4 bis DB7 des LCD sind mit PD0 bis PD3 des AVR verbunden&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Datei &#039;&#039;&#039;lcd-routines.c&#039;&#039;&#039;:&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
// Ansteuerung eines HD44780 kompatiblen LCD im 4-Bit-Interfacemodus&lt;br /&gt;
// http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial&lt;br /&gt;
//&lt;br /&gt;
// Die Pinbelegung ist über defines in lcd-routines.h einstellbar&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;quot;lcd-routines.h&amp;quot;&lt;br /&gt;
#include &amp;lt;util/delay.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
// sendet ein Datenbyte an das LCD&lt;br /&gt;
&lt;br /&gt;
void lcd_data(unsigned char temp1)&lt;br /&gt;
{&lt;br /&gt;
   unsigned char temp2 = temp1;&lt;br /&gt;
 &lt;br /&gt;
   LCD_PORT |= (1&amp;lt;&amp;lt;LCD_RS);        // RS auf 1 setzen&lt;br /&gt;
&lt;br /&gt;
   temp1 = temp1 &amp;gt;&amp;gt; 4;&lt;br /&gt;
   temp1 = temp1 &amp;amp; 0x0F;&lt;br /&gt;
   LCD_PORT &amp;amp;= 0xF0;&lt;br /&gt;
   LCD_PORT |= temp1;               // setzen&lt;br /&gt;
   lcd_enable();&lt;br /&gt;
 &lt;br /&gt;
   temp2 = temp2 &amp;amp; 0x0F;&lt;br /&gt;
   LCD_PORT &amp;amp;= 0xF0;&lt;br /&gt;
   LCD_PORT |= temp2;               // setzen&lt;br /&gt;
   lcd_enable();&lt;br /&gt;
   &lt;br /&gt;
   _delay_us(42);&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
// sendet einen Befehl an das LCD&lt;br /&gt;
&lt;br /&gt;
void lcd_command(unsigned char temp1)&lt;br /&gt;
{&lt;br /&gt;
   unsigned char temp2 = temp1;&lt;br /&gt;
 &lt;br /&gt;
   LCD_PORT &amp;amp;= ~(1&amp;lt;&amp;lt;LCD_RS);        // RS auf 0 setzen&lt;br /&gt;
&lt;br /&gt;
   temp1 = temp1 &amp;gt;&amp;gt; 4;              // oberes Nibble holen&lt;br /&gt;
   temp1 = temp1 &amp;amp; 0x0F;            // maskieren&lt;br /&gt;
   LCD_PORT &amp;amp;= 0xF0;&lt;br /&gt;
   LCD_PORT |= temp1;               // setzen&lt;br /&gt;
   lcd_enable();&lt;br /&gt;
 &lt;br /&gt;
   temp2 = temp2 &amp;amp; 0x0F;            // unteres Nibble holen und maskieren&lt;br /&gt;
   LCD_PORT &amp;amp;= 0xF0;&lt;br /&gt;
   LCD_PORT |= temp2;               // setzen&lt;br /&gt;
   lcd_enable();&lt;br /&gt;
   &lt;br /&gt;
   _delay_us(42);&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
// erzeugt den Enable-Puls&lt;br /&gt;
void lcd_enable(void)&lt;br /&gt;
{&lt;br /&gt;
   // Bei Problemen ggf. Pause gemäß Datenblatt des LCD Controllers einfügen&lt;br /&gt;
   // http://www.mikrocontroller.net/topic/81974#685882&lt;br /&gt;
   LCD_PORT |= (1&amp;lt;&amp;lt;LCD_EN);&lt;br /&gt;
    _delay_us(1);                   // kurze Pause&lt;br /&gt;
   // Bei Problemen ggf. Pause gemäß Datenblatt des LCD Controllers verlängern&lt;br /&gt;
   // http://www.mikrocontroller.net/topic/80900&lt;br /&gt;
   LCD_PORT &amp;amp;= ~(1&amp;lt;&amp;lt;LCD_EN);&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
// Initialisierung: &lt;br /&gt;
// Muss ganz am Anfang des Programms aufgerufen werden.&lt;br /&gt;
&lt;br /&gt;
void lcd_init(void)&lt;br /&gt;
{&lt;br /&gt;
   LCD_DDR = LCD_DDR | 0x0F | (1&amp;lt;&amp;lt;LCD_RS) | (1&amp;lt;&amp;lt;LCD_EN);   // Port auf Ausgang schalten&lt;br /&gt;
&lt;br /&gt;
   // muss 3mal hintereinander gesendet werden zur Initialisierung&lt;br /&gt;
&lt;br /&gt;
   _delay_ms(15);&lt;br /&gt;
   LCD_PORT &amp;amp;= 0xF0;&lt;br /&gt;
   LCD_PORT |= 0x03;            &lt;br /&gt;
   LCD_PORT &amp;amp;= ~(1&amp;lt;&amp;lt;LCD_RS);      // RS auf 0&lt;br /&gt;
   lcd_enable();&lt;br /&gt;
&lt;br /&gt;
   _delay_ms(5);&lt;br /&gt;
   lcd_enable();&lt;br /&gt;
&lt;br /&gt;
   _delay_ms(1);&lt;br /&gt;
   lcd_enable();&lt;br /&gt;
   _delay_ms(1);&lt;br /&gt;
&lt;br /&gt;
   // 4 Bit Modus aktivieren &lt;br /&gt;
   LCD_PORT &amp;amp;= 0xF0;&lt;br /&gt;
   LCD_PORT |= 0x02;&lt;br /&gt;
   lcd_enable();&lt;br /&gt;
   _delay_ms(1);&lt;br /&gt;
&lt;br /&gt;
   // 4Bit / 2 Zeilen / 5x7&lt;br /&gt;
   lcd_command(0x28);&lt;br /&gt;
    &lt;br /&gt;
   // Display ein / Cursor aus / kein Blinken&lt;br /&gt;
   lcd_command(0x0C); &lt;br /&gt;
 &lt;br /&gt;
   // inkrement / kein Scrollen&lt;br /&gt;
   lcd_command(0x06);&lt;br /&gt;
&lt;br /&gt;
   lcd_clear();&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
// Sendet den Befehl zur Löschung des Displays&lt;br /&gt;
&lt;br /&gt;
void lcd_clear(void)&lt;br /&gt;
{&lt;br /&gt;
   lcd_command(CLEAR_DISPLAY);&lt;br /&gt;
   _delay_ms(5);&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
// Sendet den Befehl: Cursor Home&lt;br /&gt;
&lt;br /&gt;
void lcd_home(void)&lt;br /&gt;
{&lt;br /&gt;
   lcd_command(CURSOR_HOME);&lt;br /&gt;
   _delay_ms(5);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// setzt den Cursor in Zeile y (1..4) Spalte x (0..15)&lt;br /&gt;
&lt;br /&gt;
void set_cursor(uint8_t x, uint8_t y)&lt;br /&gt;
{&lt;br /&gt;
  uint8_t tmp;&lt;br /&gt;
&lt;br /&gt;
  switch (y) {&lt;br /&gt;
    case 1: tmp=0x80+0x00+x; break;    // 1. Zeile&lt;br /&gt;
    case 2: tmp=0x80+0x40+x; break;    // 2. Zeile&lt;br /&gt;
    case 3: tmp=0x80+0x10+x; break;    // 3. Zeile&lt;br /&gt;
    case 4: tmp=0x80+0x50+x; break;    // 4. Zeile&lt;br /&gt;
    default: return;                   // für den Fall einer falschen Zeile&lt;br /&gt;
  }&lt;br /&gt;
  lcd_command(tmp);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Schreibt einen String auf das LCD&lt;br /&gt;
&lt;br /&gt;
void lcd_string(char *data)&lt;br /&gt;
{&lt;br /&gt;
    while(*data) {&lt;br /&gt;
        lcd_data(*data);&lt;br /&gt;
        data++;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein Hauptprogramm, welches die Funktionen benutzt, sieht zb. so aus:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
// &lt;br /&gt;
// Anpassungen im makefile:&lt;br /&gt;
//    ATMega8 =&amp;gt; MCU=atmega8 im makefile einstellen&lt;br /&gt;
//    lcd-routines.c in SRC = ... Zeile anhängen&lt;br /&gt;
// &lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;quot;lcd-routines.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
int main(void)&lt;br /&gt;
{&lt;br /&gt;
    lcd_init();&lt;br /&gt;
&lt;br /&gt;
    lcd_data(&#039;T&#039;);&lt;br /&gt;
    lcd_data(&#039;e&#039;);&lt;br /&gt;
    lcd_data(&#039;s&#039;);&lt;br /&gt;
    lcd_data(&#039;t&#039;);&lt;br /&gt;
&lt;br /&gt;
    set_cursor(0,2);&lt;br /&gt;
&lt;br /&gt;
    lcd_string(&amp;quot;Hello World!&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    while(1)&lt;br /&gt;
    {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wichtig ist dabei, dass die Optimierung bei der Compilierung eingeschaltet ist, sonst stimmen die Zeiten der Funktionen _delay_us() und _delay_ms() nicht und der Code wird wesentlich länger (Siehe Dokumentation der libc im WinAVR).&lt;br /&gt;
&lt;br /&gt;
Ein Hauptprogramm, welches eine Variable ausgibt, sieht zb. so aus.&lt;br /&gt;
Mittels der itoa() Funktion (itoa = &amp;lt;b&amp;gt;I&amp;lt;/b&amp;gt;nteger &amp;lt;b&amp;gt;To&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;A&amp;lt;/b&amp;gt;scii ) wird von einem Zahlenwert eine textuelle Repräsentierung ermittelt (sprich: ein String erzeugt) und dieser String mit der bereits vorhandenen Funktion lcd_string ausgegeben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
// &lt;br /&gt;
// Anpassungen im makefile:&lt;br /&gt;
//    ATMega8 =&amp;gt; MCU=atmega8 im makefile einstellen&lt;br /&gt;
//    lcd-routines.c in SRC = ... Zeile anhängen &lt;br /&gt;
// &lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
#include &amp;quot;lcd-routines.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
// Beispiel&lt;br /&gt;
int variable = 42;&lt;br /&gt;
&lt;br /&gt;
int main(void)&lt;br /&gt;
{&lt;br /&gt;
    lcd_init();&lt;br /&gt;
&lt;br /&gt;
    // Ausgabe des Zeichens dessen ASCII-Code gleich dem Variablenwert ist&lt;br /&gt;
    // (Im Beispiel entspricht der ASCII-Code 42 dem Zeichen *)&lt;br /&gt;
    // http://www.code-knacker.de/ascii.htm&lt;br /&gt;
    lcd_data(variable);&lt;br /&gt;
&lt;br /&gt;
    set_cursor(0,2);&lt;br /&gt;
 &lt;br /&gt;
    // Ausgabe der Variable als Text in dezimaler Schreibweise&lt;br /&gt;
    {&lt;br /&gt;
       // ... umwandeln siehe FAQ Artikel bei www.mikrocontroller.net&lt;br /&gt;
       // WinAVR hat eine itoa()-Funktion, das erfordert obiges #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
       char Buffer[20]; // in diesem {} lokal&lt;br /&gt;
       itoa( variable, Buffer, 10 ); &lt;br /&gt;
&lt;br /&gt;
       // ... ausgeben  &lt;br /&gt;
       lcd_string( Buffer );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    while(1)&lt;br /&gt;
    {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Beim Einrichten eines Projekts muss man zu der Datei mit dem Hauptprogramm auch die Datei lcd-routines.c in das Projekt aufnehmen. Dies geschieht beim AVR Studio unter Source Files im Fenster AVR GCC oder bei WinAVR im Makefile (z.B. durch SRC += lcd-routines.c).&lt;br /&gt;
&lt;br /&gt;
= Die Timer/Counter des AVR =&lt;br /&gt;
&lt;br /&gt;
Die heutigen Mikrocontroller und insbesondere die RISC-AVRs sind für viele Steuerungsaufgaben zu schnell. Wenn wir beispielsweise eine LED oder Lampe blinken lassen wollen, können wir selbstverständlich nicht die CPU-Frequenz verwenden, da ja dann nichts mehr vom Blinken zu bemerken wäre.&lt;br /&gt;
&lt;br /&gt;
Wir brauchen also eine Möglichkeit, Vorgänge in Zeitabständen durchzuführen, die geringer als die Taktfrequenz des Controllers sind. Selbstverständlich sollte die resultierende Frequenz auch noch möglichst genau und stabil sein.&lt;br /&gt;
&lt;br /&gt;
Hier kommen die im AVR vorhandenen Timer/Counter zum Einsatz.&lt;br /&gt;
&lt;br /&gt;
Ein Timer ist ganz einfach ein bestimmtes Register im µC, das völlig ohne Zutun des Programms, also per Hardware, hochgezählt wird. Das alleine wäre noch nicht allzu nützlich, wenn nicht dieses Hardwareregister bei bestimmten Zählerständen einen Interrupt auslösen könnte. Ein solches Ereignis ist der Overflow: Da die Bitbreite des Registers beschränkt ist, kommt es natürlich auch vor, dass der Zähler so hoch zählt, dass der nächste Zählerstand mit dieser Bitbreite nicht mehr darstellbar ist und der Zähler wieder auf 0 zurückgesetzt wird. Dieses Ereignis nennt man den Overflow und es ist möglich an dieses Ereignis einen Interrupt zu koppeln.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- Alternativvorschlag mthomas &lt;br /&gt;
Jeder Timer verfügt über ein Zählerregister im Mikrocontroller, das automatisch und ohne Zutun des Programms von der Hardware weitergezählt wird. In einem einfachen Anwendungsfall stellt man den Timer auf eine Zählgeschwindigkeit (Frequenz) und kann dann anhand des Zählerstands ermitteln, wie viel Zeit vergangen ist. Das eigentlich Nützliche an Timern ist jedoch, dass man  bestimmte Zählerstände mit Interrupts verknüpfen kann, so dass der Controller beim Auftreten automatisch eine vom Anwender geschriebene Routine aufruft. Eines dieser möglichen Ereignis ist der Overflow ((Zähler-)Überlauf), der dann auftritt, wenn der Wert des Zählerregisters (Timer/Counter-Register) den maximal möglichen Wert überschreitet. Der Maximalwert wird durch die Bitbreite des Zählerregisters bestimmt (z.B. 255 bei 8-Bit Timern). Beim Überlauf/Overflow wird der Zähler durch die Hardware auf 0 zurückgesetzt und die Zählung beginnt von neuem. Wurde vorher der Overflow-Interrupt für den Timer aktiviert (im Timer Control Register) unterbricht der Controller automatisch die Ausführung des Hauptprogramms und verzweigt in die Interrupt-Routine des Anwenders.&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein anderes Anwendungsgebiet ist die Zählung von Signalen, welche über einen I/O-Pin zugeführt werden können.&lt;br /&gt;
&lt;br /&gt;
Die folgenden Ausführungen beziehen sich auf den AT90S2313. Für andere Modelltypen müsst ihr euch die allenfalls notwendigen Anpassungen aus den Datenblättern der entsprechenden Controller herauslesen.&lt;br /&gt;
&lt;br /&gt;
Wir unterscheiden grundsätzlich zwischen 8-Bit Timern, welche eine Auflösung von 256 aufweisen und 16-Bit Timern mit (logischerweise) einer Auflösung von 65536. Als Eingangstakt für die Timer/Counter kann entweder die CPU-Taktfrequenz, der Vorteiler-Ausgang oder ein an einen I/O-Pin angelegtes Signal verwendet werden. Wenn ein externes Signal verwendet wird, so darf dessen Frequenz nicht höher sein als die Hälfte des CPU-Taktes.&lt;br /&gt;
&lt;br /&gt;
== Der Vorteiler (Prescaler) ==&lt;br /&gt;
&lt;br /&gt;
Der Vorteiler dient dazu, den CPU-Takt vorerst um einen einstellbaren Faktor zu reduzieren. Die so geteilte Frequenz wird den Eingängen der Timer zugeführt.&lt;br /&gt;
&lt;br /&gt;
Wenn wir mit einem CPU-Takt von 4 MHz arbeiten und den Vorteiler auf 1024 einstellen, wird also der Timer mit einer Frequenz von 4 MHz / 1024, also mit ca. 4 kHz versorgt. Wenn also der Timer läuft, so wird das Daten- bzw. Zählregister (TCNTx) mit dieser Frequenz inkrementiert.&lt;br /&gt;
&lt;br /&gt;
== 8-Bit Timer/Counter ==&lt;br /&gt;
&lt;br /&gt;
Alle AVR-Modelle verfügen über mindestens einen, teilweise sogar zwei, 8-Bit Timer.&lt;br /&gt;
&lt;br /&gt;
Der 8-Bit Timer wird z.B bei AT90S2313 über folgende Register angesprochen (bei anderen Typen weitestgehend analog):&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;TCCR0&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;T&#039;&#039;&#039;imer/&#039;&#039;&#039;C&#039;&#039;&#039;ounter &#039;&#039;&#039;C&#039;&#039;&#039;ontrol &#039;&#039;&#039;R&#039;&#039;&#039;egister&lt;br /&gt;
Timer &#039;&#039;&#039;0&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
In diesem Register stellen wir ein, wie wir den Timer/Counter verwenden möchten.&lt;br /&gt;
&lt;br /&gt;
Das Register ist wie folgt aufgebaut:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Bit&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 7&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 6&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 5&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 4&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 2&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Name&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;CS02&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;CS01&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;CS00&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;R/W&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Initialwert&#039;&#039;&#039;&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;
| 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;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;CS02, CS01, CS00&#039;&#039;&#039; (&#039;&#039;&#039;C&#039;&#039;&#039;lock &#039;&#039;&#039;S&#039;&#039;&#039;elect Bits)&lt;br /&gt;
:Diese 3 Bits bestimmen die Quelle für den Timer/Counter:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | CS02&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | CS01&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | CS00&lt;br /&gt;
| Resultat&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;
| Stopp, Der Timer/Counter wird 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;
| CPU-Takt&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;
| CPU-Takt / 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;
| CPU-Takt / 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;
| CPU-Takt / 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;
| CPU-Takt / 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;
| Externer Pin &#039;&#039;&#039;TO&#039;&#039;&#039;, 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;
| Externer Pin &#039;&#039;&#039;TO&#039;&#039;&#039;, steigende Flanke&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/dd&amp;gt;&lt;br /&gt;
&amp;lt;/dl&amp;gt;&lt;br /&gt;
:Wenn als Quelle der externe Pin &#039;&#039;&#039;TO&#039;&#039;&#039; verwendet wird, so wird ein Flankenwechsel auch erkannt, wenn der Pin &#039;&#039;&#039;TO&#039;&#039;&#039; als Ausgang geschaltet ist.&lt;br /&gt;
&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;TCNT0&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;T&#039;&#039;&#039;imer/&#039;&#039;&#039;C&#039;&#039;&#039;ou&#039;&#039;&#039;nt&#039;&#039;&#039;er Daten Register Timer &#039;&#039;&#039;0&#039;&#039;&#039;&amp;lt;br /&amp;gt;&lt;br /&gt;
Dieses ist als 8-Bit Aufwärtszähler mit Schreib- und Lesezugriff&lt;br /&gt;
realisiert. Wenn der Zähler den Wert 255 erreicht hat beginnt er beim&lt;br /&gt;
nächsten Zyklus wieder bei 0.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Bit&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 7&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 6&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 5&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 4&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 2&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Name&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;MSB&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;LSB&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;R/W&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Initialwert&#039;&#039;&#039;&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;
| 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;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Um nun also den Timer0 in Betrieb zu setzen und ihn mit einer Frequenz von 1/1024-tel des CPU-Taktes zählen zu lassen, schreiben wir die folgende Befehlszeile:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
    TCCR0 |= (1&amp;lt;&amp;lt;CS00)|(1&amp;lt;&amp;lt;CS02);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Zähler zählt nun aufwärts bis 255, um dann wieder bei 0 zu beginnen. Der aktuelle Zählerstand steht in TCNT0. Bei jedem Überlauf von 255 auf 0 wird das Timer Overflow Flag &#039;&#039;&#039;TOV0&#039;&#039;&#039; im Timer Interrupt Flag &#039;&#039;&#039;TIFR&#039;&#039;&#039;-Register gesetzt und, falls so konfiguriert, ein entsprechender Timer-Overflow-Interrupt ausgelöst und die daran gebundene Interrupt-Routine abgearbeitet. Das TOV Flag &lt;br /&gt;
lässt sich durch das Hineinschreiben einer 1 und nicht wie erwartet einer 0 wieder zurücksetzen.&lt;br /&gt;
&lt;br /&gt;
== 16-Bit Timer/Counter ==&lt;br /&gt;
&lt;br /&gt;
Viele AVR-Modelle besitzen außer den 8-Bit Timern auch 16-Bit Timer. Die 16-Bit Timer/Counter sind etwas komplexer aufgebaut als die 8-Bit Timer/Counter, bieten dafür aber auch viel mehr Möglichkeiten, als da sind:&lt;br /&gt;
&lt;br /&gt;
* Die [[PWM]]-Betriebsart Erzeugung eines pulsweitenmodulierten Ausgangssignals. &lt;br /&gt;
* Vergleichswert-Überprüfung mit Erzeugung eines Ausgangssignals (Output Compare Match).&lt;br /&gt;
* Einfangen eines Eingangssignals mit Speicherung des aktuellen Zählerwertes (Input Capturing), mit zuschaltbarer Rauschunterdrückung (Noise Filtering).&lt;br /&gt;
&lt;br /&gt;
Folgende Register sind dem Timer/Counter 1 zugeordnet:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;TCCR1A&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;T&#039;&#039;&#039;imer/&#039;&#039;&#039;C&#039;&#039;&#039;ounter &#039;&#039;&#039;C&#039;&#039;&#039;ontrol &#039;&#039;&#039;R&#039;&#039;&#039;egister &#039;&#039;&#039;A&#039;&#039;&#039; Timer &#039;&#039;&#039;1&#039;&#039;&#039;&amp;lt;br /&amp;gt;&lt;br /&gt;
In diesem und dem folgenden Register stellen wir ein, wie wir den Timer/Counter verwenden möchten.&amp;lt;br /&amp;gt;&lt;br /&gt;
Das Register ist wie folgt aufgebaut:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Bit&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 7&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 6&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 5&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 4&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 2&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Name&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;COM1A1&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;COM1A0&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;PWM11&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;PWM10&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;R/W&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Initialwert&#039;&#039;&#039;&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;
| 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;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;COM1A1&#039;&#039;&#039;, &#039;&#039;&#039;COM1A0&#039;&#039;&#039; (&#039;&#039;&#039;Co&#039;&#039;&#039;mpare &#039;&#039;&#039;M&#039;&#039;&#039;atch Control Bits)&lt;br /&gt;
:Diese 2 Bits bestimmen die Aktion, welche am Output-Pin &#039;&#039;&#039;OC1&#039;&#039;&#039; ausgeführt werden soll, wenn der Wert des Datenregisters des Timer/Counter 1 den Wert des Vergleichsregisters erreicht, also ein so genannter Compare Match auftritt.&lt;br /&gt;
:Der Pin &#039;&#039;&#039;OC1&#039;&#039;&#039; (&#039;&#039;&#039;PB3&#039;&#039;&#039; beim 2313) muss mit dem Datenrichtungsregister als Ausgang konfiguriert werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | COM1A1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | COM1A0&lt;br /&gt;
| Resultat&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;
| Output-Pin &#039;&#039;&#039;OC1&#039;&#039;&#039; wird nicht angesteuert.&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;
| Das Signal am Pin &#039;&#039;&#039;OC1&#039;&#039;&#039; wird invertiert (Toggle).&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;
| Der Output Pin &#039;&#039;&#039;OC1&#039;&#039;&#039; wird auf 0 gesetzt.&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;
| Der Output Pin &#039;&#039;&#039;OC1&#039;&#039;&#039; wird auf 1 gesetzt.&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&lt;br /&gt;
:In der PWM-Betriebsart haben diese Bits eine andere Funktion.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | COM1A1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | COM1A0&lt;br /&gt;
| Resultat&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;
| Output-Pin &#039;&#039;&#039;OC1&#039;&#039;&#039; wird nicht angesteuert.&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;
| Output-Pin &#039;&#039;&#039;OC1&#039;&#039;&#039; wird nicht angesteuert.&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;
| Wird beim Hochzählen der Wert im Vergleichsregister erreicht, so wird der Pin &#039;&#039;&#039;OC1&#039;&#039;&#039; auf 0 gesetzt.&lt;br /&gt;
Wird beim Herunterzählen der Wert im Vergleichsregister erreicht, so wird der Pin auf 1 gesetzt.&lt;br /&gt;
&lt;br /&gt;
Man nennt dies &#039;&#039;nicht invertierende PWM&#039;&#039;.&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;
| Wird beim Hochzählen der Wert im Vergleichsregister erreicht, so wird der Pin &#039;&#039;&#039;OC1&#039;&#039;&#039; auf 1 gesetzt.&lt;br /&gt;
Wird beim Herunterzählen der Wert im Vergleichsregister erreicht, so wird der Pin auf 0 gesetzt.&lt;br /&gt;
&lt;br /&gt;
Man nennt dies &#039;&#039;invertierende PWM&#039;&#039;.&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;PWM11&#039;&#039;&#039;, &#039;&#039;&#039;PWM10&#039;&#039;&#039; (&#039;&#039;&#039;PWM&#039;&#039;&#039; Mode Select Bits)&lt;br /&gt;
:Mit diesen 2 Bits wird die PWM-Betriebsart des Timer/Counter 1 gesteuert.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | PWM11&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | PWM10&lt;br /&gt;
| Resultat&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;
| Die PWM-Betriebsart ist nicht aktiviert. Timer/Counter 1 arbeitet als normaler Timer bzw. Zähler.&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;
| 8-Bit PWM Betriebsart aktivieren.&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;
| 9-Bit PWM Betriebsart aktivieren.&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;
| 10-Bit PWM Betriebsart aktivieren.&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;TCCR1B&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;T&#039;&#039;&#039;imer/&#039;&#039;&#039;C&#039;&#039;&#039;ounter &#039;&#039;&#039;C&#039;&#039;&#039;ontrol &#039;&#039;&#039;R&#039;&#039;&#039;egister &#039;&#039;&#039;B&#039;&#039;&#039; Timer &#039;&#039;&#039;1&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Bit&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 7&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 6&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 5&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 4&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 2&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Name&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ICNC1&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ICES1&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;WGM13&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;WGM12 (CTC1)&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;CS12&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;CS11&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;CS10&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;R/W&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Initialwert&#039;&#039;&#039;&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;
| 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;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ICNC1&#039;&#039;&#039; (&#039;&#039;&#039;I&#039;&#039;&#039;nput &#039;&#039;&#039;C&#039;&#039;&#039;apture &#039;&#039;&#039;N&#039;&#039;&#039;oise &#039;&#039;&#039;C&#039;&#039;&#039;anceler (4 CKs) Timer/Counter 1&lt;br /&gt;
:oder auf Deutsch Rauschunterdrückung des Eingangssignals.&lt;br /&gt;
:Wenn dieses Bit gesetzt ist und mit dem Input Capture Signal gearbeitet wird so werden nach der Triggerung des Signals mit der entsprechenden Flanke (steigend oder fallend) am Input Capture Pin &#039;&#039;&#039;ICP&#039;&#039;&#039; jeweils 4 Messungen mit der CPU-Frequenz des Eingangssignals abgefragt. Nur dann, wenn alle 4 Messungen den gleichen Zustand aufweisen gilt das Signal als erkannt.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ICES1&#039;&#039;&#039; (&#039;&#039;&#039;I&#039;&#039;&#039;nput &#039;&#039;&#039;C&#039;&#039;&#039;apture &#039;&#039;&#039;E&#039;&#039;&#039;dge &#039;&#039;&#039;S&#039;&#039;&#039;elect Timer/Counter &#039;&#039;&#039;1&#039;&#039;&#039;)&lt;br /&gt;
:Mit diesem Bit wird bestimmt, ob die steigende (&#039;&#039;&#039;ICES1&#039;&#039;&#039;=1) oder fallende (&#039;&#039;&#039;ICES1&#039;&#039;&#039;=0) Flanke zur Auswertung des Input Capture Signals an Pin &#039;&#039;&#039;ICP&#039;&#039;&#039; heran gezogen wird.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;CTC1&#039;&#039;&#039; (&#039;&#039;&#039;C&#039;&#039;&#039;lear &#039;&#039;&#039;T&#039;&#039;&#039;imer/&#039;&#039;&#039;C&#039;&#039;&#039;ounter on Compare Match Timer/Counter &#039;&#039;&#039;1&#039;&#039;&#039;)&lt;br /&gt;
:Wenn dieses Bit gesetzt ist, so wird nach einer Übereinstimmung des Datenregisters &#039;&#039;&#039;TCNT1H&#039;&#039;&#039;/&#039;&#039;&#039;TCNT1L&#039;&#039;&#039; mit dem Vergleichswert in &#039;&#039;&#039;OCR1H&#039;&#039;&#039;/&#039;&#039;&#039;OCR1L&#039;&#039;&#039; das Datenregister &#039;&#039;&#039;TCNT1H&#039;&#039;&#039;/&#039;&#039;&#039;TCNT1L&#039;&#039;&#039; auf 0 gesetzt.&lt;br /&gt;
:Da die Übereinstimmung im Takt nach dem Vergleich behandelt wird, ergibt sich je nach eingestelltem Vorteiler ein etwas anderes Zählverhalten:&lt;br /&gt;
:Wenn der Vorteiler auf 1 gestellt, und C der voreingestellte Vergleichswert ist, dann nimmt das Datenregister, im CPU-Takt betrachtet, folgende Werte an:&lt;br /&gt;
:... | C-2 | C-1 | C | 0 | 1 |...&lt;br /&gt;
:Wenn der Vorteiler z.B. auf 8 eingestellt ist, dann nimmt das Datenregister folgende Werte an:&lt;br /&gt;
:... | C-2, C-2, C-2, C-2, C-2, C-2, C-2, C-2 | C-1, C-1, C-1, C-1, C-1, C-1, C-1, C-1 | C, 0, 0, 0, 0, 0, 0, 0 |...&lt;br /&gt;
:In der PWM-Betriebsart hat dieses Bit keine Funktion.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;CS12&#039;&#039;&#039;, &#039;&#039;&#039;CS11&#039;&#039;&#039;, &#039;&#039;&#039;CS10&#039;&#039;&#039; (&#039;&#039;&#039;C&#039;&#039;&#039;lock &#039;&#039;&#039;S&#039;&#039;&#039;elect Bits)&lt;br /&gt;
:Diese 3 Bits bestimmen die Quelle für den Timer/Counter:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | CS12&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | CS11&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | CS10&lt;br /&gt;
| Resultat&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;
| Stopp, Der Timer/Counter wird 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;
| CPU-Takt&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;
| CPU-Takt / 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;
| CPU-Takt / 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;
| CPU-Takt / 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;
| CPU-Takt / 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;
| Externer 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;
| Externer Pin T1, steigende Flanke&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&lt;br /&gt;
:Wenn als Quelle der externe Pin T1 verwendet wird, so wird ein Flankenwechsel auch erkannt, wenn der Pin T1 als Ausgang geschaltet ist.&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;TCNT1H&#039;&#039;&#039;&amp;lt;br /&amp;gt;&#039;&#039;&#039;TCNT1L&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;T&#039;&#039;&#039;imer/&#039;&#039;&#039;C&#039;&#039;&#039;ou&#039;&#039;&#039;nt&#039;&#039;&#039;er Daten Register Timer/Counter &#039;&#039;&#039;1&#039;&#039;&#039;&lt;br /&gt;
Dieses ist als 16-Bit Aufwärtszähler mit Schreib- und Lesezugriff realisiert. Wenn der Zähler den Wert 65535 erreicht hat, beginnt er beim nächsten Zyklus wieder bei 0.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Bit&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 7&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 6&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 5&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 4&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 2&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; | &amp;amp;nbsp;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Name&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;MSB&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;TCNT1H&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Name&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;LSB&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;TCNT1L&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;R/W&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Initialwert&#039;&#039;&#039;&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;
| 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;
| 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; | &amp;amp;nbsp;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
In der PWM-Betriebsart wird das Register als Auf/Ab-Zähler verwendet, d.h. der Wert steigt zuerst von 0, bis er den Überlauf von 65535 auf 0 erreicht hat. Dann zählt das Register rückwärts wiederum bis 0.&lt;br /&gt;
&lt;br /&gt;
Zum Auslesen des Registers wird von der CPU ein internes TEMP-Register verwendet. Das gleiche Register wird auch verwendet, wenn auf &#039;&#039;&#039;OCR1&#039;&#039;&#039; oder &#039;&#039;&#039;ICR1&#039;&#039;&#039; zugegriffen wird.&lt;br /&gt;
&lt;br /&gt;
Deshalb müssen vor dem Zugriff auf eines dieser Register alle Interrupts gesperrt werden, weil sonst die Möglichkeit des gleichzeitigen Zugriffs auf das Temporärregister gegeben ist, was natürlich zu fehlerhaftem Verhalten des Programms führt.. Zudem muss zuerst &#039;&#039;&#039;TCNT1L&#039;&#039;&#039; und erst danach &#039;&#039;&#039;TCNT1H&#039;&#039;&#039; ausgelesen werden.&lt;br /&gt;
&lt;br /&gt;
Wenn in das Register geschrieben werden soll, müssen ebenfalls alle Interrrupts gesperrt werden. Dann muss zuerst das &#039;&#039;&#039;TCNT1H&#039;&#039;&#039;-Register und erst danach das &#039;&#039;&#039;TCNT1L&#039;&#039;&#039;-Register geschrieben werden, also genau die umgekehrte Reihenfolge wie beim Lesen des Registers.&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;OCR1H&#039;&#039;&#039;&amp;lt;br /&amp;gt;&#039;&#039;&#039;OCR1L&#039;&#039;&#039;&lt;br /&gt;
| Timer/Counter &#039;&#039;&#039;O&#039;&#039;&#039;utput &#039;&#039;&#039;C&#039;&#039;&#039;ompare &#039;&#039;&#039;R&#039;&#039;&#039;egister Timer/Counter &#039;&#039;&#039;1&#039;&#039;&#039;&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Bit&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 7&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 6&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 5&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 4&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 2&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; | &amp;amp;nbsp;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Name&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;MSB&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;OCR1H&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Name&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;LSB&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;OCR1L&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;R/W&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Initialwert&#039;&#039;&#039;&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;
| 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;
| 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; | &amp;amp;nbsp;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Der Wert im Output Compare Register wird ständig mit dem aktuellen Wert im Datenregister TCNT1H/TCNT1L verglichen. Stimmen die beiden Werte überein, so wird ein sogenannter Output Compare Match ausgelöst. Die entsprechenden Aktionen werden über die Timer/Counter 1 Control und Status Register eingestellt.&lt;br /&gt;
&lt;br /&gt;
Zum Auslesen des Registers wird von der CPU ein internes TEMP-Register verwendet. Das gleiche Register wird auch verwendet, wenn auf &#039;&#039;&#039;TCNT1&#039;&#039;&#039; oder &#039;&#039;&#039;ICR1&#039;&#039;&#039; zugegriffen wird.&lt;br /&gt;
Deshalb müssen vor dem Zugriff auf eines dieser Register alle Interrupts gesperrt werden, weil sonst die Möglichkeit des gleichzeitigen Zugriffs auf das Temporärregister gegeben ist, was natürlich zu fehlerhaftem Verhalten des Programms führt.. Zudem muss zuerst &#039;&#039;&#039;OCR1L&#039;&#039;&#039; und erst danach &#039;&#039;&#039;OCR1H&#039;&#039;&#039; ausgelesen werden.&lt;br /&gt;
&lt;br /&gt;
Wenn in das Register geschrieben werden soll, müssen ebenfalls alle Interrupts gesperrt werden. Dann muss zuerst das &#039;&#039;&#039;OCR1H&#039;&#039;&#039;-Register und erst danach das &#039;&#039;&#039;OCR1L&#039;&#039;&#039;-Register geschrieben werden, also genau die umgekehrte Reihenfolge wie beim Lesen des Registers.&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;ICR1H&#039;&#039;&#039;&amp;lt;br /&amp;gt;&#039;&#039;&#039;ICR1L&#039;&#039;&#039;&lt;br /&gt;
| Timer/Counter &#039;&#039;&#039;I&#039;&#039;&#039;nput &#039;&#039;&#039;C&#039;&#039;&#039;apture &#039;&#039;&#039;R&#039;&#039;&#039;egister Timer/Counter &#039;&#039;&#039;1&#039;&#039;&#039;&amp;lt;br /&amp;gt;&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Bit&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 7&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 6&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 5&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 4&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 2&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; | &amp;amp;nbsp;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Name&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;MSB&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ICR1&#039;&#039;&#039;&#039;&#039;&#039;H&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Name&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;LSB&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ICR1&#039;&#039;&#039;&#039;&#039;&#039;L&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;R/W&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Initialwert&#039;&#039;&#039;&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;
| 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;
| 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; | &amp;amp;nbsp;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Das Input Capture Register ist ein 16-Bit Register mit Lesezugriff. Es kann nicht beschrieben werden.&lt;br /&gt;
&lt;br /&gt;
Wenn am Input Capture Pin &#039;&#039;&#039;ICP&#039;&#039;&#039; die gemäß Einstellungen im &#039;&#039;&#039;TCCR1B&#039;&#039;&#039; definierte Flanke erkannt wird, so wird der aktuelle Inhalt des Datenregisters &#039;&#039;&#039;TCNT1H&#039;&#039;&#039;/&#039;&#039;&#039;TCNT1L&#039;&#039;&#039; sofort in dieses Register kopiert und das Input Capture Flag &#039;&#039;&#039;ICF1&#039;&#039;&#039; im Timer Interrupt Flag Register &#039;&#039;&#039;TIFR&#039;&#039;&#039; gesetzt.&lt;br /&gt;
&lt;br /&gt;
Wie bereits oben erwähnt, müssen vor dem Zugriff auf dieses Register alle Interrupts gesperrt werden. Zudem müssen Low- und Highbyte des Registers in der richtigen Reihenfolge bearbeitet werden:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;0&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| Lesen:&lt;br /&gt;
| &#039;&#039;&#039;ICR1L&#039;&#039;&#039; -&amp;gt; &#039;&#039;&#039;ICR1H&#039;&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Die PWM-Betriebsart ===&lt;br /&gt;
&lt;br /&gt;
Wenn der Timer/Counter 1 in der PWM-Betriebsart betrieben wird, so bilden das Datenregister &#039;&#039;&#039;TCNT1H&#039;&#039;&#039;/&#039;&#039;&#039;TCNT1L&#039;&#039;&#039; und das Vergleichsregister &#039;&#039;&#039;OCR1H&#039;&#039;&#039;/&#039;&#039;&#039;OCR1L&#039;&#039;&#039; einen 8-, 9- oder 10-Bit, frei laufenden PWM-Modulator, welcher als PWM-Signal am &#039;&#039;&#039;OC1&#039;&#039;&#039;-Pin (&#039;&#039;&#039;PB3&#039;&#039;&#039; beim 2313) abgegriffen werden kann. Das Datenregister &#039;&#039;&#039;TCNT1H&#039;&#039;&#039;/&#039;&#039;&#039;TCNT1L&#039;&#039;&#039; wird dabei als Auf-/Ab-Zähler betrieben, welcher von 0 an aufwärts zählt bis zur Obergrenze und danach wieder zurück auf 0.&lt;br /&gt;
Die Obergrenze ergibt sich daraus, ob 8-, 9- oder 10-Bit PWM verwendet wird, und zwar gemäß folgender Tabelle:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;Auflösung&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;Obergrenze&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Frequenz&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 8&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 255&lt;br /&gt;
| f&amp;lt;sub&amp;gt;TC1&amp;lt;/sub&amp;gt; / 510&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 9&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 511&lt;br /&gt;
| f&amp;lt;sub&amp;gt;TC1&amp;lt;/sub&amp;gt; / 1022&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 10&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1023&lt;br /&gt;
| f&amp;lt;sub&amp;gt;TC1&amp;lt;/sub&amp;gt; / 2046&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Wenn nun der Zählerwert im Datenregister den in &#039;&#039;&#039;OCR1H&#039;&#039;&#039;/&#039;&#039;&#039;OCR1L&#039;&#039;&#039; gespeicherten Wert erreicht, wird der Ausgabepin &#039;&#039;&#039;OC1&#039;&#039;&#039; gesetzt bzw. gelöscht, je nach Einstellung von &#039;&#039;&#039;COM1A1&#039;&#039;&#039; und &#039;&#039;&#039;COM1A0&#039;&#039;&#039; im &#039;&#039;&#039;TCCR1A&#039;&#039;&#039;-Register.&lt;br /&gt;
&lt;br /&gt;
Ich habe versucht, die entsprechenden Signale in der folgenden Grafik zusammenzufassen&lt;br /&gt;
&lt;br /&gt;
[[Image:PWM Theorie 3.gif]] [[Image:PWM Theorie 4.gif]]&lt;br /&gt;
&lt;br /&gt;
=== Vergleichswert-Überprüfung ===&lt;br /&gt;
&lt;br /&gt;
Hier wird in ein spezielles Vergleichswertregister (&#039;&#039;&#039;OCR1H&#039;&#039;&#039;/&#039;&#039;&#039;OCR1L&#039;&#039;&#039;) ein Wert eingeschrieben, welcher ständig mit dem aktuellen Zählerwert verglichen wird.&lt;br /&gt;
Erreicht der Zähler den in diesem Register eingetragenen Wert, so kann ein Signal (0 oder 1) am Pin &#039;&#039;&#039;OC1&#039;&#039;&#039; erzeugt und/oder ein Interrupt ausgelöst werden.&lt;br /&gt;
&lt;br /&gt;
=== Einfangen eines Eingangssignals (Input Capturing) ===&lt;br /&gt;
&lt;br /&gt;
Bei dieser Betriebsart wird an den Input Capturing Pin (ICP) des Controllers eine Signalquelle angeschlossen.&lt;br /&gt;
Nun kann je nach Konfiguration entweder ein Signalwechsel von 0 nach 1 (steigende Flanke) oder von 1 nach 0 (fallende Flanke) erkannt werden und der zu diesem Zeitpunkt aktuelle Zählerstand in ein spezielles Register abgelegt werden. Gleichzeitig kann auch ein entsprechender Interrupt ausgelöst werden.&lt;br /&gt;
Wenn die Signalquelle ein starkes Rauschen beinhaltet, kann die Rauschunterdrückung eingeschaltet werden. Dann wird beim Erkennen der konfigurierten Flanke über 4 Taktzyklen das Signal überwacht und nur dann, wenn alle 4 Messungen gleich sind, wird die entsprechende Aktion ausgelöst.&lt;br /&gt;
&lt;br /&gt;
== Gemeinsame Register ==&lt;br /&gt;
&lt;br /&gt;
Verschiedene Register beinhalten Zustände und Einstellungen, welche sowohl&lt;br /&gt;
für den 8-Bit, als auch für den 16-Bit Timer/Counter in ein und demselben&lt;br /&gt;
Register zu finden sind.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;TIMSK&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;T&#039;&#039;&#039;imer/Counter &#039;&#039;&#039;I&#039;&#039;&#039;nterrupt &#039;&#039;&#039;M&#039;&#039;&#039;a&#039;&#039;&#039;sk&#039;&#039;&#039;&lt;br /&gt;
Register&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Bit&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 7&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 6&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 5&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 4&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 2&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Name&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;TOIE1&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;OCIE1A&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;TICIE&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;TOIE0&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;R/W&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Initialwert&#039;&#039;&#039;&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;
| 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;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;TOIE1&#039;&#039;&#039; (&#039;&#039;&#039;T&#039;&#039;&#039;imer/Counter &#039;&#039;&#039;O&#039;&#039;&#039;verflow &#039;&#039;&#039;I&#039;&#039;&#039;nterrupt &#039;&#039;&#039;E&#039;&#039;&#039;nable Timer/Counter &#039;&#039;&#039;1&#039;&#039;&#039;)&lt;br /&gt;
:Wenn dieses Bit gesetzt ist, wird bei einem Überlauf des Datenregisters des Timer/Counter 1 ein Timer Overflow 1 Interrupt ausgelöst. Das Global Enable Interrupt Flag muss selbstverständlich auch gesetzt sein.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;OCIE1A&#039;&#039;&#039; (&#039;&#039;&#039;O&#039;&#039;&#039;utput &#039;&#039;&#039;C&#039;&#039;&#039;ompare Match &#039;&#039;&#039;I&#039;&#039;&#039;nterrupt &#039;&#039;&#039;E&#039;&#039;&#039;nable Timer/Counter &#039;&#039;&#039;1&#039;&#039;&#039;)&lt;br /&gt;
:Beim Timer/Counter 1 kann zusätzlich zum Überlauf ein Vergleichswert definiert werden.&lt;br /&gt;
&lt;br /&gt;
:Wenn dieses Bit gesetzt ist, wird beim Erreichen des Vergleichswertes ein Compare Match Interrupt ausgelöst. Das Global Enable Interrupt Flag muss selbstverständlich auch gesetzt sein.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;TICIE&#039;&#039;&#039; (&#039;&#039;&#039;T&#039;&#039;&#039;imer/Counter &#039;&#039;&#039;I&#039;&#039;&#039;nput &#039;&#039;&#039;C&#039;&#039;&#039;apture &#039;&#039;&#039;I&#039;&#039;&#039;nterrupt &#039;&#039;&#039;E&#039;&#039;&#039;nable)&lt;br /&gt;
:Wenn dieses Bit gesetzt ist, wird ein Capture Event Interrupt ausgelöst, wenn ein entsprechendes Signalereignis am Pin PD6(ICP) auftritt. Das Global Enable Interrupt Flag muss selbstverständlich auch gesetzt sein, wenn auch ein entsprechender Interrupt ausgelöst werden soll.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;TOIE0&#039;&#039;&#039; (&#039;&#039;&#039;T&#039;&#039;&#039;imer/Counter &#039;&#039;&#039;O&#039;&#039;&#039;verflow &#039;&#039;&#039;I&#039;&#039;&#039;nterrupt &#039;&#039;&#039;E&#039;&#039;&#039;nable Timer/Counter &#039;&#039;&#039;0&#039;&#039;&#039;)&lt;br /&gt;
:Wenn dieses Bit gesetzt ist, wird bei einem Überlauf des Datenregisters des Timer/Counter 0 ein Timer Overflow 0 Interrupt ausgelöst. Das Global Enable Interrupt Flag muss selbstverständlich auch gesetzt sein.&lt;br /&gt;
&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;TIFR&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;T&#039;&#039;&#039;imer/Counter &#039;&#039;&#039;I&#039;&#039;&#039;nterrupt &#039;&#039;&#039;F&#039;&#039;&#039;lag &#039;&#039;&#039;R&#039;&#039;&#039;egister&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Bit&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 7&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 6&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 5&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 4&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 2&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Name&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;TOV1&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;OCF1A&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ICF1&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;TOV0&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;R/W&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Initialwert&#039;&#039;&#039;&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;
| 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;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;TOV1&#039;&#039;&#039; (&#039;&#039;&#039;T&#039;&#039;&#039;imer/Counter &#039;&#039;&#039;O&#039;&#039;&#039;verflow Flag Timer/Counter &#039;&#039;&#039;1&#039;&#039;&#039;)&lt;br /&gt;
:Dieses Bit wird vom Controller gesetzt, wenn beim Timer 1 ein Überlauf des Datenregisters stattfindet.&lt;br /&gt;
&lt;br /&gt;
:In der PWM-Betriebsart wird das Bit gesetzt, wenn die Zählrichtung von auf- zu abwärts und umgekehrt geändert wird (Zählerwert = 0).&lt;br /&gt;
&lt;br /&gt;
:Das Flag wird automatisch gelöscht, wenn der zugehörige Interrupt-Vektor aufgerufen wird. Es kann jedoch auch gelöscht werden, indem eine logische 1 (!) in das entsprechende Bit geschrieben wird.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;OCF1A&#039;&#039;&#039; (&#039;&#039;&#039;O&#039;&#039;&#039;utput &#039;&#039;&#039;C&#039;&#039;&#039;ompare &#039;&#039;&#039;F&#039;&#039;&#039;lag Timer/Counter &#039;&#039;&#039;1&#039;&#039;&#039;)&lt;br /&gt;
:Dieses Bit wird gesetzt, wenn der aktuelle Wert des Datenregisters von Timer/Counter 1 mit demjenigen im Vergleichsregister &#039;&#039;&#039;OCR1&#039;&#039;&#039; übereinstimmt.&lt;br /&gt;
&lt;br /&gt;
:Das Flag wird automatisch gelöscht, wenn der zugehörige Interrupt-Vektor aufgerufen wird. Es kann jedoch auch gelöscht werden, indem eine logische 1 (!) in das entsprechende Bit geschrieben wird.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ICF1&#039;&#039;&#039; (&#039;&#039;&#039;I&#039;&#039;&#039;nput &#039;&#039;&#039;C&#039;&#039;&#039;apture &#039;&#039;&#039;F&#039;&#039;&#039;lag Timer/Counter &#039;&#039;&#039;1&#039;&#039;&#039;)&lt;br /&gt;
:Dieses Bit wird gesetzt, wenn ein Capture-Ereignis aufgetreten ist, welches anzeigt, dass der Wert des Datenregisters des  Timer/Counter 1 in das Input Capture Register ICR1 übertragen wurde.&lt;br /&gt;
&lt;br /&gt;
:Das Flag wird automatisch gelöscht, wenn der zugehörige Interrupt-Vektor aufgerufen wird. Es kann jedoch auch gelöscht werden, indem eine logische 1 (!) in das entsprechende Bit geschrieben wird.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;TOV0&#039;&#039;&#039; (&#039;&#039;&#039;T&#039;&#039;&#039;imer/Counter &#039;&#039;&#039;O&#039;&#039;&#039;verflow Flag Timer/Counter &#039;&#039;&#039;0&#039;&#039;&#039;)&lt;br /&gt;
:Dieses Bit wird vom Controller gesetzt, wenn beim Timer 0 ein Überlauf des Datenregisters stattfindet.&lt;br /&gt;
&lt;br /&gt;
:Das Flag wird automatisch gelöscht, wenn der zugehörige Interrupt-Vektor aufgerufen wird. Es kann jedoch auch gelöscht werden, indem eine logische 1 (!) in das entsprechende Bit geschrieben wird.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;amp;nbsp;&lt;br /&gt;
&lt;br /&gt;
= Warteschleifen (delay.h) =&lt;br /&gt;
&lt;br /&gt;
Der Programmablauf kann verschiedene Arten von Wartefunktionen erfordern:&lt;br /&gt;
&lt;br /&gt;
* Warten im Sinn von Zeitvertrödeln&lt;br /&gt;
* Warten auf einen bestimmten Zustand an den I/O-Pins&lt;br /&gt;
* Warten auf einen bestimmten Zeitpunkt (siehe Timer)&lt;br /&gt;
* Warten auf einen bestimmten Zählerstand (siehe Counter)&lt;br /&gt;
&lt;br /&gt;
Der einfachste Fall, das Zeitvertrödeln, kann in vielen Fällen und mit großer Genauigkeit anhand der avr-libc Bibliotheksfunktionen _delay_ms() und _delay_us() erledigt werden. Die Bibliotheksfunktionen sind einfachen Zählschleifen (Warteschleifen) vorzuziehen, da leere Zählschleifen ohne besondere Vorkehrungen sonst bei eingeschalteter Optimierung vom avr-gcc-Compiler wegoptimiert werden. Weiterhin sind die Bibliotheksfunktionen bereits darauf vorbereitet, die in F_CPU definierte Taktfrequenz zu verwenden. Ausserdem sind die Funktionen der Bibliothek wirklich getestet.&lt;br /&gt;
&lt;br /&gt;
Einfach!? Schon, aber während gewartet wird, macht der µC nichts anderes mehr. Die Wartefunktion blockiert den Programmablauf. Möchte man einerseits warten, um z.B. eine LED blinken zu lassen und gleichzeitig andere Aktionen ausführen z.B. weitere LED bedienen, sollten die Timer/Counter des AVR verwendet werden.&lt;br /&gt;
&lt;br /&gt;
Die Bibliotheksfunktionen funktionieren allerdings nur dann korrekt, wenn sie mit zur Übersetzungszeit (beim Compilieren) bekannten konstanten Werten aufgerufen werden. Der Quellcode muss mit eingeschalteter Optimierung übersetzt werden, sonst wird sehr viel Maschinencode erzeugt und die Wartezeiten stimmen nicht mehr mit dem Parameter überein.&lt;br /&gt;
&lt;br /&gt;
Abhängig von der Version der Bibliothek verhalten sich die Bibliotheksfunktionen etwas unterschiedlich.&lt;br /&gt;
&lt;br /&gt;
== avr-libc Versionen kleiner 1.6 ==&lt;br /&gt;
&lt;br /&gt;
Die Wartezeit der Funktion _delay_ms() ist auf 262,14ms/F_CPU (in MHz) begrenzt, d.h. bei 20 MHz kann man nur max. 13,1ms warten. Die Wartezeit der Funktion _delay_us() ist auf 768us/F_CPU (in MHz) begrenzt, d.h. bei 20 MHz kann man nur max. 38,4us warten. Längere Wartezeiten müssen dann über einen mehrfachen Aufruf in einer Schleife gelöst werden.&lt;br /&gt;
&lt;br /&gt;
Beispiel: Blinken einer LED an PORTB Pin PB0 im ca. 1s Rhythmus&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#ifndef F_CPU&lt;br /&gt;
/* Definiere F_CPU, wenn F_CPU nicht bereits vorher definiert &lt;br /&gt;
   (z.B. durch Übergabe als Parameter zum Compiler innerhalb &lt;br /&gt;
   des Makefiles). Zusätzlich Ausgabe einer Warnung, die auf die&lt;br /&gt;
   &amp;quot;nachträgliche&amp;quot; Definition hinweist */&lt;br /&gt;
#warning &amp;quot;F_CPU war noch nicht definiert, wird nun mit 3686400 definiert&amp;quot;&lt;br /&gt;
#define F_CPU 3686400UL     /* Quarz mit 3.6864 Mhz */&lt;br /&gt;
#endif&lt;br /&gt;
#include &amp;lt;util/delay.h&amp;gt;     /* in älteren avr-libc Versionen &amp;lt;avr/delay.h&amp;gt; */ &lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
 lange, variable Verzögerungszeit, Einheit in Millisekunden&lt;br /&gt;
&lt;br /&gt;
Die maximale Zeit pro Funktionsaufruf ist begrenzt auf &lt;br /&gt;
262.14 ms / F_CPU in MHz (im Beispiel: &lt;br /&gt;
262.1 / 3.6864 = max. 71 ms) &lt;br /&gt;
&lt;br /&gt;
Daher wird die kleine Warteschleife mehrfach aufgerufen,&lt;br /&gt;
um auf eine längere Wartezeit zu kommen. Die zusätzliche &lt;br /&gt;
Prüfung der Schleifenbedingung lässt die Wartezeit geringfügig&lt;br /&gt;
ungenau werden (macht hier vielleicht 2-3ms aus).&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
void long_delay(uint16_t ms) {&lt;br /&gt;
    for(; ms&amp;gt;0; ms--) _delay_ms(1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int main( void )&lt;br /&gt;
{&lt;br /&gt;
    DDRB = ( 1 &amp;lt;&amp;lt; PB0 );        // PB0 an PORTB als Ausgang setzen&lt;br /&gt;
&lt;br /&gt;
    while( 1 ) {                // Endlosschleife&lt;br /&gt;
        PORTB ^= ( 1 &amp;lt;&amp;lt; PB0 );  // Toggle PB0 z.B. angeschlossene LED&lt;br /&gt;
        long_delay(1000);       // Eine Sekunde warten...&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== avr-libc Versionen ab 1.6 ==&lt;br /&gt;
&lt;br /&gt;
_delay_ms() kann mit einem Argument bis 6553,5 ms (= 6,5535 Sekunden) benutzt werden. Wird die früher gültige Grenze von 262,14 ms/F_CPU (in MHz) überschritten, so arbeitet _delay_ms() einfach etwas ungenauer und zählt nur noch mit einer Auflösung von 1/10 ms. Eine Verzögerung von 1000,10 ms ließe sich nicht mehr von einer von 1000,19 ms unterscheiden. Ein Verlust, der sich im Allgemeinen verschmerzen lässt. Dem Programmierer wird keine Rückmeldung gegeben, dass die Funktion ggf. gröber arbeitet, d.h. wenn es darauf ankommt, bitte den Parameter wie bisher geschickt wählen.&lt;br /&gt;
&lt;br /&gt;
Die Funktion _delay_us() wurde ebenfalls erweitert. Wenn deren maximal als genau behandelbares Argument überschritten wird, benutzt diese intern _delay_ms(). Damit gelten in diesem Fall die _delay_ms() Einschränkungen.&lt;br /&gt;
&lt;br /&gt;
Beispiel: Blinken einer LED an PORTB Pin PB0 im ca. 1s Rhythmus, avr-libc ab Version 1.6&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#ifndef F_CPU&lt;br /&gt;
/* Definiere F_CPU, wenn F_CPU nicht bereits vorher definiert &lt;br /&gt;
   (z.B. durch Übergabe als Parameter zum Compiler innerhalb &lt;br /&gt;
   des Makefiles). Zusätzlich Ausgabe einer Warnung, die auf die&lt;br /&gt;
   &amp;quot;nachträgliche&amp;quot; Definition hinweist */&lt;br /&gt;
#warning &amp;quot;F_CPU war noch nicht definiert, wird nun mit 3686400 definiert&amp;quot;&lt;br /&gt;
#define F_CPU 3686400UL     /* Quarz mit 3.6864 Mhz */&lt;br /&gt;
#endif&lt;br /&gt;
#include &amp;lt;util/delay.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
int main( void )&lt;br /&gt;
{&lt;br /&gt;
    DDRB = ( 1 &amp;lt;&amp;lt; PB0 );        // PB0 an PORTB als Ausgang setzen&lt;br /&gt;
&lt;br /&gt;
    while( 1 ) {                // Endlosschleife&lt;br /&gt;
        PORTB ^= ( 1 &amp;lt;&amp;lt; PB0 );  // Toggle PB0 z.B. angeschlossene LED&lt;br /&gt;
        _delay_ms(1000);        // Eine Sekunde +/-1/10000 Sekunde warten...&lt;br /&gt;
                                // funktioniert nicht mit Bibliotheken vor 1.6&lt;br /&gt;
&lt;br /&gt;
    }&lt;br /&gt;
    return 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Der Watchdog =&lt;br /&gt;
&lt;br /&gt;
Und hier kommt das ultimative Mittel gegen die Unvollkommenheit von uns&lt;br /&gt;
Programmierern, der Watchdog.&lt;br /&gt;
&lt;br /&gt;
So sehr wir uns auch anstrengen, es wird uns kaum je gelingen, das absolut&lt;br /&gt;
perfekte und fehlerfreie Programm zu entwickeln.&lt;br /&gt;
&lt;br /&gt;
Der Watchdog kann uns zwar auch nicht zu besseren Programmen verhelfen aber er&lt;br /&gt;
kann dafür sorgen, dass unser Programm, wenn es sich wieder mal in&#039;s Nirwana&lt;br /&gt;
verabschiedet hat, neu gestartet wird, indem ein Reset des Controllers&lt;br /&gt;
ausgelöst wird.&lt;br /&gt;
&lt;br /&gt;
Betrachten wir doch einmal folgende Codesequenz:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
    uint8_t x;&lt;br /&gt;
&lt;br /&gt;
    x = 10;&lt;br /&gt;
&lt;br /&gt;
    while (x &amp;gt;= 0)&lt;br /&gt;
    {&lt;br /&gt;
      // tu was&lt;br /&gt;
&lt;br /&gt;
      x--;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn wir die Schleife mal genau anschauen sollte uns auffallen, dass dieselbe niemals beendet wird. Warum nicht? Ganz einfach, weil eine als &#039;&#039;&#039;&#039;&#039;unsigned&#039;&#039;&#039;&#039;&#039; deklarierte Variable niemals kleiner als Null werden kann (der Compiler sollte jedoch eine ensprechende Warnung ausgeben).&lt;br /&gt;
Das Programm würde sich also hier aufhängen und auf ewig in der Schleife drehen.&lt;br /&gt;
Und hier genau kommt der Watchdog zum Zug.&lt;br /&gt;
&lt;br /&gt;
== Wie funktioniert nun der Watchdog? ==&lt;br /&gt;
&lt;br /&gt;
Der Watchdog enthält einen separaten Timer/Counter, welcher mit einem intern erzeugten Takt von 1 MHz bei 5V Vcc getaktet wird. Einige Controller haben einen eigenen Watchdog Oszillator, z.B. der Tiny2313 mit 128kHz. Nachdem der Watchdog aktiviert und der gewünschte Vorteiler eingestellt wurde, beginnt der Counter von 0 an hochzuzählen. &lt;br /&gt;
Wenn nun die je nach Vorteiler eingestellte Anzahl Zyklen erreicht wurde, löst der Watchdog einen Reset aus. Um nun also im Normalbetrieb den Reset zu verhindern, müssen wir den Watchdog regelmäßig wieder neu starten bzw. rücksetzen (Watchdog Reset). &lt;br /&gt;
Dies sollte innerhalb unserer Hauptschleife passieren.&lt;br /&gt;
&lt;br /&gt;
Um ein unbeabsichtigtes Ausschalten des Watchdogs zu verhindern, muss ein spezielles Prozedere verwendet werden, um den WD auszuschalten. Es müssen zuerst die beiden Bits WDTOE und WDE in einer einzelnen Operation (also nicht mit sbi) auf 1 gesetzt werden. &lt;br /&gt;
Dann muss innerhalb der nächsten 4 Taktzyklen das Bit WDE auf 0 gesetzt werden.&lt;br /&gt;
&lt;br /&gt;
Das Watchdog Control Register:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;WDTCR&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;W&#039;&#039;&#039;atchog &#039;&#039;&#039;T&#039;&#039;&#039;imer&amp;amp;nbsp; &#039;&#039;&#039;C&#039;&#039;&#039;ontrol &#039;&#039;&#039;R&#039;&#039;&#039;egister&lt;br /&gt;
&lt;br /&gt;
In diesem Register stellen wir ein, wie wir den Watchdog verwenden möchten.&lt;br /&gt;
&lt;br /&gt;
Das Register ist wie folgt aufgebaut:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Bit&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 7&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 6&lt;br /&gt;
| align=&amp;amp;quot;center&amp;quot; | 5&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 4&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 2&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Name&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;WDTOE&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;WDE&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;WDP2&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;WDP1&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;WDP0&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;R/W&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Initialwert&#039;&#039;&#039;&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;
| 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;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;WDTOE&#039;&#039;&#039; (&#039;&#039;&#039;W&#039;&#039;&#039;atch&#039;&#039;&#039;d&#039;&#039;&#039;og &#039;&#039;&#039;T&#039;&#039;&#039;urn &#039;&#039;&#039;O&#039;&#039;&#039;ff &#039;&#039;&#039;E&#039;&#039;&#039;nable)&lt;br /&gt;
:Dieses Bit muss gesetzt sein, wenn das Bit &#039;&#039;&#039;WDE&#039;&#039;&#039; gelöscht wird, andernfalls wird der Watchdog nicht ausgeschaltet.&lt;br /&gt;
:Wenn das Bit einmal gesetzt ist, wird es von der Hardware nach 4 Taktzyklen automatisch wieder gelöscht.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;WDE&#039;&#039;&#039; (&#039;&#039;&#039;W&#039;&#039;&#039;atch&#039;&#039;&#039;d&#039;&#039;&#039;og &#039;&#039;&#039;E&#039;&#039;&#039;nable)&lt;br /&gt;
:Wenn dieses Bit gesetzt wird, so wird der Watchdog aktiviert.&lt;br /&gt;
:Das Bit kann nur gelöscht werden, solange das Bit &#039;&#039;&#039;WDTOE&#039;&#039;&#039; auf 1 steht.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;WDP2&#039;&#039;&#039;, &#039;&#039;&#039;WDP1&#039;&#039;&#039;, &#039;&#039;&#039;WDP0&#039;&#039;&#039; (&#039;&#039;&#039;W&#039;&#039;&#039;atch&#039;&#039;&#039;d&#039;&#039;&#039;og Timer &#039;&#039;&#039;P&#039;&#039;&#039;rescaler Bits)&lt;br /&gt;
:Diese 3 Bits bestimmen die Anzahl Oszillatorzyklen für den Watchdog, also, wie lange es dauert, bis ein Reset ausgelöst wird:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | WDP2&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | WDP1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | WDP0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | Anzahl Zyklen&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | Typ. Timeoutzeit bei Vcc = 3V&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | Typ. Timeoutzeit bei Vcc = 5V&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;
| align=&amp;quot;center&amp;quot; | 16K&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 47ms&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 15ms&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;
| align=&amp;quot;center&amp;quot; | 32K&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 94ms&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 30ms&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;
| align=&amp;quot;center&amp;quot; | 64K&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0.19s&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 60ms&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;
| align=&amp;quot;center&amp;quot; | 128K&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0.38s&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0.12s&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;
| align=&amp;quot;center&amp;quot; | 256K&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0.75s&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0.24s&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;
| align=&amp;quot;center&amp;quot; | 512K&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1.5s&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0.49s&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;
| align=&amp;quot;center&amp;quot; | 1024K&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3s&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0.97s&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;
| align=&amp;quot;center&amp;quot; | 2048K&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 6s&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1.9s&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Um den Watchdog mit dem AVR-GCC Compiler zu verwenden, muss die Headerdatei &#039;&#039;wdt.h&#039;&#039; (&#039;&#039;#include &amp;lt;avr/wdt.h&amp;gt;&#039;&#039;) in die Quelldatei eingebunden werden. &lt;br /&gt;
&amp;lt;!-- mt: das stimmt wohl nicht mehr?!:&lt;br /&gt;
Dadurch wird auch der Startup-Code entsprechend angepasst, so dass der Watchdog nach einem Reset automatisch gestartet wird. &lt;br /&gt;
Das WDTCR-Register wird dabei mit dem Wert 0 beschrieben. &lt;br /&gt;
Falls ein anderer Wert gewünscht ist, so kann dies im Makfile in den Linker-Optionen eingetragen werden. &lt;br /&gt;
Dazu muss in der Zeile LDFLAGS folgende Option angefügt werden:&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; --defsym __init_wdtcr__=0x1f&amp;lt;br /&amp;gt;&lt;br /&gt;
wenn beispielsweise der Wert des Registers auf 0x1f gestellt werden soll.&amp;lt;br /&amp;gt; --&amp;gt;&lt;br /&gt;
Danach können die folgenden Funktionen verwendet werden:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;wdt_enable(uint8_t timeout)&#039;&#039;&#039;&lt;br /&gt;
:Aktiviert den Watchdog und stellt den Vorteiler auf den gewünschten Wert ein bzw. der in timeout übergebene Wert wird in das WDTCR-Register eingetragen. Einige Timeout-Werte sind als Konstanten vordefiniert&lt;br /&gt;
:Mögliche Timeoutwerte:&lt;br /&gt;
&amp;lt;div align=&amp;quot;center&amp;quot;&amp;gt;&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
! Konstante&lt;br /&gt;
! Wert&lt;br /&gt;
! TimeOut&lt;br /&gt;
|- &lt;br /&gt;
| WDTO_15MS   &lt;br /&gt;
| 0&lt;br /&gt;
| 15 ms&lt;br /&gt;
|-&lt;br /&gt;
| WDTO_30MS   &lt;br /&gt;
| 1&lt;br /&gt;
| 30 ms&lt;br /&gt;
|-&lt;br /&gt;
| WDTO_60MS   &lt;br /&gt;
| 2&lt;br /&gt;
| 60 ms&lt;br /&gt;
|-&lt;br /&gt;
| WDTO_120MS   &lt;br /&gt;
| 3&lt;br /&gt;
| 120 ms&lt;br /&gt;
|-&lt;br /&gt;
| WDTO_250MS   &lt;br /&gt;
| 4&lt;br /&gt;
| 250 ms&lt;br /&gt;
|-&lt;br /&gt;
| WDTO_500MS   &lt;br /&gt;
| 5&lt;br /&gt;
| 500 ms&lt;br /&gt;
|-&lt;br /&gt;
| WDTO_1S   &lt;br /&gt;
| 6&lt;br /&gt;
| 1 s&lt;br /&gt;
|-&lt;br /&gt;
| WDTO_2S   &lt;br /&gt;
| 7&lt;br /&gt;
| 2 s&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;wdt_disable()&#039;&#039;&#039;&lt;br /&gt;
:Mit dieser Funktion kann der Watchdog ausgeschaltet werden. Dabei wird das notwendige Prozedere, wie oben beschrieben, automatisch ausgeführt.&lt;br /&gt;
* &#039;&#039;&#039;wdt_reset()&#039;&#039;&#039;&lt;br /&gt;
:Dies ist wohl die wichtigste der Watchdog-Funktionen. Sie erzeugt einen Watchdog-Reset, welcher periodisch, und zwar vor Ablauf der Timeoutzeit, ausgeführt werden muss, damit der Watchdog nicht den AVR zurücksetzt.&lt;br /&gt;
&lt;br /&gt;
Selbstverständlich kann das &#039;&#039;&#039;WDTCR&#039;&#039;&#039;-Register auch mit den uns bereits bekannten Funktionen für den Zugriff auf Register programmiert werden.&lt;br /&gt;
&lt;br /&gt;
== Watchdog-Anwendungshinweise ==&lt;br /&gt;
&lt;br /&gt;
Ob nun der Watchdog als Schutzfunktion überhaupt verwendet werden soll, hängt stark von der Anwendung, der genutzten Peripherie und dem Umfang und der Qualitätssicherung des Codes ab. Will man sicher gehen, dass ein Programm sich nicht in einer Endlosschleife verfängt, ist der Wachdog das geeignete Mittel dies zu verhindern. Weiterhin kann bei geschickter Programmierung der Watchdog dazu genutzt werden, bestimmte Stromsparfunktionen zu implementieren. Bei einigen neueren AVRs (z.B. dem ATTiny13) kann der Watchdog auch direkt als Timer genutzt werden, der den Controller aus einem Schlafmodus aufweckt. Auch dies kann im &#039;&#039;&#039;WDTCR&#039;&#039;&#039;-Register eingestellt werden. Außerdem bietet der WD die einzige Möglichkeit einen beabsichtigten System-Reset (ein &amp;quot;richtiger Reset&amp;quot;, kein &amp;quot;jmp 0x0000&amp;quot;) ohne externe Beschaltung auszulösen, was z.B. bei der Implementierung eines Bootloaders nützlich ist. Bei bestimmten Anwendungen kann die Nutzung des WD als &amp;quot;ultimative Deadlock-Sicherung für nicht bedachte Zustände&amp;quot; natürlich immer als zusätzliche Sicherung dienen. &lt;br /&gt;
&lt;br /&gt;
Es besteht die Möglichkeit herauszufinden, ob ein Reset durch den Watchdog ausgelöst wurde (beim ATmega16 z.B. Bit WDRF in MCUCSR). Diese Information sollte auch genutzt werden, falls ein WD-Reset in der Anwendung nicht planmäßig implementiert wurde. Zum Beispiel kann man eine LED an einen freien Pin hängen, die nur bei einem Reset durch den WD aufleuchtet oder aber das &amp;quot;Ereignis WD-Reset&amp;quot; im internen EEPROM des AVR absichern, um die Information später z.B. über UART oder ein Display auszugeben (oder einfach den EEPROM-Inhalt über die ISP/JTAG-Schnittstelle auslesen).&lt;br /&gt;
&lt;br /&gt;
Siehe auch: &lt;br /&gt;
* [http://www.nongnu.org/avr-libc/user-manual/index.html Dokumentation der avr-libc] Abschnitt Modules/Watchdog timer handling&lt;br /&gt;
* [http://www.mikrocontroller.net/topic/77273#642501 Bug in ATtiny2313?]&lt;br /&gt;
&lt;br /&gt;
= Programmieren mit Interrupts =&lt;br /&gt;
&lt;br /&gt;
Nachdem wir nun alles Wissenswerte für die serielle Programmerstellung&lt;br /&gt;
gelernt haben nehmen wir jetzt ein völlig anderes Thema in Angriff, nämlich&lt;br /&gt;
die Programmierung unter Zuhilfenahme der Interrupts des AVR.&lt;br /&gt;
&lt;br /&gt;
Als erstes wollen wir uns noch einmal den allgemeinen Programmablauf bei der&lt;br /&gt;
Interrupt-Programmierung zu Gemüte führen.&lt;br /&gt;
&lt;br /&gt;
[[Image:Interrupt Programme.gif]]&lt;br /&gt;
&lt;br /&gt;
Man sieht, dass die Interruptroutine quasi parallel zum Hauptprogramm&lt;br /&gt;
abläuft. Da wir nur eine CPU haben ist es natürlich keine echte Parallelität,&lt;br /&gt;
sondern das Hauptprogramm wird beim Eintreffen eines Interrupts unterbrochen,&lt;br /&gt;
die Interruptroutine wird ausgeführt und danach erst wieder zum Hauptprogramm&lt;br /&gt;
zurückgekehrt.&lt;br /&gt;
&lt;br /&gt;
[http://www.mikrocontroller.net/forum/read-1-235092.html#new Ausführlicher Thread im Forum]&lt;br /&gt;
&lt;br /&gt;
== Anforderungen an Interrupt-Routinen ==&lt;br /&gt;
&lt;br /&gt;
Um unliebsamen Überraschungen vorzubeugen, sollten einige Grundregeln bei der Implementierung der Interruptroutinen beachtet werden. Interruptroutinen soll möglichst kurz und schnell abarbeitbar sein, daraus folgt:&lt;br /&gt;
&lt;br /&gt;
* Keine umfangreichen Berechnungen innerhalb der Interruptroutine. (*)&lt;br /&gt;
* Keine langen Programmschleifen.&lt;br /&gt;
* Obwohl es möglich ist, während der Abarbeitung einer Interruptroutine andere oder sogar den gleichen Interrupt wieder zuzulassen, wird davon ohne genaue Kenntnis der internen Abläufe dringend abgeraten.&lt;br /&gt;
&lt;br /&gt;
Interruptroutinen (ISRs) sollten also möglichst kurz sein und keine Schleifen mit vielen Durchläufen enthalten. Längere Operationen können meist in einen &amp;quot;Interrupt-Teil&amp;quot; in einer ISR und einen &amp;quot;Arbeitsteil&amp;quot; im Hauptprogramm aufgetrennt werden. Z.B. Speichern des Zustands aller Eingänge im EEPROM in bestimmten Zeitabständen: ISR-Teil: Zeitvergleich (Timer,RTC) mit Logzeit/-intervall. Bei Übereinstimmung ein globales Flag setzen (volatile bei Flag-Deklaration nicht vergessen, s.u.). Dann im Hauptprogramm prüfen, ob das Flag gesetzt ist. Wenn ja: die Daten im EEPROM ablegen und Flag löschen.&lt;br /&gt;
&lt;br /&gt;
(*)&lt;br /&gt;
Hinweis: &lt;br /&gt;
Es gibt allerdings die seltene Situation, dass man gerade eingelesene&lt;br /&gt;
ADC-Werte sofort verarbeiten muss. Besonders dann, wenn man mehrere Werte sehr&lt;br /&gt;
schnell hintereinander bekommt. Dann bleibt einem nichts anderes übrig, als die&lt;br /&gt;
Werte noch in der ISR zu verarbeiten. Kommt aber sehr selten vor und sollte&lt;br /&gt;
durch geeignete Wahl des Systemtaktes bzw. Auswahl des Controllers vermieden werden!&lt;br /&gt;
&lt;br /&gt;
== Interrupt-Quellen ==&lt;br /&gt;
&lt;br /&gt;
Die folgenden Ereignisse können einen Interrupt auf einem AVR AT90S2313 auslösen, wobei die Reihenfolge der Auflistung auch die Priorität der Interrupts aufzeigt.&lt;br /&gt;
&lt;br /&gt;
* Reset&lt;br /&gt;
* Externer Interrupt 0&lt;br /&gt;
* Externer Interrupt 1&lt;br /&gt;
* Timer/Counter 1 Capture Ereignis&lt;br /&gt;
* Timer/Counter 1 Compare Match&lt;br /&gt;
* Timer/Counter 1 Überlauf&lt;br /&gt;
* Timer/Counter 0 Überlauf&lt;br /&gt;
* UART Zeichen empfangen&lt;br /&gt;
* UART Datenregister leer&lt;br /&gt;
* UART Zeichen gesendet&lt;br /&gt;
* Analoger Komparator&lt;br /&gt;
&lt;br /&gt;
Die Anzahl der möglichen Interruptquellen variiert zwischen den verschiedenen Typen. Im Zweifel hilft ein Blick ins Datenblatt (&amp;quot;Interrupt Vectors&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
== Register ==&lt;br /&gt;
&lt;br /&gt;
Der AT90S2313 verfügt über 2 Register die mit den&lt;br /&gt;
Interrupts zusammen hängen.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;GIMSK&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;G&#039;&#039;&#039;eneral &#039;&#039;&#039;I&#039;&#039;&#039;nterrupt &#039;&#039;&#039;M&#039;&#039;&#039;ask &#039;&#039;&#039;R&#039;&#039;&#039;egister.&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Bit&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 7&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 6&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 5&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 4&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 2&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Name&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;INT1&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;INT0&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;R/W&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Initialwert&#039;&#039;&#039;&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;
| 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;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;INT1&#039;&#039;&#039; (External &#039;&#039;&#039;Int&#039;&#039;&#039;errupt Request &#039;&#039;&#039;1&#039;&#039;&#039; Enable)&lt;br /&gt;
:Wenn dieses Bit gesetzt ist, wird ein Interrupt ausgelöst, wenn am &#039;&#039;&#039;INT1&#039;&#039;&#039;-Pin eine steigende oder fallende (je nach Konfiguration im &#039;&#039;&#039;MCUCR&#039;&#039;&#039;) Flanke erkannt wird.&lt;br /&gt;
:Das Global Enable Interrupt Flag muss selbstverständlich auch gesetzt sein.&lt;br /&gt;
:Der Interrupt wird auch ausgelöst, wenn der Pin als Ausgang geschaltet ist. Auf diese Weise bietet sich die Möglichkeit, Software-Interrupts zu realisieren.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;INT0&#039;&#039;&#039; (External &#039;&#039;&#039;Int&#039;&#039;&#039;errupt Request &#039;&#039;&#039;0&#039;&#039;&#039; Enable)&lt;br /&gt;
:Wenn dieses Bit gesetzt ist, wird ein Interrupt ausgelöst, wenn am &#039;&#039;&#039;INT0&#039;&#039;&#039;-Pin eine steigende oder fallende (je nach Konfiguration im &#039;&#039;&#039;MCUCR&#039;&#039;&#039;) Flanke erkannt wird.&lt;br /&gt;
:Das Global Enable Interrupt Flag muss selbstverständlich auch gesetzt sein.&lt;br /&gt;
:Der Interrupt wird auch ausgelöst, wenn der Pin als Ausgang geschaltet ist. Auf diese Weise bietet sich die Möglichkeit, Software-Interrupts zu realisieren.&lt;br /&gt;
&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;GIFR&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;G&#039;&#039;&#039;eneral &#039;&#039;&#039;I&#039;&#039;&#039;nterrupt &#039;&#039;&#039;F&#039;&#039;&#039;lag &#039;&#039;&#039;R&#039;&#039;&#039;egister.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Bit&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 7&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 6&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 5&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 4&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 2&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Name&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;INTF1&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;INTF0&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;R/W&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Initialwert&#039;&#039;&#039;&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;
| 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;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;INTF1&#039;&#039;&#039; (External &#039;&#039;&#039;Int&#039;&#039;&#039;errupt Flag &#039;&#039;&#039;1&#039;&#039;&#039;)&lt;br /&gt;
:Dieses Bit wird gesetzt, wenn am &#039;&#039;&#039;INT1&#039;&#039;&#039;-Pin eine Interrupt-Kondition, entsprechend der Konfiguration, erkannt wird. Wenn das Global Enable Interrupt Flag gesetzt ist, wird die Interruptroutine angesprungen.&lt;br /&gt;
:Das Flag wird automatisch gelöscht, wenn die Interruptroutine beendet ist. Alternativ kann das Flag gelöscht werden, indem der Wert &#039;&#039;&#039;1(!)&#039;&#039;&#039; eingeschrieben wird.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;INTF0&#039;&#039;&#039; (External &#039;&#039;&#039;Int&#039;&#039;&#039;errupt Flag &#039;&#039;&#039;0&#039;&#039;&#039;)&lt;br /&gt;
:Dieses Bit wird gesetzt, wenn am &#039;&#039;&#039;INT0&#039;&#039;&#039;-Pin eine Interrupt-Kondition, entsprechend der Konfiguration, erkannt wird. Wenn das Global Enable Interrupt Flag gesetzt ist, wird die Interruptroutine angesprungen.&lt;br /&gt;
:Das Flag wird automatisch gelöscht, wenn die Interruptroutine beendet ist. Alternativ kann das Flag gelöscht werden, indem der Wert &#039;&#039;&#039;1(!)&#039;&#039;&#039; eingeschrieben wird.&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;MCUCR&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;MCU&#039;&#039;&#039; &#039;&#039;&#039;C&#039;&#039;&#039;ontrol &#039;&#039;&#039;R&#039;&#039;&#039;egister.&lt;br /&gt;
&lt;br /&gt;
Das MCU Control Register enthält Kontrollbits für allgemeine&lt;br /&gt;
MCU-Funktionen.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Bit&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 7&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 6&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 5&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 4&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 2&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Name&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;SE&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;SM&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ISC11&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ISC10&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ISC01&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ISC00&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;R/W&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Initialwert&#039;&#039;&#039;&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;
| 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;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;SE&#039;&#039;&#039; (&#039;&#039;&#039;S&#039;&#039;&#039;leep &#039;&#039;&#039;E&#039;&#039;&#039;nable)&lt;br /&gt;
:Dieses Bit muss gesetzt sein, um den Controller mit dem &#039;&#039;&#039;SLEEP&#039;&#039;&#039;-Befehl in den Schlafzustand versetzen zu können.&lt;br /&gt;
:Um den Schlafmodus nicht irrtümlich einzuschalten, wird empfohlen, das Bit erst unmittelbar vor Ausführung des &#039;&#039;&#039;SLEEP&#039;&#039;&#039;-Befehls zu setzen.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;SM&#039;&#039;&#039; (&#039;&#039;&#039;S&#039;&#039;&#039;leep &#039;&#039;&#039;M&#039;&#039;&#039;ode)&lt;br /&gt;
:Dieses Bit bestimmt der Schlafmodus.&lt;br /&gt;
:Ist das Bit gelöscht, so wird der &#039;&#039;&#039;Idle&#039;&#039;&#039;-Modus ausgeführt. Ist das Bit gesetzt, so wird der &#039;&#039;&#039;Power-Down&#039;&#039;&#039;-Modus ausgeführt. (für andere AVR Controller siehe Abschnitt &amp;quot;Sleep-Mode&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ISC11&#039;&#039;&#039;, &#039;&#039;&#039;ISC10&#039;&#039;&#039; (&#039;&#039;&#039;I&#039;&#039;&#039;nterrupt &#039;&#039;&#039;S&#039;&#039;&#039;ense &#039;&#039;&#039;C&#039;&#039;&#039;ontrol &#039;&#039;&#039;1&#039;&#039;&#039; Bits)&lt;br /&gt;
:Diese beiden Bits bestimmen, ob die steigende oder die fallende Flanke für die Interrupterkennung am &#039;&#039;&#039;INT1&#039;&#039;&#039;-Pin ausgewertet wird.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ISC11&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ISC10&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Bedeutung&#039;&#039;&#039;&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;
| Low Level an &#039;&#039;&#039;INT1&#039;&#039;&#039; erzeugt einen Interrupt.&lt;br /&gt;
&lt;br /&gt;
In der Beschreibung heißt es, der Interrupt wird getriggert, solange der Pin auf 0 bleibt, also eigentlich unbrauchbar.&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;
| Reserviert&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;
| Die fallende Flanke an &#039;&#039;&#039;INT1&#039;&#039;&#039; erzeugt einen Interrupt.&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;
| Die steigende Flanke an &#039;&#039;&#039;INT1&#039;&#039;&#039; erzeugt einen Interrupt.&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;ISC01&#039;&#039;&#039;, &#039;&#039;&#039;ISC00&#039;&#039;&#039; (&#039;&#039;&#039;I&#039;&#039;&#039;nterrupt &#039;&#039;&#039;S&#039;&#039;&#039;ense &#039;&#039;&#039;C&#039;&#039;&#039;ontrol &#039;&#039;&#039;0&#039;&#039;&#039; Bits)&lt;br /&gt;
:Diese beiden Bits bestimmen, ob die steigende oder die fallende Flanke für die Interrupterkennung am &#039;&#039;&#039;INT0&#039;&#039;&#039;-Pin ausgewertet wird.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ISC01&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ISC00&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Bedeutung&#039;&#039;&#039;&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;
| Low Level an &#039;&#039;&#039;INT0&#039;&#039;&#039; erzeugt einen Interrupt.&lt;br /&gt;
&lt;br /&gt;
In der Beschreibung heißt es, der Interrupt wird getriggert, solange der Pin auf 0 bleibt, also eigentlich unbrauchbar.&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;
| Reserviert&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;
| Die fallende Flanke an &#039;&#039;&#039;INT0&#039;&#039;&#039; erzeugt einen Interrupt.&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;
| Die steigende Flanke an &#039;&#039;&#039;INT0&#039;&#039;&#039; erzeugt einen Interrupt.&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Allgemeines über die Interrupt-Abarbeitung ==&lt;br /&gt;
&lt;br /&gt;
Wenn ein Interrupt eintrifft, wird automatisch das &#039;&#039;&#039;Global Interrupt Enable&#039;&#039;&#039; Bit im Status Register &#039;&#039;&#039;SREG&#039;&#039;&#039; gelöscht und alle weiteren Interrupts unterbunden. Obwohl es möglich ist, zu diesem Zeitpunkt bereits wieder das GIE-bit zu setzen, rate ich dringend davon ab. Dieses wird nämlich automatisch gesetzt, wenn die Interruptroutine beendet wird. Wenn in der Zwischenzeit weitere Interrupts eintreffen, werden die zugehörigen Interrupt-Bits gesetzt und die Interrupts bei Beendigung der laufenden Interrupt-Routine in der Reihenfolge ihrer Priorität ausgeführt. Dies kann&lt;br /&gt;
eigentlich nur dann zu Problemen führen, wenn ein hoch priorisierter Interrupt ständig und in kurzer Folge auftritt. Dieser sperrt dann möglicherweise alle anderen Interrupts mit niedrigerer Priorität. Dies ist einer der Gründe, weshalb die Interrupt-Routinen sehr kurz gehalten werden sollen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- === Das Status-Register ===&lt;br /&gt;
&lt;br /&gt;
Es gilt auch zu beachten, dass das Status-Register während der Abarbeitung einer Interruptroutine nicht automatisch gesichert wird. Falls notwendig, muss dies vom Programmierer selber vorgesehen werden. --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Interrupts mit dem AVR GCC Compiler (WinAVR) ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- Selbstverständlich können alle interruptspezifischen Registerzugriffe wie gewohnt über I/O-Adressierung vorgenommen werden. Etwas einfacher geht es jedoch, wenn wir die vom Compiler zur Verfügung gestellten Mittel einsetzen.--&amp;gt;&lt;br /&gt;
Funktionen zur Interrupt-Verarbeitung werden in den Includedateien &#039;&#039;interrupt.h&#039;&#039;  der avr-libc zur Verfügung gestellt (bei älterem Quellcode zusätzlich &#039;&#039;signal.h&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
// fuer sei(), cli() und ISR():&lt;br /&gt;
#include &amp;lt;avr/interrupt.h&amp;gt;&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Makro &#039;&#039;&#039;sei()&#039;&#039;&#039; schaltet die Interrupts ein. Eigentlich wird nichts anderes gemacht, als das &#039;&#039;&#039;Global Interrupt Enable&#039;&#039;&#039; Bit im Status Register gesetzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
    sei();&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Makro &#039;&#039;&#039;cli()&#039;&#039;&#039; schaltet die Interrupts aus, oder anders gesagt, das &#039;&#039;&#039;Global Interrupt Enable&#039;&#039;&#039; Bit im Status Register wird gelöscht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
    cli();&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Oft steht man vor der Aufgabe, dass eine Codesequenz nicht unterbrochen werden darf. Es liegt dann nahe, zu Beginn dieser Sequenz ein cli() und am Ende ein sei() einzufügen. Dies ist jedoch ungünstig, wenn die Interrupts vor Aufruf der Sequenz deaktiviert waren und danach auch weiterhin deaktiviert bleiben sollen. Ein sei() würde ungeachtet des vorherigen  Zustands die Interrups aktivieren, was zu unerwünschten Seiteneffekten führen kann. Die aus dem folgenden Beispiel ersichtliche Vorgehensweise ist in solchen Fällen vorzuziehen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/interrupt.h&amp;gt;&lt;br /&gt;
#include &amp;lt;inttypes.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
void NichtUnterbrechenBitte(void)&lt;br /&gt;
{&lt;br /&gt;
   uint8_t tmp_sreg;  // temporaerer Speicher fuer das Statusregister&lt;br /&gt;
&lt;br /&gt;
   tmp_sreg = SREG;   // Statusregister (also auch das I-Flag darin) sichern&lt;br /&gt;
   cli();             // Interrupts global deaktivieren&lt;br /&gt;
&lt;br /&gt;
   /* hier &amp;quot;unterbrechnungsfreier&amp;quot; Code */&lt;br /&gt;
&lt;br /&gt;
   /* Beispiel Anfang&lt;br /&gt;
     JTAG-Interface eines ATmega16 per Software deaktivieren &lt;br /&gt;
     und damit die JTAG-Pins an PORTC für &amp;quot;general I/O&amp;quot; nutzbar machen&lt;br /&gt;
     ohne die JTAG-Fuse-Bit zu aendern. Dazu ist eine &amp;quot;timed sequence&amp;quot;&lt;br /&gt;
     einzuhalten (vgl Datenblatt ATmega16, Stand 10/04, S. 229): &lt;br /&gt;
     Das JTD-Bit muss zweimal innerhalb von 4 Taktzyklen geschrieben &lt;br /&gt;
     werden. Ein Interrupt zwischen den beiden Schreibzugriffen wuerde &lt;br /&gt;
     die erforderliche Sequenz &amp;quot;brechen&amp;quot;, das JTAG-Interface bliebe&lt;br /&gt;
     weiterhin aktiv und die IO-Pins weiterhin für JTAG reserviert. */&lt;br /&gt;
&lt;br /&gt;
   MCUCSR |= (1&amp;lt;&amp;lt;JTD);&lt;br /&gt;
   MCUCSR |= (1&amp;lt;&amp;lt;JTD); // 2 mal in Folge ,vgl. Datenblatt fuer mehr Information&lt;br /&gt;
&lt;br /&gt;
   /* Beispiel Ende */&lt;br /&gt;
  &lt;br /&gt;
   SREG = tmp_sreg;     // Status-Register wieder herstellen &lt;br /&gt;
                      // somit auch das I-Flag auf gesicherten Zustand setzen&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void NichtSoGut(void)&lt;br /&gt;
{&lt;br /&gt;
   cli();&lt;br /&gt;
   &lt;br /&gt;
   /* hier &amp;quot;unterbrechnungsfreier&amp;quot; Code */&lt;br /&gt;
   &lt;br /&gt;
   sei();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
int main(void)&lt;br /&gt;
{&lt;br /&gt;
   //...&lt;br /&gt;
&lt;br /&gt;
   cli();  &lt;br /&gt;
   // Interrupts global deaktiviert &lt;br /&gt;
&lt;br /&gt;
   NichtUnterbrechenBitte();&lt;br /&gt;
   // auch nach Aufruf der Funktion deaktiviert&lt;br /&gt;
&lt;br /&gt;
   sei();&lt;br /&gt;
   // Interrupts global aktiviert &lt;br /&gt;
&lt;br /&gt;
   NichtUnterbrechenBitte();&lt;br /&gt;
   // weiterhin aktiviert&lt;br /&gt;
   //...&lt;br /&gt;
&lt;br /&gt;
   /* Verdeutlichung der unguenstigen Vorgehensweise mit cli/sei: */&lt;br /&gt;
   cli();  &lt;br /&gt;
   // Interrupts jetzt global deaktiviert &lt;br /&gt;
&lt;br /&gt;
   NichtSoGut();&lt;br /&gt;
   // nach Aufruf der Funktion sind Interrupts global aktiviert &lt;br /&gt;
   // dies ist mglw. ungewollt!&lt;br /&gt;
   //...&lt;br /&gt;
   &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- mt: besser so nicht(?), lieber &amp;quot;datenblattkonform&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;font face=&amp;quot;Courier New&amp;quot;&amp;gt;&#039;&#039;&#039;timer_enable_int (unsigned char ints);&amp;lt;br /&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;/font&amp;gt;Schaltet Timerbezogene Interrupts ein bzw. aus.&amp;lt;br /&amp;gt;&lt;br /&gt;
Wenn als Argument &#039;&#039;&#039;ints&#039;&#039;&#039; der Wert 0 übergeben wird so werden alle&lt;br /&gt;
Timerinterrupts ausgeschaltet, ansonsten muss in &#039;&#039;&#039;ints&#039;&#039;&#039; angegeben werden,&lt;br /&gt;
welche Interrupts zu aktivieren sind. Dabei müssen einfach die entsprechend zu&lt;br /&gt;
setzenden Bits definiert werden.&amp;lt;br /&amp;gt;&lt;br /&gt;
Beispiel: &#039;&#039;&#039;&amp;lt;font face=&amp;quot;Courier New&amp;quot;&amp;gt;timer_enable_int (1 &amp;lt;&amp;lt; TOIE1));&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;/font&amp;gt;&#039;&#039;&#039;Achtung: Wenn ein Timerinterrupt eingeschaltet wird während ein&lt;br /&gt;
anderer Timerinterrupt bereits läuft, dann müssen beide Bits angegeben werden&lt;br /&gt;
sonst wird der andere Timerinterrupt versehentlich ausgeschaltet.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;font face=&amp;quot;Courier New&amp;quot;&amp;gt;&#039;&#039;&#039;enable_external_int (unsigned char ints);&amp;lt;br /&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;/font&amp;gt;Schaltet die externen Interrupts ein bzw. aus.&amp;lt;br /&amp;gt;&lt;br /&gt;
Wenn als Argument &#039;&#039;&#039;ints&#039;&#039;&#039; der Wert 0 übergeben wird so werden alle externen&lt;br /&gt;
Interrrups ausgeschaltet, ansonsten muss in &#039;&#039;&#039;ints&#039;&#039;&#039; angegeben werden, welche&lt;br /&gt;
Interrupts zu aktivieren sind. Dabei müssen einfach die entsprechend zu&lt;br /&gt;
setzenden Bits definiert werden.&amp;lt;br /&amp;gt;&lt;br /&gt;
Beispiel: &#039;&#039;&#039;&amp;lt;font face=&amp;quot;Courier New&amp;quot;&amp;gt;enable_external_int ((1&amp;lt;&lt;br /&gt;
&amp;lt;/font&amp;gt;&#039;&#039;&#039;Schaltet die externen Interrupts 0 und 1 ein.&lt;br /&gt;
&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nachdem nun die Interrupts aktiviert sind, braucht es selbstverständlich noch den auszuführenden Code, der ablaufen soll, wenn ein Interrupt eintrifft. Dazu existiert die Definition (ein Makro) &#039;&#039;&#039;ISR&#039;&#039;&#039;. SIGNAL sollte nicht mehr genutzt werden, zur Portierung von SIGNAL nach ISR siehe Abschnitt (TODO: verlinken) im Anhang.&lt;br /&gt;
&amp;lt;!--Dazu gibt es zwei Definitionen: &#039;&#039;&#039;SIGNAL&#039;&#039;&#039; und &#039;&#039;&#039;INTERRUPT&#039;&#039;&#039;, welche allerdings AVR-GCC spezifisch sind und bei anderen Compilern womöglich anders heissen können.--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== ISR ===&lt;br /&gt;
&lt;br /&gt;
(&#039;&#039;ISR()&#039;&#039; ersetzt bei neueren Versionen der avr-libc &#039;&#039;SIGNAL()&#039;&#039;. vgl. [[AVR-GCC-Tutorial#Anhang|Anhang]])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/signal.h&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
SIGNAL (siglabel)&lt;br /&gt;
{&lt;br /&gt;
    /* Interrupt Code */&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/interrupt.h&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
ISR(Vectorname) /* vormals: SIGNAL(siglabel) dabei Vectorname != siglabel ! */&lt;br /&gt;
{&lt;br /&gt;
    /* Interrupt Code */&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;ISR&#039;&#039; wird eine Funktion für die Bearbeitung eines Interrupts eingeleitet. Als Argument muss dabei die Benennung des entsprechenden Interruptvektors angegeben werden. Diese sind in den jeweiligen Includedateien IOxxxx.h zu finden. Die Bezeichnung entspricht dem Namen aus dem Datenblatt, bei dem die Leerzeichen durch Unterstriche ersetzt sind und ein &#039;&#039;_vect&#039;&#039; angehängt ist.&lt;br /&gt;
&lt;br /&gt;
Als Beispiel ein Ausschnitt aus der Datei für den ATmega8 (bei WinAVR Standardinstallation in C:\WinAVR\avr\include\avr\iom8.h) in der neben den aktuellen Namen für &#039;&#039;ISR&#039;&#039; (*_vect) noch die Bezeichnungen für das inzwischen nicht mehr aktuelle &#039;&#039;SIGNAL&#039;&#039; (SIG_*) enthalten sind.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
/* $Id: iom8.h,v 1.13 2005/10/30 22:11:23 joerg_wunsch Exp $ */&lt;br /&gt;
&lt;br /&gt;
/* avr/iom8.h - definitions for ATmega8 */&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
/* Interrupt vectors */&lt;br /&gt;
&lt;br /&gt;
/* External Interrupt Request 0 */&lt;br /&gt;
#define INT0_vect                       _VECTOR(1)&lt;br /&gt;
#define SIG_INTERRUPT0                  _VECTOR(1)&lt;br /&gt;
&lt;br /&gt;
/* External Interrupt Request 1 */&lt;br /&gt;
#define INT1_vect                       _VECTOR(2)&lt;br /&gt;
#define SIG_INTERRUPT1                  _VECTOR(2)&lt;br /&gt;
&lt;br /&gt;
/* Timer/Counter2 Compare Match */&lt;br /&gt;
#define TIMER2_COMP_vect                _VECTOR(3)&lt;br /&gt;
#define SIG_OUTPUT_COMPARE2             _VECTOR(3)&lt;br /&gt;
&lt;br /&gt;
/* Timer/Counter2 Overflow */&lt;br /&gt;
#define TIMER2_OVF_vect                 _VECTOR(4)&lt;br /&gt;
#define SIG_OVERFLOW2                   _VECTOR(4)&lt;br /&gt;
&lt;br /&gt;
/* Timer/Counter1 Capture Event */&lt;br /&gt;
#define TIMER1_CAPT_vect                _VECTOR(5)&lt;br /&gt;
#define SIG_INPUT_CAPTURE1              _VECTOR(5)&lt;br /&gt;
&lt;br /&gt;
/* Timer/Counter1 Compare Match A */&lt;br /&gt;
#define TIMER1_COMPA_vect               _VECTOR(6)&lt;br /&gt;
#define SIG_OUTPUT_COMPARE1A            _VECTOR(6)&lt;br /&gt;
&lt;br /&gt;
/* Timer/Counter1 Compare Match B */&lt;br /&gt;
#define TIMER1_COMPB_vect               _VECTOR(7)&lt;br /&gt;
#define SIG_OUTPUT_COMPARE1B            _VECTOR(7)&lt;br /&gt;
&lt;br /&gt;
//...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--Vor Nutzung von SIGNAL muss ebenfalls die Header-Datei signal.h eingebunden werden.--&amp;gt; &lt;br /&gt;
Mögliche Funktionsrümpfe für Interruptfunktionen sind zum Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/interrupt.h&amp;gt;&lt;br /&gt;
/* veraltet: #include &amp;lt;avr/signal.h&amp;gt; */&lt;br /&gt;
&lt;br /&gt;
ISR(INT0_vect)       /* veraltet: SIGNAL(SIG_INTERRUPT0) */&lt;br /&gt;
{&lt;br /&gt;
    /* Interrupt Code */&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
ISR(TIMER0_OVF_vect) /* veraltet: SIGNAL(SIG_OVERFLOW0) */&lt;br /&gt;
{&lt;br /&gt;
    /* Interrupt Code */&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
ISR(USART_RXC_vect) /* veraltet: SIGNAL(SIG_UART_RECV) */&lt;br /&gt;
{&lt;br /&gt;
    /* Interrupt Code */&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// und so weiter und so fort...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Auf die korrekte Schreibweise der Vektorbezeichnung ist zu achten. Der gcc-Compiler prüft erst ab Version 4.x, ob ein Signal/Interrupt der angegebenen Bezeichnung tatsächlich in der Includedatei definiert ist und gibt andernfalls eine Warnung aus. Bei WinAVR (ab 2/2005) wurde die Überprüfung auch in den mitgelieferten Compiler der Version 3.x integriert. Aus dem gcc-Quellcode Version 3.x selbst erstellte Compiler enthalten die Prüfung nicht (vgl. [[AVR-GCC]]). &lt;br /&gt;
&lt;br /&gt;
Während der Ausführung der Funktion sind alle weiteren Interrupts automatisch gesperrt. Beim Verlassen der Funktion werden die Interrupts wieder zugelassen.&lt;br /&gt;
&lt;br /&gt;
Sollte während der Abarbeitung der Interruptroutine ein weiterer Interrupt (gleiche oder andere Interruptquelle) auftreten, so wird das entsprechende Bit im zugeordneten Interrupt Flag Register gesetzt und die entsprechende Interruptroutine automatisch nach dem Beenden der aktuellen Funktion aufgerufen.&lt;br /&gt;
&lt;br /&gt;
Ein Problem ergibt sich eigentlich nur dann, wenn während der Abarbeitung der aktuellen Interruptroutine mehrere gleichartige Interrupts auftreten. Die entsprechende Interruptroutine wird im Nachhinein zwar aufgerufen jedoch wissen wir nicht, ob nun der entsprechende Interrupt einmal, zweimal oder gar noch öfter aufgetreten ist. Deshalb soll hier noch einmal betont werden, dass Interruptroutinen so schnell wie nur irgend möglich wieder verlassen werden sollten.&lt;br /&gt;
&lt;br /&gt;
=== Unterbrechbare Interruptroutinen ===&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Faustregel&amp;quot;: im Zweifel &#039;&#039;&#039;ISR&#039;&#039;&#039;. Die nachfolgend beschriebene Methode nur dann verwenden, wenn man sich über die unterschiedliche Funktionsweise im Klaren ist.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/interrupt.h&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
INTERRUPT (signame)&lt;br /&gt;
{&lt;br /&gt;
    /* Interrupt Code */&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/interrupt.h&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
void XXX_vect(void) __attribute__((interrupt));&lt;br /&gt;
void XXX_vect(void) {&lt;br /&gt;
  //...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hierbei steht XXX für den oben beschriebenen Namen des Vektors (also z.B. &#039;&#039;void TIMER0_OVF_vect(void)...&#039;&#039;). Der Unterschied im Vergleich zu ISR ist, dass hier beim Aufrufen der Funktion das &#039;&#039;&#039;Global Enable Interrupt&#039;&#039;&#039; Bit automatisch wieder gesetzt und somit weitere Interrupts zugelassen werden. Dies kann zu nicht unerheblichen Problemen von im einfachsten Fall einem Stack overflow bis zu sonstigen unerwarteten Effekten führen und sollte wirklich &#039;&#039;&#039;nur dann&#039;&#039;&#039; angewendet werden, wenn man sich absolut sicher ist, das Ganze auch im Griff zu haben.  &amp;lt;!--Vor Nutzung von INTERRUPT muss die Header-Datei interrupt.h eingebunden werden.--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
siehe auch: Hinweise in [[AVR-GCC]]&lt;br /&gt;
&lt;br /&gt;
siehe dazu: http://www.nongnu.org/avr-libc/user-manual/group__avr__interrupts.html&lt;br /&gt;
&lt;br /&gt;
== Datenaustausch mit Interrupt-Routinen ==&lt;br /&gt;
&lt;br /&gt;
Variablen die sowohl in Interrupt-Routinen (ISR = Interrupt Service Routine(s)), als auch vom übrigen Programmcode geschrieben oder gelesen werden, müssen mit einem &#039;&#039;&#039;volatile&#039;&#039;&#039; deklariert werden. Damit wird dem Compiler mitgeteilt, dass der Inhalt der Variablen vor jedem Lesezugriff aus dem Speicher gelesen und nach jedem Schreibzugriff in den Speicher geschrieben wird. Ansonsten könnte der Compiler den Code so optimieren, dass der Wert der Variablen nur &lt;br /&gt;
in Prozessorregistern zwischengespeichert wird, die nichts von der Änderung woanders mitbekommen.&lt;br /&gt;
&lt;br /&gt;
Zur Veranschaulichung ein Codefragment für eine Tastenentprellung mit Erkennung einer &amp;quot;lange gedrückten&amp;quot; Taste.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/interrupt.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
// Schwellwerte&lt;br /&gt;
// Entprellung: &lt;br /&gt;
#define CNTDEBOUNCE 10&lt;br /&gt;
// &amp;quot;lange gedrueckt:&amp;quot;&lt;br /&gt;
#define CNTREPEAT 200&lt;br /&gt;
&lt;br /&gt;
// hier z.B. Taste an Pin2 PortA &amp;quot;active low&amp;quot; = 0 wenn gedrueckt&lt;br /&gt;
#define KEY_PIN  PINA&lt;br /&gt;
#define KEY_PINNO PA2&lt;br /&gt;
&lt;br /&gt;
// beachte: volatile! &lt;br /&gt;
volatile uint8_t gKeyCounter;&lt;br /&gt;
&lt;br /&gt;
// Timer-Compare Interrupt ISR, wird z.B. alle 10ms ausgefuehrt&lt;br /&gt;
ISR(TIMER1_COMPA_vect)&lt;br /&gt;
{&lt;br /&gt;
   // hier wird gKeyCounter veraendert. Die übrigen&lt;br /&gt;
   // Programmteile müssen diese Aenderung &amp;quot;sehen&amp;quot;:&lt;br /&gt;
   // volatile -&amp;gt; aktuellen Wert immer in den Speicher schreiben&lt;br /&gt;
   if ( !(KEY_PIN &amp;amp; (1&amp;lt;&amp;lt;KEY_PINNO)) ) {&lt;br /&gt;
      if (gKeyCounter &amp;lt; CNTREPEAT) gKeyCounter++;&lt;br /&gt;
   }&lt;br /&gt;
   else {&lt;br /&gt;
      gKeyCounter = 0;&lt;br /&gt;
   }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
int main(void)&lt;br /&gt;
{&lt;br /&gt;
//...&lt;br /&gt;
    /* hier: Initialisierung der Ports und des Timer-Interrupts */&lt;br /&gt;
//... &lt;br /&gt;
   // hier wird auf gKeyCounter zugegriffen. Dazu muss der in der&lt;br /&gt;
   // ISR geschriebene Wert bekannt sein:&lt;br /&gt;
   // volatile -&amp;gt; aktuellen Wert immer aus dem Speicher lesen&lt;br /&gt;
   if ( gKeyCounter &amp;gt; CNTDEBOUNCE ) { // Taste mind. 10*10 ms &amp;quot;prellfrei&amp;quot;&lt;br /&gt;
       if (gKeyCounter == CNTREPEAT) {&lt;br /&gt;
          /* hier: Code fuer &amp;quot;Taste lange gedrueckt&amp;quot; */&lt;br /&gt;
       }&lt;br /&gt;
       else {&lt;br /&gt;
          /* hier: Code fuer &amp;quot;Taste kurz gedrueckt&amp;quot; */&lt;br /&gt;
       }&lt;br /&gt;
   }&lt;br /&gt;
//...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== volatile und Pointer ===&lt;br /&gt;
&lt;br /&gt;
Bei &#039;&#039;&#039;volatile&#039;&#039;&#039; in Verbindung mit Pointern ist zu beachten, ob der Pointer selbst oder die Variable auf die der Pointer zeigt &#039;&#039;&#039;volatile&#039;&#039;&#039; ist.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
volatile uint8_t *a;   // das Ziel von a ist volatile&lt;br /&gt;
&lt;br /&gt;
uint8_t *volatile a;   // a selbst ist volatile&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Variablen größer 1 Byte ===&lt;br /&gt;
&lt;br /&gt;
Bei Variablen größer ein Byte, auf die in Interrupt-Routinen und im Hauptprogramm zugegriffen wird, muss darauf geachtet werden, dass die Zugriffe auf die einzelnen Bytes außerhalb der ISR nicht durch einen Interrupt unterbrochen werden. (Allgemeinplatz: AVRs sind 8-bit Controller). Zur Veranschaulichung ein Codefragment:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
volatile uint16_t gMyCounter16bit;&lt;br /&gt;
//...&lt;br /&gt;
ISR(...)&lt;br /&gt;
{&lt;br /&gt;
//...&lt;br /&gt;
   gMyCounter16Bit++;&lt;br /&gt;
//...&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int main(void)&lt;br /&gt;
{&lt;br /&gt;
   uint16_t tmpCnt;&lt;br /&gt;
//...&lt;br /&gt;
   // nicht gut: Mglw. hier ein Fehler, wenn ein Byte von MyCounter &lt;br /&gt;
   // schon in tmpCnt kopiert ist aber vor dem Kopieren des zweiten Bytes &lt;br /&gt;
   // ein Interrupt auftritt, der den Inhalt von MyCounter verändert.&lt;br /&gt;
   tmpCnt = gMyCounter16bit; &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
   // besser: Änderungen &amp;quot;außerhalb&amp;quot; verhindern -&amp;gt; alle &amp;quot;Teilbytes&amp;quot;&lt;br /&gt;
   // bleiben konsistent&lt;br /&gt;
   cli();  // Interupts deaktivieren&lt;br /&gt;
   tmpCnt = gMyCounter16Bit;&lt;br /&gt;
   sei();  // wieder aktivieren&lt;br /&gt;
&lt;br /&gt;
   // oder: vorheriger Status des globalen Interrupt-Flags bleibt erhalten&lt;br /&gt;
   uint8_t sreg_tmp;&lt;br /&gt;
   sreg_tmp = SREG;    /* Sichern */&lt;br /&gt;
   cli()&lt;br /&gt;
   tmpCnt = gMyCounter16Bit;&lt;br /&gt;
   SREG = sreg_tmp;    /* Wiederherstellen */&lt;br /&gt;
&lt;br /&gt;
   // oder: mehrfach lesen, bis man konsistente Daten hat&lt;br /&gt;
   uint16_t count1 = gMyCounter16Bit;&lt;br /&gt;
   uint16_t count2 = gMyCounter16Bit;&lt;br /&gt;
   while (count1 != count2) {&lt;br /&gt;
       count1 = count2;&lt;br /&gt;
       count2 = gMyCounter16Bit;&lt;br /&gt;
   }&lt;br /&gt;
   tmpCnt = count1;&lt;br /&gt;
//...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Interrupt-Routinen und Registerzugriffe ==&lt;br /&gt;
&lt;br /&gt;
Falls Register sowohl im Hauptprogramm als auch in Interrupt-Routinen verändert werden, ist darauf zu achten, dass diese Zugriffe sich nicht überlappen. Nur wenige Anweisungen lassen sich in sogenannte &amp;quot;atomare&amp;quot; Zugriffe übersetzen, die nicht von Interrupt-Routinen unterbrochen werden können. &lt;br /&gt;
&lt;br /&gt;
Zur Veranschaulichung eine Anweisung, bei der ein Bit und im Anschluss drei Bits in einem Register gesetzt werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
int main(void)&lt;br /&gt;
{&lt;br /&gt;
//...&lt;br /&gt;
	PORTA |= (1&amp;lt;&amp;lt;PA0);&lt;br /&gt;
	&lt;br /&gt;
	PORTA |= (1&amp;lt;&amp;lt;PA2)|(1&amp;lt;&amp;lt;PA3)|(1&amp;lt;&amp;lt;PA4);&lt;br /&gt;
//...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Compiler übersetzt diese Anweisungen für einen ATmega128 bei Optimierungsstufe &amp;quot;S&amp;quot; nach:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;code&amp;quot;&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
        PORTA |= (1&amp;lt;&amp;lt;PA0);&lt;br /&gt;
  d2:	d8 9a       	sbi	0x1b, 0	; 27 (a)&lt;br /&gt;
	&lt;br /&gt;
        PORTA |= (1&amp;lt;&amp;lt;PA2)|(1&amp;lt;&amp;lt;PA3)|(1&amp;lt;&amp;lt;PA4);&lt;br /&gt;
  d4:	8b b3       	in	r24, 0x1b	; 27 (b)&lt;br /&gt;
  d6:	8c 61       	ori	r24, 0x1C	; 28 (c)&lt;br /&gt;
  d8:	8b bb       	out	0x1b, r24	; 27 (d)&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Setzen des einzelnen Bits wird bei eingeschalteter Optimierung für Register im unteren Speicherbereich in eine einzige Assembler-Anweisung (sbi) übersetzt und ist nicht anfällig für Unterbrechnungen durch Interrupts. Die Anweisung zum Setzen von drei Bits wird jedoch in drei abhängige Assembler-Anweisungen übersetzt und bietet damit zwei &amp;quot;Angriffspunkte&amp;quot; für Unterbrechnungen. Eine Interrupt-Routine könnte nach dem Laden des Ausgangszustands in den Zwischenspeicher (hier Register 24) den Wert des Registers ändern, z.B. ein Bit löschen. Damit würde der Zwischenspeicher nicht mehr mit dem tatsächlichen Zustand übereinstimmen aber dennoch nach der Bitoperation (hier ori) in das Register zurückgeschrieben. &lt;br /&gt;
&lt;br /&gt;
Beispiel: PORTA sei anfangs 0b00000000. Die erste Anweisung (a) setzt Bit 0, PORTA ist danach 0b00000001. Nun wird im ersten Teil der zweiten Anweisung der Portzustand in ein Register eingelesen (b). Unmittelbar darauf (vor (c)) &amp;quot;feuert&amp;quot; ein Interrupt, in dessen Interrupt-Routine Bit 0 von PORTA gelöscht wird. Nach Verlassen der Interrupt-Routine hat PORTA den Wert 0b00000000. In den beiden noch folgenden Anweisungen des Hauptprogramms wird nun der zwischengespeicherte &amp;quot;alte&amp;quot; Zustand 0b00000001 mit 0b00011100 logisch-oder-verknüft (c) und das Ergebnis 0b00011101 in PortA geschrieben (d). Obwohl zwischenzeitlich Bit 0 gelöscht wurde, ist es nach (d) wieder gesetzt. &lt;br /&gt;
&lt;br /&gt;
Lösungsmöglichkeiten:&lt;br /&gt;
* Register ohne besondere Vorkehrungen nicht in Interruptroutinen &#039;&#039;und&#039;&#039; im Hauptprogramm verändern.&lt;br /&gt;
* Interrupts vor Veränderungen in Registern, die auch in ISRs verändert werden, deaktivieren (&amp;quot;cli&amp;quot;).&lt;br /&gt;
* Bits einzeln löschen oder setzen. sbi und cbi können nicht unterbrochen werden. Vorsicht: nur Register im unteren Speicherbereich sind mittels sbi/cbi ansprechbar. Der Compiler kann nur für diese sbi/cbi-Anweisungen generieren. Für Register außerhalb dieses Adressbereichs (&amp;quot;Memory-Mapped&amp;quot;-Register) werden auch zur Manipulation einzelner Bits abhängige Anweisungen erzeugt (lds,...,sts).&lt;br /&gt;
&lt;br /&gt;
* siehe auch: [http://www.nongnu.org/avr-libc/user-manual/index.html Dokumentation der avr-libc] Frequently asked Questions/Fragen Nr. 1 und 8. (Stand: avr-libc Vers. 1.0.4)&lt;br /&gt;
&lt;br /&gt;
== Was macht das Hauptprogramm? ==&lt;br /&gt;
&lt;br /&gt;
Im einfachsten (Ausnahme-)Fall gar nichts mehr. Es ist also durchaus denkbar, ein Programm zu schreiben, welches in der main-Funktion lediglich noch die Interrupts aktiviert und dann in einer Endlosschleife verharrt. Sämtliche Funktionen werden dann in den ISRs abgearbeitet. Diese Vorgehensweise ist jedoch bei den meisten Anwendungen schlecht: man verschenkt eine Verarbeitungsebene und hat außerdem möglicherweise Probleme durch Interruptroutinen, die zu viel Verarbeitungszeit benötigen.&lt;br /&gt;
&lt;br /&gt;
Normalerweise wird man in den Interruptroutinen nur die bei Auftreten des jeweiligen Interruptereignisses unbedingt notwendigen Operationen ausführen lassen. Alle weniger kritischen Aufgaben werden dann im Hauptprogramm abgearbeitet.&lt;br /&gt;
&lt;br /&gt;
* siehe auch: [http://www.nongnu.org/avr-libc/user-manual/index.html Dokumentation der avr-libc] Abschnitt Modules/Interrupts and Signals&lt;br /&gt;
&lt;br /&gt;
= Sleep-Modes =&lt;br /&gt;
&lt;br /&gt;
AVR Controller verfügen über eine Reihe von sogenannten &#039;&#039;Sleep-Modes&#039;&#039; (&amp;quot;Schlaf-Modi&amp;quot;). Diese ermöglichen es, Teile des Controllers abzuschalten. Zum Einen kann damit besonders bei Batteriebetrieb Strom gespart werden, zum Anderen können Komponenten des Controllers deaktiviert werden, die die Genauigkeit des Analog-Digital-Wandlers bzw. des Analog-Comparators negativ beeinflussen. Der Controller wird durch Interrupts aus dem Schlaf geweckt. Welche Interrupts den jeweiligen Schlafmodus beenden, ist einer Tabelle im Datenblatt des jeweiligen Controllers zu entnehmen.&lt;br /&gt;
Die Funktionen (eigentlich Makros) der avr-libc stehen nach Einbinden der header-Datei &#039;&#039;sleep.h&#039;&#039; zur Verfügung.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;set_sleep_mode(uint8_t mode)&#039;&#039;&#039;&lt;br /&gt;
:Setzt den Schlafmodus, der bei Aufruf von sleep() aktiviert wird. In sleep.h sind einige Konstanten definiert (z.B. SLEEP_MODE_PWR_DOWN). Die definierten Modi werden jedoch nicht alle von sämtlichten AVR-Controllern unterstützt.&lt;br /&gt;
* &#039;&#039;&#039;sleep_enable()&#039;&#039;&#039;&lt;br /&gt;
:aktiviert den gesetzten Schlafmodus, versetzt den Controller aber noch nicht in den Schlafmodus&lt;br /&gt;
* &#039;&#039;&#039;sleep_cpu()&#039;&#039;&#039;&lt;br /&gt;
: Versetzt den Controller in den Schlafmodus (sleep_cpu wird im Prinzip durch die Assembler-Anweisung &#039;&#039;sleep&#039;&#039; ersetzt)&lt;br /&gt;
* &#039;&#039;&#039;sleep_disable()&#039;&#039;&#039;&lt;br /&gt;
:deaktiviert den gesetzten Schlafmodus&lt;br /&gt;
* &#039;&#039;&#039;sleep_mode()&#039;&#039;&#039;&lt;br /&gt;
:Versetzt den Controller in den mit set_sleep_mode gewählten Schlafmodus. Das Makro entspricht sleep_enable()+sleep_cpu()+sleep_disable(), beinhaltet also nicht die Aktivierung von Interrupts (besser nicht benutzen).&lt;br /&gt;
&lt;br /&gt;
Bei Anwendung von sleep_cpu() müssen Interrupts also bereits freigeben sein (sei()), da der Controller sonst nicht mehr &amp;quot;aufwachen&amp;quot; kann. sleep_mode() ist nicht geeignet für die Verwendung in ISR Interrupt-Service-Routinen, da bei deren Abarbeitung Interrupts global deaktiviert sind und somit auch die möglichen &amp;quot;Aufwachinterrupts&amp;quot;. Abhilfe: stattdessen sleep_enable(), sei(), sleep_cpu(), sleep_disable() und evtl. cli() verwenden (vgl. Dokumentation der avr-libc).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/sleep.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
int main(void)&lt;br /&gt;
{&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
   while (1) {&lt;br /&gt;
...&lt;br /&gt;
      set_sleep_mode(SLEEP_MODE_PWR_DOWN);&lt;br /&gt;
      sleep_mode();&lt;br /&gt;
   &lt;br /&gt;
      // Code hier wird erst nach Auftreten eines entsprechenden&lt;br /&gt;
      // &amp;quot;Aufwach-Interrupts&amp;quot; verarbeitet&lt;br /&gt;
...&lt;br /&gt;
   }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In älteren Versionenen der avr-libc wurden nicht alle AVR-Controller durch die sleep-Funktionen richtig angesteuert. Mit avr-libc 1.2.0 wurde die Anzahl der unterstützten Typen jedoch deutlich erweitert. Bei nicht-unterstützten Typen erreicht man die gewünschte Funktionalität durch direkte &amp;quot;[[Bitmanipulation]]&amp;quot; der entsprechenden Register (vgl. Datenblatt) und Aufruf des Sleep-Befehls via Inline-Assembler oder sleep_cpu():&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
   // Sleep-Mode &amp;quot;Power-Save&amp;quot; beim ATmega169 &amp;quot;manuell&amp;quot; aktivieren&lt;br /&gt;
   SMCR = (3&amp;lt;&amp;lt;SM0) | (1&amp;lt;&amp;lt;SE);&lt;br /&gt;
   asm volatile (&amp;quot;sleep&amp;quot;::); // alternativ sleep_cpu() aus sleep.h&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* siehe auch: [http://www.nongnu.org/avr-libc/user-manual/index.html Dokumentation der avr-libc] Abschnitt Modules/Power Management and Sleep-Modes&lt;br /&gt;
* [http://www.mikrocontroller.net/topic/96369#832712 Forenbeitrag] zur &amp;quot;Nichtverwendung&amp;quot; von sleep_mode in ISRs.&lt;br /&gt;
&lt;br /&gt;
= Speicherzugriffe =&lt;br /&gt;
&lt;br /&gt;
Atmel AVR-Controller verfügen typisch über drei Speicher:&lt;br /&gt;
&lt;br /&gt;
* [[RAM]]: Im RAM (genauer statisches RAM/SRAM) wird vom gcc-Compiler Platz für Variablen reserviert. Auch der Stack befindet sich im RAM. Dieser Speicher ist &amp;quot;flüchtig&amp;quot;, d.h. der Inhalt der Variablen geht beim Ausschalten oder einem Zusammenbruch der Spannungsversorgung verloren.&lt;br /&gt;
&lt;br /&gt;
* Programmspeicher: Ausgeführt als FLASH-Speicher, seitenweise wiederbeschreibbar. Darin ist das Anwendungsprogramm abgelegt.&lt;br /&gt;
&lt;br /&gt;
* [[EEPROM]]: Nichtflüchtiger Speicher, d.h. der einmal geschriebene Inhalt bleibt auch ohne Stromversorgung erhalten. Byte-weise schreib/lesbar. Im EEPROM werden typischerweise gerätespezifische Werte wie z.B. Kalibrierungswerte von Sensoren abgelegt.&lt;br /&gt;
&lt;br /&gt;
Einige AVRs besitzen keinen RAM-Speicher, lediglich die Register können als &amp;quot;Arbeitsvariablen&amp;quot;&lt;br /&gt;
genutzt werden. Da die Anwendung des avr-gcc auf solch &amp;quot;kleinen&amp;quot; Controllern ohnehin selten sinnvoll ist und auch nur bei einigen RAM-losen Typen nach [http://lightner.net/avr/ATtinyAvrGcc.html &amp;quot;Bastelarbeiten&amp;quot;] möglich ist, werden diese Controller hier nicht weiter berücksichtigt. Auch EEPROM-Speicher ist nicht auf allen Typen verfügbar. Generell sollten die nachfolgenden Erläuterungen auf alle ATmega-Controller und die größeren AT90-Typen übertragbar sein. Für die Typen ATtiny2313, ATtiny26 und viele weitere der &amp;quot;ATtiny-Reihe&amp;quot; gelten die Ausführungen ebenfalls.&lt;br /&gt;
&lt;br /&gt;
== RAM ==&lt;br /&gt;
&lt;br /&gt;
Die Verwaltung des RAM-Speichers erfolgt durch den Compiler, im Regelfall ist beim Zugriff auf Variablen im RAM nichts Besonderes zu beachten. Die Erläuterungen in jedem brauchbaren C-Buch gelten auch für den vom avr-gcc-Compiler erzeugten Code.&lt;br /&gt;
&lt;br /&gt;
Um Speicher dynamisch (während der Laufzeit) zu reservieren, kann &#039;&#039;&#039;malloc()&#039;&#039;&#039; verwendet werden. malloc(size) &amp;quot;allozieren&amp;quot; (~reserviert) einen gewissen Speicherblock mit &#039;&#039;&#039;size&#039;&#039;&#039; Bytes. Ist kein Platz für den neuen Block, wird NULL (0) zurückgegeben.&lt;br /&gt;
&lt;br /&gt;
Wird der angelegte Block zu klein (groß), kann die Größe mit realloc() verändert werden. Den allozierten Speicherbereich kann man mit free() wieder freigeben. Wenn das Freigeben eines Blocks vergessen wird spricht man von einem &amp;quot;Speicherleck&amp;quot; (memory leak).&lt;br /&gt;
&lt;br /&gt;
malloc() legt Speicherblöcke im &#039;&#039;&#039;Heap&#039;&#039;&#039; an, belegt man zuviel Platz, dann wächst der Heap zu weit nach oben und überschreibt den Stack, und der Controller kommt in Teufels Küche. Das kann leider nicht nur passieren wenn man insgesamt zu viel Speicher anfordert, sondern auch wenn man Blöcke unterschiedlicher Größe in ungünstiger Reihenfolge alloziert/freigibt (siehe Artikel [[Heap-Fragmentierung]]). Aus diesem Grund sollte man malloc() auf Mikrocontrollern sehr sparsam (am besten gar nicht) verwenden.&lt;br /&gt;
&lt;br /&gt;
Beispiel zur Verwendung von malloc():&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
void foo(void) {&lt;br /&gt;
  // neuen speicherbereich anlegen,&lt;br /&gt;
  // platz für 10 uint16&lt;br /&gt;
  uint16_t* pBuffer = malloc(10 * sizeof(uint16_t));&lt;br /&gt;
&lt;br /&gt;
  // darauf zugreifen, als wärs ein gewohnter Buffer&lt;br /&gt;
  pBuffer[2] = 5;&lt;br /&gt;
&lt;br /&gt;
  // Speicher (unbedingt!) wieder freigeben&lt;br /&gt;
  free(pBuffer);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn (wie in obigem Beispiel) dynamischer Speicher nur für die Dauer einer Funktion benötigt und am Ende wieder freigegeben wird, bietet es sich an, statt malloc() &#039;&#039;&#039;alloca()&#039;&#039;&#039; zu verwenden. Der Unterschied zu malloc() ist, dass der Speicher auf dem Stack reserviert wird, und beim Verlassen der Funktion automatisch wieder freigegeben wird. Es kann somit kein Speicherleck und keine Fragmentierung entstehen.&lt;br /&gt;
&lt;br /&gt;
siehe auch:&lt;br /&gt;
* http://www.nongnu.org/avr-libc/user-manual/malloc.html&lt;br /&gt;
&lt;br /&gt;
== Programmspeicher (Flash) ==&lt;br /&gt;
&lt;br /&gt;
Ein Zugriff auf Konstanten im Programmspeicher ist mittels avr-gcc nicht &amp;quot;transparent&amp;quot; möglich. D.h. es sind besondere Zugriffsfunktionen erforderlich, um Daten aus diesem Speicher zu lesen. Grundsätzlich basieren alle Zugriffsfunktionen auf der Assembler-Anweisung lpm (load program memory, bei AVR Controllern mit mehr als 64kB Flash auch elpm). Die Standard-Laufzeitbibliothek des avr-gcc (die avr-libc) stellt diese Funktionen nach Einbinden der Header-Datei pgmspace.h zur Verfügung. Mit diesen Funktionen können einzelne Bytes, Datenworte (16bit) und Datenblöcke gelesen werden. &lt;br /&gt;
&lt;br /&gt;
Deklarationen von Variablen im Flash-Speicher werden durch das &amp;quot;Attribut&amp;quot; PROGMEM ergänzt. Lokale Variablen (eigentlich Konstanten) innerhalb von Funktionen können ebenfalls im Programmspeicher abgelegt werden. Dazu ist bei der Definition jedoch ein &#039;&#039;static&#039;&#039; voranzustellen, da solche &amp;quot;Variablen&amp;quot; nicht auf dem Stack bzw. (bei Optimierung) in Registern verwaltet werden können. Der Compiler &amp;quot;wirft&amp;quot; eine Warnung falls static fehlt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/pgmspace.h&amp;gt;&lt;br /&gt;
#include &amp;lt;inttypes.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
/* Byte */&lt;br /&gt;
const uint8_t pgmFooByte PROGMEM = 123;&lt;br /&gt;
&lt;br /&gt;
/* Wort */&lt;br /&gt;
const uint16_t pgmFooWort PROGMEM = 12345;&lt;br /&gt;
&lt;br /&gt;
/* Byte-Feld */&lt;br /&gt;
const uint8_t pgmFooByteArray1[] PROGMEM = { 18, 3 ,70 };&lt;br /&gt;
const uint8_t pgmFooByteArray2[] PROGMEM = { 30, 7 ,79 };&lt;br /&gt;
&lt;br /&gt;
/* Zeiger */&lt;br /&gt;
const uint8_t *pgmPointerToArray1 PROGMEM = pgmFooByteArray1;&lt;br /&gt;
const uint8_t *pgmPointerArray[] PROGMEM = { pgmFooByteArray1, pgmFooByteArray2 };&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
void foo(void)&lt;br /&gt;
{&lt;br /&gt;
  static /*const*/ uint8_t pgmTestByteLocal PROGMEM = 0x55;&lt;br /&gt;
  static /*const*/ char pgmTestStringLocal[] PROGMEM = &amp;quot;im Flash&amp;quot;;&lt;br /&gt;
  // so nicht (static fehlt): char pgmTestStringLocalFalsch [] PROGMEM = &amp;quot;so nicht&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 // ...&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Byte lesen ===&lt;br /&gt;
&lt;br /&gt;
Mit der Funktion pgm_read_byte aus pgmspace.h erfolgt der Zugriff auf die Daten. Parameter der Funktion ist die Adresse des Bytes im Flash-Speicher.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
const uint8_t pgmFooByte PROGMEM = 123;&lt;br /&gt;
const uint8_t pgmFooByteArray1[] PROGMEM = { 18, 3 ,70 };&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    // Wert der Ram-Variablen myByte auf den Wert von pgmFooByte setzen:&lt;br /&gt;
    uint8_t myByte;&lt;br /&gt;
&lt;br /&gt;
    myByte = pgm_read_byte(&amp;amp;pgmFooByte);&lt;br /&gt;
    // myByte hat nun den Wert 123&lt;br /&gt;
&lt;br /&gt;
    //...&lt;br /&gt;
&lt;br /&gt;
    // Schleife ueber ein Array aus Byte-Werten im Flash&lt;br /&gt;
    uint8_t i;&lt;br /&gt;
&lt;br /&gt;
    for (i=0;i&amp;lt;3;i++) {&lt;br /&gt;
        myByte = pgm_read_byte(&amp;amp;pgmFooByteArray1[i]);&lt;br /&gt;
        // mach&#039; was mit myByte....&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Wort lesen ===&lt;br /&gt;
&lt;br /&gt;
Für &amp;quot;einfache&amp;quot; 16-bit breite Variablen erfolgt der Zugriff analog zum Byte-Beispiel, jedoch mit der Funktion pgm_read_word.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
const uint16_t pgmFooWort PROGMEM = 12345;&lt;br /&gt;
&lt;br /&gt;
    uint16_t myWord;&lt;br /&gt;
&lt;br /&gt;
    myWord = pgm_read_word(&amp;amp;pgmFooWort);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zeiger auf Werte im Flash sind ebenfalls 16 Bits &amp;quot;groß&amp;quot; (Stand avr-gcc 3.4.x). Damit ist der mögliche Speicherbereich für &amp;quot;Flash-Konstanten&amp;quot; auf 64kB begrenzt.  &amp;lt;!-- Einige avr-libc/pgmspace-Funktionen ermöglichen den Lesezugriff auf den gesamten Flash-Speicher) (intern via Assembler Anweisung ELPM). Die Initialisierungswerde des Speicherinhalts jenseits der 64kB-Marke müssen dann jedoch auf anderem Weg angelegt werden (nicht PROGMEM, evtl. eigene Section und Linker-Optionen - TODO) /// alt - und nicht ganz korrekt: (Die avr-libc pgmspace-Funktionen unterstützen nur die unteren 64kB Flash bei Controllern mit mehr als 64kB.)--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
    uint8_t *ptrToArray;&lt;br /&gt;
&lt;br /&gt;
    ptrToArray = (uint8_t*)(pgm_read_word(&amp;amp;pgmPointerToArray1));&lt;br /&gt;
    // ptrToArray enthält nun die Startadresse des Byte-Arrays pgmFooByteArray1&lt;br /&gt;
    // Allerdings würde ein direkter Zugriff mit diesem Pointer (z.B. temp=*ptrToArray)&lt;br /&gt;
    // &#039;&#039;&#039;nicht&#039;&#039;&#039; den Inhalt von pgmFooByteArray1[0] liefern, sondern von einer Speicherstelle&lt;br /&gt;
    // im &#039;&#039;&#039;RAM&#039;&#039;&#039;, die die gleiche Adresse hat wie pgmFooByteArray1[0]&lt;br /&gt;
    // Daher muss nun die Funktion pgm_read_byte() benutzt werden, die die in ptrToArray&lt;br /&gt;
    // enthaltene Adresse benutzt und auf das Flash zugreift.&lt;br /&gt;
&lt;br /&gt;
    for (i=0;i&amp;lt;3;i++) {&lt;br /&gt;
        myByte = pgm_read_byte(ptrToArray+i);&lt;br /&gt;
        // mach&#039; was mit myByte... (18, 3, 70)&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    ptrToArray = (uint8_t*)(pgm_read_word(&amp;amp;pgmPointerArray[1]));&lt;br /&gt;
    &lt;br /&gt;
    // ptrToArray enthält nun die Adresse des ersten Elements des Byte-Arrays pgmFooByteArray2&lt;br /&gt;
    // da im zweiten Element des Pointer-Arrays pgmPointerArray die Adresse&lt;br /&gt;
    // von pgmFooByteArray2 abgelegt ist&lt;br /&gt;
&lt;br /&gt;
    for (i=0;i&amp;lt;3;i++) {&lt;br /&gt;
        myByte = pgm_read_byte(ptrToArray+i);&lt;br /&gt;
        // mach&#039; was mit myByte... (30, 7, 79)&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Floats und Structs lesen ===&lt;br /&gt;
&lt;br /&gt;
Um komplexe Datentypen (structs), nicht-integer Datentypen (floats) aus dem Flash auszulesen, sind Hilfsfunktionen erforderlich. Einige Beispiele:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
/* Beispiel float aus Flash */&lt;br /&gt;
&lt;br /&gt;
float pgmFloatArray[3] PROGMEM = {1.1, 2.2, 3.3};&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
/* liest float von Flash-Addresse addr und gibt diese als return-value zurueck */&lt;br /&gt;
inline float pgm_read_float(const float *addr)&lt;br /&gt;
{	&lt;br /&gt;
	union&lt;br /&gt;
	{&lt;br /&gt;
		uint16_t i[2];	// 2 16-bit-Worte&lt;br /&gt;
		float f;&lt;br /&gt;
	} u;&lt;br /&gt;
	&lt;br /&gt;
	u.i[0]=pgm_read_word((PGM_P)addr);&lt;br /&gt;
	u.i[1]=pgm_read_word((PGM_P)addr+2);&lt;br /&gt;
	&lt;br /&gt;
	return u.f;&lt;br /&gt;
} &lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
void egal(void)&lt;br /&gt;
{&lt;br /&gt;
   int i;&lt;br /&gt;
   float f;&lt;br /&gt;
&lt;br /&gt;
   for (i=0;i&amp;lt;3;i++) {&lt;br /&gt;
      f = pgm_read_float(&amp;amp;pgmFloatArray[i]); // entspr. &amp;quot;f = pgmFloatArray[i];&amp;quot;&lt;br /&gt;
      // mach&#039; was mit f &lt;br /&gt;
   }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
TODO: Beispiele fuer structs und pointer aus flash auf struct im flash (menues, state-machines etc.)&lt;br /&gt;
&lt;br /&gt;
=== Array aus Zeichenketten im Flash-Speicher ===&lt;br /&gt;
&lt;br /&gt;
Felder aus Zeichenketten im Flash-Speicher werden in zwei Schritten angelegt: Zuerst die einzelnen Elemente des Arrays und im Anschluss ein Array, in dem die Addressen der Zeichenketten abgelegt werden. Zum Auslesen wird zuerst die Adresse des i-ten Elements aus dem Array im Flash-Speicher gelesen, die im Anschluss dazu genutzt wird, auf das Element (die Zeichenkette) selbst zuzugreifen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/pgmspace.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
const char str1[] PROGMEM = &amp;quot;first_A&amp;quot;;&lt;br /&gt;
const char str2[] PROGMEM = &amp;quot;second_A&amp;quot;;&lt;br /&gt;
const char str3[] PROGMEM = &amp;quot;third_A&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
const char *strarray1[] PROGMEM = {&lt;br /&gt;
	str1,&lt;br /&gt;
	str2,&lt;br /&gt;
	str3&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
int main(void)&lt;br /&gt;
{&lt;br /&gt;
	int i, j, l;&lt;br /&gt;
	const char *pstrflash;&lt;br /&gt;
	char work[20], work2[20];&lt;br /&gt;
	// fuer Simulation: per volatile Optimierung verhindern, &lt;br /&gt;
	//                  da c nicht genutzt&lt;br /&gt;
	volatile char c;&lt;br /&gt;
	&lt;br /&gt;
	for ( i = 0; i &amp;lt; (sizeof(strarray1)/sizeof(strarray1[0]) ); i++ ) {&lt;br /&gt;
&lt;br /&gt;
		// setze Pointer auf die Addresse des i-ten Elements des&lt;br /&gt;
		// &amp;quot;Flash-Arrays&amp;quot; (str1, str2, ...)&lt;br /&gt;
		pstrflash = (const char*)( pgm_read_word( &amp;amp;(strarray1[i]) ) );&lt;br /&gt;
		&lt;br /&gt;
		// kopiere den Inhalt der Zeichenkette von der&lt;br /&gt;
		// in pstrflash abgelegten Adresse in das work-Array&lt;br /&gt;
		// analog zu strcpy( work, strarray1[i]) wenn alles im RAM&lt;br /&gt;
		strcpy_P( work, pstrflash );&lt;br /&gt;
		// verkuerzt:&lt;br /&gt;
		strcpy_P( work2, (const char*)( pgm_read_word( &amp;amp;(strarray1[i]) ) ) );&lt;br /&gt;
		&lt;br /&gt;
&lt;br /&gt;
		// Zeichen-fuer-Zeichen&lt;br /&gt;
		l = strlen_P( pstrflash );&lt;br /&gt;
		for ( j=0; j &amp;lt; l; j++ ) {&lt;br /&gt;
			// analog zu c=strarray[i][j] wenn alles im RAM&lt;br /&gt;
			c = (char)( pgm_read_byte( pstrflash++ ) );&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	while (1) { ; }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Siehe dazu auch die avr-libc FAQ: &amp;quot;How do I put an array of strings completely in ROM?&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=== Vereinfachung für Zeichenketten (Strings) im Flash ===&lt;br /&gt;
&lt;br /&gt;
Zeichenketten können innerhalb des Quellcodes als &amp;quot;Flash-Konstanten&amp;quot; ausgewiesen werden. Dazu dient das Makro PSTR aus pgmspace.h. Dies erspart die getrennte Deklaration mit PROGMEM-Attribut.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/pgmspace.h&amp;gt;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#define MAXLEN 30&lt;br /&gt;
&lt;br /&gt;
char StringImFlash[] PROGMEM = &amp;quot;Erwin Lindemann&amp;quot;; // im &amp;quot;Flash&amp;quot;&lt;br /&gt;
char StringImRam[MAXLEN];&lt;br /&gt;
&lt;br /&gt;
//...&lt;br /&gt;
    strcpy(StringImRam, &amp;quot;Mueller-Luedenscheidt&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (!strncmp_P(StringImRam, StringImFlash, 5)) { &lt;br /&gt;
        // mach&#039; was, wenn die ersten 5 Zeichen identisch - hier nicht&lt;br /&gt;
    }&lt;br /&gt;
    else {&lt;br /&gt;
        // der Code hier wuerde ausgefuehrt &lt;br /&gt;
    } &lt;br /&gt;
&lt;br /&gt;
    if (!strncmp_P(StringImRam, PSTR(&amp;quot;Mueller-Schmitt&amp;quot;), 5)) {&lt;br /&gt;
        // der Code hier wuerde ausgefuehrt, die ersten 5 Zeichen stimmen ueberein&lt;br /&gt;
    }&lt;br /&gt;
    else {&lt;br /&gt;
        // wuerde bei nicht-Uebereinstimmung ausgefuehrt&lt;br /&gt;
    }&lt;br /&gt;
//...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Aber Vorsicht: Ersetzt man zum Beispiel&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
const char textImFlashOK[] PROGMEM = &amp;quot;mit[]&amp;quot;; &lt;br /&gt;
// = Daten im &amp;quot;Flash&amp;quot;, textImFlashOK* zeigt auf Flashadresse&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
durch&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
const char* textImFlashProblem PROGMEM = &amp;quot;mit*&amp;quot;;&lt;br /&gt;
// Konflikt: Daten im BSS (lies: RAM), textImFlashFAIL* zeigt auf Flashadresse&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
dann kann es zu Problemen mit AVR-GCC kommen. Zu erkennen daran, dass der Initialisierungsstring von &amp;quot;textImFlashProblem&amp;quot; zu den Konstanten ans Ende des Programmcodes gelegt wird (BSS), von dem aus er zur Benutzung eigentlich ins RAM kopiert werden sollte (und wird). Da der lesende Code (mittels pgm_read*) trotzdem an einer Stelle vorne im Flash sucht, wird Unsinn gelesen. Dies scheint ein weiters Problem des AVR-GCC (gesehen bei avr-gcc 3.4.1 und 3.4.2) bei der Anpassung an die Harvard-Architektur zu sein (konstanter Pointer auf variable Daten?!). Abhilfe (&amp;quot;Workaround&amp;quot;): Initialisierung bei Zeichenketten mit [] oder gleich im Code PSTR(&amp;quot;...&amp;quot;) nutzen.&lt;br /&gt;
&lt;br /&gt;
Übergibt man Zeichenketten (genauer: die Adresse des ersten Zeichens), die im Flash abglegt sind an eine Funktion, muss diese entsprechend programmiert sein. Die Funktion selbst hat keine Möglichkeit zu unterscheiden, ob es sich um eine Adresse im Flash oder im RAM handelt. Die avr-libc und viele andere avr-gcc-Bibliotheken halten sich an die Konvention, dass Namen von Funktionen die Flash-Adressen erwarten mit dem Suffix _p (oder _P) versehen sind.&lt;br /&gt;
&lt;br /&gt;
Eine Funktion, die einen im Flash abgelegten String z.B. an eine UART ausgibt, würde dann so aussehen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
void uart_puts_p(const char *text)&lt;br /&gt;
{&lt;br /&gt;
    char Zeichen;&lt;br /&gt;
&lt;br /&gt;
    while (Zeichen = pgm_read_byte(text))&lt;br /&gt;
    {   /* so lange, wie mittels pgm_read_byte ein Zeichen vom Flash gelesen&lt;br /&gt;
           werden konnte, welches nicht das &amp;quot;String-Endezeichen&amp;quot; darstellt */&lt;br /&gt;
&lt;br /&gt;
        /* Das gelesene Zeichen über die normalen Kanäle verschicken */&lt;br /&gt;
        uart_putc(Zeichen);&lt;br /&gt;
        text++;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Von einigen Bibliotheken werden Makros definiert, die &amp;quot;automatisch&amp;quot; ein PSTR bei Verwendung einer Funktion einfügen. Ein Blick in den Header-File der Bibliothek zeigt, ob dies der Fall ist. Ein Beispiel aus P. Fleurys lcd-Library:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
// Ausschnitt aus dem Header-File lcd.h der &amp;quot;Fleury-LCD-Lib.&amp;quot;&lt;br /&gt;
//...&lt;br /&gt;
extern void lcd_puts_p(const char *progmem_s);&lt;br /&gt;
#define lcd_puts_P(__s) lcd_puts_p(PSTR(__s))&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
// in einer Anwendung (wieauchimmmer.c)&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/pgmspace.h&amp;gt;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
#include &amp;quot;lcd.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
char StringImFlash[] PROGMEM = &amp;quot;Erwin Lindemann&amp;quot;; // im &amp;quot;Flash&amp;quot;&lt;br /&gt;
&lt;br /&gt;
//...&lt;br /&gt;
    lcd_puts_p(StringImFlash); &lt;br /&gt;
    lcd_puts_P(&amp;quot;Dr. Kloebner&amp;quot;); &lt;br /&gt;
    // daraus wird wg. #define lcd_put_P...:  lcd_puts_p( PSTR(&amp;quot;Dr. Kloebner&amp;quot;) );&lt;br /&gt;
//...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Flash in der Anwendung schreiben ===&lt;br /&gt;
&lt;br /&gt;
Bei AVRs mit &amp;quot;self-programming&amp;quot;-Option (auch bekannt als Bootloader-Support) können Teile des Flash-Speichers auch vom Anwendungsprogramm selbst beschrieben werden. Dies ist nur möglich, wenn die Schreibfunktionen in einem besonderen Speicherbereich (boot-section) des Programmspeichers/Flash abgelegt sind. Bei wenigen &amp;quot;kleinen&amp;quot; AVRs gibt es keine gesonderte Boot-Section, bei diesen kann der Flashspeicher von jeder Stelle des Programms geschrieben werden. Für Details sei hier auf das jeweilige Controller-Datenblatt und die Erläuterungen zum Modul boot.h der avr-libc verwiesen. Es existieren auch Application-Notes dazu bei atmel.com, die auf avr-gcc-Code übertragbar sind.&lt;br /&gt;
&lt;br /&gt;
=== Warum so kompliziert? ===&lt;br /&gt;
&lt;br /&gt;
Zu dem Thema, warum die Verabeitung von Werten aus dem Flash-Speicher so &amp;quot;kompliziert&amp;quot; ist, sei hier nur kurz erläutert: Die Harvard-Architektur des AVR weist getrennte Adressräume für Programm(Flash)- und Datenspeicher(RAM) auf. Der C-Standard und der gcc-Compiler sehen keine unterschiedlichen Adressräume vor. &lt;br /&gt;
Hat man zum Beispiel eine Funktion string_an_uart(const char* s) und übergibt an diese Funktion die Adresse einer Zeichenkette (einen Pointer, z.B. 0x01fe), &amp;quot;weiß&amp;quot; die Funktion nicht, ob die Adresse auf den Flash-Speicher oder den/das RAM zeigt. Allein aus dem Pointer-Wert (der Zahl) kann nicht geschlossen werden, ob ein &amp;quot;einfaches&amp;quot; zeichen_an_uart(s[i]) oder zeichen_an_uart(pgm_read_byte(&amp;amp;s[i]) genutzt werden muss, um das i-te Zeichen auszugeben.&lt;br /&gt;
&lt;br /&gt;
Einige AVR-Compiler &amp;quot;tricksen&amp;quot; etwas, in dem sie für einen Pointer nicht nur die Adresse anlegen, sondern zusätzlich zu jedem Pointer den Ablageort (Flash oder RAM) intern sichern. Bei Aufruf einer Funktion wird dann bei Pointer-Parametern neben der Adresse auch der Speicherbereich, auf den der Pointer zeigt, übergeben. Dies hat jedoch nicht nur Vorteile; Erläuterungen warum dies so ist, führen an dieser Stelle zu weit.&lt;br /&gt;
&lt;br /&gt;
* siehe auch: [http://www.nongnu.org/avr-libc/user-manual/index.html Dokumentation der avr-libc] Abschnitte Modules/Program Space String Utilities und Abschnitt Modules/Bootloader Support Utilities&lt;br /&gt;
&lt;br /&gt;
== EEPROM ==&lt;br /&gt;
&lt;br /&gt;
Man beachte, dass der EEPROM-Speicher nur eine begrenzte Anzahl von Schreibzugriffen zulässt. Beschreibt man eine EEPROM-Zelle öfter als die im Datenblatt zugesicherte Anzahl (typisch 100.000), wird die Funktion der Zelle nicht mehr garantiert. &lt;br /&gt;
Dies gilt für jede einzelne Zelle. Bei geschickter Programmierung (z.B. Ring-Puffer), bei der die zu beschreibenden Zellen regelmäßig gewechselt werden, kann man eine deutlich höhere Anzahl an Schreibzugriffen, bezogen auf den Gesamtspeicher, erreichen.&lt;br /&gt;
&lt;br /&gt;
Schreib- und Lesezugriffe auf den EEPROM-Speicher erfolgen über die im Modul eeprom.h definierten Funktionen. Mit diesen Funktionen können einzelne Bytes, Datenworte (16bit) und Datenblöcke geschrieben und gelesen werden. &lt;br /&gt;
&lt;br /&gt;
Bei Nutzung des EEPROMs ist zu beachten, dass vor dem Zugriff auf diesen Speicher abgefragt wird, ob der Controller die vorherige EEPROM-Operation abgeschlossen hat. Die avr-libc-Funktionen beinhalten diese Prüfung, man muss sie nicht selbst implementieren. Man sollte auch verhindern, dass der Zugriff durch die Abarbeitung einer Interrupt-Routine unterbrochen wird, da bestimme Befehlsabfolgen vorgegeben sind, die innerhalb weniger Taktzyklen aufeinanderfolgen müssen (&amp;quot;timed sequence&amp;quot;). Auch dies muss bei Nutzung der Funktionen aus der avr-libc/eeprom.h-Datei nicht selbst implementiert werden. Innerhalb der Funktionen werden Interrupts vor der &amp;quot;EEPROM-Sequenz&amp;quot; global deaktiviert und im Anschluss, falls vorher auch schon eingeschaltet, wieder aktiviert.&lt;br /&gt;
&lt;br /&gt;
Bei der Deklaration einer Variable im EEPROM, ist das Attribut für die Section &amp;quot;.eeprom&amp;quot; zu ergänzen. Siehe dazu folgendes Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/eeprom.h&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/interrupt.h&amp;gt;&lt;br /&gt;
#include &amp;lt;inttypes.h&amp;gt; // wird in aktuellen Versionen der avr-lib mit xx.h eingebunden&lt;br /&gt;
&lt;br /&gt;
// EEMEM wird bei aktuellen Versionen der avr-lib in eeprom.h definiert&lt;br /&gt;
// hier: definiere falls noch nicht bekannt (&amp;quot;alte&amp;quot; avr-libc)&lt;br /&gt;
#ifndef EEMEM&lt;br /&gt;
// alle Textstellen EEMEM im Quellcode durch __attribute__ ... ersetzen&lt;br /&gt;
#define EEMEM  __attribute__ ((section (&amp;quot;.eeprom&amp;quot;)))&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
/* Byte */&lt;br /&gt;
uint8_t eeFooByte EEMEM = 123;&lt;br /&gt;
&lt;br /&gt;
/* Wort */&lt;br /&gt;
uint16_t eeFooWord EEMEM = 12345;&lt;br /&gt;
&lt;br /&gt;
/* float */&lt;br /&gt;
float eeFooFloat EEMEM;&lt;br /&gt;
&lt;br /&gt;
/* Byte-Feld */&lt;br /&gt;
uint8_t eeFooByteArray1[] EEMEM = { 18, 3 ,70 };&lt;br /&gt;
uint8_t eeFooByteArray2[] EEMEM = { 30, 7 ,79 };&lt;br /&gt;
&lt;br /&gt;
/* 16-bit unsigned short feld */&lt;br /&gt;
uint16_t eeFooWordArray1[4] EEMEM;&lt;br /&gt;
//...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Bytes lesen/schreiben ===&lt;br /&gt;
&lt;br /&gt;
Die avr-libc Funktion zum Lesen eines Bytes heißt eeprom_read_byte. Parameter ist die Adresse des Bytes im EEPROM. Geschrieben wird über die Funktion eeprom_write_byte mit den Parametern Adresse und Inhalt. Anwendungsbeispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
    uint8_t myByte;&lt;br /&gt;
&lt;br /&gt;
    myByte = eeprom_read_byte(&amp;amp;eeFooByte); // lesen&lt;br /&gt;
    // myByte hat nun den Wert 123&lt;br /&gt;
//...&lt;br /&gt;
    myByte = 99;&lt;br /&gt;
    eeprom_write_byte(&amp;amp;eeFooByte, myByte); // schreiben&lt;br /&gt;
    // der Wert 99 wird im EEPROM an die Adresse der&lt;br /&gt;
    // &#039;Variablen&#039; eeFooByte geschrieben&lt;br /&gt;
//...&lt;br /&gt;
    myByte = eeprom_read_byte(&amp;amp;eeFooByteArray1[1]); &lt;br /&gt;
    // myByte hat nun den Wert 3&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
    // Beispiel zur &amp;quot;Sicherung&amp;quot; gegen leeres EEPROM nach &amp;quot;Chip Erase&amp;quot;&lt;br /&gt;
    // (z.B. wenn die .eep-Datei nach Programmierung einer neuen Version&lt;br /&gt;
    // des Programms nicht in den EEPROM uebertragen wurde und EESAVE&lt;br /&gt;
    // deaktiviert ist (unprogrammed/1)&lt;br /&gt;
    // &lt;br /&gt;
    // Vorsicht: wenn EESAVE &amp;quot;programmed&amp;quot; ist, hilft diese Sicherung nicht&lt;br /&gt;
    // weiter, da die Speicheraddressen in einem neuen/erweiterten Programm&lt;br /&gt;
    // moeglicherweise verschoben wurden. An der Stelle &amp;amp;eeFooByte steht&lt;br /&gt;
    // dann u.U. der Wert einer anderen Variable aus einer &amp;quot;alten&amp;quot; Version.&lt;br /&gt;
&lt;br /&gt;
    #define EEPROM_DEF 0xFF&lt;br /&gt;
    uint8_t fooByteDefault = 222;&lt;br /&gt;
    if ( ( myByte = eeprom_read_byte(&amp;amp;eeFooByte) ) == EEPROM_DEF ) {&lt;br /&gt;
        myByte = fooByteDefault;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Wort lesen/schreiben ===&lt;br /&gt;
&lt;br /&gt;
Schreiben und Lesen von Datenworten erfolgt analog zur Vorgehensweise bei Bytes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
    uint16_t myWord;&lt;br /&gt;
&lt;br /&gt;
    myWord = eeprom_read_word(&amp;amp;eeFooWord); // lesen&lt;br /&gt;
    // myWord hat nun den Wert 12345&lt;br /&gt;
//...&lt;br /&gt;
    myWord = 2222;&lt;br /&gt;
    eeprom_write_word(&amp;amp;eeFooWord, myWord); // schreiben&lt;br /&gt;
//...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Block lesen/schreiben ===&lt;br /&gt;
&lt;br /&gt;
Lesen und Schreiben von Datenblöcken erfolgt über die Funktionen &#039;&#039;eeprom_read_block()&#039;&#039; bzw. &#039;&#039;eeprom_write_block()&#039;&#039;. Die Funktionen erwarten drei Parameter: die Adresse der Quell- bzw. Zieldaten im RAM, die EEPROM-Addresse und die Länge des Datenblocks in Bytes (size_t).&lt;br /&gt;
&lt;br /&gt;
TODO: &#039;&#039;&#039;Vorsicht!&#039;&#039;&#039; die folgenden Beispiele sind noch nicht geprüft, erstmal nur als Hinweis auf &amp;quot;das Prinzip&amp;quot;. Evtl. fehlen &amp;quot;casts&amp;quot; und möglicherweise noch mehr.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
    uint8_t  myByteBuffer[3];&lt;br /&gt;
    uint16_t myWordBuffer[4];&lt;br /&gt;
&lt;br /&gt;
    /* Datenblock aus EEPROM LESEN  */&lt;br /&gt;
&lt;br /&gt;
    /* liest 3 Bytes ab der von eeFooByteArray1 definierten EEPROM-Adresse&lt;br /&gt;
       in das RAM-Array myByteBuffer */&lt;br /&gt;
    eeprom_read_block(myByteBuffer,eeFooByteArray1,3);&lt;br /&gt;
&lt;br /&gt;
    /* dito etwas anschaulicher aber &amp;quot;unnütze Tipparbeit&amp;quot;: */&lt;br /&gt;
    eeprom_read_block(&amp;amp;myByteBuffer[0],&amp;amp;eeFooByteArray[0],3);&lt;br /&gt;
&lt;br /&gt;
    /* dito mit etwas Absicherung betr. der Länge */&lt;br /&gt;
    eeprom_read_block(myByteBuffer,eeFooByteArray1,sizeof(myByteBuffer));&lt;br /&gt;
&lt;br /&gt;
    /* und nun mit &amp;quot;16bit&amp;quot; */&lt;br /&gt;
    eeprom_read_block(myWordBuffer,eeFooWordArray1,sizeof(myWordBuffer));&lt;br /&gt;
&lt;br /&gt;
    /* Datenlock in EEPROM SCHREIBEN */&lt;br /&gt;
    eeprom_write_block(eeFooByteArray1,myByteBuffer,sizeof(myByteBuffer));&lt;br /&gt;
    eeprom_write_block(eeFooWordArray1,myWordBuffer,sizeof(myWordBuffer));&lt;br /&gt;
//...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Nicht-Integer&amp;quot;-Datentypen wie z.B. Fließkommazahlen lassen sich recht praktisch über eine &#039;&#039;union&#039;&#039; in &amp;quot;Byte-Arrays&amp;quot; konvertieren und wieder &amp;quot;zurückwandeln&amp;quot;. Dies erweist sich hier (aber nicht nur hier) als nützlich.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
   float myFloat = 12.34;&lt;br /&gt;
&lt;br /&gt;
   union {&lt;br /&gt;
      float r;&lt;br /&gt;
      uint8_t i[sizeof(float)];&lt;br /&gt;
   } u;&lt;br /&gt;
&lt;br /&gt;
   u.r = myFloat;&lt;br /&gt;
   &lt;br /&gt;
   /* float in EEPROM */&lt;br /&gt;
   eeprom_write_block(&amp;amp;eeFooFloat,&amp;amp;(u.i),sizeof(float));&lt;br /&gt;
&lt;br /&gt;
   /* float aus EEPROM */&lt;br /&gt;
   eeprom_read_block(&amp;amp;(u.i),&amp;amp;eeFooFloat,sizeof(float));&lt;br /&gt;
   /* u.r wieder 12.34 */&lt;br /&gt;
//...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Auch zusammengesetzte Typen lassen sich mit den Block-Routinen verarbeiten.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
typedef struct {&lt;br /&gt;
    uint8_t   label[8];&lt;br /&gt;
    uint8_t   rom_code[8];&lt;br /&gt;
} tMyStruct;&lt;br /&gt;
&lt;br /&gt;
#define MAXSENSORS 3&lt;br /&gt;
tMyStruct eeMyStruct[MAXSENSORS] EEMEM;&lt;br /&gt;
&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
void egal(void)&lt;br /&gt;
{&lt;br /&gt;
   tMyStruct work;&lt;br /&gt;
   &lt;br /&gt;
   strcpy(work.label,&amp;quot;Flur&amp;quot;);&lt;br /&gt;
   GetRomCode(work.rom_code);     // Dummy zur Veranschaulichung - setzt rom-code&lt;br /&gt;
&lt;br /&gt;
   /* Sichern von &amp;quot;work&amp;quot; im EEPROM */&lt;br /&gt;
   eeprom_write_block(&amp;amp;eeMyStruct[0],&amp;amp;work,sizeof(tMyStruct)); // f. Index 0&lt;br /&gt;
   strcpy(work.label,&amp;quot;Bad&amp;quot;);&lt;br /&gt;
   GetRomCode(work.rom_code);&lt;br /&gt;
   eeprom_write_block(&amp;amp;eeMyStruct[1],&amp;amp;work,sizeof(tMyStruct)); // f. Index 1&lt;br /&gt;
//...&lt;br /&gt;
   /* Lesen der Daten EEPROM Index 0 in &amp;quot;work&amp;quot; */&lt;br /&gt;
   eeprom_read_block(&amp;amp;work,&amp;amp;eeMyStruct[0],sizeof(tMyStruct));&lt;br /&gt;
   // work.label hat nun den Inhalt &amp;quot;Flur&amp;quot;&lt;br /&gt;
//...&lt;br /&gt;
}&lt;br /&gt;
//...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== EEPROM-Speicherabbild in .eep-Datei ===&lt;br /&gt;
&lt;br /&gt;
Mit den zum Compiler gehörenden Werkzeugen kann der aus den Variablendeklaration abgeleiteten EEPROM-Inhalt in eine Datei geschrieben werden (übliche Dateiendung: .eep, Daten im Intel Hex-Format). Damit können recht elegant Standardwerte für den EEPROM-Inhalt im Quellcode definiert werden. Makefiles nach WinAVR/MFile-Vorlage enthalten bereits die notwendigen Einstellungen (siehe dazu die Erläuterungen im Abschnitt Exkurs: Makefiles). Der Inhalt der eep-Datei muss ebenfalls zum Mikrocontroller übertragen werden (Write EEPROM), wenn die Initialisierungswerte aus der Deklaration vom Programm erwartet werden. Ansonsten enthält der EEPROM-Speicher nach der Übertragung des Programmers mittels ISP abhängig von der Einstellung der EESAVE-Fuse (vgl. Datenblatt Abschnitt Fuse Bits) die vorherigen Daten (EESAVE programmed = 0), deren Position möglicherweise nicht mehr mit der Belegung im aktuellen Programm übereinstimmt oder den Standardwert nach &amp;quot;Chip Erase&amp;quot;: 0xFF (EESAVE unprogrammed = 1). Als Sicherung kann man im Programm nochmals die Standardwerte vorhalten, beim Lesen auf 0xFF prüfen und gegebenfalls einen Standardwert nutzen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--Eine besondere Funktion des avr-gcc ist, dass mit entsprechenden Optionen im Makefile aus den Initialisierungswerten der Variablen im Quellcode eine Datei erzeugt werden kann, die man auf den Controller programmieren kann (.eep-Datei). Damit können sehr elegant Standardwerte für den EEPROM-Inhalt im Quellcode definiert werden. Die Vorgehensweise wird aus dem WinAVR-Beispielmakefile ersichtlich. Siehe dazu die Erläuterungen im Abschnitt Exkurs: Makefiles.--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== EEPROM-Variable auf feste Adressen legen ===&lt;br /&gt;
&lt;br /&gt;
Gleich zu Beginn möchte ich darauf hinweisen, dass dieses Verfahren nur ein Workaround ist, mit dem man das Problem der anscheinend &amp;quot;zufälligen&amp;quot; Verteilung&lt;br /&gt;
der EEPROM-Variablen durch den Compiler etwas in den Griff bekommen kann.&lt;br /&gt;
&lt;br /&gt;
Hilfreich kann dies vor allem dann sein, wenn man z.B. über einen Kommandointerpreter (o.ä. Funktionen) direkt bestimmte EEPROM-Adressen manipulieren möchte. Auch wenn man über einen JTAG-Adapter (mk I oder mkII) den Programmablauf manipulieren möchte, indem man die EEPROM-Werte direkt ändert, kann diese Technik hilfreich sein.&lt;br /&gt;
&lt;br /&gt;
Im folgenden nun zwei Sourcelistings mit einem Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
/////////////////////////////////////////////////&lt;br /&gt;
// Datei &amp;quot;eeprom.h&amp;quot; eines eigenen Projektes&lt;br /&gt;
/////////////////////////////////////////////////&lt;br /&gt;
&lt;br /&gt;
#inlcude &amp;lt;avr/eeprom.h&amp;gt;     // Die EEPROM-Definitionen/Macros der avr-libc einbinden&lt;br /&gt;
&lt;br /&gt;
#define   EESIZE   512      // Maximale Größe des EEPROMS&lt;br /&gt;
&lt;br /&gt;
#define   EE_DUMMY   0x000  // Dummyelement (Adresse 0 sollte nicht genutzt werden)&lt;br /&gt;
#define   EE_VALUE1  0x001  // Eine Bytevariable  &lt;br /&gt;
#define   EE_WORD1L  0x002  // Eine Wordvariable (Lowbyte)&lt;br /&gt;
#define   EE_WORD1H  0x003  // Eine Wordvariable (Highbyte)&lt;br /&gt;
#define   EE_VALUE2  0x004  // Eine weitere Bytevariable&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit den Macros &#039;&#039;&#039;#define EE_VALUE1&#039;&#039;&#039; legt man den Namen und die Adresse der&lt;br /&gt;
&#039;Variablen&#039; fest.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;font color=$FF0000&amp;gt;WICHTIG:&amp;lt;/font&amp;gt;Die Adressen sollten fortlaufend, zumindest aber aufsteigend sortiert sein! Ansonsten besteht die Gefahr, daß man sehr schnell ein Durcheinander im EEPROM Speicher veranstaltet.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;font color=$FF0000&amp;gt;WICHTIG:&amp;lt;/font&amp;gt;Für den Compiler sind das lediglich Speicher-Adressen, über die auf das EEPROM zugegriffen wird. Der Compiler sieht nichts davon als eine echte Variable an und stößt sich daher auch nicht daran, wenn 2 Makros mit der gleichen Speicheradresse, bzw. überlappenden Speicherbereichen definiert werden. Es liegt einzig und alleine in der Hand des Programmierers, hier keinen Fehler zu machen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
/////////////////////////////////////////////////&lt;br /&gt;
// Datei &amp;quot;eeprom.c&amp;quot; eines eigenen Projektes&lt;br /&gt;
/////////////////////////////////////////////////&lt;br /&gt;
&lt;br /&gt;
#include &amp;quot;eeprom.h&amp;quot;          // Eigene EEPROM-Headerdatei einbinden&lt;br /&gt;
&lt;br /&gt;
uint8_t ee_mem[EESIZE] EEMEM =&lt;br /&gt;
{&lt;br /&gt;
   [EE_DUMMY]   = 0x00,&lt;br /&gt;
   [EE_VALUE1]  = 0x05,&lt;br /&gt;
   [EE_WORD1L]  = 0x01,   &lt;br /&gt;
   [EE_WORD1H]  = 0x00,&lt;br /&gt;
   [EE_VALUE2]  = 0xFF&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Durch die Verwendung eines Array, welches das gesammte EEPROM umfasst, bleibt&lt;br /&gt;
dem Compiler nicht anderes übrig, als das Array so zu platzieren, dass Element 0&lt;br /&gt;
des Arrays der Adresse 0 des EEPROMs entspricht. (&#039;&#039;Ich hoffe nur, dass die Compilerbauer daran nichts ändern!&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
Wie man in dem obigen Codelisting auch sehen kann, hat das Verfahren einen kleinen Haken. Variablen die größer sind als 1 Byte, müssen etwas umständlicher&lt;br /&gt;
definiert werden. Benötigt man keine Initialisierung durch das Programm (was der Normalfall sein dürfte), dann kann man das auch so machen:&lt;br /&gt;
&lt;br /&gt;
Möchte man im EEPROM hintereinander beispielsweise Variablen, mit den Namen &#039;&#039;&#039;Wert&#039;&#039;&#039;, &#039;&#039;&#039;Anzahl&#039;&#039;&#039;, &#039;&#039;&#039;Name&#039;&#039;&#039; und &#039;&#039;&#039;Wertigkeit&#039;&#039;&#039; definieren, wobei Wert und Wertigkeit 1 Byte belegen sollen, Anzahl als 1 Wort (also 2 Bytes) und Name mit 10 Bytes reserviert werden soll, so geht auch folgendes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#define EE_DUMMY      0x000&lt;br /&gt;
#define EE_WERT       ( 0x000 + sizeof( uint8_t ) )&lt;br /&gt;
#define EE_ANZAHL     ( EE_WERT + sizeof( uint8_t ) )&lt;br /&gt;
#define EE_NAME       ( EE_ANZAHL + sizeof( uint16_t ) )&lt;br /&gt;
#define EE_WERTIGKEIT ( EE_NAME + 10 * sizeof( uint8_t ) )&lt;br /&gt;
#define EE_LAST       ( EE_WERTIGKEIT + sizeof( uint8_t ) )&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jedes Makro definiert also seine Startadresse durch die Startadresse der unmittelbar vorhergehende &#039;Variablen&#039; plus der Anzahl der Bytes die von der vorhergehenden &#039;Variablen&#039; verbraucht werden. Dadurch ist man zumindest etwas auf der sicheren Seite, dass keine 2 &#039;Variablen&#039; im EEPROM überlappend definiert werden. Möchte man eine weitere &#039;Variable&#039; hinzufügen, so wird deren&lt;br /&gt;
Name, einfach anstelle der EE_LAST eingesetzt und eine neue Zeile für EE_LAST eingefügt, in der dann die Größe der &#039;Variablen&#039; festgelegt wird. Zb.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#define EE_DUMMY      0x000&lt;br /&gt;
#define EE_WERT       ( 0x000 + sizeof( uint8_t ) )&lt;br /&gt;
#define EE_ANZAHL     ( EE_WERT + sizeof( uint8_t ) )&lt;br /&gt;
#define EE_NAME       ( EE_ANZAHL + sizeof( uint16_t ) )&lt;br /&gt;
#define EE_WERTIGKEIT ( EE_NAME + 10 * sizeof( uint8_t ) )&lt;br /&gt;
#define EE_PROZENT    ( EE_WERTIGKEIT + sizeof( uint8_t ) )&lt;br /&gt;
#define EE_LAST       ( EE_WERTIGKEIT + sizeof( double ) )&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
EE_PROZENT legt die Startadresse für eine neue &#039;Variable&#039; des Datentyps double fest.&lt;br /&gt;
&lt;br /&gt;
Der Zugriff auf die EEPROM Werte kann dann z.B.so erfolgen:&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
uint8_t   temp1;&lt;br /&gt;
uint16_t  temp2;&lt;br /&gt;
&lt;br /&gt;
temp1 = eeprom_read_byte(EE_VALUE1);&lt;br /&gt;
temp2 = eeprom_read_word(EE_WORD1L);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ob die in der avr-libc vorhandenen Funktionen dafür verwendet werden können, weiß ich nicht. Aber in einigen Fällen muss man sich sowieso eigene Funktionen&lt;br /&gt;
bauen, welche die spezifischen Anforderungen (Interrupt - Atom Problem, etc.)&lt;br /&gt;
erfüllen.&lt;br /&gt;
&lt;br /&gt;
Die oben beschriebene Möglichkeit ist nur eine Möglichkeit, wie man dies realisieren kann. Sie bietet einem eine relativ einfache Art die EEPROM-Werte&lt;br /&gt;
auf beliebige Adressen zu legen oder Adressen zu ändern. Die Andere Möglichkeit besteht darin, die EEPROM-Werte wie folgt zu belegen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
/////////////////////////////////////////////////&lt;br /&gt;
// Datei &amp;quot;eeprom.c&amp;quot; eines eigenen Projektes&lt;br /&gt;
/////////////////////////////////////////////////&lt;br /&gt;
&lt;br /&gt;
#include &amp;quot;eeprom.h&amp;quot;          // Eigene EEPROM-Headerdatei einbinden&lt;br /&gt;
&lt;br /&gt;
uint8_t ee_mem[EESIZE] EEMEM =&lt;br /&gt;
{&lt;br /&gt;
  0x00,                     //  ee_dummy&lt;br /&gt;
  0x05,                     //  ee_value1&lt;br /&gt;
  0x01,                     //  ee_word1L&lt;br /&gt;
  0x00,                     // (ee_word1H)&lt;br /&gt;
  0xFF                      //  ee_value2&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hierbei kann man Variablen, die größer sind als 1 Byte einfacher definieren und&lt;br /&gt;
man muss nur die Highbyte- oder Lowbyte-Adresse in der &amp;quot;eeprom.h&amp;quot; definieren.&lt;br /&gt;
Allerdings muss man hier höllisch aufpassen, dass man nicht um eine oder mehrere&lt;br /&gt;
Positionen verrutscht!&lt;br /&gt;
&lt;br /&gt;
Welche der beiden Möglichkeiten man einsetzt, hängt vor allem davon ab, wieviele&lt;br /&gt;
Byte, Word und sonstige Variablen man benutzt. Gewöhnen sollte man sich an beide Varianten können ;)&lt;br /&gt;
&lt;br /&gt;
Kleine Schlussbemerkung:&lt;br /&gt;
&lt;br /&gt;
* Der avr-gcc unterstützt die Variante 1 und die Variante 2&lt;br /&gt;
* Der icc-avr Compiler unterstützt nur die Variante 2!&lt;br /&gt;
&lt;br /&gt;
=== Bekannte Probleme bei den EEPROM-Funktionen ===&lt;br /&gt;
&lt;br /&gt;
Vorsicht: Bei alten Versionen der avr-libc wurden nicht alle AVR Controller  untersützt. Z.B. bei der avr-libc Version 1.2.3 insbesondere bei AVRs &amp;quot;der neuen Generation&amp;quot; (ATmega48/88/168/169) funktionieren die Funktionen nicht korrekt (Ursache: unterschiedliche Speicheradressen der EEPROM-Register). In neueren Versionen (z.B. avr-libc 1.4.3 aus WinAVR 20050125) wurde die Zahl der unterstüzten Controller deutlich erweitert und eine Methode zur leichten Anpassung an zukünftige Controller eingeführt.&lt;br /&gt;
&lt;br /&gt;
In jedem Datenblatt zu AVR-Controllern mit EEPROM sind kurze Beispielecodes für den Schreib- und Lesezugriff enthalten. Will oder kann man nicht auf die neue Version aktualisieren, kann der dort gezeigte Code auch mit dem avr-gcc (ohne avr-libc/eeprom.h) genutzt werden (&amp;quot;copy/paste&amp;quot;, gegebenfalls Schutz vor Unterbrechnung/Interrupt ergänzen &#039;&#039;uint8_t sreg; sreg=SREG; cli(); [EEPROM-Code] ; SREG=sreg; return;&#039;&#039;, siehe Abschnitt Interrupts). Im Zweifel hilft ein Blick in den vom Compiler erzeugten Assembler-Code (lst/lss-Dateien).&lt;br /&gt;
&lt;br /&gt;
* siehe auch: [http://www.nongnu.org/avr-libc/user-manual/index.html Dokumentation der avr-libc] Abschnitt Modules/EEPROM handling&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== EEPROM Register ===&lt;br /&gt;
Um das EEPROM anzusteuern sind drei Register von Bedeutung.&amp;lt;BR&amp;gt;&lt;br /&gt;
&amp;lt;LI&amp;gt; EEAR Hier werden die Adressen eingetragen zum Schreiben oder Lesen. Dieses Register unterteilt sich nochmal in EEARH und EEARL da in einem 8 Bit Register keine 512 Adressen adressiert werden können&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
&amp;lt;LI&amp;gt; EEDR Hier werden die Daten eingetragen die geschrieben werden sollen bzw. es enthält die gelesenen Daten&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
&amp;lt;LI&amp;gt; EECR Ist das Kontrollregister für das EEPROM&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das EECR steuert den Zugriff auf das EEPROM und ist wie folgt aufgebaut:&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;TABLE BORDER=1&amp;gt;&lt;br /&gt;
&amp;lt;TR&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;Bit&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;&amp;amp;nbsp;&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;7&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;6&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;5&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;4&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;3&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;2&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;1&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;0&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;/TD&amp;gt;&lt;br /&gt;
&amp;lt;/TR&amp;gt;&lt;br /&gt;
&amp;lt;TR&amp;gt; &lt;br /&gt;
  &amp;lt;TD&amp;gt;Name&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;&amp;amp;nbsp;&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;-&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;-&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;-&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;-&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;EERIE&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;EEMWE&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;EEWE&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;EERE&amp;lt;/TD&amp;gt;&lt;br /&gt;
&amp;lt;/TR&amp;gt;&lt;br /&gt;
&amp;lt;TR&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;Read/Write&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;R&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;R&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;R&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;R&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;R/W&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;R/W&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;R/W&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;R/W&amp;lt;/TD&amp;gt;&lt;br /&gt;
&amp;lt;/TR&amp;gt;&lt;br /&gt;
&amp;lt;TR&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;Init Value&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;0&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;0&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;0&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;0&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;0&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;0&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;0&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;0&amp;lt;/TD&amp;gt;&lt;br /&gt;
&amp;lt;/TR&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/TABLE&amp;gt;&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;U&amp;gt;Bedeutung der Bits:&amp;lt;/U&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
Bit 4-7 nicht belegt.&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;U&amp;gt;Bit 3 (EERIE) - EEPROM Ready Interrupt Enable:&amp;lt;/U&amp;gt; Wenn das Bit gesetzt ist und globale Interrupts erlaubt sind in Register SREG (Bit 7) wird ein Interrupt ausgelöst nach Beendigung des Schreibzyklus (EEPROM Ready Interrupt). Ist einer der beiden Bits 0 wird kein Interrupt ausgelöst.&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;U&amp;gt;Bit 2(EEMWE) - EEPROM Master Write Enable:&amp;lt;/U&amp;gt; Dieses Bit bestimmt, daß wenn EEWE = 1 gesetzt wird (innerhalb von 4 Taktzyklen), das EEPROM beschrieben wird mit den Daten in EEDR bei Adresse EEAR. Wenn EEMWE =0 ist und EEWE = 1 gesetzt wird hat das keine Auswirkungen. Der Schreibvorgang wird dann nicht ausgelöst.&lt;br /&gt;
Nach 4 Taktzyklen wird das Bit EEMWE automatisch wieder auf 0 gesetzt. Dieses Bit löst den Schreibvorgang nicht aus, es dient sozusagen als Sicherungsbit für EEWE.&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;U&amp;gt;Bit 1 (EEWE) - EEPROM Write Enable:&amp;lt;/U&amp;gt; Dieses Bit löst den Schreibvorgang aus wenn es auf 1 gesetzt wird, sofern vorher EEMWE gesetzt wurde und seitdem nicht mehr als 4 Taktzyklen vergangen sind. Wenn der Schreibvorgang abgeschlossen ist wird dieses Bit automatisch wieder auf 0 gesetzt und sofern EERIE gesetzt ist ein Interrupt ausgelöst. &amp;lt;BR&amp;gt;&lt;br /&gt;
Ein Schreibvorgang sieht typischerweise wie folgt aus:&amp;lt;BR&amp;gt;&lt;br /&gt;
1. EEPROM Bereitschaft abwarten (EEWE=0) &lt;br /&gt;
2. Adresse übergeben an EEAR&amp;lt;BR&amp;gt;&lt;br /&gt;
3. Daten übergeben an EEDR&amp;lt;BR&amp;gt;&lt;br /&gt;
4. Schreibvorgang auslösen in EECR mit Bit EEMWE=1 und EEWE=1 &amp;lt;BR&amp;gt;&lt;br /&gt;
5. (Optinal) Warten bis Schreibvorgang abgeschlossen ist.&amp;lt;BR&amp;gt;&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
&amp;lt;U&amp;gt;Bit 0 EERE – EEPROM Read Enable:&amp;lt;/U&amp;gt; Wird dieses Bit auf 1 gesetzt wird das EEPROM an der Adresse in EEAR ausgelesen und die Daten in EEDR gespeichert. Das EEPROM kann nicht ausgelesen werden wenn bereits eine Schreiboperation gestartet wurde. Es ist daher zu empfehlen die Bereitschaft vorher zu prüfen. Das EEPROM ist lesebereit wenn das Bit EEWE=0 ist. ISt der LEsevorgang abgeschlossen wird das Bit wieder auf 0 gesetzt und das EEPROM ist für neue Lese/Schreibbefehle wieder bereit.&amp;lt;BR&amp;gt;&lt;br /&gt;
Ein typischer Lesevorgang kann wie folgt aufgebaut sein:&amp;lt;BR&amp;gt;&lt;br /&gt;
1. Bereitschaft zum lesen prüfen (EEWE=0)&amp;lt;BR&amp;gt;&lt;br /&gt;
2. Adresse übergeben an EEAR&amp;lt;BR&amp;gt;&lt;br /&gt;
3. Lesezyklus auslösen mit EERE = 1&amp;lt;BR&amp;gt;&lt;br /&gt;
4. Warten bis Lesevorgang abgeschlossen EERE = 0&amp;lt;BR&amp;gt;&lt;br /&gt;
5. Daten abholen aus EEDR&amp;lt;BR&amp;gt;&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Die Nutzung von printf =&lt;br /&gt;
&lt;br /&gt;
Um komfortabel Ausgaben auf ein Display oder die serielle Schnittstelle zu tätigen, bietet sich printf/sprintf an. &lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// ...&lt;br /&gt;
// nicht dargestellt: Implementierung von uart_puts (vgl. Abschnitt UART)&lt;br /&gt;
// ...&lt;br /&gt;
&lt;br /&gt;
uint16_t counter;&lt;br /&gt;
&lt;br /&gt;
void uart_puti( uint16_t value )&lt;br /&gt;
{&lt;br /&gt;
    uint8_t s[20];&lt;br /&gt;
&lt;br /&gt;
    sprintf( s, &amp;quot;Zählerstand: %d&amp;quot;, value );&lt;br /&gt;
    uart_puts( s );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int main()&lt;br /&gt;
{&lt;br /&gt;
  counter = 5;&lt;br /&gt;
&lt;br /&gt;
  uart_puti( counter );&lt;br /&gt;
  uart_puti( 42 );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Eine weitere elegante Möglichkeit besteht darin, die Ausgabe stdout auf eigene Ausgabefunktionen umzuleiten. Dazu wird dem Ausgabemechanismus eine neue Ausgabefunktion bekannt gemacht, deren Aufgabe es ist, ein einzelnes Zeichen auszugeben (wie auch immer die Ausgabe stattfindet). Alle anderen, höheren, Funktionen greifen letztendlich auf diese eine Ausgabefunktion zurück, die die Ausgabe eines einzelnen Zeichens vornimmt. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
void uart_init(void);&lt;br /&gt;
int uart_putchar(char c, FILE *stream);&lt;br /&gt;
&lt;br /&gt;
static FILE mystdout = FDEV_SETUP_STREAM( uart_putchar, NULL, _FDEV_SETUP_WRITE );&lt;br /&gt;
&lt;br /&gt;
void uart_init(void)&lt;br /&gt;
{&lt;br /&gt;
    /* hier µC spezifischen Code zur Initialisierung */&lt;br /&gt;
    /* des UART einfügen... s.o. im AVR-GCC-Tutorial */&lt;br /&gt;
&lt;br /&gt;
    // Beispiel: &lt;br /&gt;
    //&lt;br /&gt;
    // myAVR Board 1.5 mit externem Quarz Q1 3,6864 MHz&lt;br /&gt;
    // 9600 Baud 8N1&lt;br /&gt;
&lt;br /&gt;
#ifndef F_CPU&lt;br /&gt;
#define F_CPU 3686400&lt;br /&gt;
#endif&lt;br /&gt;
#define UART_BAUD_RATE 9600&lt;br /&gt;
&lt;br /&gt;
// Hilfsmakro zur UBRR-Berechnung (&amp;quot;Formel&amp;quot; laut Datenblatt)&lt;br /&gt;
#define UART_UBRR_CALC(BAUD_,FREQ_) ((FREQ_)/((BAUD_)*16L)-1)&lt;br /&gt;
&lt;br /&gt;
    UCSRB |= (1&amp;lt;&amp;lt;TXEN) | (1&amp;lt;&amp;lt;RXEN);    // UART TX und RX einschalten&lt;br /&gt;
    UCSRC |= (1&amp;lt;&amp;lt;URSEL)|(3&amp;lt;&amp;lt;UCSZ0);    // Asynchron 8N1 &lt;br /&gt;
 &lt;br /&gt;
    UBRRH = (uint8_t)( UART_UBRR_CALC( UART_BAUD_RATE, F_CPU ) &amp;gt;&amp;gt; 8 );&lt;br /&gt;
    UBRRL = (uint8_t)UART_UBRR_CALC( UART_BAUD_RATE, F_CPU );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int uart_putchar( char c, FILE *stream )&lt;br /&gt;
{&lt;br /&gt;
    if( c == &#039;\n&#039; )&lt;br /&gt;
        uart_putchar( &#039;\r&#039;, stream );&lt;br /&gt;
&lt;br /&gt;
    loop_until_bit_is_set( UCSRA, UDRE );&lt;br /&gt;
    UDR = c;&lt;br /&gt;
    return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int main(void)&lt;br /&gt;
{&lt;br /&gt;
    uart_init();&lt;br /&gt;
    stdout = &amp;amp;mystdout;&lt;br /&gt;
    printf( &amp;quot;Hello, world!\n&amp;quot; );&lt;br /&gt;
    return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Quelle: avr-libc-user-manual-1.4.3.pdf, S.74&lt;br /&gt;
//         + Ergänzungen&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Sollen Fließkommazahlen ausgegeben werden, muss im Makefile eine andere (größere) Version der [[FAQ#Aktivieren_der_Floating_Point_Version_von_sprintf_beim_WinAVR_mit_AVR-Studio|printflib]] eingebunden werden.&lt;br /&gt;
&lt;br /&gt;
Der Nachteil aller printf-Varianten: Sie sind recht speicherintensiv.&lt;br /&gt;
&lt;br /&gt;
= Assembler und Inline-Assembler =&lt;br /&gt;
&lt;br /&gt;
Gelegentlich erweist es sich als nützlich, C- und Assembler-Code in einer Anwendung zu nutzen. Typischerweise wird das Hauptprogramm in C verfasst und wenige, extrem zeitkritische oder hardwarenahe Operationen in Assembler.&lt;br /&gt;
&lt;br /&gt;
Die &amp;quot;gnu-Toolchain&amp;quot; bietet dazu zwei Möglichkeiten:&lt;br /&gt;
&lt;br /&gt;
* Inline-Assembler: Die Assembleranweisungen werden direkt in den C-Code integriert. Eine Quellcode-Datei enthält somit C- und Assembleranweisungen&lt;br /&gt;
* Assembler-Dateien: Der Assemblercode befindet sich in eigenen Quellcodedateien. Diese werden vom gnu-Assembler (avr-as) zu Object-Dateien assembliert (&amp;quot;compiliert&amp;quot;) und mit den aus dem C-Code erstellten Object-Dateien zusammengebunden (gelinkt).&lt;br /&gt;
&lt;br /&gt;
== Inline-Assembler ==&lt;br /&gt;
&lt;br /&gt;
Inline-Assembler bietet sich an, wenn nur wenig Assembleranweisungen benötigt werden. Typische Anwendung sind kurze Codesequenzen für zeitkritische Operationen in Interrupt-Routinen oder sehr präzise Warteschleifen (z.B. 1-Wire). Inline-Assembler wird mit &#039;&#039;&#039;asm volatile&#039;&#039;&#039; eingeleitet, die Assembler-Anweisungen werden in einer Zeichenkette zusammengefasst, die als &amp;quot;Parameter&amp;quot; übergeben wird. Durch Doppelpunkte getrennt werden die Ein- und Ausgaben sowie die &amp;quot;Clobber-Liste&amp;quot; angegeben.&lt;br /&gt;
&lt;br /&gt;
Ein einfaches Beispiel für Inline-Assembler ist das Einfügen einer NOP-Anweisung (NOP steht für No Operation). Dieser Assembler-Befehl benötigt genau einen Taktzyklus, ansonsten &amp;quot;tut sich nichts&amp;quot;. Sinnvolle Anwendungen für NOP sind genaue Delay(=Warte)-Funktionen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
    ...&lt;br /&gt;
   /* Verzögern der weiteren Programmausführung um&lt;br /&gt;
      genau 3 Taktzyklen */&lt;br /&gt;
    asm volatile (&amp;quot;nop&amp;quot;);&lt;br /&gt;
    asm volatile (&amp;quot;nop&amp;quot;);&lt;br /&gt;
    asm volatile (&amp;quot;nop&amp;quot;);&lt;br /&gt;
    ...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Weiterhin kann mit einem NOP verhindert werden, dass leere Schleifen, die als Warteschleifen gedacht sind, wegoptimiert werden. Der Compiler erkennt ansonsten die vermeintlich nutzlose Schleife und erzeugt dafür keinen Code im ausführbaren Programm.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
    ...&lt;br /&gt;
    uint16_t i;&lt;br /&gt;
&lt;br /&gt;
    /* leere Schleife - wird bei eingeschalteter Compiler-Optimierung   wegoptimiert */&lt;br /&gt;
    for (i = 0; i &amp;lt; 1000; i++)&lt;br /&gt;
      ;&lt;br /&gt;
&lt;br /&gt;
    ...&lt;br /&gt;
&lt;br /&gt;
    /* Schleife erzwingen (keine Optimierung): &amp;quot;NOP-Methode&amp;quot; */&lt;br /&gt;
    for (i = 0; i &amp;lt; 1000; i++)&lt;br /&gt;
      asm volatile(&amp;quot;NOP&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    ...&lt;br /&gt;
&lt;br /&gt;
    /* alternative Methode (keine Optimierung): */&lt;br /&gt;
    volatile uint16_t j;&lt;br /&gt;
    for (j = 0; j &amp;lt; 1000; j++)&lt;br /&gt;
      ;&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein weiterer nützlicher &amp;quot;Assembler-Einzeiler&amp;quot; ist der Aufruf von sleep (&#039;&#039;asm volatile (&amp;quot;sleep&amp;quot;);&#039;&#039;), da hierzu in älteren Versionen der avr-libc keine eigene Funktion existiert (in neueren Versionen &#039;&#039;sleep_cpu()&#039;&#039; aus sleep.h).&lt;br /&gt;
&lt;br /&gt;
Als Beispiel für mehrzeiligen Inline-Assembler eine präzise Delay-Funktion. Die Funktion erhält ein 16-bit Wort als Parameter, prüft den Parameter auf 0 und beendet die Funktion in diesem Fall oder durchläuft die folgende Schleife sooft wie im Wert des Parameters angegeben. Inline-Assembler hat hier den Vorteil, dass die Laufzeit unabhängig von der Optimierungsstufe (Parameter -O, vgl. makefile) und der Compiler-Version ist.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
static inline void delayloop16 (uint16_t count)&lt;br /&gt;
{&lt;br /&gt;
    asm volatile (&amp;quot;cp  %A0, __zero_reg__ \n\t&amp;quot;&lt;br /&gt;
                  &amp;quot;cpc %B0, __zero_reg__ \n\t&amp;quot;&lt;br /&gt;
                  &amp;quot;breq 2f               \n\t&amp;quot;&lt;br /&gt;
                  &amp;quot;1:                    \n\t&amp;quot;&lt;br /&gt;
                  &amp;quot;sbiw %0,1             \n\t&amp;quot;&lt;br /&gt;
                  &amp;quot;brne 1b               \n\t&amp;quot;&lt;br /&gt;
                  &amp;quot;2:                    &amp;quot;  &lt;br /&gt;
                  : &amp;quot;=w&amp;quot; (count)&lt;br /&gt;
	          : &amp;quot;0&amp;quot;  (count)&lt;br /&gt;
    );                            &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Jede Anweisung wird mit &#039;&#039;&#039;\n\t&#039;&#039;&#039; abgeschlossen. Der Zeilenumbruch teilt dem Assembler mit, dass ein neuer Befehl beginnt.&lt;br /&gt;
* Als Sprung-Marken (Labels) werden Ziffern verwendet. Diese speziellen Labels sind mehrfach im Code verwendbar. Gesprungen wird jeweils zurück (b) oder vorwärts (f) zum nächsten ausffindbaren Label.&lt;br /&gt;
&lt;br /&gt;
Das Resultat zeigt ein Blick in die Assembler-Datei, die der Compiler mit der option &amp;lt;tt&amp;gt;-save-temps&amp;lt;/tt&amp;gt; nicht löscht:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;avrasm&amp;gt;&lt;br /&gt;
	cp  r24, __zero_reg__ 	 ;  count&lt;br /&gt;
	cpc r25, __zero_reg__ 	 ;  count&lt;br /&gt;
	breq 2f               &lt;br /&gt;
	1:                    &lt;br /&gt;
	sbiw r24,1             	 ;  count&lt;br /&gt;
	brne 1b               &lt;br /&gt;
	2:&lt;br /&gt;
&amp;lt;/avrasm&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Detaillierte Ausführungen zum Thema Inline-Assembler finden sich in der Dokumentation der avr-libc im Abschnitt [http://www.nongnu.org/avr-libc/user-manual/inline_asm.html Related Pages/Inline Asm]. &lt;br /&gt;
&lt;br /&gt;
Siehe auch: &lt;br /&gt;
* [http://www.atmel.com/dyn/resources/prod_documents/doc0856.pdf AVR Assembler-Anweisungsliste]&lt;br /&gt;
* [http://www.roboternetz.de/wissen/index.php/Inline-Assembler_in_avr-gcc Deutsche Einführung in Inline-Assembler]&lt;br /&gt;
&lt;br /&gt;
== Assembler-Dateien ==&lt;br /&gt;
&lt;br /&gt;
Assembler-Dateien erhalten die Endung .S (&#039;&#039;grosses&#039;&#039; S) und werden im makefile nach WinAVR/mfile-Vorlage hinter &#039;&#039;ASRC=&#039;&#039; durch Leerzeichen getrennt aufgelistet.&lt;br /&gt;
&lt;br /&gt;
Wenn man mit dem AVR Studio arbeitet, kann alternativ auch das standardmäßig erstellte Makefile bearbeitet und folgende Zeilen eingefügt werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;code&amp;quot;&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
## Objects that must be built in order to link&lt;br /&gt;
OBJECTS = (alte Dateien...) useful.o&lt;br /&gt;
&lt;br /&gt;
## Compile&lt;br /&gt;
## Hier folgt eine Liste der gelinkten Dateien, darunter einfügen:&lt;br /&gt;
useful.o: ../useful.S&lt;br /&gt;
	$(CC) $(INCLUDES) $(ASMFLAGS) -c  $&amp;lt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
Das war es schon. Allerdings gilt es zu beachten, dass das makefile über &amp;quot;Project -&amp;gt; Configuration options&amp;quot; selbst einzubinden ist, sonst wird es natürlich wieder überschrieben.&lt;br /&gt;
&lt;br /&gt;
Im Beispiel eine Funktion &#039;&#039;superFunc&#039;&#039;, die alle Pins des Ports D auf &amp;quot;Ausgang&amp;quot; schaltet, eine Funktion &#039;&#039;ultraFunc&#039;&#039;, die die Ausgänge entsprechend des übergebenen Parameters schaltet, eine Funktion &#039;&#039;gigaFunc&#039;&#039;, die den Status von Port A zurückgibt und eine Funktion &#039;&#039;addFunc&#039;&#039;, die zwei Bytes zu einem 16-bit-Wort addiert. Die Zuweisungen im C-Code (PORTx = ...) verhindern, dass der Compiler die Aufrufe wegoptimiert und dienen nur zur Veranschaulichung der Parameterübergaben.&lt;br /&gt;
&lt;br /&gt;
Zuerst der Assembler-Code. Der Dateiname sei useful.S:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;avrasm&amp;gt;&lt;br /&gt;
#include &amp;quot;avr/io.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
//; Arbeitsregister (ohne &amp;quot;r&amp;quot;) &lt;br /&gt;
workreg  = 16&lt;br /&gt;
workreg2 = 17&lt;br /&gt;
&lt;br /&gt;
//; Konstante:&lt;br /&gt;
ALLOUT = 0xff&lt;br /&gt;
&lt;br /&gt;
//; ** Setze alle Pins von PortD auf Ausgang **&lt;br /&gt;
//; keine Parameter, keine Rückgabe&lt;br /&gt;
.global superFunc&lt;br /&gt;
.func superFunc&lt;br /&gt;
superFunc:&lt;br /&gt;
   push workreg&lt;br /&gt;
   ldi workreg, ALLOUT&lt;br /&gt;
   out  _SFR_IO_ADDR(DDRD), workreg  // beachte: _SFR_IO_ADDR()&lt;br /&gt;
   pop workreg&lt;br /&gt;
   ret&lt;br /&gt;
.endfunc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
//; ** Setze PORTD auf übergebenen Wert **&lt;br /&gt;
//; Parameter in r24 (LSB immer bei &amp;quot;graden&amp;quot; Nummern)&lt;br /&gt;
.global ultraFunc&lt;br /&gt;
.func ultraFunc&lt;br /&gt;
ultraFunc:&lt;br /&gt;
   out  _SFR_IO_ADDR(PORTD), 24&lt;br /&gt;
   ret&lt;br /&gt;
.endfunc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
//; ** Zustand von PINA zurückgeben **&lt;br /&gt;
//; Rückgabewerte in r24:r25 (LSB:MSB), hier nur LSB genutzt&lt;br /&gt;
.global gigaFunc&lt;br /&gt;
.func gigaFunc&lt;br /&gt;
gigaFunc:&lt;br /&gt;
   in 24, _SFR_IO_ADDR(PINA)&lt;br /&gt;
   ret&lt;br /&gt;
.endfunc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
//; ** Zwei Bytes addieren und 16-bit-Wort zurückgeben **&lt;br /&gt;
//; Parameter in r24 (Summand1) und r22 (Summand2) -&lt;br /&gt;
//;  Parameter sind Word-&amp;quot;aligned&amp;quot; d.h. LSB immer auf &amp;quot;graden&amp;quot;&lt;br /&gt;
//;  Registernummern. Bei 8-Bit und 16-Bit Paramtern somit &lt;br /&gt;
//;  beginnend bei r24 dann r22 dann r20 etc.&lt;br /&gt;
//; Rückgabewert in r24:r25&lt;br /&gt;
.global addFunc&lt;br /&gt;
.func addFunc&lt;br /&gt;
addFunc:&lt;br /&gt;
   push workreg&lt;br /&gt;
   push workreg2&lt;br /&gt;
   clr workreg2&lt;br /&gt;
   mov workreg, 22&lt;br /&gt;
   add workreg, 24&lt;br /&gt;
   adc workreg2, 1    // r1 - assumed to be always zero ...&lt;br /&gt;
   movw r24, workreg&lt;br /&gt;
   pop workreg2&lt;br /&gt;
   pop workreg&lt;br /&gt;
   ret&lt;br /&gt;
.endfunc&lt;br /&gt;
&lt;br /&gt;
//; oh je - sorry - Mein AVR-Assembler ist eingerostet, hoffe das stimmt so...&lt;br /&gt;
&lt;br /&gt;
.end&lt;br /&gt;
&amp;lt;/avrasm&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im Makefile ist der Name der Assembler-Quellcodedatei einzutragen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;code&amp;quot;&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
ASRC = useful.S&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Aufruf erfolgt dann im C-Code so:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
extern void superFunc(void);&lt;br /&gt;
extern void ultraFunc(uint8_t setVal);&lt;br /&gt;
extern uint8_t gigaFunc(void);&lt;br /&gt;
extern uint16_t addFunc(uint8_t w1, uint8_t w2);&lt;br /&gt;
&lt;br /&gt;
int main(void)&lt;br /&gt;
{&lt;br /&gt;
[...]&lt;br /&gt;
  superFunc();&lt;br /&gt;
  &lt;br /&gt;
  ultraFunc(0x55);&lt;br /&gt;
  &lt;br /&gt;
  PORTD = gigaFunc();&lt;br /&gt;
&lt;br /&gt;
  PORTA = (addFunc(0xF0, 0x11) &amp;amp; 0xff);&lt;br /&gt;
  PORTB = (addFunc(0xF0, 0x11) &amp;gt;&amp;gt; 8);&lt;br /&gt;
[...]&lt;br /&gt;
} &lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Ergebnis wird wieder in der lss-Datei ersichtlich:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;code&amp;quot;&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
[...]&lt;br /&gt;
   superFunc();&lt;br /&gt;
 148:	0e 94 f6 00 	call	0x1ec&lt;br /&gt;
  &lt;br /&gt;
  ultraFunc(0x55);&lt;br /&gt;
 14c:	85 e5       	ldi	r24, 0x55	; 85&lt;br /&gt;
 14e:	0e 94 fb 00 	call	0x1f6&lt;br /&gt;
  &lt;br /&gt;
  PORTD = gigaFunc();&lt;br /&gt;
 152:	0e 94 fd 00 	call	0x1fa&lt;br /&gt;
 156:	82 bb       	out	0x12, r24	; 18&lt;br /&gt;
  &lt;br /&gt;
  PORTA = (addFunc(0xF0, 0x11) &amp;amp; 0xff);&lt;br /&gt;
 158:	61 e1       	ldi	r22, 0x11	; 17&lt;br /&gt;
 15a:	80 ef       	ldi	r24, 0xF0	; 240&lt;br /&gt;
 15c:	0e 94 ff 00 	call	0x1fe&lt;br /&gt;
 160:	8b bb       	out	0x1b, r24	; 27&lt;br /&gt;
  PORTB = (addFunc(0xF0, 0x11) &amp;gt;&amp;gt; 8);&lt;br /&gt;
 162:	61 e1       	ldi	r22, 0x11	; 17&lt;br /&gt;
 164:	80 ef       	ldi	r24, 0xF0	; 240&lt;br /&gt;
 166:	0e 94 fc 00 	call	0x1f8&lt;br /&gt;
 16a:	89 2f       	mov	r24, r25&lt;br /&gt;
 16c:	99 27       	eor	r25, r25&lt;br /&gt;
 16e:	88 bb       	out	0x18, r24	; 24&lt;br /&gt;
&lt;br /&gt;
[...]&lt;br /&gt;
000001ec &amp;lt;superFunc&amp;gt;:&lt;br /&gt;
// setze alle Pins von PortD auf Ausgang&lt;br /&gt;
.global superFunc&lt;br /&gt;
.func superFunc&lt;br /&gt;
superFunc:&lt;br /&gt;
   push workreg&lt;br /&gt;
 1ec:	0f 93       	push	r16&lt;br /&gt;
   ldi workreg, ALLOUT&lt;br /&gt;
 1ee:	0f ef       	ldi	r16, 0xFF	; 255&lt;br /&gt;
   out  _SFR_IO_ADDR(DDRD), workreg&lt;br /&gt;
 1f0:	01 bb       	out	0x11, r16	; 17&lt;br /&gt;
   pop workreg&lt;br /&gt;
 1f2:	0f 91       	pop	r16&lt;br /&gt;
   ret&lt;br /&gt;
 1f4:	08 95       	ret&lt;br /&gt;
&lt;br /&gt;
000001f6 &amp;lt;ultraFunc&amp;gt;:&lt;br /&gt;
.endfunc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// setze PORTD auf übergebenen Wert&lt;br /&gt;
.global ultraFunc&lt;br /&gt;
.func ultraFunc&lt;br /&gt;
ultraFunc:&lt;br /&gt;
   out  _SFR_IO_ADDR(PORTD), 24&lt;br /&gt;
 1f6:	82 bb       	out	0x12, r24	; 18&lt;br /&gt;
   ret&lt;br /&gt;
 1f8:	08 95       	ret&lt;br /&gt;
&lt;br /&gt;
000001fa &amp;lt;gigaFunc&amp;gt;:&lt;br /&gt;
.endfunc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// Zustand von PINA zurückgeben&lt;br /&gt;
.global gigaFunc&lt;br /&gt;
.func gigaFunc&lt;br /&gt;
gigaFunc:&lt;br /&gt;
   in 24, _SFR_IO_ADDR(PINA)&lt;br /&gt;
 1fa:	89 b3       	in	r24, 0x19	; 25&lt;br /&gt;
   ret&lt;br /&gt;
 1fc:	08 95       	ret&lt;br /&gt;
&lt;br /&gt;
000001fe &amp;lt;addFunc&amp;gt;:&lt;br /&gt;
.endfunc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// zwei Bytes addieren und 16-bit-Wort zurückgeben&lt;br /&gt;
.global addFunc&lt;br /&gt;
.func addFunc&lt;br /&gt;
addFunc:&lt;br /&gt;
   push workreg&lt;br /&gt;
 1fe:	0f 93       	push	r16&lt;br /&gt;
   push workreg2&lt;br /&gt;
 200:	1f 93       	push	r17&lt;br /&gt;
   clr workreg2&lt;br /&gt;
 202:	11 27       	eor	r17, r17&lt;br /&gt;
   mov workreg, 22&lt;br /&gt;
 204:	06 2f       	mov	r16, r22&lt;br /&gt;
   add workreg, 24&lt;br /&gt;
 206:	08 0f       	add	r16, r24&lt;br /&gt;
   adc workreg2, 1    // r1 - assumed to be always zero ...&lt;br /&gt;
 208:	11 1d       	adc	r17, r1&lt;br /&gt;
   movw r24, workreg&lt;br /&gt;
 20a:	c8 01       	movw	r24, r16&lt;br /&gt;
   pop workreg2&lt;br /&gt;
 20c:	1f 91       	pop	r17&lt;br /&gt;
   pop workreg&lt;br /&gt;
 20e:	0f 91       	pop	r16&lt;br /&gt;
   ret&lt;br /&gt;
 210:	08 95       	ret&lt;br /&gt;
&lt;br /&gt;
[...]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Zuweisung von Registern zu Parameternummer und die Register für die Rückgabewerte sind in den &amp;quot;Register Usage Guidelines&amp;quot; der avr-libc-Dokumentation erläutert.&lt;br /&gt;
&lt;br /&gt;
Siehe auch:&lt;br /&gt;
* [http://www.nongnu.org/avr-libc/user-manual/assembler.html avr-libc-Dokumentation: Related Pages/avr-libc and assembler programs]&lt;br /&gt;
* [http://www.nongnu.org/avr-libc/user-manual/FAQ.html#faq_reg_usage avr-libc-Dokumentation: Related Pages/FAQ/&amp;quot;What registers are used by the C compiler?&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
== Globale Variablen für Datenaustausch ==&lt;br /&gt;
&lt;br /&gt;
Oftmals kommt man um globale Variablen nicht herum, z.B. um den Datenaustausch zwischen Hauptprogramm und Interrupt-Routinen zu realisieren. &lt;br /&gt;
Hierzu muss man im Assembler wissen, wo genau die Variable vom C-Compiler abgespeichert wird.&lt;br /&gt;
&lt;br /&gt;
Hierzu muss die Variable, hier &amp;quot;zaehler&amp;quot; genannt, zuerst im C-Code als Global definiert werden, z.B. so:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
volatile uint8_t zaehler;&lt;br /&gt;
&lt;br /&gt;
int16_t main (void)&lt;br /&gt;
{&lt;br /&gt;
    // irgendein Code, in dem zaehler benutzt werden kann&lt;br /&gt;
    &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im foldenden Assembler-Beispiel wird der Externe Interrupt0  verwendet, um den Zähler hochzuzählen. Es fehlen die Initialisierungen des Interrupts und die Interrupt-Freigabe, so richtig sinnvoll ist der Code auch nicht, aber er zeigt (hoffentlich) wie es geht.&lt;br /&gt;
&lt;br /&gt;
Im Umgang mit Interrupt-Vektoren gilt beim GCC-Assembler das Gleiche, wie bei C: Man muss die exakte Schreibweise beachten, ansonsten wird nicht der Interrupt-Vektor angelegt, sondern eine neue Funktion - und man wundert sich, dass nichts funktionert (vgl. das AVR-GCC-Handbuch).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;avrasm&amp;gt;&lt;br /&gt;
#include &amp;quot;avr/io.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
temp = 16&lt;br /&gt;
&lt;br /&gt;
.extern zaehler&lt;br /&gt;
&lt;br /&gt;
.global INT0_vect&lt;br /&gt;
INT0_vect:&lt;br /&gt;
&lt;br /&gt;
     push temp                      //; wichtig: Benutzte Register und das&lt;br /&gt;
     in temp,_SFR_IO_ADDR(SREG)     //; Status-Register (SREG) sichern!&lt;br /&gt;
     push temp&lt;br /&gt;
&lt;br /&gt;
     lds temp,zaehler               //; Wert aus dem Speicher lesen&lt;br /&gt;
     inc temp                       //; bearbeiten&lt;br /&gt;
     sts zaehler,temp               //; und wieder zurückschreiben&lt;br /&gt;
&lt;br /&gt;
     pop temp                       //; die benutzten Register wiederherstellen&lt;br /&gt;
     out _SFR_IO_ADDR(SREG),temp&lt;br /&gt;
     pop temp&lt;br /&gt;
     reti&lt;br /&gt;
&lt;br /&gt;
.end&lt;br /&gt;
&amp;lt;/avrasm&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Globale Variablen im Assemblerfile anlegen ===&lt;br /&gt;
&lt;br /&gt;
Alternativ können Variablen aber auch im Assemblerfile angelegt werden. Dadurch kann auf eine .c-Datei verzichtet werden. Für das obige Beispiel könnte der Quelltext dann die Dateien zaehl_asm.S und zaehl_asm.h abgelegt werden, so dass nur noch zaehl_asm.S mit kompiliert werden müsste.&lt;br /&gt;
&lt;br /&gt;
Anstatt im Assemblerfile über das Schlüsselwort &#039;&#039;.extern &#039;&#039; auf eine vorhandene Variable zu verweisen, wird dazu mit dem Schlüsselwort &#039;&#039;.comm&#039;&#039; die benötigte Anzahl von Bytes für eine Variable reserviert.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;zaehl_asm.S&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;avrasm&amp;gt;&lt;br /&gt;
#include &amp;quot;avr/io.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
temp = 16&lt;br /&gt;
&lt;br /&gt;
//; 1 Byte im RAM für den Zähler reservieren&lt;br /&gt;
.comm zaehler, 1&lt;br /&gt;
&lt;br /&gt;
.global INT0_vect&lt;br /&gt;
INT0_vect:&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/avrasm&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In der Headerdatei wird dann auf die Variable nur noch verwiesen (Schlüsselwort &#039;&#039;extern&#039;&#039;):&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;zaehl_asm.h&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#ifndef ZAEHL_ASM_H&lt;br /&gt;
#define ZAEHL_ASM_H&lt;br /&gt;
&lt;br /&gt;
extern volatile uint8_t zaehler;&lt;br /&gt;
&lt;br /&gt;
#endif&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im Gegensatz zu globalen Variablen in C werden so angelegte Variablen nicht automatisch mit dem Wert 0 initialisiert. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Variablen größer als 1 Byte ===&lt;br /&gt;
&lt;br /&gt;
Variablen, die größer als &#039;&#039;&#039;ein&#039;&#039;&#039; Byte sind, können in Assembler auf ähnliche Art angesprochen werden. Hierzu müssen nur genug Bytes angefordert werden, um die Variable aufzunehmen. Soll z.B. für den Zähler eine Variable vom Typ &#039;&#039;unsigned long&#039;&#039;, also &#039;&#039;uint32_t&#039;&#039; verwendet werden, so müssen 4 Bytes reserviert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;avrasm&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
// 4 Byte im RAM für den Zähler reservieren&lt;br /&gt;
.comm zaehler, 4&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/avrasm&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die dazugehörige Deklaration im Headerfile wäre dann:&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
extern volatile uint32_t zaehler;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bei Variablen, die größer als ein Byte sind, werden die Werte beginnend mit dem niederwertigsten Byte im RAM abgelegt. Das folgende Codeschnippsel zeigt, wie unter Assembler auf die einzelnen Bytes zugegriffen werden kann. Dazu wird im Interrupt nun ein 32-Bit Zähler erhöht:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;avrasm&amp;gt;&lt;br /&gt;
#include &amp;quot;avr/io.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
temp = 16&lt;br /&gt;
&lt;br /&gt;
// 4 Byte im RAM für den Zähler reservieren&lt;br /&gt;
.comm zaehler, 4&lt;br /&gt;
&lt;br /&gt;
.global INT0_vect&lt;br /&gt;
INT0_vect:&lt;br /&gt;
&lt;br /&gt;
     push temp                      // wichtig: Benutzte Register und das&lt;br /&gt;
     in temp,_SFR_IO_ADDR(SREG)     // Status-Register (SREG) sichern !&lt;br /&gt;
     push temp&lt;br /&gt;
&lt;br /&gt;
     // 32-Bit-Zähler incrementieren&lt;br /&gt;
     lds temp, (zaehler + 0)        // 0. Byte (niederwertigstes Byte)&lt;br /&gt;
     inc temp&lt;br /&gt;
     sts (zaehler + 0), temp&lt;br /&gt;
     brne RAUS&lt;br /&gt;
	&lt;br /&gt;
     lds temp, (zaehler + 1)        // 1. Byte&lt;br /&gt;
     inc temp&lt;br /&gt;
     sts (zaehler + 1), temp&lt;br /&gt;
     brne RAUS&lt;br /&gt;
&lt;br /&gt;
     lds temp, (zaehler + 2)        // 2. Byte&lt;br /&gt;
     inc temp&lt;br /&gt;
     sts (zaehler + 2), temp&lt;br /&gt;
     brne RAUS&lt;br /&gt;
&lt;br /&gt;
     lds temp, (zaehler + 3)        // 3. Byte (höchstwertigstes Byte)&lt;br /&gt;
     inc temp&lt;br /&gt;
     sts (zaehler + 3), temp&lt;br /&gt;
     brne RAUS&lt;br /&gt;
	&lt;br /&gt;
RAUS:&lt;br /&gt;
     pop temp                       // die benutzten Register wiederherstellen&lt;br /&gt;
     out _SFR_IO_ADDR(SREG),temp&lt;br /&gt;
     pop temp&lt;br /&gt;
     reti&lt;br /&gt;
&lt;br /&gt;
.end&lt;br /&gt;
&amp;lt;/avrasm&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;TODO:&#039;&#039;&#039; 16-Bit / 32-Bit Variablen, Zugriff auf Arrays (Strings)&lt;br /&gt;
&lt;br /&gt;
= Anhang =&lt;br /&gt;
&lt;br /&gt;
== Besonderheiten bei der Anpassung bestehenden Quellcodes ==&lt;br /&gt;
&lt;br /&gt;
Einige Funktionen, die in frühren Versionen der avr-libc vorhanden waren, werden inzwischen als veraltet angesehen. Sie sind nicht mehr vorhanden oder als &#039;&#039;deprecated&#039;&#039; (missbilligt) ausgewiesen und Definitionen in &amp;lt;compat/deprecated.h&amp;gt; verschoben. Es empfiehlt sich, vorhandenen Code zu portieren und die alten Funktionen nicht mehr zu nutzen, auch wenn diese noch zur Verfügung stehen.&lt;br /&gt;
&lt;br /&gt;
=== Veraltete Funktionen zur Deklaration von Interrupt-Routinen ===&lt;br /&gt;
&lt;br /&gt;
Die Funktionen (eigentlich Makros) &#039;&#039;SIGNAL&#039;&#039; und &#039;&#039;INTERRUPT&#039;&#039; zur Deklaration von Interruptroutinen sollten nicht mehr genutzt werden. &lt;br /&gt;
&lt;br /&gt;
In aktuellen Versionen der avr-libc (z.B. avr-libc 1.4.3 aus WinAVR 20060125) werden Interruptroutinen, die &#039;&#039;&#039;nicht&#039;&#039;&#039; durch andere Interrupts &#039;&#039;&#039;unterbrechbar&#039;&#039;&#039; sind, mit ISR deklariert (siehe Abschnitt im Hauptteil). Auch die Benennung wurden vereinheitlicht und an die üblichen Bezeichnungen in den AVR Datenblättern angepasst. In der Dokumentation der avr-libc sind alte und neue Bezeichnungen in der Tabelle gegenübergestellt. Die erforderlichen Schritte zur Portierung:&lt;br /&gt;
&lt;br /&gt;
* #include von avr/signal.h entfernen&lt;br /&gt;
* SIGNAL duch ISR ersetzen&lt;br /&gt;
* Name des Interrupt-Vektors anpassen (SIG_* durch entsprechendes *_vect)&lt;br /&gt;
&lt;br /&gt;
Als Beispiel für die Anpassung zuerst ein &amp;quot;alter&amp;quot; Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/interrupt.h&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/signal.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
/* Timer2 Output Compare bei einem ATmega8 */&lt;br /&gt;
SIGNAL(SIG_OUTPUT_COMPARE2)&lt;br /&gt;
{&lt;br /&gt;
   ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im Datenblatt wird der Vektor mit TIMER2 COMP bezeichnet. Die Bezeichnung in der avr-libc entspricht dem Namen im Datenblatt, Leerzeichen werden durch Unterstriche (_) ersetzt und ein _vect angehängt. &lt;br /&gt;
&lt;br /&gt;
Der neue Code sieht dann so aus:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/interrupt.h&amp;gt; &lt;br /&gt;
/* signal.h entfällt */&lt;br /&gt;
&lt;br /&gt;
ISR(TIMER2_COMP_vect)&lt;br /&gt;
{&lt;br /&gt;
   ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bei Unklarheiten bezüglich der neuen Vektorlabels hilft (noch) ein Blick in die Headerdatei des entsprechenden Controllers. Für das vorherige Beispiel also der Blick in die Datei iom8.h für den ATmega8, dort findet man die veraltete Bezeichnung unterhalb der aktuellen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
/* $Id: iom8.h,v 1.13 2005/10/30 22:11:23 joerg_wunsch Exp $ */&lt;br /&gt;
/* avr/iom8.h - definitions for ATmega8 */&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
/* Timer/Counter2 Compare Match */&lt;br /&gt;
#define TIMER2_COMP_vect		_VECTOR(3)&lt;br /&gt;
#define SIG_OUTPUT_COMPARE2		_VECTOR(3)&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- Nachfolgendes mit avr-libc 1.4.5 (in WinAVR 1/2007 behoben - noch eine Weile auskommentiert lassen und dann löschen.&lt;br /&gt;
Konnte in alten Versionen signal.h ohne interrupt.h eingebunden werden, erhält man bei Verwendung der avr-libc Version 1.4.3 (WinAVR 2/2005) beim Compilieren eine Fehlermeldung, da mit signal.h nicht die erforderlichen Definitionen eingebunden werden. Der Lösungsvorschlag in signal.h auch interrupt.h einzubinden, wurde von den avr-libc-Enwicklern akzeptiert und das Problem ist  im Quellcode (CVS) bereits behoben. Es ist aber noch keine avr-libc-&amp;quot;Release&amp;quot; bzw. noch kein WinAVR mit dieser avr-libc-Korrektur verfügbar (Stand 5.2.2006). Will oder kann man den Quellcode nicht aktualisieren, gibt es folgende Alternativen:&lt;br /&gt;
* in Quellcodedateien, in denen nur avr/signal.h eingebunden wird, interrupt.h einbinden (&#039;&#039;#include &amp;amp;lt;avr/interrupt.h&amp;amp;gt;&#039;&#039;). signal.h weiterhin einbinden, falls Kompatibiltät mit alten Versionen gewünscht ist.&lt;br /&gt;
* in der Datei signal.h (bein WinAVR in c:/WinAVR/avr/include/avr/signal.h) ein (&#039;&#039;#include &amp;amp;lt;avr/interrupt.h&amp;amp;gt;&#039;&#039;) ergänzen --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für &#039;&#039;&#039;unterbrechbare&#039;&#039;&#039; Interruptroutinen, die mittels &#039;&#039;INTERRUPT&#039;&#039; deklariert sind, gibt es keinen direkten Ersatz in Form eines Makros. Solche Routinen sind laut Dokumentation der avr-libc in folgender Form zu deklarieren:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
void XXX_vect(void) __attribute__((interrupt));&lt;br /&gt;
void XXX_vect(void) {&lt;br /&gt;
  ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
/* ** alt ** */&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/interrupt.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
INTERRUPT(SIG_OVERFLOW0)&lt;br /&gt;
{&lt;br /&gt;
   ...&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* ** neu: ** */&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
void TIMER0_OVF_vect(void) __attribute__((interrupt));&lt;br /&gt;
void TIMER0_OVF_vect(void) &lt;br /&gt;
{&lt;br /&gt;
   ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Will oder kann man den Code nicht portieren, ist zur weiteren Verwendung von &#039;&#039;INTERRUPT&#039;&#039; die Header-Datei &#039;&#039;compat/deprecated.h&#039;&#039; einzubinden. Man sollte bei dieser Gelegenheit jedoch nochmals überprüfen, ob die Funktionalität von &#039;&#039;INTERRUPT&#039;&#039; tatsächlich gewollt ist. In vielen Fällen wurde &#039;&#039;INTERRUPT&#039;&#039; dort genutzt, wo eigentlich &#039;&#039;SIGNAL&#039;&#039; (nunmehr &#039;&#039;ISR&#039;&#039;) hätte genutzt werden sollen.&lt;br /&gt;
&lt;br /&gt;
=== Veraltete Funktionen zum Portzugriff ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;inp&#039;&#039; und &#039;&#039;outp&#039;&#039; zum Einlesen bzw. Schreiben von Registern sind nicht mehr erforderlich, der Compiler unterstützt dies ohne diesen Umweg.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
unsigned char i, j;&lt;br /&gt;
&lt;br /&gt;
// alt:&lt;br /&gt;
  i = inp(PINA);&lt;br /&gt;
  j = 0xff;&lt;br /&gt;
  outp(PORTB, j);&lt;br /&gt;
&lt;br /&gt;
// neu (nicht mehr wirklich neu...):&lt;br /&gt;
  i = PINA&lt;br /&gt;
  j = 0xff;&lt;br /&gt;
  PORTB = j;&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Will oder kann man den Code nicht portieren, ist zur weiteren Verwendung von inp und outp die Header-Datei &#039;&#039;&#039;compat/deprecated.h&#039;&#039;&#039; einzubinden.&lt;br /&gt;
&lt;br /&gt;
=== Veraltete Funktionen zum Zugriff auf Bits in Registern ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;cbi&#039;&#039; und &#039;&#039;sbi&#039;&#039; zum Löschen und Setzen von Bits sind nicht mehr erforderlich, der Compiler unterstützt dies ohne diesen Umweg. Die Bezeichnung ist ohnehin irreführend da die Funktionen nur für Register mit Adressen im unteren Speicherbereich tatsächlich in die Assembleranweisungen cbi und sbi übersetzt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
// alt:&lt;br /&gt;
  sbi(PORTB, PB2);&lt;br /&gt;
  cbi(PORTC, PC1);&lt;br /&gt;
&lt;br /&gt;
// neu (auch nicht mehr wirklich neu...):&lt;br /&gt;
  PORTB |=  (1&amp;lt;&amp;lt;PB2);&lt;br /&gt;
  PORTC &amp;amp;= ~(1&amp;lt;&amp;lt;PC1);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Will oder kann man den Code nicht portieren, ist zur weiteren Verwendung von sbi und cbi die Header-Datei &#039;&#039;&#039;compat/deprecated.h&#039;&#039;&#039; einzubinden. Wer unbedingt will, kann sich natürlich eigene Makros mit aussagekräftigeren Namen definieren. Zum Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#define SET_BIT(PORT, BITNUM)    ((PORT) |=  (1&amp;lt;&amp;lt;(BITNUM)))&lt;br /&gt;
#define CLEAR_BIT(PORT, BITNUM)  ((PORT) &amp;amp;= ~(1&amp;lt;&amp;lt;(BITNUM)))&lt;br /&gt;
#define TOGGLE_BIT(PORT, BITNUM) ((PORT) ^=  (1&amp;lt;&amp;lt;(BITNUM)))&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Selbstdefinierte (nicht-standardisierte) ganzzahlige Datentypen ===&lt;br /&gt;
&lt;br /&gt;
Bei den im Folgenden genannten Typdefinitionen ist zu beachten, dass die Bezeichnungen für &amp;quot;Worte&amp;quot; teilweise je nach Prozessorplattform unterschiedlich verwendet werden. Die angegebenen Definitionen beziehen sich auf die im Zusammenhang mit AVR/8-bit-Controllern üblichen &amp;quot;Bit-Breiten&amp;quot; (In Erläuterungen zum ARM7TDMI z.B. werden oft 32-bit Integer mit &amp;quot;Wort&amp;quot; ohne weitere Ergänzung bezeichnet). Es empfiehlt sich, bei der Überarbeitung von altem Code die im Abschnitt &#039;&#039;standardisierten ganzzahligen Datentypen&#039;&#039; beschriebenen Datentypen zu nutzen (stdint.h) und damit &amp;quot;Missverständnissen&amp;quot; vorzubeugen, die z.B. bei der Portierung von C-Code zwischen verschiedenen Plattformen auftreten können.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
typedef unsigned char      BYTE;       // besser: uint8_t  aus &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
typedef unsigned short     WORD;       // besser: uint16_t aus &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
typedef unsigned long      DWORD;      // besser: uint32_t aus &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
typedef unsigned long long QWORD;      // besser: uint64_t aus &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; BYTE : Der Datentyp BYTE definiert eine Variable mit 8 Bit Breite zur Darstellung von ganzen Zahlen im Bereich zwischen 0 ... 255. &lt;br /&gt;
&lt;br /&gt;
; WORD : Der Datentyp WORD definiert eine Variable mit 16 Bit Breite zur Darstellung von ganzen Zahlen im Bereich zwischen 0 ... 65535. &lt;br /&gt;
&lt;br /&gt;
; DWORD : Der Datentyp DWORD (gesprochen: Double-Word) definiert eine Variable mit 32 Bit Breite zur Darstellung von ganzen Zahlen im Bereich zwischen 0 ... 4294967295.&lt;br /&gt;
&lt;br /&gt;
; QWORD : Der Datentyp QWORD (gesprochen: Quad-Word) definiert eine Variable mit 64 Bit Breite zur Darstellung von ganzen Zahlen im Bereich zwischen 0 ... 18446744073709551615.&lt;br /&gt;
&lt;br /&gt;
== Zusätzliche Funktionen im Makefile ==&lt;br /&gt;
&lt;br /&gt;
=== Bibliotheken (Libraries/.a-Dateien) hinzufügen ===&lt;br /&gt;
&lt;br /&gt;
Um Funktionen aus Bibliotheken (&amp;quot;echte&amp;quot; Libraries, *.a-Dateien) zu nutzen, sind dem Linker die Namen der Bibliotheken als Parameter zu übergeben. Dazu ist die Option -l (kleines L) vorgesehen, an die der Name der Library angehängt wird. &lt;br /&gt;
&lt;br /&gt;
Dabei ist zu beachten, dass der Name der Library und der Dateiname der Library nicht identisch sind. Der hinter -l angegebene Name entspricht dem Dateinamen der Library ohne die Zeichenfolge &#039;&#039;lib&#039;&#039; am Anfang des Dateinamens und ohne die Endung &#039;&#039;.a&#039;&#039;. Sollen z.B. Funktionen aus einer Library mit dem Dateinamen &#039;&#039;libefsl.a&#039;&#039; eingebunden (gelinkt) werden, lautet der entsprechende Parameter -lefsl (vergl. auch -lm zum Anbinden von libm.a). &lt;br /&gt;
&lt;br /&gt;
In Makefiles wird traditonell eine make-Variable LDLIBS genutzt, in die &amp;quot;l-Parameter&amp;quot; abgelegt werden. Die WinAVR-makefile-Vorlage enthält diese Variable zwar nicht, dies stellt jedoch keine Einschränkung dar, da alle in der make-Variable LDFLAGS abgelegten Parameter an den Linker weitergereicht werden. &lt;br /&gt;
&lt;br /&gt;
Beispiele:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;code&amp;quot;&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
# Einbinden von Funktionen aus einer Library efsl (Dateiname libefsl.a)&lt;br /&gt;
LDFLAGS += -lefsl&lt;br /&gt;
# Einbinden von Funktionen aus einer Library xyz (Dateiname libxyz.a)&lt;br /&gt;
LDFLAGS += -lxyz&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Liegen die Library-Dateien nicht im Standard Library-Suchpfad, sind die Pfade mittels Parameter &#039;&#039;-L&#039;&#039; ebenfalls anzugeben. (Der vordefinierte Suchpfad kann mittels &#039;&#039;avr-gcc --print-search-dirs&#039;&#039; angezeigt werden.)&lt;br /&gt;
&lt;br /&gt;
Als Beispiel ein Projekt (&amp;quot;superapp2&amp;quot;), in dem der Quellcode von zwei Libraries (efsl und xyz) und der Quellcode der eigentlichen Anwendung in verschiedenen Verzeichnissen mit der folgenden &amp;quot;Baumstruktur&amp;quot; abgelegt sind:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;code&amp;quot;&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
superapp2&lt;br /&gt;
|&lt;br /&gt;
+----- efslsource (darin libefsl.a)&lt;br /&gt;
|&lt;br /&gt;
+----- xyzsource (darin libxyz.a)&lt;br /&gt;
|&lt;br /&gt;
+----- firmware (darin Anwendungs-Quellcode und Makefile)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Daraus folgt, dass im Makefile die Verzeichnis efslsource und xyzsource in den Library-Suchpfad aufzunehmen sind:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;code&amp;quot;&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
LDFLAGS += -L../efslsource/ -L../xyzsource/&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Fuse-Bits ===&lt;br /&gt;
&lt;br /&gt;
Zur Berechnung der Fuse-Bits bietet sich neben dem Studium des Datenblattes auch der [http://palmavr.sourceforge.net/cgi-bin/fc.cgi AVR Fuse Calculator] an. Gewarnt werden muss vor der Benutzung von PonyProg, weil dort durch die negierte Darstellung gern Fehler gemacht werden.&lt;br /&gt;
&lt;br /&gt;
Soll die Programmierung von Fuse- und Lockbits automatisiert werden, kann man dies ebenfalls durch Einträge im Makefile vornehmen, die beim Aufruf von &amp;quot;make program&amp;quot; an die genutzte Programmiersoftware übergeben werden. In der makefile-Vorlage von WinAVR (und mfile) gibt es dafuer jedoch keine &amp;quot;Ausfüllhilfe&amp;quot; (Stand 9/2006). Die folgenden Ausführungen gelten für die Programmiersoftware [[AVRDUDE]] (Standard in der WinAVR-Vorlage), können jedoch sinngemäß auf andere Programmiersoftware übertragen werden, die die Angabe der Fuse- und Lockbits-Einstellungen per Kommandozeilenparameter unterstützt (z.B. stk500.exe). Im einfachsten Fall ergänzt man im Makefile einige Variablen, deren Werte natürlich vom verwendeten Controller und den gewünschten Einstellungen abhängen (vgl. Datenblatt Fuse-/Lockbits):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#---------------- Programming Options (avrdude) ----------------&lt;br /&gt;
&lt;br /&gt;
#...&lt;br /&gt;
#Beispiel! f. ATmega16 - nicht einfach uebernehmen! Zahlenwerte anhand&lt;br /&gt;
#--------- des Datenblatts nachvollziehen und gegebenenfalls aendern.&lt;br /&gt;
#&lt;br /&gt;
AVRDUDE_WRITE_LFUSE = -U lfuse:w:0xff:m&lt;br /&gt;
AVRDUDE_WRITE_HFUSE = -U hfuse:w:0xd8:m&lt;br /&gt;
AVRDUDE_WRITE_LOCK  = -U lock:w:0x2f:m&lt;br /&gt;
#...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Damit diese Variablen auch genutzt werden, ist der Aufruf von avrdude im Makefile entsprechend zu ergänzen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
# Program the device.  &lt;br /&gt;
program: $(TARGET).hex $(TARGET).eep&lt;br /&gt;
# ohne Fuse-/Lock-Einstellungen (nach WinAVR Vorlage Stand 4/2006)&lt;br /&gt;
#	$(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH) \&lt;br /&gt;
#        $(AVRDUDE_WRITE_EEPROM)&lt;br /&gt;
# mit Fuse-/Lock-Einstellungen&lt;br /&gt;
        $(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_LFUSE) \&lt;br /&gt;
        $(AVRDUDE_WRITE_HFUSE) $(AVRDUDE_WRITE_FLASH) \&lt;br /&gt;
        $(AVRDUDE_WRITE_EEPROM) $(AVRDUDE_WRITE_LOCK)&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Eine weiter Möglichkeit besteht darin, die Fuse- und Lockbit-Einstellungen vom Preprozessor/Compiler generieren zu lassen. Die Fuse-Bits werden dann bei Verwendung von AVRDUDE in eigene Hex-Files geschrieben. Hierzu kann man z.B. folgendes Konstrukt verwenden:&lt;br /&gt;
&lt;br /&gt;
In eine der C-Sourcen wird eine Variable je Fuse-Byte vom Typ &#039;&#039;unsigned char&#039;&#039; deklariert und in eine extra Section gepackt. Dies kann entweder in einem vorhandenen File passieren oder in ein neues (z.B. fuses.c) geschrieben werden. Das File muss im Makefile aber auf jeden Fall mit kompiliert und gelinkt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
// tiny 2313 fuses low byte&lt;br /&gt;
#define CKDIV8  7&lt;br /&gt;
#define CKOUT   6&lt;br /&gt;
#define SUT1    5&lt;br /&gt;
#define SUT0    4&lt;br /&gt;
#define CKSEL3  3&lt;br /&gt;
#define CKSEL2  2&lt;br /&gt;
#define CKSEL1  1&lt;br /&gt;
#define CKSEL0  0&lt;br /&gt;
&lt;br /&gt;
// tiny2313 fuses high byte&lt;br /&gt;
#define DWEN       7&lt;br /&gt;
#define EESAVE     6&lt;br /&gt;
#define SPIEN      5&lt;br /&gt;
#define WDTON      4&lt;br /&gt;
#define BODLEVEL2  3&lt;br /&gt;
#define BODLEVEL1  2&lt;br /&gt;
#define BODLEVEL0  1&lt;br /&gt;
#define RSTDISBL   0&lt;br /&gt;
&lt;br /&gt;
// tiny2313 fuses extended byte&lt;br /&gt;
#define SELFPRGEN  0&lt;br /&gt;
&lt;br /&gt;
#define LFUSE         __attribute__ ((section (&amp;quot;lfuses&amp;quot;)))&lt;br /&gt;
#define HFUSE         __attribute__ ((section (&amp;quot;hfuses&amp;quot;)))&lt;br /&gt;
#define EFUSE         __attribute__ ((section (&amp;quot;efuses&amp;quot;)))&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// select ext crystal 3-8Mhz&lt;br /&gt;
unsigned char lfuse LFUSE =&lt;br /&gt;
    ( (1&amp;lt;&amp;lt;CKDIV8) | (1&amp;lt;&amp;lt;CKOUT) | (1&amp;lt;&amp;lt;CKSEL3) | (1&amp;lt;&amp;lt;CKSEL2) | &lt;br /&gt;
      (0&amp;lt;&amp;lt;CKSEL1) | (1&amp;lt;&amp;lt;CKSEL0) | (0&amp;lt;&amp;lt;SUT1) | (1&amp;lt;&amp;lt;SUT0) );&lt;br /&gt;
unsigned char hfuse HFUSE =&lt;br /&gt;
    ( (1&amp;lt;&amp;lt;DWEN) | (1&amp;lt;&amp;lt;EESAVE) | (0&amp;lt;&amp;lt;SPIEN) | (1&amp;lt;&amp;lt;WDTON) | &lt;br /&gt;
      (1&amp;lt;&amp;lt;BODLEVEL2) | (1&amp;lt;&amp;lt;BODLEVEL1) | (0&amp;lt;&amp;lt;BODLEVEL0) | (1&amp;lt;&amp;lt;RSTDISBL) );&lt;br /&gt;
unsigned char efuse EFUSE =&lt;br /&gt;
    ((0&amp;lt;&amp;lt;SELFPRGEN));&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ACHTUNG: Die Bitpositionen wurden nicht vollständig getestet!&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Eine &amp;quot;1&amp;quot; bedeutet hier, dass das Fuse-Bit &#039;&#039;nicht&#039;&#039; programmiert wird - die Funktion also i.A. nicht aktiviert ist. Eine &amp;quot;0&amp;quot; hingegen aktiviert die meisten Funktionen. Dies ist wie im Datenblatt (1 = unprogrammed, 0 = programmed).&lt;br /&gt;
&lt;br /&gt;
Das Makefile muss nun noch um folgende Targets erweitert werden (mit Tabulator einrücken - nicht mit Leerzeichen):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;code&amp;quot;&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
lfuses: build&lt;br /&gt;
        -$(OBJCOPY) -j lfuses --change-section-address lfuses=0 \&lt;br /&gt;
          -O ihex $(TARGET).elf $(TARGET)-lfuse.hex&lt;br /&gt;
        @if [ -f $(TARGET)-lfuse.hex ]; then \&lt;br /&gt;
         $(AVRDUDE) $(AVRDUDE_FLAGS) -U lfuse:w:$(TARGET)-lfuse.hex; \&lt;br /&gt;
        fi;&lt;br /&gt;
&lt;br /&gt;
hfuses: build&lt;br /&gt;
        -$(OBJCOPY) -j hfuses --change-section-address hfuses=0 \&lt;br /&gt;
          -O ihex $(TARGET).elf $(TARGET)-hfuse.hex&lt;br /&gt;
        @if [ -f $(TARGET)-hfuse.hex ]; then \&lt;br /&gt;
         $(AVRDUDE) $(AVRDUDE_FLAGS) -U hfuse:w:$(TARGET)-hfuse.hex; \&lt;br /&gt;
        fi;&lt;br /&gt;
&lt;br /&gt;
efuses: build&lt;br /&gt;
        -$(OBJCOPY) -j efuses --change-section-address efuses=0 \&lt;br /&gt;
         -O ihex $(TARGET).elf $(TARGET)-efuse.hex&lt;br /&gt;
        @if [ -f $(TARGET)-efuse.hex ]; then \&lt;br /&gt;
         $(AVRDUDE) $(AVRDUDE_FLAGS) -U efuse:w:$(TARGET)-efuse.hex;&lt;br /&gt;
        fi;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Target &amp;quot;clean&amp;quot; muss noch um die Zeilen&lt;br /&gt;
&amp;lt;div class=&amp;quot;code&amp;quot;&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
        $(REMOVE) $(TARGET)-lfuse.hex&lt;br /&gt;
        $(REMOVE) $(TARGET)-hfuse.hex&lt;br /&gt;
        $(REMOVE) $(TARGET)-efuse.hex&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
erweitert werden, wenn auch die Fuse-Dateien gelöscht werden sollen.&lt;br /&gt;
&lt;br /&gt;
Um nun die Fusebits des angeschlossenen Controllers zu programmieren muss lediglichein &amp;quot;make lfuses&amp;quot;, &amp;quot;make hfuses&amp;quot; oder &amp;quot;make efuses&amp;quot; gestartet werden.&lt;br /&gt;
Bei den Fuse-Bits ist besondere Vorsicht geboten, da diese das Programmieren des Controllers unmöglich machen können. Also erst programmieren, wenn man einen HV-Programmierer hat oder ein paar Reserve-AVRs zur Hand ;-)&lt;br /&gt;
&lt;br /&gt;
Um weiterhin den &amp;quot;normalen&amp;quot; Flash beschreiben zu können, ist es wichtig, für das Target &amp;quot;*.hex&amp;quot; im Makefile nicht nur &amp;quot;-R .eeprom&amp;quot; als Parameter zu übergeben sondern zusätzlich noch &amp;quot;-R lfuses -R efuses -R hfuses&amp;quot;. Sonst bekommt AVRDUDE Probleme diese Sections in den Flash (wo sie ja nicht hingehören) zu schreiben.&lt;br /&gt;
&lt;br /&gt;
Siehe auch: [[AVR_Fuses#Vergleich_der_Fuses_bei_verschiedenen_Programmen|Vergleich der Fuses bei verschiedenen Programmen]]&lt;br /&gt;
&lt;br /&gt;
== Externe Referenzspannung des internen Analog-Digital-Wandlers ==&lt;br /&gt;
&lt;br /&gt;
Die minimale (externe) Referenzspannung des ADC darf nicht beliebig niedrig sein, vgl. dazu das (aktuellste) Datenblatt des verwendeten Controllers. z.B. beim ATMEGA8 darf sie laut Datenblatt (S.245, Tabelle 103, Zeile &amp;quot;VREF&amp;quot;) 2,0V nicht unterschreiten. HINWEIS: diese Information findet sich erst in der letzten Revision (Rev. 2486O-10/04) des Datenblatts.&lt;br /&gt;
&lt;br /&gt;
Meiner &amp;lt;!-- Wer? - es gibt inzwischen x Leute die mehr oder weniger viel in diesem Artikel geschrieben haben --&amp;gt; eigenen Erfahrung nach kann man aber (auf eigene Gefahr und natürlich nicht für Seriengeräte) durchaus noch ein klein wenig weiter heruntergehen, bei dem von mir unter die Lupe genommenen ATMEGA8L (also die Low-Voltage-Variante) funktioniert der ADC bei 5V Betriebsspannung mit bis zu VREF=1,15V hinunter korrekt, ab 1,1V und darunter digitalisiert er jedoch nur noch Blödsinn). Ich würde sicherheitshalber nicht unter 1,5V gehen und bei niedrigeren Betriebsspannungen mag sich die Untergrenze für VREF am Pin AREF ggf. nach oben&#039;&#039;&#039;(!)&#039;&#039;&#039; verschieben.&lt;br /&gt;
&lt;br /&gt;
In der letzten Revision des Datenblatts ist außerdem korrigiert, dass ADC4 und ADC5 sehr wohl 10 Bit Genauigkeit bieten (und nicht bloß 8 Bit, wie in älteren Revisionen irrtümlich angegeben.)&lt;br /&gt;
&lt;br /&gt;
= TODO =&lt;br /&gt;
* Aktualisierung Register- und Bitbeschreibungen an aktuelle AVR&lt;br /&gt;
* stdio.h, malloc() &lt;br /&gt;
* Code-Optimierungen (&amp;quot;tricks&amp;quot;), siehe auch Application Note [http://www.atmel.com/dyn/resources/prod_documents/doc1497.pdf AVR035: Efficient C Coding for AVR]&lt;br /&gt;
* &amp;quot;naked&amp;quot;-Funktionen&lt;br /&gt;
* SPI siehe [http://www.uni-koblenz.de/~physik/informatik/MCU/SPI.pdf SPI Bus mit Atmel AVR]&lt;br /&gt;
* I²C / TWI Bus [http://www.roboternetz.de/wissen/index.php/TWI]&lt;br /&gt;
* Bootloader (bez. auf boot.h)&lt;br /&gt;
* CAN-Bus&lt;br /&gt;
* Einsatz von einfachen Betriebssystemen auf dem AVR&lt;br /&gt;
* Übersicht zu den C bzw. GCC-predefined Makros (__DATE__, __TIME__,...)&lt;br /&gt;
[[Category:AVR]]&lt;br /&gt;
* ADC ; &lt;br /&gt;
* Timer&lt;br /&gt;
* USB ; Steuerung mit USB&lt;br /&gt;
* Multiplexen Siebensegment&lt;br /&gt;
* Sichere vs. effiziente Serialisierung von Datentypen&lt;/div&gt;</summary>
		<author><name>Thymythos</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=AVR-GCC-Tutorial&amp;diff=32642</id>
		<title>AVR-GCC-Tutorial</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=AVR-GCC-Tutorial&amp;diff=32642"/>
		<updated>2008-11-22T11:00:08Z</updated>

		<summary type="html">&lt;p&gt;Thymythos: /* 16-Bit Portregister (ADC, ICR1, OCR1, TCNT1, UBRR) */ Fehler im Beispiel (keine Dereferenzierung)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Vorwort =&lt;br /&gt;
&lt;br /&gt;
Dieses Tutorial soll den Einstieg in die Programmierung von Atmel [[AVR]]-Mikrocontrollern in der Programmiersprache [[C]] mit dem freien C-Compiler [[AVR-GCC]] erleichtern.&lt;br /&gt;
&lt;br /&gt;
Vorausgesetzt werden Grundkenntnisse der Progammiersprache C. Diese Kenntnisse kann man sich online erarbeiten, z. B. mit dem [http://www.schellong.de/c.htm C Tutorial von Helmut Schellong]. Nicht erforderlich sind Vorkenntnisse in der Programmierung von Mikrocontrollern, weder in Assembler noch in einer anderen Sprache. &lt;br /&gt;
&lt;br /&gt;
In diesem Text wird häufig auf die Standardbibliothek avr-libc verwiesen, für die es eine [http://www.nongnu.org/avr-libc/user-manual/index.html Online-Dokumentation] gibt, in der sich auch viele nützliche Informationen zum Compiler und zur Programmierung von AVR Controllern finden. Bei WinAVR gehört die avr-libc Dokumentation zum Lieferumfang und wird mitinstalliert.&lt;br /&gt;
&lt;br /&gt;
Der Compiler und die Standardbibliothek avr-libc werden stetig weiterentwickelt. Erläuterungen und Beispiele beziehen sich auf den C-Compiler avr-gcc ab Version 3.4 und die avr-libc ab Version 1.4.3. Die Unterschiede zu älteren Versionen werden im Haupttext und Anhang zwar erläutert, Anfängern sei jedoch empfohlen, die aktuellen Versionen zu nutzen (für MS-Windows: aktuelle Version des [[WinAVR]]-Pakets; für Linux gibt es CDK4AVR: http://cdk4avr.sf.net oder auch fertige Pakete bei verschiedenen Distributionen.). &lt;br /&gt;
&lt;br /&gt;
Das ursprüngliche Tutorial stammt von Christian Schifferle, viele neue Abschnitte und aktuelle Anpassungen von Martin Thomas.&lt;br /&gt;
&lt;br /&gt;
Dieses Tutorial ist in PDF-Form erhältlich bei:&lt;br /&gt;
http://www.siwawi.arubi.uni-kl.de/avr_projects/AVR-GCC-Tutorial_-_www_mikrocontroller_net.pdf&lt;br /&gt;
(nicht immer auf aktuellem Stand)&lt;br /&gt;
&lt;br /&gt;
= Benötigte Werkzeuge =&lt;br /&gt;
&lt;br /&gt;
Um eigene Programme für AVRs mittels avr-gcc/avr-libc zu erstellen und zu testen, wird folgende Hard- und Software benötigt:&lt;br /&gt;
&lt;br /&gt;
* Platine oder Versuchsaufbau für die Aufnahme eines AVR Controllers, der vom avr-gcc Compiler unterstützt wird (alle ATmegas und die meisten AT90, siehe Dokumentation der avr-libc für unterstützte Typen). Dieses Testboard kann durchaus auch selbst gelötet oder auf einem Steckbrett aufgebaut werden. Einige Registerbeschreibungen dieses Tutorials beziehen sich auf den inzwischen veralteten AT90S2313. Der weitaus größte Teil des Textes ist aber für alle Controller der AVR-Familie gültig. Brauchbare Testplattformen sind auch das [[STK500]] und der [[AVR Butterfly]] von Atmel. Weitere Infos findet man [[AVR#Starterkits|hier]].&lt;br /&gt;
&lt;br /&gt;
* Der avr-gcc Compiler und die avr-libc. Kostenlos erhältlich für nahezu alle Plattformen und Betriebssysteme. Für MS-Windows im Paket [[WinAVR]]; für Unix/Linux siehe auch Hinweise im Artikel [[AVR-GCC]].&lt;br /&gt;
&lt;br /&gt;
* Programmiersoftware und -[[AVR In System Programmer |hardware]] z. B. PonyProg (siehe auch: [[Pony-Prog Tutorial]]) oder [[AVRDUDE]] mit [[STK200]]-Dongle oder die von Atmel verfügbare Hard- und Software ([[STK500]], Atmel AVRISP, [[AVR-Studio]]).&lt;br /&gt;
&lt;br /&gt;
* Nicht unbedingt erforderlich, aber zur Simulation und zum Debuggen unter MS-Windows recht nützlich: [[AVR-Studio]] (siehe Abschnitt [[AVR-GCC-Tutorial#Exkurs: Makefiles|Exkurs: Makefiles]]).&lt;br /&gt;
&lt;br /&gt;
= Was tun, wenn&#039;s nicht &amp;quot;klappt&amp;quot;? =&lt;br /&gt;
&lt;br /&gt;
* Herausfinden, ob es tatsächlich ein avr(-gcc) spezifisches Problem ist oder nur die eigenen C-Kenntnisse einer Auffrischung bedürfen. Allgemeine C-Fragen kann man eventuell &amp;quot;beim freundlichen Programmierer zwei Büro-, Zimmer- oder Haustüren weiter&amp;quot; loswerden. Ansonsten: [[C]]-Buch (gibt&#039;s auch &amp;quot;gratis&amp;quot; online) lesen.&lt;br /&gt;
&lt;br /&gt;
* Die [[AVR Checkliste]] durcharbeiten.&lt;br /&gt;
&lt;br /&gt;
* Die &#039;&#039;&#039;[http://www.nongnu.org/avr-libc/user-manual/index.html Dokumentation der avr-libc]&#039;&#039;&#039; lesen, vor allem (aber nicht nur) den Abschnitt Related Pages/&#039;&#039;&#039;Frequently Asked Questions&#039;&#039;&#039; = Oft gestellte Fragen (und Antworten dazu). Z.Zt leider nur in englischer Sprache verfügbar.&lt;br /&gt;
&lt;br /&gt;
* Den Artikel [[AVR-GCC]] in diesem Wiki lesen.&lt;br /&gt;
&lt;br /&gt;
* Das [http://www.mikrocontroller.net/forum/2 GCC-Forum auf  www.mikrocontroller.net] nach vergleichbaren Problemen absuchen.&lt;br /&gt;
&lt;br /&gt;
* Das avr-gcc-Forum bei [http://www.avrfreaks.net avrfreaks] nach vergleichbaren Problemen absuchen.&lt;br /&gt;
&lt;br /&gt;
* Das [http://lists.gnu.org/archive/html/avr-gcc-list/ Archiv der avr-gcc Mailing-Liste] nach vergleichbaren Problemen absuchen.&lt;br /&gt;
&lt;br /&gt;
* Nach Beispielcode suchen. Vor allem im &#039;&#039;Projects&#039;&#039;-Bereich von [http://www.avrfreaks.net AVRFREAKS] (anmelden).&lt;br /&gt;
&lt;br /&gt;
* Google oder yahoo befragen schadet nie.&lt;br /&gt;
&lt;br /&gt;
* Bei Problemen mit der Ansteuerung interner AVR-Funktionen mit C-Code: das Datenblatt des Controllers lesen (ganz und am Besten zweimal). Datenblätter sind  auf den [http://www.atmel.com Atmel Webseiten] als pdf-Dateien verfügbar. Das komplette Datenblatt (complete) und nicht die Kurzfassung (summary) verwenden.&lt;br /&gt;
&lt;br /&gt;
* Die Beispieleprogramme im [[AVR-Tutorial]] sind zwar in AVR-Assembler verfasst, Erläuterungen und Vorgehensweisen sind aber auch auf C-Programme übertragbar.&lt;br /&gt;
&lt;br /&gt;
* Einen Beitrag in eines der Foren oder eine Mail an die Mailing-Liste schreiben. Dabei möglichst viel Information geben: Controller, Compilerversion, genutzte Bibliotheken, Ausschnitte aus dem Quellcode oder besser ein [http://www.mikrocontroller.net/topic/72767#598986 Testprojekt] mit allen notwendigen Dateien, um das Problem nachzuvollziehen, sowie genaue Fehlermeldungen bzw. Beschreibung des Fehlverhaltens. Bei Ansteuerung externer Geräte die Beschaltung beschreiben oder skizzieren (z. B. mit [http://www.tech-chat.de/ Andys ASCII Circuit]). Siehe dazu auch: &#039;&#039;&#039;[http://www.lugbz.org/documents/smart-questions_de.html &amp;quot;Wie man Fragen richtig stellt&amp;quot;]&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
= Erzeugen von Maschinencode =&lt;br /&gt;
&lt;br /&gt;
Aus dem C-Quellcode erzeugt der avr-gcc Compiler (zusammen mit Hilfsprogrammen wie z.&amp;amp;nbsp;B. Präprozessor, Assembler und Linker) Maschinencode für den AVR-Controller. Üblicherweise liegt dieser Code dann im Intel Hex-Format vor (&amp;quot;Hex-Datei&amp;quot;). Die Programmiersoftware (z.&amp;amp;nbsp;B. [[AVRDUDE]], PonyProg oder AVRStudio/STK500-plugin) liest diese Datei ein und überträgt die enthaltene Information (den Maschinencode) in den Speicher des Controllers. Im Prinzip sind also &amp;quot;nur&amp;quot; der avr-gcc-Compiler (und wenige Hilfsprogramme) mit den &amp;quot;richtigen&amp;quot; Optionen aufzurufen, um aus C-Code eine &amp;quot;Hex-Datei&amp;quot; zu erzeugen. Grundsätzlich stehen dazu zwei verschiedene Ansätze zur Verfügung:&lt;br /&gt;
&lt;br /&gt;
* Die Verwendung einer integrierten Entwicklungsumgebung (IDE = &#039;&#039;&#039;I&#039;&#039;&#039;ntegrated &#039;&#039;&#039;D&#039;&#039;&#039;evelopment &#039;&#039;&#039;E&#039;&#039;&#039;nvironment), bei der alle Einstellungen z.&amp;amp;nbsp;B. in Dialogboxen durchgeführt werden können. Unter Anderem kann AVRStudio ab Version 4.12 (kostenlos auf [http://www.atmel.com/ atmel.com]) zusammen mit WinAVR als integrierte Entwicklungsumgebung für den Compiler avr-gcc genutzt werden (dazu müssen AVRStudio und WinAVR auf dem Rechner installiert sein). Weitere IDEs für den avr-gcc (ohne Anspruch auf Vollständigkeit): AtmanAvr C (relativ günstig), KamAVR (kostenlos), VMLab (ab Version 3.12 ebenfalls kostenlos). Integrierte Entwicklungsumgebungen unterscheiden sich stark in Ihrer Bedienung und stehen auch nicht für alle Plattformen zur Verfügung, auf denen der Compiler  ausführbar ist (z.&amp;amp;nbsp;B. AVRStudio nur für MS-Windows). Zur Anwendung des avr-gcc Compilers mit IDEs sei hier auf deren Dokumentation verwiesen. &lt;br /&gt;
&lt;br /&gt;
* Die Nutzung des Programms make mit passenden Makefiles. In den folgenden Abschnitten wird die Generierung von Maschinencode für einen AVR (&amp;quot;hex-Datei&amp;quot;) aus C-Quellcode (&amp;quot;c-Dateien&amp;quot;) anhand von &amp;quot;make&amp;quot; und den &amp;quot;Makefiles&amp;quot; näher erläutert. Viele der darin beschriebenen Optionen findet man auch im Konfigurationsdialog des avr-gcc-Plugins von AVRStudio (AVRStudio generiert ein makefile in einem Unterverzeichnis des Projektverzeichnisses). &lt;br /&gt;
&lt;br /&gt;
Beim Wechsel vom makefile-Ansatz nach WinAVR-Vorlage zu AVRStudio ist darauf zu achten, dass AVRStudio (Stand: AVRStudio Version 4.13) bei einem neuen Projekt die Optimierungsoption (vgl. Abschnitt [[AVR-GCC-Tutorial#Exkurs: Makefiles|Exkurs: Makefiles]], typisch: -Os) nicht einstellt und die mathematische Bibliothek der avr-libc (libm.a, Linker-Option -lm) nicht einbindet. Beides ist Standard bei Verwendung von makefiles nach WinAVR-Vorlage und sollte daher auch im Konfigurationsdialog des avr-gcc-Plugins von AVRStudio &amp;quot;manuell&amp;quot; eingestellt werden, um auch mit AVRStudio kompakten Code zu erzeugen.&lt;br /&gt;
&lt;br /&gt;
= Einführungsbeispiel =&lt;br /&gt;
&lt;br /&gt;
Zum Einstieg ein kleines Beispiel, an dem die Nutzung des Compilers und der Hilfsprogramme (der sogenannten &#039;&#039;Toolchain&#039;&#039;) demonstriert wird. Detaillierte Erläuterungen folgen in den weiteren Abschnitten dieses Tutorials.&lt;br /&gt;
&lt;br /&gt;
Das Programm soll auf einem AVR Mikrocontroller einige Ausgänge ein- und andere ausschalten. Das Beispiel ist für einen ATmega16 programmiert ([http://www.atmel.com/dyn/resources/prod_documents/doc2466.pdf Datenblatt]), kann aber sinngemäß für andere Controller der AVR-Familie modifiziert werden. &lt;br /&gt;
&lt;br /&gt;
Zunächst der Quellcode der Anwendung, der in einer Text-Datei mit dem Namen &#039;&#039;main.c&#039;&#039; abgespeichert wird.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
/* Alle Zeichen zwischen Schrägstrich-Stern &lt;br /&gt;
   und Stern-Schrägstrich sind lediglich Kommentare */&lt;br /&gt;
&lt;br /&gt;
// Zeilenkommentare sind ebenfalls möglich&lt;br /&gt;
// alle auf die beiden Schrägstriche folgenden&lt;br /&gt;
// Zeichen einer Zeile sind Kommentar&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;          // (1)&lt;br /&gt;
&lt;br /&gt;
int main (void) {            // (2)&lt;br /&gt;
&lt;br /&gt;
   DDRB  = 0xff;             // (3)&lt;br /&gt;
   PORTB = 0x03;             // (4)&lt;br /&gt;
&lt;br /&gt;
   while(1) {                // (5a)&lt;br /&gt;
     /* &amp;quot;leere&amp;quot; Schleife*/;  // (5b)&lt;br /&gt;
   }                         // (5c)&lt;br /&gt;
&lt;br /&gt;
   /* wird nie erreicht */&lt;br /&gt;
   return 0;                 // (6)&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* In der mit (1) markierten Zeile wird eine so genannte Header-Datei eingebunden. In io.h sind die Registernamen definiert, die im späteren Verlauf genutzt werden.&lt;br /&gt;
&lt;br /&gt;
* Bei (2) beginnt das eigentliche Programm. Jedes C-Programm beginnt mit den Anweisungen in der Funktion main.&lt;br /&gt;
&lt;br /&gt;
* Die Anschlüsse eines AVR (&amp;quot;Beinchen&amp;quot;) werden zu Blöcken zusammengefasst, einen solchen Block bezeichnet man als Port. Beim ATmega16 hat jeder Port 8 Anschlüsse, bei kleineren AVRs können einem Port auch weniger als 8 Anschlüsse zugeordnet sein. Da per Definition (Datenblatt) alle gesetzten Bits in einem Richtungsregister den entsprechenden Anschluss auf Ausgang schalten, werden mit DDRB=0xff alle Anschlüsse des Ports B zu Ausgängen.&lt;br /&gt;
&lt;br /&gt;
* (4) stellt die Werte der Ausgänge ein. Die den ersten beiden Bits des Ports zugeordneten Anschlüsse (PB0 und PB1) werden 1, alle anderen Anschlüsse des Ports B (PB2-PB7) zu 0. Aktivierte Ausgänge (logisch 1 oder &amp;quot;high&amp;quot;) liegen auf Betriebsspannung (VCC, meist 5 Volt), nicht aktivierte Ausgänge führen 0 Volt (GND, Bezugspotential).&lt;br /&gt;
&lt;br /&gt;
* (5) ist die so genannte Hauptschleife (main-loop). Dies ist eine Programmschleife, welche kontinuierlich wiederkehrende Befehle enthält. In diesem Beispiel ist sie leer. Der Controller durchläuft die Schleife immer wieder, ohne dass etwas passiert (außer das Strom verbraucht wird). Eine solche Schleife ist notwendig, da es auf dem Controller kein Betriebssystem gibt, das nach Beendigung des Programmes die Kontrolle übernehmen könnte. Ohne diese Schleife wäre der Zustand des Controllers nach dem Programmende undefiniert.&lt;br /&gt;
&lt;br /&gt;
* (6) wäre das Programmende. Die Zeile ist nur aus Gründen der C-Kompatibilität enthalten: int main(void) besagt, dass die Funktion einen Wert zurückgibt. Die Anweisung wird aber nicht erreicht, da das Programm die Hauptschleife nie verlässt.&lt;br /&gt;
&lt;br /&gt;
Um diesen Quellcode in ein auf dem Controller lauffähiges Programm zu übersetzen, wird hier ein Makefile genutzt. Das verwendete Makefile findet sich auf der Seite [[Beispiel Makefile]] und basiert auf der Vorlage, die in WinAVR mitgeliefert wird und wurde bereits angepasst (Controllertyp ATmega16). Man kann das Makefile bearbeiten und an andere Controller anpassen oder sich mit dem Programm MFile menügesteuert ein Makefile &amp;quot;zusammenklicken&amp;quot;. Das Makefile speichert man unter dem Namen Makefile (ohne Endung) im selben Verzeichnis, in dem auch die Datei main.c mit dem Programmcode abgelegt ist. Detailliertere Erklärungen zur Funktion von Makefiles finden sich im folgenden Abschnitt [[AVR-GCC-Tutorial#Exkurs: Makefiles|Exkurs: Makefiles]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
D:\tmp\gcc_tut\quickstart&amp;gt;dir&lt;br /&gt;
&lt;br /&gt;
 Verzeichnis von D:\tmp\gcc_tut\quickstart&lt;br /&gt;
&lt;br /&gt;
28.11.2006  22:53    &amp;lt;DIR&amp;gt;          .&lt;br /&gt;
28.11.2006  22:53    &amp;lt;DIR&amp;gt;          ..&lt;br /&gt;
28.11.2006  20:06               118 main.c&lt;br /&gt;
28.11.2006  20:03            16.810 Makefile&lt;br /&gt;
               2 Datei(en)         16.928 Bytes&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nun gibt man &#039;&#039;make all&#039;&#039; ein. Falls das mit WinAVR installierte Programmers Notepad genutzt wird, gibt es dazu einen Menüpunkt im Tools Menü. Sind alle Einstellungen korrekt, entsteht eine Datei main.hex, in der der Code für den AVR enthalten ist. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
D:\tmp\gcc_tut\quickstart&amp;gt;make all&lt;br /&gt;
&lt;br /&gt;
-------- begin --------&lt;br /&gt;
avr-gcc (GCC) 3.4.6&lt;br /&gt;
Copyright (C) 2006 Free Software Foundation, Inc.&lt;br /&gt;
This is free software; see the source for copying conditions.  There is NO&lt;br /&gt;
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Compiling C: main.c&lt;br /&gt;
avr-gcc -c -mmcu=atmega16 -I. -gdwarf-2 -DF_CPU=1000000UL -Os -funsigned-char -f&lt;br /&gt;
unsigned-bitfields -fpack-struct -fshort-enums -Wall -Wstrict-prototypes -Wundef&lt;br /&gt;
 -Wa,-adhlns=obj/main.lst  -std=gnu99 -Wundef -MD -MP -MF .dep/main.o.d main.c -&lt;br /&gt;
o obj/main.o&lt;br /&gt;
&lt;br /&gt;
Linking: main.elf&lt;br /&gt;
avr-gcc -mmcu=atmega16 -I. -gdwarf-2 -DF_CPU=1000000UL -Os -funsigned-char -funs&lt;br /&gt;
igned-bitfields -fpack-struct -fshort-enums -Wall -Wstrict-prototypes -Wundef -W&lt;br /&gt;
a,-adhlns=obj/main.o  -std=gnu99 -Wundef -MD -MP -MF .dep/main.elf.d obj/main.o&lt;br /&gt;
--output main.elf -Wl,-Map=main.map,--cref    -lm&lt;br /&gt;
&lt;br /&gt;
Creating load file for Flash: main.hex&lt;br /&gt;
avr-objcopy -O ihex -R .eeprom main.elf main.hex&lt;br /&gt;
&lt;br /&gt;
[...]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Inhalt der hex-Datei kann nun zum Controller übertragen werden. Dies kann z.&amp;amp;nbsp;B. über In-System-Programming (ISP) erfolgen, das im [[AVR-Tutorial: Equipment]] beschrieben ist. Makefiles nach der WinAVR/MFile-Vorlage sind für die Nutzung des Programms [[AVRDUDE]] vorbereitet. Wenn man den Typ und Anschluss des Programmiergerätes richtig eingestellt hat, kann mit &#039;&#039;make program&#039;&#039; die Übertragung mittels AVRDUDE gestartet werden. Jede andere Software, die hex-Dateien lesen und zu einem AVR übertragen kann (z.&amp;amp;nbsp;B. [[Pony-Prog_Tutorial|Ponyprog]], yapp, AVRStudio), kann natürlich ebenfalls genutzt werden.&lt;br /&gt;
&lt;br /&gt;
Startet man nun den Controller (Reset-Taster oder Stromzufuhr aus/an), werden vom Programm die Anschlüsse PB0 und PB1 auf 1 gesetzt. Man kann mit einem Messgerät nun an diesem Anschluss die Betriebsspannung messen oder eine LED leuchten lassen (Anode an den Pin, Vorwiderstand nicht vergessen). An den Anschlüssen PB2-PB7 misst man 0 Volt. Eine mit der Anode mit einem dieser Anschlüsse verbundene LED leuchtet nicht.&lt;br /&gt;
&lt;br /&gt;
= Exkurs: Makefiles =&lt;br /&gt;
&lt;br /&gt;
Wenn man bisher gewohnt ist, mit integrierten Entwicklungsumgebungen à la Visual-C Programme zu erstellen, wirkt das makefile-Konzept auf den ersten Blick etwas kryptisch. Nach kurzer Einarbeitung ist diese Vorgehensweise jedoch sehr praktisch. Diese Dateien (üblicher Name: &#039;Makefile&#039; ohne Dateiendung) dienen der Ablaufsteuerung des Programms make, das auf allen Unix/Linux-Systemen installiert sein sollte, und in einer Fassung fuer MS-Windows auch in [[WinAVR]] (Unterverzeichnis utils/bin) enthalten ist.&lt;br /&gt;
&lt;br /&gt;
Im Unterverzeichnis &#039;&#039;sample&#039;&#039; einer WinAVR-Installation findet man eine sehr brauchbare Vorlage, die sich einfach an das eigene Projekt anpassen lässt ([[Media:Makefile|lokale Kopie Stand Sept. 2004]]). Wahlweise kann man auch [http://www.sax.de/~joerg/mfile/ mfile] von Jörg Wunsch nutzen. mfile erzeugt ein makefile nach Einstellungen in einer grafischen Nutzeroberfläche, wird bei WinAVR mitinstalliert, ist aber als TCL/TK-Programm auf nahezu allen Plattformen lauffähig.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Die folgenden Ausführungen beziehen sich auf das WinAVR Beispiel-Makefile.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Ist im Makefile alles richtig eingestellt, genügt es, sich drei Parameter zu merken, die über die shell bzw. die Windows-Kommandozeile (cmd.exe/command.com) als Parameter an &amp;quot;make&amp;quot; übergeben werden. Das Programm make sucht sich &amp;quot;automatisch&amp;quot; das Makefile im aktuellen Arbeitsverzeichnis und führt die darin definierten Operationen für den entsprechenden Aufrufparameter durch.&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
| &#039;&#039;make all&#039;&#039;&lt;br /&gt;
| Erstellt aus den im Makefile angegebenen Quellcodes eine &#039;&#039;hex&#039;&#039;-Datei (und ggf. auch &#039;&#039;eep&#039;&#039;-Datei).&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;make program&#039;&#039;&lt;br /&gt;
| Überträgt die hex-Datei (und wahlweise auch die eep-Datei für den EEPROM) zum AVR. &lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;make clean&#039;&#039;&lt;br /&gt;
| löscht alle temporären Dateien, also auch die hex-Datei&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Diese Aufrufe können in die allermeisten Editoren in &amp;quot;Tool-Menüs&amp;quot; eingebunden werden. Dies erspart den Kontakt mit der Kommandozeile. Bei WinAVR sind die Aufrufe bereits im Tools-Menü des mitgelieferten Editors Programmers-Notepad eingefügt.&lt;br /&gt;
&lt;br /&gt;
Üblicherweise sind folgende Daten im Makefile anzupassen:&lt;br /&gt;
* Controllertyp&lt;br /&gt;
&lt;br /&gt;
* Quellcode-Dateien (c-Dateien)&lt;br /&gt;
&lt;br /&gt;
* Typ und Anschluss des Programmiergeräts&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Seltener sind folgende Einstellungen durchzuführen:&lt;br /&gt;
* Grad der Optimierung&lt;br /&gt;
&lt;br /&gt;
* Methode zur Erzeugung der Debug-Symbole (Debug-Format)&lt;br /&gt;
&lt;br /&gt;
* Assembler-Quellcode-Dateien (S-Dateien)&lt;br /&gt;
&lt;br /&gt;
Die in den folgenden Unterabschnitten gezeigten Makefile-Ausschnitte sind für ein Programm, das auf einem ATmega8 ausgeführt werden soll. Der Quellcode besteht aus den c-Dateien superprog.c (darin main()), uart.c, lcd.c und 1wire.c. Im Quellcodeverzeichnis befinden sich diese Dateien: superprog.c, uart.h, uart.c, lcd.h, lcd.c, 1wire.h, 1wire.c und das makefile (die angepasste Kopie des WinAVR-Beispiels).&lt;br /&gt;
&lt;br /&gt;
Der Controller wird mittels [[AVRDUDE]] über ein [[STK200]]-Programmierdongle an der Schnittstelle lpt1 (bzw. /dev/lp0) programmiert. Im Quellcode sind auch Daten für die &#039;&#039;section .eeprom&#039;&#039; definiert (siehe Abschnitt [[AVR-GCC-Tutorial#EEPROM|Speicherzugriffe]]), diese sollen beim Programmieren gleich mit ins EEPROM geschrieben werden. &lt;br /&gt;
&lt;br /&gt;
== Controllertyp setzen ==&lt;br /&gt;
&lt;br /&gt;
Dazu wird die &amp;quot;make-Variable&amp;quot; MCU entsprechend dem Namen des verwendeten Controllers gesetzt. Eine Liste der von avr-gcc und der avr-libc unterstützten Typen findet sich in der [http://www.nongnu.org/avr-libc/user-manual/index.html Dokumentation der avr-libc].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;code&amp;quot;&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
# Kommentare in Makefiles beginnen mit einem Doppelkreuz &lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
# ATmega8 at work&lt;br /&gt;
MCU = atmega8&lt;br /&gt;
# oder MCU = atmega16 &lt;br /&gt;
# oder MCU = at90s8535&lt;br /&gt;
# oder ...&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Quellcode-Dateien eintragen ==&lt;br /&gt;
&lt;br /&gt;
Der Name der Quellcodedatei, welche die Funktion main enthält, wird hinter TARGET eingetragen. Dies jedoch ohne die Endung &#039;&#039;.c&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;code&amp;quot;&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
TARGET = superprog&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Besteht das Projekt wie im Beispiel aus mehr als einer Quellcodedatei, sind die weiteren c-Dateien (nicht die Header-Dateien, vgl. [[Include-Files (C)]]) durch Leerzeichen getrennt bei SRC einzutragen. Die bei TARGET definierte Datei ist schon in der SRC-Liste enthalten. Diesen Eintrag nicht löschen!&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;code&amp;quot;&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
SRC = $(TARGET).c uart.c lcd.c 1wire.c &lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Alternativ kann man die Liste der Quellcodedateien auch mit dem Operator += erweitern.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;code&amp;quot;&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
SRC = $(TARGET).c uart.c 1wire.c&lt;br /&gt;
# lcd-Code fuer Controller xyz123 (auskommentiert)&lt;br /&gt;
# SRC += lcd_xyz.c&lt;br /&gt;
# lcd-Code fuer &amp;quot;Standard-Controller&amp;quot; (genutzt)&lt;br /&gt;
SRC += lcd.c&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Programmiergerät einstellen ==&lt;br /&gt;
&lt;br /&gt;
Die Vorlagen sind auf die Programmiersoftware [[AVRDUDE]] angepasst, jedoch lässt sich auch andere Programmiersoftware einbinden, sofern diese über Kommandozeile gesteuert werden kann (z.&amp;amp;nbsp;B. stk500.exe, uisp, sp12).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;code&amp;quot;&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
# Einstellung fuer STK500 an com1 (auskommentiert)&lt;br /&gt;
# AVRDUDE_PROGRAMMER = stk500&lt;br /&gt;
# com1 = serial port. Use lpt1 to connect to parallel port.&lt;br /&gt;
# AVRDUDE_PORT = com1    # programmer connected to serial device&lt;br /&gt;
&lt;br /&gt;
# Einstellung fuer STK200-Dongle an lpt1&lt;br /&gt;
AVRDUDE_PROGRAMMER = stk200&lt;br /&gt;
AVRDUDE_PORT = lpt1&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sollen Flash(=.hex) und EEPROM(=.eep) zusammen auf den Controller programmiert werden, ist das Kommentarzeichen vor AVRDUDE_WRITE_EEPROM zu löschen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;code&amp;quot;&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
# auskommentiert: EERPOM-Inhalt wird nicht mitgeschrieben&lt;br /&gt;
#AVRDUDE_WRITE_EEPROM = -U eeprom:w:$(TARGET).eep&lt;br /&gt;
&lt;br /&gt;
# nicht auskommentiert: EERPOM-Inhalt wird mitgeschrieben&lt;br /&gt;
AVRDUDE_WRITE_EEPROM = -U eeprom:w:$(TARGET).eep&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Anwendung ==&lt;br /&gt;
&lt;br /&gt;
Das erstellte Makefile und der Code müssen im gleichen Ordner sein, auch sollte der Dateiname nicht verändert werden. &lt;br /&gt;
&lt;br /&gt;
Die Eingabe von &#039;&#039;make all&#039;&#039; im Arbeitsverzeichnis mit dem Makefile und den Quellcodedateien erzeugt (unter anderem) die Dateien superprog.hex und superprog.eep. Abhängigkeiten zwischen den einzelnen c-Dateien werden dabei automatisch berücksichtigt. Die &#039;&#039;superprog.hex&#039;&#039; und &#039;&#039;superprog.eep&#039;&#039; werden mit &#039;&#039;make program&#039;&#039; zum Controller  übertragen. Mit &#039;&#039;make clean&#039;&#039; werden alle temporären Dateien gelöscht (=&amp;quot;aufgeräumt&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
== Sonstige Einstellungen ==&lt;br /&gt;
&lt;br /&gt;
=== Optimierungsgrad ===&lt;br /&gt;
&lt;br /&gt;
Der gcc-Compiler kennt verschiedene Stufen der Optimierung. Nur zu Testzwecken sollte die Optimierung ganz deaktiviert werden (&#039;&#039;OPT = 0&#039;&#039;). Die weiteren möglichen Optionen weisen den Compiler an, möglichst kompakten oder möglichst schnellen Code zu erzeugen. In den weitaus meisten Fällen ist &#039;&#039;OPT = s&#039;&#039; die empfohlene Einstellung, damit wird kompakter und oft auch der schnellste Maschinencode erzeugt. Beim Update auf eine neue Compilerversion ist zu beachten, dass diese möglicherweise intern andere Optimierungsalgorithmen verwendet und sich dadurch die Größe des Machinencodes etwas ändert, ohne dass man im Quellcode etwas geändert hat.&lt;br /&gt;
&lt;br /&gt;
Als Orientierungswerte die Größe des Maschinencodes bei verschiedenen Optionen für einen nicht näher spezifizierten relativ kleinen Testcode bei Verwendung einer nicht näher spezifizierten Compilerversion. &lt;br /&gt;
&lt;br /&gt;
* -O0 : 12&#039;217 Byte&lt;br /&gt;
&lt;br /&gt;
* -O1 : 9&#039;128 Byte&lt;br /&gt;
&lt;br /&gt;
* -O2 : 1&#039;670 Byte&lt;br /&gt;
&lt;br /&gt;
* -O3 : 3&#039;004 Byte&lt;br /&gt;
&lt;br /&gt;
* -Os : 1&#039;695 Byte&lt;br /&gt;
&lt;br /&gt;
Im diesem Testfall führt die Option -O2 mit zum kompaktesten Code, dies  allerdings hier nur mit 25 Bytes &amp;quot;Vorsprung&amp;quot;. Es kann durchaus sein, dass nur wenige Programmerweiterungen dazu führen, dass Compilieren mit -Os wieder in kompakteren Code resultiert.&lt;br /&gt;
&lt;br /&gt;
Siehe dazu auch: &lt;br /&gt;
* [http://www.nongnu.org/avr-libc/user-manual/using_tools.html#gcc_optO avr-libc manual Abschnitt Using the gnu-tools/Compiler-Optionen]&lt;br /&gt;
&lt;br /&gt;
* [http://www.nongnu.org/avr-libc/user-manual/FAQ.html#faq_optflags avr-libc Manual FAQ Nr. 16] (Stand avr-libc Version 1.4.5)&lt;br /&gt;
&lt;br /&gt;
=== Debug-Format ===&lt;br /&gt;
&lt;br /&gt;
Unterstützt werden die Formate stabs und dwarf-2. Das Format wird hinter &#039;&#039;DEBUG =&#039;&#039; eingestellt. Siehe dazu Abschnitt &#039;&#039;Eingabedateien zur Simulation&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Assembler-Dateien ===&lt;br /&gt;
&lt;br /&gt;
Die im Projekt genutzten Assembler-Dateien werden hinter ASRC durch Leerzeichen getrennt aufgelistet. Assembler-Dateien haben immer die Endung .S (großes S). Ist zum Beispiel der Assembler-Quellcode eines Software-UARTs in einer Datei softuart.S enthalten, lautet die Zeile: &#039;&#039;ASRC = softuart.S&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Taktfrequenz ===&lt;br /&gt;
&lt;br /&gt;
Neuere Versionen der WinAVR/Mfile Vorlage für Makefiles beinhalten die Definition einer Variablen F_CPU (WinAVR 2/2005). Darin wird die Taktfrequenz des Controllers in Hertz eingetragen. Die Definition steht dann im gesamten Projekt ebenfalls unter der Bezeichnung F_CPU zur Verfügung (z.&amp;amp;nbsp;B. um daraus UART-, SPI- oder ADC-Frequenzeinstellungen abzuleiten).&lt;br /&gt;
&lt;br /&gt;
Die Angabe hat rein &amp;quot;informativen&amp;quot; Charakter, die tatsächliche Taktrate wird über den externen Takt (z.&amp;amp;nbsp;B. Quarz) bzw. die Einstellung des internen R/C-Oszillators  bestimmt. Die Nutzung von F_CPU hat also nur Sinn, wenn die Angabe mit dem tatsächlichen Takt übereinstimmt.&lt;br /&gt;
&lt;br /&gt;
Innerhalb neuerer Versionen der avr-libc (ab Version 1.2) wird die Definition der Taktfrequenz (F_CPU) zur Berechnung der Wartefunktionen in delay.h genutzt. Diese funktionieren nur dann korrekt, wenn F_CPU mit der tatsächlichen Taktfrequenz übereinstimmt.&lt;br /&gt;
F_CPU muss dazu jedoch nicht unbedingt im makefile definiert werden. Es reicht aus, wird aber bei mehrfacher Anwendung unübersichtlich, vor &#039;&#039;#include &amp;lt;util/delay.h&amp;gt;&#039;&#039; (veraltet: &#039;&#039;#include &amp;lt;avr/delay.h&amp;gt;&#039;&#039;) ein &#039;&#039;#define F_CPU [hier Takt in Hz]UL&#039;&#039; einzufügen. Bei Nutzung von delay.h ist darauf zu achten, dass die Optimierung des Compilers nicht ausgeschaltet ist, sonst wird sehr viel Code erzeugt und die Wartezeit stimmt nicht mit der gewünschten Zeitspanne überein. Vgl. dazu den [http://www.nongnu.org/avr-libc/user-manual/group__util__delay.html entsprechenden Abschnitt der Dokumentation].&lt;br /&gt;
&lt;br /&gt;
== Eingabedateien zur Simulation in AVR-Studio ==&lt;br /&gt;
&lt;br /&gt;
Mit älteren AVR-Studio-Versionen kann man nur auf Grundlage so genannter &#039;&#039;coff&#039;&#039;-Dateien simulieren. Neuere Versionen von AVR-Studio (ab 4.10.356) unterstützen zudem das modernere aber noch experimentelle dwarf-2-Format, das ab WinAVR 20040722 (avr-gcc 3.4.1/Binutils inkl. Atmel add-ons) &amp;quot;direkt&amp;quot; vom Compiler erzeugt wird.&lt;br /&gt;
&lt;br /&gt;
; Vorgehensweise bei dwarf-2:&lt;br /&gt;
* Im Makefile bei DEBUG: &amp;lt;div class=&amp;quot;code&amp;quot;&amp;gt;&amp;lt;pre&amp;gt;DEBUG=dwarf-2&amp;lt;/pre&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;make all&#039;&#039; (evtl. vorher &#039;&#039;make clean&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
* Die erzeugte &#039;&#039;elf&#039;&#039;-Datei (im Beispiel oben &#039;&#039;superprog.elf&#039;&#039;) in AVR-Studio laden&lt;br /&gt;
&lt;br /&gt;
* AVR-Simulator und zu simulierenden Controller wählen, &amp;quot;Finish&amp;quot;&lt;br /&gt;
&lt;br /&gt;
* Weiteres siehe AVR-Studio Online-Hilfe&lt;br /&gt;
&lt;br /&gt;
; Vorgehensweise bei extcoff: (sollte nur noch in Ausnahmefällen genutzt werden)&lt;br /&gt;
&lt;br /&gt;
* Im Makefile bei DEBUG: &amp;lt;div class=&amp;quot;code&amp;quot;&amp;gt;&amp;lt;pre&amp;gt;DEBUG=stabs&amp;lt;/pre&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;make extcoff&#039;&#039; (evtl. vorher &#039;&#039;make clean&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
* Die erzeugte &#039;&#039;cof&#039;&#039;-Datei (im Beispiel oben &#039;&#039;superprog.cof&#039;&#039;) in AVR-Studio laden&lt;br /&gt;
&lt;br /&gt;
* AVR-Simulator und zu simulierenden Controller wählen, &amp;quot;Finish&amp;quot;&lt;br /&gt;
&lt;br /&gt;
* Weiteres siehe AVR-Studio Online-Hilfe&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Beim Simulieren scheinen oft &amp;quot;Variablen zu fehlen&amp;quot;. Ursache dafür ist, dass der Compiler diese &amp;quot;Variablen&amp;quot; direkt Registern zuweist. Dies kann vermieden werden, indem die Optimierung abgeschaltet wird (im makefile). Man simuliert dann jedoch ein vom optimierten Code stark abweichendes Programm. Das Abschalten der Optimierung wird nicht empfohlen.&lt;br /&gt;
&lt;br /&gt;
Statt des Software-Simulators kann das AVR-Studio auch genutzt werden, um mit dem ATMEL JTAGICE, einem Nachbau davon (BootICE, Evertool o.&amp;amp;nbsp;ä.) oder dem ATMEL JTAGICE MKII &amp;quot;im System&amp;quot; zu debuggen. Dazu sind keine speziellen Einstellungen im makefile erforderlich. Debugging bzw. &amp;quot;In-System-Emulation&amp;quot; mit dem JTAGICE und JTAGICE MKII sind in der AVR-Studio Online-Hilfe beschrieben.&lt;br /&gt;
&lt;br /&gt;
Die Verwendung von Makefiles bietet noch viele weitere Möglichkeiten, einige davon werden im Anhang [[AVR-GCC-Tutorial#Zus.C3.A4tzliche_Funktionen_im_Makefile|Zusätzliche Funktionen im Makefile]] erläutert.&lt;br /&gt;
&lt;br /&gt;
= Ganzzahlige (Integer) Datentypen =&lt;br /&gt;
&lt;br /&gt;
Bei der Programmierung von Mikrokontrollern ist die Definition einiger ganzzahliger Datentypen sinnvoll, an denen eindeutig die Bit-Länge abgelesen werden kann.&lt;br /&gt;
&lt;br /&gt;
Standardisierte Datentypen werden in der Header-Datei stdint.h definiert. &lt;br /&gt;
Zur Nutzung der standardisierten Typen bindet man die &amp;quot;Definitionsdatei&amp;quot; wie folgt ein:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
// ab avr-libc Version 1.2.0 möglich und empfohlen:&lt;br /&gt;
#include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
// veraltet: #include &amp;lt;inttypes.h&amp;gt;&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Einige der dort definierten Typen (avr-libc Version 1.0.4):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
typedef signed char        int8_t;&lt;br /&gt;
typedef unsigned char      uint8_t;&lt;br /&gt;
&lt;br /&gt;
typedef short              int16_t;&lt;br /&gt;
typedef unsigned short     uint16_t;&lt;br /&gt;
&lt;br /&gt;
typedef long               int32_t;&lt;br /&gt;
typedef unsigned long      uint32_t;&lt;br /&gt;
&lt;br /&gt;
typedef long long          int64_t;&lt;br /&gt;
typedef unsigned long long uint64_t;&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* int8_t steht für einen 8-Bit Integer mit einem Wertebereich -128 bis +127.&lt;br /&gt;
&lt;br /&gt;
* uint8_t steht für einen 8-Bit Integer ohne Vorzeichen (unsigned int) mit einem Wertebereich von 0 bis 255&lt;br /&gt;
&lt;br /&gt;
* int16_t steht für einen 16-Bit Integer mit einem Wertebereich -32768 bis +32767.&lt;br /&gt;
&lt;br /&gt;
* uint16_t steht für einen 16-Bit Integer ohne Vorzeichen (unsigned int) mit einem Wertebereich von 0 bis 65535.&lt;br /&gt;
&lt;br /&gt;
Die Typen ohne vorangestelltes &#039;&#039;u&#039;&#039; werden als vorzeichenbehaftete Zahlen abgespeichert. Typen mit vorgestelltem &#039;&#039;u&#039;&#039; dienen der Ablage von postiven Zahlen (inkl. 0). Siehe dazu auch: [http://www.nongnu.org/avr-libc/user-manual/index.html Dokumentation der avr-libc] Abschnitt Modules/(Standard) Integer Types.&lt;br /&gt;
&lt;br /&gt;
= Bitfelder =&lt;br /&gt;
&lt;br /&gt;
Beim Programmieren von Mikrocontrollern muss auf jedes Byte oder sogar auf&lt;br /&gt;
jedes Bit geachtet werden. Oft müssen wir in einer Variablen lediglich den&lt;br /&gt;
Zustand 0 oder 1 speichern. Wenn wir nun zur Speicherung eines einzelnen Wertes&lt;br /&gt;
den kleinsten bekannten Datentypen, nämlich &#039;&#039;&#039;unsigned char&#039;&#039;&#039;, nehmen, dann&lt;br /&gt;
verschwenden wir 7 Bits, da ein &#039;&#039;&#039;unsigned char&#039;&#039;&#039; ja 8 Bits breit ist.&lt;br /&gt;
&lt;br /&gt;
Hier bietet uns die Programmiersprache C ein mächtiges Werkzeug an, mit dessen&lt;br /&gt;
Hilfe wir 8 Bits in eine einzelne Bytevariable zusammenfassen und (fast) wie&lt;br /&gt;
8 einzelne Variablen ansprechen können. Die Rede ist von so genannten Bitfeldern. Diese werden als Strukturelemente definiert. Sehen wir uns dazu doch am besten gleich ein Beispiel an:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
struct {&lt;br /&gt;
   unsigned bStatus_1:1; // 1 Bit für bStatus_1&lt;br /&gt;
   unsigned bStatus_2:1; // 1 Bit für bStatus_2&lt;br /&gt;
   unsigned bNochNBit:1; // Und hier noch mal ein Bit&lt;br /&gt;
   unsigned b2Bits:2;    // Dieses Feld ist 2 Bits breit&lt;br /&gt;
   // All das hat in einer einzigen Byte-Variable Platz.&lt;br /&gt;
   // die 3 verbleibenden Bits bleiben ungenutzt&lt;br /&gt;
} x;&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Zugriff auf ein solches Feld erfolgt nun wie beim Strukturzugriff bekannt&lt;br /&gt;
über den Punkt- oder den Dereferenzierungs-Operator:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
x.bStatus_1 = 1;&lt;br /&gt;
x.bStatus_2 = 0;&lt;br /&gt;
x.b2Bits = 3;&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bitfelder sparen Platz im RAM, zu Lasten von Platz im Flash, verschlechtern aber unter Umständen die Les- und Wartbarkeit des Codes. Anfängern wird deshalb geraten, ein &amp;quot;ganzes&amp;quot; Byte (uint8_t) zu nutzen, auch wenn nur ein Bitwert gespeichert werden soll.&lt;br /&gt;
&lt;br /&gt;
Wenn man nur ein paar wenige Variablen vom Typ bool verwenden möchte, kann man&lt;br /&gt;
auch die Headerdatei &amp;lt;stdbool.h&amp;gt; einbinden und sich dann wie gewohnt einen Booltyp anlegen. Variablen dieses Typs brauchen dennoch 1 Byte Speicher, ermöglichen aber eine genaue Unterscheidung zwischen Zahlenvariable und boolscher Variable.&lt;br /&gt;
&lt;br /&gt;
= Grundsätzlicher Programmaufbau eines &amp;amp;micro;C-Programms =&lt;br /&gt;
&lt;br /&gt;
Wir unterscheiden zwischen 2 verschiedenen Methoden, um ein&lt;br /&gt;
Mikrocontroller-Programm zu schreiben, und zwar völlig unabhängig davon, in&lt;br /&gt;
welcher Programmiersprache das Programm geschrieben wird.&lt;br /&gt;
&lt;br /&gt;
== Sequentieller Programmablauf ==&lt;br /&gt;
&lt;br /&gt;
Bei dieser Programmiertechnik wird eine Endlosschleife programmiert, welche im&lt;br /&gt;
Wesentlichen immer den gleichen Aufbau hat:&lt;br /&gt;
&lt;br /&gt;
[[Image:Sequentielle Programme.gif]]&lt;br /&gt;
&lt;br /&gt;
== Interruptgesteuerter Programmablauf ==&lt;br /&gt;
&lt;br /&gt;
Bei dieser Methode werden beim Programmstart zuerst die gewünschten Interruptquellen aktiviert und dann in eine Endlosschleife gegangen, in welcher Dinge erledigt werden können, welche nicht zeitkritisch sind. Wenn ein Interrupt ausgelöst wird, so wird automatisch die zugeordnete Interruptfunktion ausgeführt.&lt;br /&gt;
&lt;br /&gt;
[[Image:Interrupt Programme.gif]]&lt;br /&gt;
&lt;br /&gt;
= Zugriff auf Register =&lt;br /&gt;
&lt;br /&gt;
Die AVR-Controller verfügen über eine Vielzahl von Registern. Die meisten&lt;br /&gt;
davon sind sogenannte Schreib-/Leseregister. Das heißt, das Programm kann die&lt;br /&gt;
Inhalte der Register sowohl auslesen als auch beschreiben.&lt;br /&gt;
&lt;br /&gt;
Register haben einen besonderen Stellenwert bei den AVR Controllern. Sie dienen dem Zugriff auf die Ports und die Schnittstellen des Controllers. Wir unterscheiden zwischen 8-Bit und 16-Bit Registern. Vorerst behandeln wir mal&lt;br /&gt;
die 8-Bit Register.&lt;br /&gt;
&lt;br /&gt;
Einzelne Register sind bei allen AVRs vorhanden, andere wiederum nur bei bestimmten Typen. So sind beispielsweise die Register, welche für den Zugriff auf den UART notwendig sind, selbstverständlich nur bei denjenigen Modellen vorhanden, welche über einen integrierten Hardware UART bzw. USART verfügen.&lt;br /&gt;
&lt;br /&gt;
Die Namen der Register sind in den Headerdateien zu den entsprechenden AVR-Typen definiert. Dazu muss man den Namen der controllerspezifischen Headerdatei nicht kennen. Es reicht aus, die allgemeine Headerdatei &#039;&#039;avr/io.h&#039;&#039; einzubinden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ist im Makefile der MCU-Typ z.&amp;amp;nbsp;B. mit dem Inhalt atmega8 definiert (und wird somit per -mmcu=atmega8 an den Compiler übergeben), wird beim Einlesen der io.h-Datei implizit (&amp;quot;automatisch&amp;quot;) auch die iom8.h-Datei mit den Register-Definitionen für den ATmega8 eingelesen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- Wohl besser als Anhang - spaeter... --&amp;gt;&lt;br /&gt;
Intern wird diese &amp;quot;Automatik&amp;quot; wie folgt realisiert: Der Controllertyp wird dem Compiler als Parameter übergeben (vgl. &#039;&#039;avr-gcc -c -mmcu=atmega16 [...]&#039;&#039; im Einführungsbeispiel). Wird ein Makefile nach der WinAVR/mfile-Vorlage verwendet, setzt man die Variable &#039;&#039;MCU&#039;&#039;, der Inhalt dieser Variable wird dann an passender Stelle für die Compilerparameter verwendet. Der Compiler definiert intern eine dem mmcu-Parameter zugeordnete &amp;quot;Variable&amp;quot; (genauer: ein Makro) mit dem Namen des Controllers, vorangestelltem &#039;&#039;__AVR_&#039;&#039; und angehängten Unterstrichen (z.B. wird bei &#039;&#039;-mmcu=atmega16&#039;&#039; das Makro &#039;&#039;__AVR_ATmega16__&#039;&#039; definiert). Beim Einbinden der Header-Datei &#039;&#039;avr/io.h&#039;&#039; wird geprüft, ob das jeweilige Makro definiert ist und die zum Controller passende Definitionsdatei eingelesen. Zur Veranschaulichung einige Ausschnitte aus einem Makefile:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
[...]&lt;br /&gt;
# MCU Type (&amp;quot;name&amp;quot;) setzen:&lt;br /&gt;
MCU = atmega16&lt;br /&gt;
[...]&lt;br /&gt;
&lt;br /&gt;
[...]&lt;br /&gt;
## Verwendung des Inhalts von MCU (hier atmega16) fuer die &lt;br /&gt;
## Compiler- und Assembler-Parameter&lt;br /&gt;
ALL_CFLAGS = -mmcu=$(MCU) -I. $(CFLAGS) $(GENDEPFLAGS)&lt;br /&gt;
ALL_CPPFLAGS = -mmcu=$(MCU) -I. -x c++ $(CPPFLAGS) $(GENDEPFLAGS)&lt;br /&gt;
ALL_ASFLAGS = -mmcu=$(MCU) -I. -x assembler-with-cpp $(ASFLAGS)&lt;br /&gt;
[...]&lt;br /&gt;
&lt;br /&gt;
[...]&lt;br /&gt;
## Aufruf des Compilers:&lt;br /&gt;
## mit den Parametern ($(ALL_CFLAGS) ist -mmcu=$(MCU)[...] = -mmcu=atmega16[...]&lt;br /&gt;
$(OBJDIR)/%.o : %.c&lt;br /&gt;
	@echo&lt;br /&gt;
	@echo $(MSG_COMPILING) $&amp;lt;&lt;br /&gt;
	$(CC) -c $(ALL_CFLAGS) $&amp;lt; -o $@ &lt;br /&gt;
[...]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Da --mmcu=atmega16 übergeben wurde, wird __AVR_ATmega16__ definiert und kann in avr/io.h zur Fallunterscheidung genutzt werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
// avr/io.h &lt;br /&gt;
// (bei WinAVR-Standardinstallation in C:\WinAVR\avr\include\avr)&lt;br /&gt;
[...]&lt;br /&gt;
#if defined (__AVR_AT94K__)&lt;br /&gt;
#  include &amp;lt;avr/ioat94k.h&amp;gt;&lt;br /&gt;
// [...]&lt;br /&gt;
#elif defined (__AVR_ATmega16__)&lt;br /&gt;
// da __AVR_ATmega16__ definiert ist, wird avr/iom16.h eingebunden:&lt;br /&gt;
#  include &amp;lt;avr/iom16.h&amp;gt;&lt;br /&gt;
// [...]&lt;br /&gt;
#else&lt;br /&gt;
#  if !defined(__COMPILING_AVR_LIBC__)&lt;br /&gt;
#    warning &amp;quot;device type not defined&amp;quot;&lt;br /&gt;
#  endif&lt;br /&gt;
#endif&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Schreiben in Register ==&lt;br /&gt;
&lt;br /&gt;
Zum Schreiben kann man Register einfach wie eine Variable setzen. In Quellcodes, die für ältere Versionen des avr-gcc/der avr-libc entwickelt wurden, erfolgt der Schreibzugriff über die Funktion outp(). Aktuelle Versionen des Compilers unterstützen den Zugriff nun direkt und outp() ist nicht mehr erforderlich.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
int main(void)&lt;br /&gt;
{&lt;br /&gt;
    /* Setzt das Richtungsregister des Ports A auf 0xff &lt;br /&gt;
       (alle Pins als Ausgang, vgl. Abschnitt Zugriff auf Ports): */&lt;br /&gt;
    DDRA = 0xff;    &lt;br /&gt;
&lt;br /&gt;
    /* Setzt PortA auf 0x03, Bit 0 und 1 &amp;quot;high&amp;quot;, restliche &amp;quot;low&amp;quot;: */&lt;br /&gt;
    PORTA = 0x03;   &lt;br /&gt;
    ...&lt;br /&gt;
&lt;br /&gt;
    // Setzen der Bits 0,1,2,3 und 4&lt;br /&gt;
    // Binär 00011111 = Hexadezimal 1F&lt;br /&gt;
    DDRB = 0x1F;    /* direkte Zuweisung - unübersichtlich */&lt;br /&gt;
&lt;br /&gt;
    /* Ausführliche Schreibweise: identische Funktionalität, mehr Tipparbeit&lt;br /&gt;
       aber übersichtlicher und selbsterklärend: */&lt;br /&gt;
    DDRB = (1 &amp;lt;&amp;lt; DDB0) | (1 &amp;lt;&amp;lt; DDB1) | (1 &amp;lt;&amp;lt; DDB2) | (1 &amp;lt;&amp;lt; DDB3) | (1 &amp;lt;&amp;lt; DDB4); &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die ausführliche Schreibweise sollte bevorzugt verwendet werden, da dadurch die Zuweisungen selbsterklärend sind und somit der Code leichter nachvollzogen werden kann. Atmel verwendet sie auch bei Beispielen in Datenblätten und in den allermeisten Quellcodes zu Application-Notes.&lt;br /&gt;
&lt;br /&gt;
Der gcc C-Compiler (genauer der Präprozessor) unterstützt ab Version 4.3.0 Konstanten im Binärformat, z.B. DDRB&amp;amp;nbsp;=&amp;amp;nbsp;0b00011111 (für WinAVR wurden schon ältere Versionen des gcc entsprechend angepasst). Diese Schreibweise ist jedoch nicht standardkonform und man sollte sie daher insbesondere dann nicht verwenden, wenn Code mit anderen ausgetauscht oder mit anderen Compilern bzw. älteren Versionen des gcc genutzt werden soll.  &lt;br /&gt;
&lt;br /&gt;
=== Verändern von Registerinhalten ===&lt;br /&gt;
&lt;br /&gt;
Einzelne Bits setzt und löscht man &amp;quot;Standard-C-konform&amp;quot; mittels logischer (Bit-) Operationen. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
 x |= (1 &amp;lt;&amp;lt; Bitnummer);  // Hiermit wird ein Bit in x gesetzt&lt;br /&gt;
 x &amp;amp;= ~(1 &amp;lt;&amp;lt; Bitnummer); // Hiermit wird ein Bit in x geloescht&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Es wird jeweils nur der Zustand des angegebenen Bits geändert, der vorherige Zustand der anderen Bits bleibt erhalten. &lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
#define MEINBIT 2&lt;br /&gt;
...&lt;br /&gt;
PORTA |= (1 &amp;lt;&amp;lt; MEINBIT);    /* setzt Bit 2 an PortA auf 1 */&lt;br /&gt;
PORTA &amp;amp;= ~(1 &amp;lt;&amp;lt; MEINBIT);   /* loescht Bit 2 an PortA */&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit dieser Methode lassen sich auch mehrere Bits eines Registers gleichzeitig setzen und löschen.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
DDRA &amp;amp;= ~( (1&amp;lt;&amp;lt;PA0) | (1&amp;lt;&amp;lt;PA3) );  /* PA0 und PA3 als Eingaenge */&lt;br /&gt;
PORTA |= (1&amp;lt;&amp;lt;PA0) | (1&amp;lt;&amp;lt;PA3);      /* Interne Pull-Up fuer beide einschalten */&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In Quellcodes, die für ältere Version den des avr-gcc/der avr-libc entwickelt wurden, werden einzelne Bits mittels der Funktionen sbi und cbi gesetzt bzw. gelöscht. Beide Funktionen sind nicht mehr erforderlich.&lt;br /&gt;
&lt;br /&gt;
Siehe auch:&lt;br /&gt;
* [[Bitmanipulation]]&lt;br /&gt;
* [http://www.nongnu.org/avr-libc/user-manual/index.html Dokumentation der avr-libc] Abschnitt Modules/Special Function Registers&lt;br /&gt;
&lt;br /&gt;
== Lesen aus Registern ==&lt;br /&gt;
&lt;br /&gt;
Zum Lesen kann man auf Register einfach wie auf eine Variable zugreifen. In Quellcodes, die für ältere Versionen des avr-gcc/der avr-libc entwickelt wurden, erfolgt der Lesezugriff über die Funktion inp(). Aktuelle Versionen des Compilers unterstützen den Zugriff nun direkt und inp() ist nicht mehr erforderlich.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
uint8_t foo;&lt;br /&gt;
&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
int main(void)&lt;br /&gt;
{&lt;br /&gt;
    /* kopiert den Status der Eingabepins an PortB &lt;br /&gt;
       in die Variable foo: */&lt;br /&gt;
    foo = PINB;    &lt;br /&gt;
    //...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Zustände von Bits erfolgt durch Einlesen des gesamten Registerinhalts und ausblenden der Bits deren Zustand nicht von Interesse ist. Einige Beispiele zum Prüfen ob Bits gesetzt oder gelöscht sind:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#define MEINBIT0 0 &lt;br /&gt;
#define MEINBIT2 2&lt;br /&gt;
&lt;br /&gt;
uint8_t i;&lt;br /&gt;
&lt;br /&gt;
extern test1();&lt;br /&gt;
&lt;br /&gt;
// Funkion test1 aufrufen, wenn Bit 0 in Register PINA gesetzt (1) ist&lt;br /&gt;
i = PINA;         // Inhalt in Arbeitsvariable&lt;br /&gt;
i = i &amp;amp; 0x01;     // alle Bits bis auf Bit 0 ausblenden (logisches und)&lt;br /&gt;
                  // falls das Bit gesetzt war, hat i den Inhalt 1&lt;br /&gt;
if ( i != 0 ) {   // Ergebnis ungleich 0 (wahr)? &lt;br /&gt;
  test1()         // dann muss Bit 0 in i gesetzt sein -&amp;gt; Funktion aufrufen&lt;br /&gt;
}&lt;br /&gt;
// verkürzt:&lt;br /&gt;
if ( ( PINA &amp;amp; 0x01 ) != 0 ) {&lt;br /&gt;
  test1();&lt;br /&gt;
}&lt;br /&gt;
// nochmals verkürzt:&lt;br /&gt;
if ( PINA &amp;amp; 0x01 ) {&lt;br /&gt;
  test1();&lt;br /&gt;
}&lt;br /&gt;
// mit definierter Bitnummer:&lt;br /&gt;
if ( PINA &amp;amp; ( 1 &amp;lt;&amp;lt; MEINBIT0 ) ) {&lt;br /&gt;
  test(1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Funktion aufrufen, wenn Bit 0 oder Bit 2 gesetzt ist&lt;br /&gt;
if ( PINA &amp;amp; 0x05 ) {&lt;br /&gt;
  test1();  // Vergleich &amp;lt;&amp;gt; 0 (wahr), also muss Bit 0 oder 2 gesetzt sein&lt;br /&gt;
}&lt;br /&gt;
// mit definierten Bitnummern:&lt;br /&gt;
if ( PINA &amp;amp; ( ( 1 &amp;lt;&amp;lt; MEINBIT0 ) | ( 1 &amp;lt;&amp;lt; MEINBIT2 ) ) ) {&lt;br /&gt;
  test1();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Funktion aufrufen, wenn Bit 0 und Bit 2 gesetzt sind&lt;br /&gt;
if ( ( PINA &amp;amp; 0x05 ) == 0x05 ) {  // nur wahr, wenn beide Bits gesetzt&lt;br /&gt;
  test1();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Funktion test2() aufrufen, wenn Bit 0 gelöscht (0) ist&lt;br /&gt;
i = PINA;        // einlesen in temporäre Variable&lt;br /&gt;
i = i &amp;amp; 0x01;    // maskieren von B&lt;br /&gt;
if ( i == 0 ) {  // Vergleich ist wahr, wenn Bit 0 nicht gesetzt ist&lt;br /&gt;
  test2();&lt;br /&gt;
}&lt;br /&gt;
// analog mit !-Operator (not)&lt;br /&gt;
if ( !i ) {&lt;br /&gt;
  test2();&lt;br /&gt;
}&lt;br /&gt;
// nochmals verkürzt:&lt;br /&gt;
if ( !( PINA &amp;amp; 0x01 ) ) {&lt;br /&gt;
  test2();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die AVR-Bibliothek (avr-libc) stellt auch Funktionen (Makros) zur Abfrage eines einzelnen Bits eines Registers zur Verfügung, diese sind bei anderen Compilern meist nicht verfügbar (können aber dann einfach durch Macros &amp;quot;nachgerüstet&amp;quot; werden).&lt;br /&gt;
&lt;br /&gt;
;bit_is_set (&amp;lt;Register&amp;gt;,&amp;lt;Bitnummer&amp;gt;): Die Funktion &#039;&#039;bit_is_set&#039;&#039; prüft, ob ein Bit gesetzt ist. Wenn das Bit gesetzt ist, wird ein Wert ungleich 0 zurückgegeben. Genau genommen ist es die Wertigkeit des abgefragten Bits, also 1 für Bit0, 2 für Bit1, 4 für Bit2 etc.&lt;br /&gt;
&lt;br /&gt;
;bit_is_clear (&amp;lt;Register&amp;gt;,&amp;lt;Bitnummer&amp;gt;): Die Funktion &#039;&#039;bit_is_clear&#039;&#039; prüft, ob ein Bit gelöscht ist. Wenn das Bit gelöscht ist, also auf 0 ist, wird ein Wert ungleich 0 zurückgegeben.&lt;br /&gt;
&lt;br /&gt;
Die Funktionen (eigentlich Makros) bit_is_clear bzw. bit_is_set sind nicht erforderlich, man kann und sollte C-Syntax verwenden, die universell verwendbar und portabel ist. Siehe auch [[Bitmanipulation]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Warten auf einen bestimmten Zustand ===&lt;br /&gt;
&lt;br /&gt;
Es gibt in der Bibliothek avr-libc Funktionen, die warten, bis ein bestimmter Zustand eines Bits erreicht ist. Es ist allerdings normalerweise eine eher unschöne Programmiertechnik, da in diesen Funktionen &amp;quot;blockierend&amp;quot; gewartet wird. Der Programmablauf bleibt also an dieser Stelle stehen, bis das maskierte Ereignis erfolgt ist. Setzt man den Watchdog ein, muss man darauf achten, dass dieser auch noch getriggert wird (Zurücksetzen des Watchdogtimers). &lt;br /&gt;
&lt;br /&gt;
Die Funktion &#039;&#039;&#039;loop_until_bit_is_set&#039;&#039;&#039; wartet in einer Schleife, bis das definierte Bit gesetzt ist. Wenn das Bit beim Aufruf der Funktion bereits gesetzt ist, wird die Funktion sofort wieder verlassen. Das niederwertigste Bit hat die Bitnummer 0. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
/* Warten bis Bit Nr. 2 (das dritte Bit) in Register PINA gesetzt (1) ist */&lt;br /&gt;
&lt;br /&gt;
#define WARTEPIN PINA&lt;br /&gt;
#define WARTEBIT PA2&lt;br /&gt;
&lt;br /&gt;
// mit der avr-libc Funktion:&lt;br /&gt;
loop_until_bit_is_set(WARTEPIN, WARTEBIT);&lt;br /&gt;
&lt;br /&gt;
// dito in &amp;quot;C-Standard&amp;quot;:&lt;br /&gt;
// Durchlaufe die (leere) Schleife solange das WARTEBIT in Register WARTEPIN&lt;br /&gt;
// _nicht_ ungleich 0 (also 0) ist.&lt;br /&gt;
while ( !(WARTEPIN &amp;amp; (1 &amp;lt;&amp;lt; WARTEBIT)) ) ;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die Funktion &#039;&#039;&#039;loop_until_bit_is_clear&#039;&#039;&#039; wartet in einer Schleife, bis das definierte Bit gelöscht ist. Wenn das Bit beim Aufruf der Funktion bereits gelöscht ist, wird die Funktion sofort wieder verlassen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
/* Warten bis Bit Nr. 4 (das fuenfte Bit) in Register PINB geloescht (0) ist */&lt;br /&gt;
#define WARTEPIN PINB&lt;br /&gt;
#define WARTEBIT PB4&lt;br /&gt;
&lt;br /&gt;
// avr-libc-Funktion:&lt;br /&gt;
loop_until_bit_is_clear(WARTEPIN, WARTEBIT);&lt;br /&gt;
&lt;br /&gt;
// dito in &amp;quot;C-Standard&amp;quot;:&lt;br /&gt;
// Durchlaufe die (leere) Schleife solange das WARTEBIT in Register WARTEPIN&lt;br /&gt;
// gesetzt (1) ist &lt;br /&gt;
while ( WARTEPIN &amp;amp; (1&amp;lt;&amp;lt;WARTEBIT) ) ;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Universeller und auch auf andere Plattformen besser übertragbar ist die Verwendung von C-Standardoperationen.&lt;br /&gt;
&lt;br /&gt;
Siehe auch: &lt;br /&gt;
* [http://www.nongnu.org/avr-libc/user-manual/index.html Dokumentation der avr-libc] Abschnitt Modules/Special Function Registers&lt;br /&gt;
* [[Bitmanipulation]]&lt;br /&gt;
&lt;br /&gt;
= Zugriff auf IO-Ports =&lt;br /&gt;
&lt;br /&gt;
Alle Ports der AVR-Controller werden über Register gesteuert. Dazu sind&lt;br /&gt;
jedem Port 3 Register zugeordnet:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;DDRx&#039;&#039;&#039; &lt;br /&gt;
| Datenrichtungsregister für Port&#039;&#039;&#039;x&#039;&#039;&#039;. &lt;br /&gt;
&#039;&#039;&#039;x&#039;&#039;&#039; entspricht &#039;&#039;&#039;A&#039;&#039;&#039;, &#039;&#039;&#039;B&#039;&#039;&#039;, &#039;&#039;&#039; C&#039;&#039;&#039;, &#039;&#039;&#039;D&#039;&#039;&#039; usw. (abhängig von der Anzahl der Ports des verwendeten AVR). Bit im Register gesetzt (1) für Ausgang, Bit gelöscht (0) für Eingang.&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;PINx&#039;&#039;&#039;&lt;br /&gt;
| Eingangsadresse für Port&#039;&#039;&#039;x&#039;&#039;&#039;. &lt;br /&gt;
Zustand des Ports. Die Bits in PINx entsprechen dem Zustand der als Eingang definierten Portpins. Bit 1 wenn Pin &amp;quot;high&amp;quot;, Bit 0 wenn Portpin low.&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;PORTx&#039;&#039;&#039;&lt;br /&gt;
| Datenregister für Port&#039;&#039;&#039;x&#039;&#039;&#039;. &lt;br /&gt;
Dieses Register wird verwendet, um die Ausgänge eines Ports anzusteuern. Bei Pins, die mittels DDRx auf Eingang geschaltet wurden, können über PORTx&lt;br /&gt;
die internen Pull-Up Widerstände aktiviert oder deaktiviert werden (1 = aktiv).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Jeder AVR implementiert eine unterschiedliche Menge an GPIO-Registern&lt;br /&gt;
(GPIO - General Purpose Input/Output). Die folgenden Beispiele gehen von einem AVR aus, der sowohl Port A als auch Port B besitzt. Sie müssen für andere AVRs (zum Beispiel ATmega8/48/88/168) entsprechend angepasst werden.&lt;br /&gt;
&lt;br /&gt;
== Datenrichtung bestimmen ==&lt;br /&gt;
&lt;br /&gt;
Zuerst muss die Datenrichtung der verwendeten Pins bestimmt werden. Um dies zu erreichen, wird das Datenrichtungsregister des entsprechenden Ports beschrieben.&lt;br /&gt;
&lt;br /&gt;
Für jeden Pin, der als Ausgang verwendet werden soll, muss dabei das&lt;br /&gt;
entsprechende Bit auf dem Port gesetzt werden. Soll der Pin als Eingang&lt;br /&gt;
verwendet werden, muss das entsprechende Bit gelöscht sein.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
Angenommen am Port B sollen die Pins 0 bis 4 als Ausgänge definiert werden, die noch verbleibenden Pins 5 bis 7 sollen als Eingänge fungieren. Dazu ist es daher notwendig, im für das Port B zuständigen Datenrichtungsregister DDRB folgende Bitkonfiguration einzutragen&lt;br /&gt;
&lt;br /&gt;
   +---+---+---+---+---+---+---+---+&lt;br /&gt;
   | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 1 |&lt;br /&gt;
   +---+---+---+---+---+---+---+---+&lt;br /&gt;
     7   6   5   4   3   2   1   0&lt;br /&gt;
&lt;br /&gt;
In C liest sich das dann so:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
// in io.h wird u.a. DDRB definiert:&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
// Setzen der Bits 0,1,2,3 und 4&lt;br /&gt;
// Binär 00011111 = Hexadezimal 1F&lt;br /&gt;
DDRB = 0x1F;    /* direkte Zuweisung - unübersichtlich */&lt;br /&gt;
&lt;br /&gt;
/* Ausführliche Schreibweise: identische Funktionalität, mehr Tipparbeit&lt;br /&gt;
   aber übersichtlicher und selbsterklärend: */&lt;br /&gt;
DDRB = (1 &amp;lt;&amp;lt; DDB0) | (1 &amp;lt;&amp;lt; DDB1) | (1 &amp;lt;&amp;lt; DDB2) | (1 &amp;lt;&amp;lt; DDB3) | (1 &amp;lt;&amp;lt; DDB4); &lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Pins 5 bis 7 werden (da 0) als Eingänge geschaltet. Weitere Beispiele:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
// Alle Pins des Ports B als Ausgang definieren:&lt;br /&gt;
DDRB = 0xff; &lt;br /&gt;
// Pin0 wieder auf Eingang und andere im ursprünglichen Zustand belassen:&lt;br /&gt;
DDRB &amp;amp;= ~( 1 &amp;lt;&amp;lt; DDB0 );&lt;br /&gt;
// Pin 3 und 4 auf Eingang und andere im ursprünglichen Zustand belassen:&lt;br /&gt;
DDRB &amp;amp;= ~( ( 1 &amp;lt;&amp;lt; DDB3 ) | ( 1&amp;lt;&amp;lt;DDB4) );&lt;br /&gt;
// Pin 0 und 3 wieder auf Ausgang und andere im ursprünglichen Zustand belassen:&lt;br /&gt;
DDRB |= ( 1 &amp;lt;&amp;lt; DDB0) | ( 1 &amp;lt;&amp;lt; DDB3 );&lt;br /&gt;
// Alle Pins auf Eingang:&lt;br /&gt;
DDRB = 0x00;&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Vordefinierte Bitnummern für I/O-Register ==&lt;br /&gt;
&lt;br /&gt;
Die Bitnummern (z.B. PCx, PINCx und DDCx für den Port C) sind in den io*.h-Dateien der avr-libc definiert und dienen lediglich der besseren Lesbarkeit. Man muss diese Definitionen nicht verwenden oder kann auch einfach &amp;quot;immer&amp;quot; PAx, PBx, PCx usw. nutzen, auch wenn der Zugriff auf Bits in DDRx- oder PINx-Registern erfolgt. Für den Compiler sind die Ausdrücke (1&amp;lt;&amp;lt;PC7), (1&amp;lt;&amp;lt;DDC7) und (1&amp;lt;&amp;lt;PINC7) identisch zu (1&amp;lt;&amp;lt;7) (genauer: der Präprozessor ersetzt die Ausdrücke (1&amp;lt;&amp;lt;PC7),... zu (1&amp;lt;&amp;lt;7)). Ein Ausschnitt der Definitionen für Port C eines ATmega32 aus der iom32.h-Datei zur Verdeutlichung (analog für die weiteren Ports):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
/* PORTC */&lt;br /&gt;
#define PC7     7&lt;br /&gt;
#define PC6     6&lt;br /&gt;
#define PC5     5&lt;br /&gt;
#define PC4     4&lt;br /&gt;
#define PC3     3&lt;br /&gt;
#define PC2     2&lt;br /&gt;
#define PC1     1&lt;br /&gt;
#define PC0     0&lt;br /&gt;
&lt;br /&gt;
/* DDRC */&lt;br /&gt;
#define DDC7    7&lt;br /&gt;
#define DDC6    6&lt;br /&gt;
#define DDC5    5&lt;br /&gt;
#define DDC4    4&lt;br /&gt;
#define DDC3    3&lt;br /&gt;
#define DDC2    2&lt;br /&gt;
#define DDC1    1&lt;br /&gt;
#define DDC0    0&lt;br /&gt;
&lt;br /&gt;
/* PINC */&lt;br /&gt;
#define PINC7   7&lt;br /&gt;
#define PINC6   6&lt;br /&gt;
#define PINC5   5&lt;br /&gt;
#define PINC4   4&lt;br /&gt;
#define PINC3   3&lt;br /&gt;
#define PINC2   2&lt;br /&gt;
#define PINC1   1&lt;br /&gt;
#define PINC0   0&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Digitale Signale ==&lt;br /&gt;
&lt;br /&gt;
Am einfachsten ist es, digitale Signale mit dem Mikrocontroller zu erfassen bzw. auszugeben.&lt;br /&gt;
&lt;br /&gt;
== Ausgänge ==&lt;br /&gt;
Will man als Ausgang definierte Pins (entsprechende DDRx-Bits = 1) auf Logisch 1 setzen, setzt man die  entsprechenden Bits im Portregister.&lt;br /&gt;
&lt;br /&gt;
Mit dem Befehl&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
    PORTB = 0x04; /* besser PORTB=(1&amp;lt;&amp;lt;PB2) */&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
wird also der Ausgang an Pin PB2 gesetzt (Beachte, dass die Bits immer &#039;&#039;von 0 an&#039;&#039; gezählt werden, das niederwertigste Bit ist also Bitnummer 0 und nicht etwa Bitnummer 1).&lt;br /&gt;
&lt;br /&gt;
Man beachte, dass bei der Zuweisung mittels &#039;&#039;&#039;=&#039;&#039;&#039; immer alle Pins gleichzeitig angegeben werden. Man sollte also, wenn nur bestimmte Ausgänge geschaltet werden sollen, zuerst den aktuellen Wert des Ports einlesen und das Bit des gewünschten Ports in diesen Wert einfließen lassen. Will man also nur den dritten Pin (Bit Nr. 2) an Port B auf &amp;quot;high&amp;quot; setzen und den Status der anderen Ausgänge unverändert lassen, nutze man diese Form:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
    PORTB = PORTB | 0x04; /* besser: PORTB = PORTB | ( 1&amp;lt;&amp;lt;PB2 ) */&lt;br /&gt;
    /* vereinfacht durch Nutzung des |= Operators : */&lt;br /&gt;
    PORTB |= (1&amp;lt;&amp;lt;PB2);&lt;br /&gt;
&lt;br /&gt;
    /* auch mehrere &amp;quot;gleichzeitig&amp;quot;: */&lt;br /&gt;
    PORTB |= (1&amp;lt;&amp;lt;PB4) | (1&amp;lt;&amp;lt;PB5); /* Pins PB4 und PB5 &amp;quot;high&amp;quot; */&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Ausschalten&amp;quot;, also  Ausgänge auf &amp;quot;low&amp;quot; setzen, erfolgt analog:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
    PORTB &amp;amp;= ~(1&amp;lt;&amp;lt;PB2); /* löscht Bit 2 in PORTB und setzt damit Pin PB2 auf low */ &lt;br /&gt;
    PORTB &amp;amp;= ~( (1&amp;lt;&amp;lt;PB4) | (1&amp;lt;&amp;lt;PB5) ); /* Pin PB4 und Pin PB5 &amp;quot;low&amp;quot; */&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In Quellcodes, die für ältere Version den des avr-gcc/der avr-libc entwickelt wurden, werden einzelne Bits mittels der Funktionen sbi und cbi gesetzt bzw. gelöscht. Beide Funktionen sind in aktuellen Versionen der avr-libc nicht mehr enthalten und auch nicht mehr erforderlich.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Falls der Anfangszustand von Ausgängen kritisch ist, muss die Reihenfolge beachtet werden, mit der die Datenrichtung (DDRx) eingestellt und der Ausgabewert (PORTx) gesetzt wird:&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Für Ausgangspins, die mit Anfangswert &amp;quot;high&amp;quot; initialisiert werden sollen:&lt;br /&gt;
* zuerst die Bits im PORTx-Register setzen&lt;br /&gt;
* anschließend die Datenrichtung auf Ausgang stellen&lt;br /&gt;
&lt;br /&gt;
Daraus ergibt sich die Abfolge für einen Pin, der bisher als Eingang mit abgeschaltetem Pull-Up konfiguriert ware:&lt;br /&gt;
* setze PORTx: interner Pull-Up aktiv&lt;br /&gt;
* setze DDRx: Ausgang (&amp;quot;high&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
Bei der Reihenfolge erst DDRx und dann PORTx, kann es zu einem kurzen &amp;quot;low-Puls&amp;quot; kommen, der auch externe Pull-Up-Widerstände &amp;quot;überstimmt&amp;quot;. Die (ungünstige) Abfolge: Eingang -&amp;gt; setze DDRx: Ausgang (auf &amp;quot;low&amp;quot;, da PORTx nach Reset 0) -&amp;gt; setze PORTx: Ausgang auf high. Vergleiche dazu auch das Datenblatt Abschnitt &#039;&#039;Configuring the Pin&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== Eingänge (Wie kommen Signale in den &amp;amp;micro;C) ==&lt;br /&gt;
&lt;br /&gt;
Die digitalen Eingangssignale können auf verschiedene Arten zu unserer Logik gelangen.&lt;br /&gt;
&lt;br /&gt;
=== Signalkopplung ===&lt;br /&gt;
&lt;br /&gt;
Am einfachsten ist es, wenn die Signale direkt aus einer anderen digitalen Schaltung übernommen werden können. Hat der Ausgang der entsprechenden Schaltung TTL-Pegel dann können wir sogar direkt den Ausgang der Schaltung mit einem Eingangspin von unserem Controller verbinden.&lt;br /&gt;
&lt;br /&gt;
Hat der Ausgang der anderen Schaltung keinen TTL-Pegel so müssen wir den Pegel über entsprechende Hardware (z.B. Optokoppler, [[Widerstand#Spannungsteiler|Spannungsteiler]], &amp;quot;Levelshifter&amp;quot; aka [[Pegelwandler]]) anpassen.&lt;br /&gt;
&lt;br /&gt;
Die Masse der beiden Schaltungen muss selbstverständlich miteinander verbunden werden. Der Software selber ist es natürlich letztendlich egal, wie das Signal eingespeist wird. Wir können ja ohnehin lediglich prüfen, ob an einem Pin unseres Controllers eine logische 1 (Spannung größer ca. 0,7*Vcc) oder eine logische 0 (Spannung kleiner ca. 0,2*Vcc) anliegt. Detaillierte Informationen darüber, ab welcher Spannung ein Eingang als 0 (&amp;quot;low&amp;quot;) bzw. 1 (&amp;quot;high&amp;quot;) erkannt wird, liefert die Tabelle DC Characteristics im Datenblatt des genutzten Controllers.&lt;br /&gt;
&lt;br /&gt;
Die Abfrage der Zustände der Portpins erfolgt direkt über den Registernamen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;font color=&amp;quot;#FF0000&amp;quot;&amp;gt;Dabei ist wichtig, zur Abfrage der Eingänge &#039;&#039;&#039;nicht&#039;&#039;&#039; etwa Portregister &#039;&#039;&#039;PORTx&#039;&#039;&#039; zu verwenden, &#039;&#039;&#039;sondern&#039;&#039;&#039; Eingangsregister &#039;&#039;&#039;PINx&#039;&#039;&#039;. Die Abfrage der Pinzustände über PORTx statt PINx ist ein häufiger Fehler beim AVR-&amp;quot;Erstkontakt&amp;quot;.&amp;lt;/font&amp;gt; (Ansonsten liest man nicht den Zustand der Eingänge, sondern den Status der internen Pull-Up-Widerstände.)&lt;br /&gt;
&lt;br /&gt;
Will man also die aktuellen Signalzustände von Port D abfragen und in eine Variable namens bPortD abspeichern, schreibt man folgende Befehlszeilen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
uint8_t bPortD;&lt;br /&gt;
...&lt;br /&gt;
bPortD = PIND;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit den C-Bitoperationen kann man den Status der Bits abfragen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
/* Fuehre Aktion aus, wenn Bit Nr. 1 (das &amp;quot;zweite&amp;quot; Bit) in PINC gesetzt (1) ist */&lt;br /&gt;
if ( PINC &amp;amp; (1&amp;lt;&amp;lt;PINC1) ) {&lt;br /&gt;
  /* Aktion */&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* Fuehre Aktion aus, wenn Bit Nr. 2 (das &amp;quot;dritte&amp;quot; Bit) in PINB geloescht (0) ist */&lt;br /&gt;
if ( !(PINB &amp;amp; (1&amp;lt;&amp;lt;PINB2)) ) {&lt;br /&gt;
  /* Aktion */&lt;br /&gt;
}&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Tasten und Schalter ===&lt;br /&gt;
&lt;br /&gt;
Der Anschluss mechanischer Kontakte an den Mikrocontroller gestaltet sich ebenfalls ganz einfach, wobei wir zwei unterschiedliche Methoden unterscheiden müssen (&#039;&#039;Active Low&#039;&#039; und &#039;&#039;Active High&#039;&#039;):&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Active Low&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Active High&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| [[Image:Active Low.gif]]&lt;br /&gt;
| [[Image:Active High.gif]]&lt;br /&gt;
|- &lt;br /&gt;
| Bei dieser Methode wird der Kontakt zwischen den Eingangspin des Controllers und Masse geschaltet.&lt;br /&gt;
&lt;br /&gt;
Damit bei offenem Schalter der Controller kein undefiniertes Signal bekommt wird zwischen die Versorgungsspannung und den Eingangspin ein sogenannter Pull-Up Widerstand geschaltet. Dieser dient dazu, den Pegel bei geöffnetem Schalter auf logisch 1 zu ziehen.&lt;br /&gt;
&lt;br /&gt;
Der Widerstandswert des Pull-Up Widerstands ist an sich nicht kritisch.  Wird er allerdings zu hoch gewählt, ist die Wirkung eventuell nicht gegeben. Als üblicher Wert haben sich 10 kOhm eingebürgert.&lt;br /&gt;
&lt;br /&gt;
Die AVRs haben sogar an den meisten Pins softwaremäßig zuschaltbare interne Pull-Up Widerstände, welche wir natürlich auch verwenden können.&lt;br /&gt;
&lt;br /&gt;
| Hier wird der Kontakt zwischen die Versorgungsspannung und den Eingangspin geschaltet.&lt;br /&gt;
&lt;br /&gt;
Damit bei offener Schalterstellung kein undefiniertes Signal am Controller ansteht, wird zwischen den Eingangspin und die Masse ein Pull-Down Widerstand geschaltet. Dieser dient dazu, den Pegel bei geöffneter Schalterstellung auf logisch 0 zu halten.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Pull-Up Widerstände aktivieren ====&lt;br /&gt;
&lt;br /&gt;
Die internen Pull-Up Widerstände von Vcc zu den einzelnen Portpins werden über das Register &#039;&#039;&#039; PORTx&#039;&#039;&#039; aktiviert bzw. deaktiviert, wenn ein Pin als &#039;&#039;&#039; Eingang&#039;&#039;&#039; geschaltet ist.&lt;br /&gt;
&lt;br /&gt;
Wird der Wert des entsprechenden Portpins auf 1 gesetzt, so ist der Pull-Up Widerstand aktiviert. Bei einem Wert von 0 ist der Pull-Up Widerstand nicht aktiv. Man sollte jeweils entweder den internen oder einen externen Pull-Up Widerstand verwenden, aber nicht beide zusammen.&lt;br /&gt;
&lt;br /&gt;
Im Beispiel werden alle Pins des Ports D als Eingänge geschaltet und alle Pull-Up Widerstände aktiviert. Weiterhin wird Pin PC7 als Eingang geschaltet und dessen interner Pull-Up Widerstand aktiviert, ohne die Einstellungen für die anderen Portpins (PC0-PC6) zu verändern.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
DDRD  = 0x00; /* alle Pins von Port D als Eingang */&lt;br /&gt;
PORTD = 0xff; /* interne Pull-Ups an allen Port-Pins aktivieren */&lt;br /&gt;
...&lt;br /&gt;
DDRC  &amp;amp;= ~(1&amp;lt;&amp;lt;DDC7);  /* Pin PC7 als Eingang */&lt;br /&gt;
PORTC |= (1&amp;lt;&amp;lt;PC7);    /* internen Pull-Up an PC7 aktivieren */&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== (Tasten-)Entprellung ====&lt;br /&gt;
&lt;br /&gt;
Nun haben alle mechanischen Kontakte, sei es von Schaltern, Tastern oder auch von Relais, die unangenehme Eigenschaft zu prellen. Dies bedeutet, dass beim Schließen des Kontaktes derselbe nicht direkt Kontakt herstellt, sondern mehrfach ein- und ausschaltet bis zum endgültigen Herstellen des Kontaktes.&lt;br /&gt;
&lt;br /&gt;
Soll nun mit einem schnellen Mikrocontroller gezählt werden, wie oft ein solcher Kontakt geschaltet wird, dann haben wir ein Problem, weil das Prellen als mehrfache Impulse gezählt wird. Diesem Phänomen muss beim Schreiben des Programms unbedingt Rechnung getragen werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;lt;inttypes.h&amp;gt;&lt;br /&gt;
#ifndef F_CPU&lt;br /&gt;
#warning &amp;quot;F_CPU war noch nicht definiert, wird nun mit 3686400 definiert&amp;quot;&lt;br /&gt;
#define F_CPU 3686400UL     /* Quarz mit 3.6864 Mhz  */&lt;br /&gt;
#endif&lt;br /&gt;
#include &amp;lt;util/delay.h&amp;gt;     /* bei alter avr-libc: #include &amp;lt;avr/delay.h&amp;gt; */      &lt;br /&gt;
&lt;br /&gt;
/* Einfache Funktion zum Entprellen eines Tasters */&lt;br /&gt;
inline uint8_t debounce(volatile uint8_t *port, uint8_t pin)&lt;br /&gt;
{&lt;br /&gt;
    if ( ! (*port &amp;amp; (1 &amp;lt;&amp;lt; pin)) )&lt;br /&gt;
    {&lt;br /&gt;
        /* Pin wurde auf Masse gezogen, 100ms warten   */&lt;br /&gt;
        _delay_ms(50);  // max. 262.1 ms / F_CPU in MHz&lt;br /&gt;
        _delay_ms(50); &lt;br /&gt;
        if ( *port &amp;amp; (1 &amp;lt;&amp;lt; pin) )&lt;br /&gt;
        {&lt;br /&gt;
            /* Anwender Zeit zum Loslassen des Tasters geben */&lt;br /&gt;
            _delay_ms(50);&lt;br /&gt;
            _delay_ms(50); &lt;br /&gt;
            return 1;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int main(void)&lt;br /&gt;
{&lt;br /&gt;
    DDRB &amp;amp;= ~( 1 &amp;lt;&amp;lt; PB0 );                 /* PIN PB0 auf Eingang (Taster)            */&lt;br /&gt;
    PORTB |= ( 1 &amp;lt;&amp;lt; PB0 );                 /* Pullup-Widerstand aktivieren            */&lt;br /&gt;
    ...&lt;br /&gt;
    if (debounce(&amp;amp;PINB, PB0))             /* Falls Taster an PIN PB0 gedrueckt..    */&lt;br /&gt;
        PORTD = PIND ^ ( 1 &amp;lt;&amp;lt; PD7 );  /* ..LED an Port PD7 an-&lt;br /&gt;
                                   bzw. ausschalten */&lt;br /&gt;
    ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bei diesem Beispiel ist zu beachten, dass der AVR im Falle eines Tastendrucks 200ms wartet, also brach liegt. Bei zeitkritische Anwendungen sollte man ein anderes Verfahren nutzen (z.B. Abfrage der Tastenzustände in einer Timer-Interrupt-Service-Routine).&lt;br /&gt;
&lt;br /&gt;
Zum Thema Entprellen siehe auch:&lt;br /&gt;
* Artikel [[Entprellung]]&lt;br /&gt;
&lt;br /&gt;
== Analog ==&lt;br /&gt;
&lt;br /&gt;
Die Verarbeitung von analogen Eingangswerten und die Ausgabe von Analogwerten wird in Kapitel [[AVR-GCC-Tutorial#Analoge_Ein-_und_Ausgabe|Analoge Ein- und Ausgabe]] behandelt.&lt;br /&gt;
&lt;br /&gt;
== 16-Bit Portregister (ADC, ICR1, OCR1, TCNT1, UBRR) ==&lt;br /&gt;
&lt;br /&gt;
Einige der Portregister in den AVR-Controllern sind 16 Bit breit. Im Datenblatt sind diese Register üblicherweise mit dem Suffix &amp;quot;L&amp;quot; (LSB) und &amp;quot;H&amp;quot; (MSB) versehen. Die avr-libc definiert zusätzlich die meisten dieser Variablen die Bezeichnung ohne &amp;quot;L&amp;quot; oder &amp;quot;H&amp;quot;. Auf diese kann direkt zugewiesen bzw. zugegriffen werden. Die Konvertierung von 16-bit Wort nach 2*8-bit Byte erfolgt intern.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
uint16_t foo;&lt;br /&gt;
&lt;br /&gt;
foo=ADC; /* setzt die Wort-Variable foo auf den Wert der letzten AD-Wandlung */&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Falls ben&amp;amp;ouml;tigt, kann eine 16-Bit Variable auch recht einfach manuell in ihre zwei 8-Bit Bestandteile zerlegt werden. Folgendes Beispiel demonstriert dies anhand des pseudo- 16-Bit Registers UBRR.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
/* Diese Variante ist normal am effizientesten */&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
#ifndef F_CPU&lt;br /&gt;
#define F_CPU 3686400&lt;br /&gt;
#endif&lt;br /&gt;
#define UART_BAUD_RATE 9600&lt;br /&gt;
&lt;br /&gt;
typedef union {&lt;br /&gt;
        uint16_t i16;&lt;br /&gt;
        struct {&lt;br /&gt;
                uint8_t i8l;&lt;br /&gt;
                uint8_t i8h;&lt;br /&gt;
        };&lt;br /&gt;
} convert16to8;&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
convert16to8 baud;&lt;br /&gt;
baud.i16 = F_CPU / (UART_BAUD_RATE * 16L) -1;&lt;br /&gt;
UBRRH = baud.i8h;&lt;br /&gt;
UBRRL = baud.i8l;&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
/* Alternative 1:*/&lt;br /&gt;
#include &amp;lt;inttypes.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
uint16_t wFoo16;&lt;br /&gt;
uint8_t bFooLow, bFooHigh;&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
wFoo16   = 0xAA55;                 /* zu &amp;quot;zerlegende&amp;quot; 16Bit-Integer */&lt;br /&gt;
bFooHigh = (uint8_t)(wFoo16 &amp;gt;&amp;gt; 8); /* MS-Byte */&lt;br /&gt;
bFooLow  = (uint8_t)(wFoo16);      /* LS-Byte */&lt;br /&gt;
&lt;br /&gt;
/* Alternative 2:*/&lt;br /&gt;
&lt;br /&gt;
#define us0(Data) (*((unsigned char *)(&amp;amp;Data)))&lt;br /&gt;
#define us1(Data) (*((unsigned char *)((&amp;amp;Data)+1)))&lt;br /&gt;
bFooHigh = us1(wFoo16);&lt;br /&gt;
bFoolow  = us0(wFoo16);&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bei einigen AVR-Typen (z.B. ATmega8) teilen sich UBRRH und UCSRC die gleiche Memory-Adresse. Damit der AVR trotzdem zwischen den beiden Registern unterscheiden kann, bestimmt das Bit7 (URSEL) welches Register tats&amp;amp;auml;chlich beschrieben werden soll. &#039;&#039;1000 0011&#039;&#039; (0x83) adressiert demnach UCSRC und &amp;amp;uuml;bergibt den Wert &#039;&#039;3&#039;&#039; und &#039;&#039;0000 0011&#039;&#039; (0x3) adressiert UBRRH und &amp;amp;uuml;bergibt ebenfalls den Wert &#039;&#039;3&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
Bei einigen 16-bit Registern (insbesondere die der 16-bit Timer) erfolgen Schreibzugriffe über das sogenannte &#039;&#039;temporary Register&#039;&#039;. Die Reihenfolge der Zugriffe bestimmt, wann der Wert tatsächlich ins Register geschrieben wird. Typisch wird erst das High-Byte beschrieben (xxxH) und intern im temporary Register zwischengespeichert. Nachdem das Low-Byte (xxxL) geschrieben wurde, setzt der Controller mit diesem und dem im temporary Register zwischengespeicherten Wert für das High-Byte das 16-bit Register. Dabei ist zu beachten, dass intern nur ein temporary Register verfügbar ist, welches in Interruptroutinen mglw. mit einem anderen Wert überschrieben wird, wenn dort ebenfalls 16-bit Register beschrieben werden. avr-gcc/avr-libc berücksichtigen die korrekte Reihenfolge automatisch, wenn die Register mit ihrem &amp;quot;16-bit Label&amp;quot; (ohne H bzw. L) angesprochen werden, dabei ist der Schutz des temporary Registers vor Überschreiben durch Interruptroutinen dennoch zu beachten (im Zweifel beim Schreibzugriff die Interrupts kurzzeitig global deaktivieren).&lt;br /&gt;
&lt;br /&gt;
Im Umgang mit 16-Bit Registern siehe auch:&lt;br /&gt;
* [http://www.nongnu.org/avr-libc/user-manual/index.html Dokumentation der avr-libc] Abschnitt Related Pages/Frequently Asked Questions/Nr. 8&lt;br /&gt;
* Datenblatt Abschnitt &#039;&#039;Accessing 16-bit Registers&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== IO-Register als Parameter und Variablen ==&lt;br /&gt;
&lt;br /&gt;
Um Register als Parameter für eigene Funktionen übergeben zu können, muss man sie als einen volatile uint8_t Pointer übergeben. Zum Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
uint8_t key_pressed(const volatile uint8_t *inputreg, uint8_t inputbit)&lt;br /&gt;
{&lt;br /&gt;
  static uint8_t last_state = 0;&lt;br /&gt;
 &lt;br /&gt;
  if ( last_state == ( *inputreg &amp;amp; (1&amp;lt;&amp;lt;inputbit) ) ) {&lt;br /&gt;
     return 0; /* keine Änderung */&lt;br /&gt;
  }&lt;br /&gt;
 &lt;br /&gt;
  /* Wenn doch, warten bis etwaiges Prellen vorbei ist: */&lt;br /&gt;
  _delay_ms(20);&lt;br /&gt;
&lt;br /&gt;
  /* Zustand für nächsten Aufruf merken: */&lt;br /&gt;
  last_state = ( *inputreg &amp;amp; (1&amp;lt;&amp;lt;inputbit) );&lt;br /&gt;
 &lt;br /&gt;
  /* und den entprellten Tastendruck zurückgeben: */&lt;br /&gt;
  return ( *inputreg &amp;amp; (1&amp;lt;&amp;lt;inputbit) );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* Beispiel für einen Funktionsaufruf: */&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
uint8_t i;&lt;br /&gt;
&lt;br /&gt;
//...&lt;br /&gt;
    i = key_pressed( &amp;amp;PINB, PB1 );&lt;br /&gt;
//...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein Aufruf der Funktion mit call by value würde Folgendes bewirken: Beim Funktionseintritt wird nur eine Kopie des momentanen Portzustandes angefertigt, die sich unabhängig vom tatsächlichen Zustand das Ports nicht mehr ändert, womit die Funktion wirkungslos wäre. Die Übergabe eines Zeigers wäre die Lösung, wenn der Compiler nicht optimieren würde. Denn dadurch wird im Programm nicht von der Hardware gelesen, sondern wieder nur von einem Abbild im Speicher. Das Ergebnis wäre das gleiche wie oben. Mit dem Schlüsselwort volatile sagt man nun dem Compiler, dass die entsprechende Variable entweder durch andere Softwareroutinen (Interrupts) oder durch die Hardware verändert werden kann.&lt;br /&gt;
&lt;br /&gt;
Im Übrigen können mit volatile gekennzeichnete Variablen auch als const deklariert werden, um sicherzustellen, dass sie nur noch von der Hardware änderbar sind.&lt;br /&gt;
&lt;br /&gt;
= Der UART =&lt;br /&gt;
&lt;br /&gt;
== Allgemeines zum UART ==&lt;br /&gt;
&lt;br /&gt;
Über den [[UART]] kann ein AVR leicht mit einer [[RS-232]]-Schnittstelle eines PC oder sonstiger Geräte mit &amp;quot;serieller Schnittstelle&amp;quot; verbunden werden. &lt;br /&gt;
&lt;br /&gt;
Mögliche Anwendungen des UART:&lt;br /&gt;
&lt;br /&gt;
* Debug-Schnittstelle: z.B. zur Anzeige von Zwischenergebnissen (&amp;quot;printf-debugging&amp;quot; - hier besser &amp;quot;UART-debugging&amp;quot;) auf einem PC. Auf dem Rechner reicht dazu ein [[RS-232#Terminalprogramme|Terminalprogramm]] (MS-Windows: Hyperterm oder besser [http://braypp.googlepages.com/terminal Bray-Terminal], [http://www.der-hammer.info/terminal/ HTerm]; Unix/Linux z.B. minicom). Ein direkter Anschluss ist aufgrund unterschiedlicher Pegel nicht möglich, jedoch sind entsprechende Schnittstellen-ICs wie z.B. ein MAX232 günstig und leicht zu integrieren. Rechner ohne serielle Schnittstelle können über fertige USB-seriell-Adapter angeschlossen werden. &lt;br /&gt;
* &amp;quot;Mensch-Maschine Schnittstelle&amp;quot;: z.B. Konfiguration und Statusabfrage über eine &amp;quot;Kommandozeile&amp;quot; oder Menüs (siehe z.B. Forumsbeitrag [http://www.mikrocontroller.net/topic/52985 Auswertung RS232-Befehle]) &lt;br /&gt;
* Übertragen von gespeicherten Werten: z.B. bei einem Datenlogger&lt;br /&gt;
* Anschluss von Geräten mit serieller Schnittstelle (z.B. (Funk-)Modems, Mobiltelefone, Drucker, Sensoren, &amp;quot;intelligente&amp;quot; LC-Displays, GPS-Empfänger). &lt;br /&gt;
* &amp;quot;Feldbusse&amp;quot; auf RS485/RS422-Basis mittels entsprechenden Bustreiberbausteinen (z.B. MAX485)&lt;br /&gt;
* DMX, Midi etc.&lt;br /&gt;
* LIN-Bus (&#039;&#039;&#039;L&#039;&#039;&#039;ocal &#039;&#039;&#039;I&#039;&#039;&#039;nterconnect &#039;&#039;&#039;N&#039;&#039;&#039;etwork): Preiswerte Sensoren/Aktoren in der Automobiltechnik und darüber hinaus&lt;br /&gt;
&lt;br /&gt;
Einige AVR-Controller haben ein bis zwei vollduplexfähigen UART (&#039;&#039;&#039;U&#039;&#039;&#039;niversal &#039;&#039;&#039;A&#039;&#039;&#039;synchronous &#039;&#039;&#039;R&#039;&#039;&#039;eceiver and &#039;&#039;&#039;T&#039;&#039;&#039;ransmitter) schon eingebaut (&amp;quot;Hardware-UART&amp;quot;). &lt;br /&gt;
Übrigens: Vollduplex heißt nichts anderes, als dass der Baustein gleichzeitig senden und empfangen kann.&lt;br /&gt;
&lt;br /&gt;
Neuere AVRs (ATmega, ATtiny) verfügen über einen oder zwei U&#039;&#039;&#039;S&#039;&#039;&#039;ART(s), dieser unterscheidet sich vom UART hauptsächlich durch interne FIFO-Puffer für Ein- und Ausgabe und erweiterte Konfigurationsmöglichkeiten. Die Puffergröße ist allerdings nur 1 Byte.&lt;br /&gt;
&lt;br /&gt;
Der UART wird über vier separate Register angesprochen. USARTs der ATMEGAs verfügen über mehrere zusätzliche Konfigurationsregister. Das Datenblatt gibt darüber Auskunft. Die Folgende Tabelle gibt nur die Register für die (veralteten) UARTs wieder.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;UCR&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;U&#039;&#039;&#039;ART &#039;&#039;&#039;C&#039;&#039;&#039;ontrol &#039;&#039;&#039;R&#039;&#039;&#039;egister.&amp;lt;br /&amp;gt;&lt;br /&gt;
In diesem Register stellen wir ein, wie wir den UART verwenden möchten.&amp;lt;br /&amp;gt;&lt;br /&gt;
Das Register ist wie folgt aufgebaut:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Bit&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 7&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 6&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 5&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 4&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 2&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Name&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;RXCIE&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;TXCIE&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;UDRIE&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;RXEN&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;TXEN&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;CHR9&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;RXB8&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;TXB8&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;R/W&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | W&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Initialwert&#039;&#039;&#039;&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;
| 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;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;RXCIE&#039;&#039;&#039; (&#039;&#039;&#039;RX&#039;&#039;&#039; &#039;&#039;&#039;C&#039;&#039;&#039;omplete &#039;&#039;&#039;I&#039;&#039;&#039;nterrupt &#039;&#039;&#039;E&#039;&#039;&#039;nable)&lt;br /&gt;
:Wenn dieses Bit gesetzt ist, wird ein UART RX Complete Interrupt ausgelöst, wenn ein Zeichen vom UART empfangen wurde. Das Global Enable Interrupt Flag muss selbstverständlich auch gesetzt sein.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;TXCIE&#039;&#039;&#039; (&#039;&#039;&#039;TX&#039;&#039;&#039; &#039;&#039;&#039;C&#039;&#039;&#039;omplete &#039;&#039;&#039;I&#039;&#039;&#039;nterrupt &#039;&#039;&#039;E&#039;&#039;&#039;nable)&lt;br /&gt;
:Wenn dieses Bit gesetzt ist, wird ein UART TX Complete Interrupt ausgelöst, wenn ein Zeichen vom UART gesendet wurde. Das Global Enable Interrupt Flag muss selbstverständlich auch gesetzt sein.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;UDRIE&#039;&#039;&#039; (&#039;&#039;&#039;U&#039;&#039;&#039;ART &#039;&#039;&#039;D&#039;&#039;&#039;ata &#039;&#039;&#039;R&#039;&#039;&#039;egister &#039;&#039;&#039;E&#039;&#039;&#039;mpty &#039;&#039;&#039;I&#039;&#039;&#039;nterrupt &#039;&#039;&#039;E&#039;&#039;&#039;nable)&lt;br /&gt;
:Wenn dieses Bit gesetzt ist, wird ein UART Datenregister Leer Interrupt ausgelöst, wenn der UART wieder bereit ist um ein neues zu sendendes Zeichen zu übernehmen. Das Global Enable Interrupt Flag muss selbstverständlich auch gesetzt sein.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;RXEN&#039;&#039;&#039; (&#039;&#039;&#039;R&#039;&#039;&#039;eceiver &#039;&#039;&#039;E&#039;&#039;&#039;nable)&lt;br /&gt;
:Nur wenn dieses Bit gesetzt ist, arbeitet der Empfänger des UART überhaupt. Wenn das Bit nicht gesetzt ist, kann der entsprechende Pin des AVR als normaler I/O-Pin verwendet werden. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;TXEN&#039;&#039;&#039; (&#039;&#039;&#039;T&#039;&#039;&#039;ransmitter &#039;&#039;&#039;E&#039;&#039;&#039;nable)&lt;br /&gt;
:Nur wenn dieses Bit gesetzt ist, arbeitet der Sender des UART überhaupt. Wenn das Bit nicht gesetzt ist, kann der entsprechende Pin des AVR als normaler I/O-Pin verwendet werden.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;CHR9&#039;&#039;&#039; (9 Bit Characters)&lt;br /&gt;
:Wenn dieses Bit gesetzt ist, können 9 Bit lange Zeichen übertragen und empfangen werden. Das 9. Bit kann bei Bedarf als zusätzliches Stopbit oder als Paritätsbit verwendet werden. Man spricht dann von einem 11-Bit Zeichenrahmen:&lt;br /&gt;
:1 Startbit + 8 Datenbits + 1 Stopbit + 1 Paritätsbit = 11 Bits&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;RXB8&#039;&#039;&#039; (Receive Data Bit 8)&lt;br /&gt;
:Wenn das vorher erwähnte CHR9-Bit gesetzt ist, dann enthält dieses Bit das 9. Datenbit eines empfangenen Zeichens.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;TXB8&#039;&#039;&#039; (Transmit Data Bit 8)&lt;br /&gt;
:Wenn das vorher erwähnte CHR9-Bit gesetzt ist, dann muss in dieses Bit das 9. Bit des zu sendenden Zeichens eingeschrieben werden bevor das eigentliche Datenbyte in das Datenregister geschrieben wird.&lt;br /&gt;
&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;USR&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;U&#039;&#039;&#039;ART &#039;&#039;&#039;S&#039;&#039;&#039;tatus &#039;&#039;&#039;R&#039;&#039;&#039;egister.&amp;lt;br /&amp;gt;&lt;br /&gt;
Hier teilt uns der UART mit, was er gerade so macht.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Bit&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 7&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 6&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 5&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 4&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 2&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Name&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;RXC&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;TXC&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;UDRE&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;FE&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;OR&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;R/W&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Initialwert&#039;&#039;&#039;&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;
| 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;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;RXC&#039;&#039;&#039; (UART Receive Complete)&lt;br /&gt;
:Dieses Bit wird vom AVR gesetzt, wenn ein empfangenes Zeichen vom Empfangs-Schieberegister in das Empfangs-Datenregister transferiert wurde.&lt;br /&gt;
:Das Zeichen muss nun schnellstmöglich aus dem Datenregister ausgelesen werden. Falls dies nicht erfolgt bevor ein weiteres Zeichen komplett empfangen wurde wird eine Überlauf-Fehlersituation eintreffen. Mit dem Auslesen des Datenregisters wird das Bit automatisch gelöscht.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;TXC&#039;&#039;&#039; (UART Transmit Complete)&lt;br /&gt;
:Dieses Bit wird vom AVR gesetzt, wenn das im Sende-Schieberegister befindliche Zeichen vollständig ausgegeben wurde und kein weiteres Zeichen im Sendedatenregister ansteht. Dies bedeutet also, wenn die Kommunikation vollumfänglich abgeschlossen ist.&lt;br /&gt;
:Dieses Bit ist wichtig bei Halbduplex-Verbindungen, wenn das Programm nach dem Senden von Daten auf Empfang schalten muss. Im Vollduplexbetrieb brauchen wir dieses Bit nicht zu beachten.&lt;br /&gt;
:Das Bit wird nur dann automatisch gelöscht, wenn der entsprechende Interrupthandler aufgerufen wird, ansonsten müssen wir das Bit selber löschen.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;UDRE&#039;&#039;&#039; (&#039;&#039;&#039;U&#039;&#039;&#039;ART &#039;&#039;&#039;D&#039;&#039;&#039;ata &#039;&#039;&#039;R&#039;&#039;&#039;egister &#039;&#039;&#039;E&#039;&#039;&#039;mpty)&lt;br /&gt;
:Dieses Bit zeigt an, ob der Sendepuffer bereit ist, um ein zu sendendes Zeichen aufzunehmen. Das Bit wird vom AVR gesetzt (1), wenn der Sendepuffer leer ist. Es wird gelöscht (0), wenn ein Zeichen im Sendedatenregister vorhanden ist und noch nicht in das Sendeschieberegister übernommen wurde. Atmel empfiehlt aus Kompatibilitätsgründen mit kommenden µC, UDRE auf 0 zu setzen, wenn das UCSRA Register beschrieben wird.&lt;br /&gt;
:Das Bit wird automatisch gelöscht, wenn ein Zeichen in das Sendedatenregister geschrieben wird.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;FE&#039;&#039;&#039; (&#039;&#039;&#039;F&#039;&#039;&#039;raming &#039;&#039;&#039;E&#039;&#039;&#039;rror)&lt;br /&gt;
:Dieses Bit wird vom AVR gesetzt, wenn der UART einen Zeichenrahmenfehler detektiert, d.h. wenn das Stopbit eines empfangenen Zeichens 0 ist.&lt;br /&gt;
:Das Bit wird automatisch gelöscht, wenn das Stopbit des empfangenen Zeichens 1 ist.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;OR&#039;&#039;&#039; (&#039;&#039;&#039;O&#039;&#039;&#039;ver&#039;&#039;&#039;R&#039;&#039;&#039;un)&amp;lt;br /&amp;gt;&lt;br /&gt;
:Dieses Bit wird vom AVR gesetzt, wenn unser Programm das im Empfangsdatenregister bereit liegende Zeichen nicht abholt bevor das nachfolgende Zeichen komplett empfangen wurde.&lt;br /&gt;
:Das nachfolgende Zeichen wird verworfen.&lt;br /&gt;
:Das Bit wird automatisch gelöscht, wenn das empfangene Zeichen in das Empfangsdatenregister transferiert werden konnte.&lt;br /&gt;
&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;UDR&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;U&#039;&#039;&#039;ART &#039;&#039;&#039;D&#039;&#039;&#039;ata &#039;&#039;&#039;R&#039;&#039;&#039;egister.&amp;lt;br /&amp;gt;&lt;br /&gt;
Hier werden Daten zwischen UART und CPU übertragen. Da der UART im&lt;br /&gt;
Vollduplexbetrieb gleichzeitig empfangen und senden kann, handelt es sich&lt;br /&gt;
hier physikalisch um 2 Register, die aber über die gleiche I/O-Adresse&lt;br /&gt;
angesprochen werden. Je nachdem, ob ein Lese- oder ein Schreibzugriff auf&lt;br /&gt;
den UART erfolgt wird automatisch das richtige UDR angesprochen.&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;UBRR&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;U&#039;&#039;&#039;ART &#039;&#039;&#039;B&#039;&#039;&#039;aud &#039;&#039;&#039;R&#039;&#039;&#039;ate &#039;&#039;&#039;R&#039;&#039;&#039;egister.&amp;lt;br /&amp;gt;&lt;br /&gt;
In diesem Register müssen wir dem UART mitteilen, wie schnell wir gerne&lt;br /&gt;
kommunizieren möchten. Der Wert, der in dieses Register geschrieben&lt;br /&gt;
werden muss, errechnet sich nach folgender Formel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
\begin{matrix}&lt;br /&gt;
\mathrm{UBRR} = \frac{\mathrm{Taktfrequenz}}{\mathrm{Baudrate} \cdot 16} - 1&lt;br /&gt;
\end{matrix}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Es sind Baudraten bis zu 115200 Baud und höher möglich.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Die Hardware ==&lt;br /&gt;
&lt;br /&gt;
Der UART basiert auf normalem TTL-Pegel mit 0V (LOW) und 5V (HIGH). Die&lt;br /&gt;
Schnittstellenspezifikation für RS-232 definiert jedoch -3V ... -12V (LOW) und&lt;br /&gt;
+3 ... +12V (HIGH). Zudem muss der Signalaustausch zwischen AVR und&lt;br /&gt;
Partnergerät invertiert werden. Für die Anpassung der Pegel und das&lt;br /&gt;
Invertieren der Signale gibt es fertige Schnittstellenbausteine. Der bekannteste&lt;br /&gt;
davon ist wohl der MAX232. &lt;br /&gt;
&amp;lt;!-- &amp;quot;Hackerloesung&amp;quot; auskommentiert - nicht so gut in einem &amp;quot;Einsteiger-Tutorial&amp;quot; - mthomas&lt;br /&gt;
Allerdings kostet der auch wieder Geld und benötigt&lt;br /&gt;
zusätzlich immerhin 4 externe Elkos.&lt;br /&gt;
&lt;br /&gt;
Die in den PC eingebauten Schnittstellen vertragen ohne Klagen auch den&lt;br /&gt;
TTL-Pegel vom AVR. Allerdings müssen wir immer noch die Signale invertieren. Im&lt;br /&gt;
einfachtesn Fall verwenden wir dazu jeweils einen einfachen NPN-Transistor und 2&lt;br /&gt;
Widerstände. Näheres dazu erfahrt ihr in den folgenden Übungen.--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Streikt die Kommunikation per UART, so ist oft eine fehlerhafte Einstellung der Baudrate die Ursache. Die Konfiguration auf eine bestimmte Baudrate ist abhängig von der Taktfrequenz des Controllers. Gerade bei neu aufgebauten Schaltungen (bzw. neu gekauften Controllern) sollte man sich daher noch einmal vergewissern, dass der Controller auch tatsächlich mit der vermuteten Taktrate arbeitet und nicht z.B. den bei einigen Modellen werksseitig eingestellten internen [[Oszillator]] statt eines externen Quarzes nutzt. Die Werte der verschiedenen fuse-bits im Fehlerfall also beispielsweise mit &#039;&#039;[[AVRDUDE]]&#039;&#039; kontrollieren und falls nötig anpassen. Grundsätzlich empfiehlt sich auch immer ein Blick in die [[AVR_Checkliste]].&lt;br /&gt;
&lt;br /&gt;
== UART initialisieren ==&lt;br /&gt;
&lt;br /&gt;
Wir wollen nun Daten mit dem UART auf die serielle Schnittstelle ausgeben. Dazu müssen wir den UART zuerst mal initialisieren. Dazu setzen wir je nach gewünschter Funktionsweise die benötigten Bits im &#039;&#039;&#039;U&#039;&#039;&#039;ART &#039;&#039;&#039;C&#039;&#039;&#039;ontrol &#039;&#039;&#039;R&#039;&#039;&#039;egister.&lt;br /&gt;
&lt;br /&gt;
Da wir vorerst nur senden möchten und noch keine Interrupts auswerten wollen, gestaltet sich die Initialisierung wirklich sehr einfach, da wir lediglich das &#039;&#039;&#039;Transmitter Enable&#039;&#039;&#039; Bit setzen müssen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
    UCR |= (1&amp;lt;&amp;lt;TXEN);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Neuere AVRs mit USART haben mehrere Konfigurationsregister und erfordern eine etwas andere Konfiguration. Für einen ATmega16 z.B.:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
    UCSRB |= (1&amp;lt;&amp;lt;TXEN);                            // UART TX einschalten&lt;br /&gt;
    UCSRC |= (1&amp;lt;&amp;lt;URSEL)|(1 &amp;lt;&amp;lt; UCSZ1)|(1 &amp;lt;&amp;lt; UCSZ0); // Asynchron 8N1&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nun ist noch das Baudratenregister &#039;&#039;&#039;UBRR&#039;&#039;&#039; einzustellen. Bei neueren AVRs besteht es aus zwei Registern &#039;&#039;&#039;UBRRL&#039;&#039;&#039; und &#039;&#039;&#039;UBRRH&#039;&#039;&#039;. Der Wert dafür ergibt sich aus der angegebenen Formel durch Einsetzen der Taktfrequenz und der gewünschten Übertragungsrate. Das Berechnen der Formel wird dem [[C-Präprozessor|Präprozessor]] überlassen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
/* UART-Init beim AT90S2313 */&lt;br /&gt;
&lt;br /&gt;
#ifndef F_CPU&lt;br /&gt;
/* In neueren Version der WinAVR/Mfile Makefile-Vorlage kann&lt;br /&gt;
   F_CPU im Makefile definiert werden, eine nochmalige Definition&lt;br /&gt;
   hier wuerde zu einer Compilerwarnung fuehren. Daher &amp;quot;Schutz&amp;quot; durch&lt;br /&gt;
   #ifndef/#endif &lt;br /&gt;
&lt;br /&gt;
   Dieser &amp;quot;Schutz&amp;quot; kann zu Debugsessions führen, wenn AVRStudio &lt;br /&gt;
   verwendet wird und dort eine andere, nicht zur Hardware passende &lt;br /&gt;
   Taktrate eingestellt ist: Dann wird die folgende Definition &lt;br /&gt;
   nicht verwendet, sondern stattdessen der Defaultwert (8 MHz?) &lt;br /&gt;
   von AVRStudio - daher Ausgabe einer Warnung falls F_CPU&lt;br /&gt;
   noch nicht definiert: */&lt;br /&gt;
#warning &amp;quot;F_CPU war noch nicht definiert, wird nun nachgeholt mit 4000000&amp;quot;&lt;br /&gt;
#define F_CPU 4000000UL    // Systemtakt in Hz - Definition als unsigned long beachten &amp;gt;&amp;gt; Ohne ergeben Fehler in der Berechnung&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
#define BAUD 9600UL          // Baudrate&lt;br /&gt;
&lt;br /&gt;
// Berechnungen&lt;br /&gt;
#define UBRR_VAL ((F_CPU+BAUD*8)/(BAUD*16)-1)   // clever runden&lt;br /&gt;
#define BAUD_REAL (F_CPU/(16*(UBRR_VAL+1)))     // Reale Baudrate&lt;br /&gt;
#define BAUD_ERROR ((BAUD_REAL*1000)/BAUD) // Fehler in Promille, 1000 = kein Fehler.&lt;br /&gt;
&lt;br /&gt;
#if ((BAUD_ERROR&amp;lt;990) || (BAUD_ERROR&amp;gt;1010))&lt;br /&gt;
  #error Systematischer Fehler der Baudrate grösser 1% und damit zu hoch! &lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
int main(void)&lt;br /&gt;
{&lt;br /&gt;
    UCR |= (1&amp;lt;&amp;lt;TXEN);&lt;br /&gt;
    UBRR = UBRR_VAL;&lt;br /&gt;
    //...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&amp;lt;!-- mthomas: warum nicht UL?, wird von AVRStudio auch mit UL übergeben --&amp;gt;&lt;br /&gt;
Wieder für den Mega16 mit zwei Registern für die Baudrateneinstellung eine etwas andere Programmierung. Wichtig ist, dass UBRRH &#039;&#039;&#039;vor&#039;&#039;&#039; UBRRL geschrieben wird.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
  /* USART-Init beim ATmega16 */&lt;br /&gt;
&lt;br /&gt;
int main(void)&lt;br /&gt;
{&lt;br /&gt;
    UCSRB |= (1&amp;lt;&amp;lt;TXEN);                // UART TX einschalten&lt;br /&gt;
    UCSRC |= (1&amp;lt;&amp;lt;URSEL)|(3&amp;lt;&amp;lt;UCSZ0);    // Asynchron 8N1 &lt;br /&gt;
&lt;br /&gt;
    UBRRH = UBRR_VAL &amp;gt;&amp;gt; 8;&lt;br /&gt;
    UBRRL = UBRR_VAL &amp;amp; 0xFF;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für einige AVR (z.B. ATmega169, ATmega48/88/168, AT90CAN jedoch nicht für z.B. ATmega16/32, ATmega128, ATtiny2313) wird durch die Registerdefinitionen der avr-libc (io*.h) auch für Controller mit zwei UBRR-Registern (UBRRL/UBRRH) ein UBRR bzw. UBRR0 als &amp;quot;16-bit-Register&amp;quot; definiert und man kann auch Werte direkt per UBRR = UBRR_VAL zuweisen. Intern werden dann zwei Zuweisungen für UBRRH und UBRRL generiert. Dies ist nicht bei allen Controllern möglich, da die beiden Register nicht bei allen aufeinanderfolgende Addressen aufweisen. Die getrennte Zuweisung an UBRRH und UBRRL wie im Beispiel gezeigt ist universeller und portabler und daher vorzuziehen.&lt;br /&gt;
&lt;br /&gt;
Die Makros sind sehr praktisch, da sie sowohl automatisch den Wert für UBRR als auch den Fehler in der generierten Baudrate berechnen und im Falle einer Überschreitung (+/-1%) einen Fehler und somit Abbruch im Compilerablauf generieren. Damit können viele Probleme mit &amp;quot;UART sendet komische Zeichen&amp;quot; vermieden werden. Ausserdem kann man mühelos die Einstellung an eine neue Taktfrequenz bzw. Baudrate anpassen, ohne selber rechnen oder in Tabellen nachschlagen zu müssen.&lt;br /&gt;
&lt;br /&gt;
Siehe auch:&lt;br /&gt;
* [http://www.wormfood.net/avrbaudcalc.php WormFood&#039;s AVR Baud Rate Calculator] online.&lt;br /&gt;
&lt;br /&gt;
== Senden mit dem UART ==&lt;br /&gt;
&lt;br /&gt;
=== Senden einzelner Zeichen ===&lt;br /&gt;
&lt;br /&gt;
Um nun ein Zeichen auf die Schnittstelle auszugeben, müssen wir dasselbe&lt;br /&gt;
lediglich in das &#039;&#039;&#039;U&#039;&#039;&#039;ART &#039;&#039;&#039;D&#039;&#039;&#039;ata &#039;&#039;&#039;R&#039;&#039;&#039;egister schreiben. Vorher ist zu prüfen, ob das UART-Modul bereit ist, das zu sendende Zeichen entgegenzunehmen. Die Bezeichnungen des/der Statusregisters mit dem Bit UDRE ist abhängig vom Controllertypen (vgl. Datenblatt).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
    // bei AVR mit einem UART (&amp;quot;classic AVR&amp;quot; z.B. AT90S8515)&lt;br /&gt;
    while (!(USR &amp;amp; (1&amp;lt;&amp;lt;UDRE)))  /* warten bis Senden moeglich                   */&lt;br /&gt;
    {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    UDR = &#039;x&#039;;                  /* schreibt das Zeichen x auf die Schnittstelle */&lt;br /&gt;
&lt;br /&gt;
    /** ODER **/&lt;br /&gt;
&lt;br /&gt;
    // bei neueren AVRs steht der Status in UCSRA/UCSR0A/UCSR1A, hier z.B. fuer ATmega16:&lt;br /&gt;
    while (!(UCSRA &amp;amp; (1&amp;lt;&amp;lt;UDRE)))  /* warten bis Senden moeglich                   */&lt;br /&gt;
    {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    UDR = &#039;x&#039;;                    /* schreibt das Zeichen x auf die Schnittstelle */&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Schreiben einer Zeichenkette (String) ===&lt;br /&gt;
&lt;br /&gt;
Die Aufgabe &amp;quot;String senden&amp;quot; wird durch zwei Funktionen abgearbeitet. Die universelle/controllerunabhängige Funktion uart_puts übergibt jeweils ein Zeichen der Zeichenkette an eine Funktion uart_putc, die abhängig von der vorhandenen Hardware implementiert werden muss. In der Funktion zum Senden eines Zeichens ist darauf zu achten, dass vor dem Senden geprüft wird, ob der UART bereit ist den &amp;quot;Sendeauftrag&amp;quot; entgegenzunehmen. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
// putc fuer AVR mit einem UART (z.B. AT90S8515)&lt;br /&gt;
int uart_putc(unsigned char c)&lt;br /&gt;
{&lt;br /&gt;
    while(!(USR &amp;amp; (1 &amp;lt;&amp;lt; UDRE)))  /* warte, bis UDR bereit */&lt;br /&gt;
    {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    UDR = c;                     /* sende Zeichen */&lt;br /&gt;
    return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/** ODER **/&lt;br /&gt;
&lt;br /&gt;
// bei neueren AVRs andere Bezeichnung fuer die Statusregister, hier ATmega16:&lt;br /&gt;
int uart_putc(unsigned char c)&lt;br /&gt;
{&lt;br /&gt;
    while (!(UCSRA &amp;amp; (1&amp;lt;&amp;lt;UDRE)))  /* warten bis Senden moeglich */&lt;br /&gt;
    {&lt;br /&gt;
    }                             &lt;br /&gt;
&lt;br /&gt;
    UDR = c;                      /* sende Zeichen */&lt;br /&gt;
    return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* puts ist unabhaengig vom Controllertyp */&lt;br /&gt;
void uart_puts (char *s)&lt;br /&gt;
{&lt;br /&gt;
    while (*s)&lt;br /&gt;
    {   /* so lange *s != &#039;\0&#039; also ungleich dem &amp;quot;String-Endezeichen&amp;quot; */&lt;br /&gt;
        uart_putc(*s);&lt;br /&gt;
        s++;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die in uart_putc verwendeten Schleifen, in denen gewartet wird bis die UART-Hardware zum senden bereit ist, sind insofern etwas kritisch, da während des Sendens eines Strings nicht mehr auf andere Ereignisse reagieren werden kann. Universeller ist die Nutzung von FIFO(first-in first-out)-Puffern, in denen die zu sendenden bzw. empfangenen Zeichen/Bytes zwischengespeichert und in Interruptroutinen an die U(S)ART-Hardware weitergegeben bzw. von ihr ausgelesen werden. Dazu existieren fertige Komponenten (Bibliotheken, Libraries), die man recht einfach in eigene Entwicklungen integrieren kann. Es empfiehlt sich, diese Komponenten zu nutzen und das Rad nicht neu zu erfinden.&lt;br /&gt;
&lt;br /&gt;
=== Schreiben von Variableninhalten ===&lt;br /&gt;
&lt;br /&gt;
Sollen Inhalte von Variablen (Ganzzahlen, Fließkomma) in &amp;quot;menschenlesbarer&amp;quot; Form gesendet werden, ist vor dem Transfer eine Umwandlung in Zeichen (&amp;quot;ASCII&amp;quot;) erforderlich. Bei nur einer Ziffer ist diese Umwandlung relativ einfach: man addiert den ASCII-Wert von Null zur Ziffer und kann diesen Wert direkt senden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
// hier uart_putc (s.o.)&lt;br /&gt;
&lt;br /&gt;
// Ausgabe von 0123456789&lt;br /&gt;
char c;&lt;br /&gt;
&lt;br /&gt;
for (uint8_t i=0; i&amp;lt;=9; ++i) {&lt;br /&gt;
    c = i + &#039;0&#039;;&lt;br /&gt;
    uart_putc( c );&lt;br /&gt;
    // verkuerzt: uart_putc( i + &#039;0&#039; );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Soll mehr als eine Ziffer ausgegeben werden, bedient man sich zweckmäßigerweise vorhandener Funktionen zur Umwandlung von Zahlen in Zeichenketten/Strings. Die Funktion der avr-libc zur Umwandlung von vorzeichenbehafteten 16bit-Ganzzahlen (int16_t) in Zeichenketten heißt &#039;&#039;itoa&#039;&#039; (Integer to ASCII). Man muss der Funktion einen Speicherbereich zur Verarbeitung (buffer) mit Platz für alle Ziffern, das String-Endezeichen (&#039;\0&#039;) und evtl. das Vorzeichen bereitstellen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
// hier uart_init, uart_putc, uart_puts (s.o.)&lt;br /&gt;
&lt;br /&gt;
int main(void)&lt;br /&gt;
{&lt;br /&gt;
   char s[7];&lt;br /&gt;
   int16_t i = -12345;&lt;br /&gt;
   &lt;br /&gt;
   uart_init();&lt;br /&gt;
&lt;br /&gt;
   itoa( i, s, 10 ); // 10 fuer radix -&amp;gt; Dezimalsystem&lt;br /&gt;
   uart_puts( s );&lt;br /&gt;
&lt;br /&gt;
   // da itoa einen Zeiger auf den Beginn von s zurueckgibt verkuerzt auch:&lt;br /&gt;
   uart_puts( itoa( i, s, 10 ) );&lt;br /&gt;
&lt;br /&gt;
   while (1) {&lt;br /&gt;
      ;&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
   return 0; // never reached &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für vorzeichenlose 16bit-Ganzzahlen (uint16_t) exisitert &#039;&#039;utoa&#039;&#039;. Die Funktionen für 32bit-Ganzzahlen (int32_t und uint32_t) heißen &#039;&#039;ltoa&#039;&#039; bzw. &#039;&#039;ultoa&#039;&#039;. Da 32bit-Ganzzahlen mehr Stellen aufweisen können, ist ein entsprechend größerer Pufferspeicher vorzusehen.&lt;br /&gt;
&lt;br /&gt;
Auch Fließkommazahlen (float/double) können mit breits vorhandenen Funktionen in Zeichenfolgen umgewandelt werden, dazu existieren die Funktionen &#039;&#039;dtostre&#039;&#039; und &#039;&#039;dtostrf&#039;&#039;. dtostre nutzt Exponentialschreibweise (&amp;quot;engineering&amp;quot;-Format). (Hinweis: z.Zt. existiert im avr-gcc kein &amp;quot;echtes&amp;quot; double, intern wird immer mit &amp;quot;einfacher Genauigkeit&amp;quot;, entsprechend float, gerechnet.) &lt;br /&gt;
&lt;br /&gt;
dtostrf und dtostre benötigen die libm.a der avr-libc. Bei Nutzung von Makefiles ist der Parameter -lm in in LDFLAGS anzugeben (Standard in den WinAVR/mfile-Makefilevorlagen). Nutzt man AVRStudio als IDE für den GNU-Compiler (gcc-Plugin) ist die libm.a unter Libaries auszuwählen: Project -&amp;gt; Configurations Options -&amp;gt; Libaries -&amp;gt; libm.a mit dem Pfeil nach rechts einbinden. Siehe auch die [[FAQ#Aktivieren_der_Floating_Point_Version_von_sprintf_beim_WinAVR_mit_AVR-Studio|FAQ]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
// hier uart_init, uart_putc, uart_puts (s.o.)&lt;br /&gt;
&lt;br /&gt;
/* lt. avr-libc Dokumentation:&lt;br /&gt;
char* dtostrf(&lt;br /&gt;
  double __val,&lt;br /&gt;
  char   __width,&lt;br /&gt;
  char   __prec,&lt;br /&gt;
  char * __s&lt;br /&gt;
)  &lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
int main(void)&lt;br /&gt;
{&lt;br /&gt;
   // Pufferspeicher ausreichend groß&lt;br /&gt;
   // evtl. Vorzeichen + width + Endezeichen:&lt;br /&gt;
   char s[8]; &lt;br /&gt;
   float f = -12.345;&lt;br /&gt;
   &lt;br /&gt;
   uart_init();&lt;br /&gt;
&lt;br /&gt;
   dtostrf( f, 6, 3, s ); &lt;br /&gt;
   uart_puts( s );&lt;br /&gt;
&lt;br /&gt;
   // verkürzt: uart_puts( dtostrf( f, 7, 3, s ) );&lt;br /&gt;
&lt;br /&gt;
   while (1) {&lt;br /&gt;
      ;&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
   return 0; // never reached &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Empfangen ==&lt;br /&gt;
=== einzelne Zeichen empfangen ===&lt;br /&gt;
&lt;br /&gt;
Zum Empfang von Zeichen muss der Empfangsteil des UART bei der Initialisierung aktiviert werden, indem das RXEN-Bit im jeweiligen Konfigurationsregister (UCSRB bzw UCSR0B/UCSR1B) gesetzt wird. Im einfachsten Fall wird solange gewartet, bis ein Zeichen empfangen wurde, dieses steht dann im UART-Datenregister (UDR bzw. UDR0 und UDR1 bei AVRs mit 2 UARTS) zur Verfügung (sogen. &amp;quot;Polling-Betrieb&amp;quot;). Ein Beispiel für den ATmega16:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;inttypes.h&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/* Zusaetzlich zur Baudrateneinstellung und der weiteren Initialisierung: */&lt;br /&gt;
void Usart_EnableRX(void)&lt;br /&gt;
{&lt;br /&gt;
    UCSRB |= ( 1 &amp;lt;&amp;lt; RXEN );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* Zeichen empfangen */&lt;br /&gt;
uint8_t uart_getc(void)&lt;br /&gt;
{&lt;br /&gt;
    while (!(UCSRA &amp;amp; (1&amp;lt;&amp;lt;RXC)))   // warten bis Zeichen verfuegbar&lt;br /&gt;
        ;&lt;br /&gt;
    return UDR;                   // Zeichen aus UDR an Aufrufer zurueckgeben&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Diese Funktion blockiert den Programmablauf. Alternativ kann das RXC-Bit in einer Programmschleife abgefragt werden und dann nur bei gesetztem RXC-Bit UDR ausgelesen werden. Eleganter und in den meisten Anwendungsfällen &amp;quot;stabiler&amp;quot; ist die Vorgehensweise, die empfangenen Zeichen in einer Interrupt-Routine einzulesen und zur späteren Verarbeitung in einem Eingangsbuffer (FIFO-Buffer) zwischenzuspeichern. Dazu existieren fertige und gut getestete [[Libraries|Bibliotheken]] &amp;lt;!-- &amp;quot;echte Libraries&amp;quot; (.a) wie im Verweis beschrieben sind hier eigentlich nicht gemeint, verwirrt hier etwas, da AVR-&amp;quot;Libraries&amp;quot; meist per #defines anpassbare Source-Codes sind, vielleicht so: --&amp;gt; und Quellcodekomponenten (z.B. UART-Library von P. Fleury, procyon-avrlib und einige in der &amp;quot;Academy&amp;quot; von avrfreaks.net).&lt;br /&gt;
&lt;br /&gt;
siehe auch:&lt;br /&gt;
* [http://www.nongnu.org/avr-libc/user-manual/group__avr__stdlib.html Dokumenation der avr-libc/stdlib.h]&lt;br /&gt;
* [http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Die_Nutzung_von_printf Die Nutzung von printf]&lt;br /&gt;
* [http://homepage.hispeed.ch/peterfleury/ Peter Fleurys] UART-Bibiliothek fuer avr-gcc/avr-libc&lt;br /&gt;
&amp;lt;!-- nimmermehr: * siehe auch: Weiterführende Informationen inkl. Beispielen für die Nutzung von stdio-Funktionen (printf etc.) im [[AVR-Tutorial:_UART]]. --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
TODO: 9bit&lt;br /&gt;
&lt;br /&gt;
=== Empfang von Zeichenketten (Strings) ===&lt;br /&gt;
&lt;br /&gt;
Beim Empfang von Zeichenketten, muß man sich zunächst darüber im klaren sein, daß es ein Kriterium geben muß, an dem der µC erkennen kann, wann ein String zu Ende ist. Sehr oft wird dazu das Zeichen &#039;Return&#039; benutzt, um das Ende eines Strings zu markieren. Dies ist vom Benutzer einfach eingebbar und er ist auch daran gewöhnt, daß er eine Eingabezeile mit einem Druck auf die Return Taste abgeschlossen wird.&lt;br /&gt;
&lt;br /&gt;
Prinzipiell gibt es jedoch keine Einschränkung bezüglich dieses speziellen Zeichens. Es muß nur sichergestellt werden, daß dieses spezielle &#039;Ende eines Strings&#039; - Zeichen nicht mit einem im Text vorkommenden Zeichen verwechselt werden kann. Wenn also im zu übertragenden Text beispielsweise kein &#039;;&#039; vorkommt, dann spricht nichts dagegen, einen String mit einem &#039;;&#039; abschließen zu lassen.&lt;br /&gt;
&lt;br /&gt;
Im Folgenden wird die durchaus übliche Annahme getroffen, daß eine Stringübertragung identisch ist mit der Übertragung einer Textzeile und daher mit einem Return (&#039;\n&#039;) abgeschlossen wird.&lt;br /&gt;
&lt;br /&gt;
Das Problem der Übertragung eines Strings reduziert sich damit auf die Aufgabenstellung: Empfange und Sammle Zeichen in einem char Array, bis entweder das Array voll ist oder das &#039;String Ende Zeichen&#039; empfangen wurde. Danach wird der empfangene Text noch mit einem &#039;\0&#039; Zeichen abgeschlossen um einen Standard C-String daraus zu machen, mit dem dann weiter gearbeitet werden kann.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;C&amp;gt;&lt;br /&gt;
/* Zeichen empfangen */&lt;br /&gt;
uint8_t uart_getc(void)&lt;br /&gt;
{&lt;br /&gt;
    while (!(UCSRA &amp;amp; (1&amp;lt;&amp;lt;RXC)))   // warten bis Zeichen verfuegbar&lt;br /&gt;
        ;&lt;br /&gt;
    return UDR;                   // Zeichen aus UDR an Aufrufer zurueckgeben&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void uart_gets( char* Buffer, uint8_t MaxLen )&lt;br /&gt;
{&lt;br /&gt;
  uint8_t NextChar;&lt;br /&gt;
  uint8_t StringLen = 0;&lt;br /&gt;
&lt;br /&gt;
  NextChar = uart_getc();         // Warte auf und empfange das nächste Zeichen&lt;br /&gt;
&lt;br /&gt;
                                  // Sammle solange Zeichen, bis:&lt;br /&gt;
                                  // * entweder das String Ende Zeichen kam&lt;br /&gt;
                                  // * oder das aufnehmende Array voll ist&lt;br /&gt;
  while( NextChar != &#039;\n&#039; &amp;amp;&amp;amp; StringLen &amp;lt; MaxLen - 1 ) {&lt;br /&gt;
    *Buffer++ = NextChar;&lt;br /&gt;
    StringLen++;&lt;br /&gt;
    NextChar = uart_getc();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
                                  // Noch ein &#039;\0&#039; anhängen um einen Standard&lt;br /&gt;
                                  // C-String daraus zu machen&lt;br /&gt;
  *Buffer = &#039;\0&#039;;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/C&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Beim Aufruf ist darauf zu achten, dass das empfangende Array auch mit einer&lt;br /&gt;
vernünftigen Größe definiert wird.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;C&amp;gt;&lt;br /&gt;
  char Line[40];      // String mit maximal 39 zeichen&lt;br /&gt;
&lt;br /&gt;
  uart_gets( Line, sizeof( Line ) );&lt;br /&gt;
&amp;lt;/C&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bei der Benutzung von sizeof() ist allerdings zu beachten, dass sizeof() nicht die Anzahl der Elemente des Arrays liefert, sondern die Länge in Byte. Da ein char nur ein Byte lang ist, passt der Aufruf &#039;uart_gets(Line, sizeof( Line ) );&#039; in diesem Fall. Falls man - aus welchen Gründen auch immer - andere Datentypen benutzen möchte, sollte man zur korrekten Angabe der Array-Länge folgende Vorgehensweise bevorzugen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;C&amp;gt;&lt;br /&gt;
  int Line[40];      // Array vom Typ int&lt;br /&gt;
&lt;br /&gt;
  uart_gets( Line, sizeof( Line ) / sizeof( Line[0] ) );&lt;br /&gt;
&amp;lt;/C&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Interruptbetrieb==&lt;br /&gt;
&lt;br /&gt;
Beim ATMEGA8 muss das RXCIE Bit im Register UCSRB gesetzt werden, damit ein Interrupt ausgelöst werden kann.&lt;br /&gt;
Der Interrupt wird immer ausgelöst, wenn Daten erfolgreich empfangen wurden.&lt;br /&gt;
&lt;br /&gt;
Zusätzlich braucht man die Routine:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
ISR (USART_RXC_vect) {&lt;br /&gt;
   //irgendein Code&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
natürlich muss &amp;quot;Global Interrupt Enable&amp;quot; Aktiviert sein.&lt;br /&gt;
!! Nur getestet beim ATMEGA8 !!&lt;br /&gt;
&lt;br /&gt;
[BAUSTELLE! Aus Lerngründen eventuell als eigenen UART-Interrupt-Block hinter den grundlegenden Interrupt-Teil im Tutorial und hier eine kurze Einführung und einen Verweis darauf anbieten.]&lt;br /&gt;
&lt;br /&gt;
* Unterschied Polling-Betrieb (bisher, oben) und Interrupt-Betrieb&lt;br /&gt;
* Empfangen (Receive)&lt;br /&gt;
** Verändertes UART-Init, ISR (RXC), ggf. Fallstricke ([http://www.mikrocontroller.net/topic/84256#707214 UDR in der ISR lesen!]), Philosophie einer ISR (kurz und schmerzlos), Datenaustausch ISR zu Restprogramm (volatile)&lt;br /&gt;
** Einfachstbeispiel ([http://www.mikrocontroller.net/topic/84228#707052 Echo] (noch buggy beim Datenzugriff, siehe Lit. 2+3!)), ggf. LED zur ISR-Empfangsanzeige oder Overflow-Anzeige&lt;br /&gt;
* FIFO-Puffer, Ringpuffer&lt;br /&gt;
* Senden (Transmit)&lt;br /&gt;
** Variante &amp;quot;UART Data Register Empty&amp;quot; (UDRE) &lt;br /&gt;
** Variante &amp;quot;UART Transmit Complete&amp;quot; (TXC) &lt;br /&gt;
* Fertige UART-Bibliotheken (-&amp;gt;Fleury, -&amp;gt;Procyon)&lt;br /&gt;
* Literatur: &lt;br /&gt;
** 1/ [http://www.avrfreaks.net/index.php?name=PNphpBB2&amp;amp;file=viewtopic&amp;amp;t=48188 avrfreaks.net Tutorial] inkl. Diskussion (engl.)&lt;br /&gt;
** 2/ avr-libc FAQ: [http://www.nongnu.org/avr-libc/user-manual/FAQ.html#faq_16bitio Why do some 16-bit timer registers sometimes get trashed?]&lt;br /&gt;
** 3/ [[Interrupt]] und atomarer Datenzugriff&lt;br /&gt;
&lt;br /&gt;
==Software-UART==&lt;br /&gt;
&lt;br /&gt;
Falls die Zahl der vorhandenen Hardware-UARTs nicht ausreicht, können weitere Schnittstellen über sogennante Software-UARTs ergänzt werden. Es gibt dazu (mindestens) zwei Ansätze: &lt;br /&gt;
* Der bei AVRs üblichste Ansatz basiert auf dem Prinzip, dass ein externer Interrupt-Pin für den Empfang (&amp;quot;RX&amp;quot;) genutzt wird. Das Startbit löst den Interrupt aus, in der Interrupt-Routine (ISR) wird der externe Interrupt deaktiviert und ein Timer aktiviert. In der Interrupt-Routine des Timers wird der Zustand des Empfangs-Pins entsprechend der Baudrate abgetastet. Nach Empfang des Stop-Bits wird der externe Interrupt wieder aktiviert. Senden kann über einen beliebigen Pin (&amp;quot;TX&amp;quot;) erfolgen, der entsprechend der Baudrate und dem zu sendenden Zeichen auf 0 oder 1 gesetzt wird. Die Implementierung ist nicht ganz einfach, es existieren dazu aber fertige Bibliotheken (z.B. bei [http://www.avrfreaks.net/ avrfreaks] oder in der [http://hubbard.engr.scu.edu/embedded/avr/avrlib/ Procyon avrlib]).&lt;br /&gt;
* Ein weiterer Ansatz erfordert keinen Pin mit &amp;quot;Interrupt-Funktion&amp;quot; aber benötigt mehr Rechenzeit. Jeder Input-Pin kann als Empfangspin (RX) dienen. Über einen Timer wird der Zustand des RX-Pins mit einem vielfachen der Baudrate abgetastet (dreifach scheint üblich) und High- bzw. Lowbits anhand einer Mindestanzahl identifiziert. (Beispiel: &amp;quot;Generic Software Uart&amp;quot; Application-Note von IAR)&lt;br /&gt;
&lt;br /&gt;
Neuere AVRs (z.B. ATtiny26 oder ATmega48,88,168,169) verfügen über ein Universal Serial Interface (USI), das teilweise UART-Funktion übernehmen kann. Atmel stellt eine Application-Note bereit, in der die Nutzung des USI als UART erläutert wird (im Prinzip &amp;quot;Hardware-unterstützter Software-UART&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
==Handshaking==&lt;br /&gt;
Wenn der Sender ständig sendet, wird irgendwann der Fall eintreten, daß der Empfänger nicht bereit ist, neue Zeichen zu empfangen. In diesem Fall muß durch ein &#039;&#039;&#039;Handshake-Verfahren&#039;&#039;&#039; die Situation bereinigt werden. Handshake bedeutet nichts anderes, als daß der Empfänger dem Sender mitteilt, daß er zur Zeit keine Daten annehmen kann und der Sender die Übertragung der nächsten Zeichen solange einstellen soll, bis der Empfänger signalisiert, daß er wieder Zeichen aufnehmen kann.&lt;br /&gt;
===Hardwarehandshake (RTS/CTS)===&lt;br /&gt;
Beim Hardwarehandshake werden zusätzlich zu den beiden Daten-Übertragungsleitungen noch 2 weitere Leitungen benötigt: &#039;&#039;&#039;RTS&#039;&#039;&#039; (&#039;&#039;&#039;R&#039;&#039;&#039;equest &#039;&#039;&#039;T&#039;&#039;&#039;o &#039;&#039;&#039;S&#039;&#039;&#039;end) und &#039;&#039;&#039;CTS&#039;&#039;&#039; (&#039;&#039;&#039;C&#039;&#039;&#039;lear &#039;&#039;&#039;T&#039;&#039;&#039;o &#039;&#039;&#039;S&#039;&#039;&#039;end). Jeder der beiden Kommunikationspartner ist verpflichtet, bevor ein Zeichen gesendet wird, den Zustand der &#039;&#039;&#039;RTS&#039;&#039;&#039; Leitung zu überprüfen. Nur wenn die Gegenstelle darauf Empfangsbereitschaft signalisiert, darf das Zeichen gesendet werden. Um der Gegenstelle zu signalisieren, daß sie zur Zeit keine Zeichen schicken soll, wird die Leitung &#039;&#039;&#039;CTS&#039;&#039;&#039; benutzt.&lt;br /&gt;
&lt;br /&gt;
===Softwarehandshake (XON/XOFF)===&lt;br /&gt;
Beim Softwarehandshake sind keine speziellen Leitungen notwendig. Statt dessen werden besondere ASCII-Zeichen benutzt, die der Gegenstelle signalisieren, daß Senden einzustellen bzw. wieder aufzunehmen.&amp;lt;br /&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;XOFF&#039;&#039;&#039; Aufforderung das Senden einzustellen&lt;br /&gt;
* &#039;&#039;&#039;XON&#039;&#039;&#039;  Gegenstelle darf wieder senden&lt;br /&gt;
&lt;br /&gt;
Nachteilig bei einem Softwarehandshake ist es, dass dadurch keine direkte binäre Datenübertragung mehr möglich ist. Von den möglichen 256 Bytewerten werden ja 2 (nämlich &#039;&#039;&#039;XON&#039;&#039;&#039; und &#039;&#039;&#039;XOFF&#039;&#039;&#039;) für besondere Zwecke benutzt und fallen daher aus.&lt;br /&gt;
&lt;br /&gt;
==Fehlersuche==&lt;br /&gt;
Erstaunlich oft wird im Forum der Hilferuf laut: &amp;quot;Meine UART funktioniert nicht, was mache ich falsch&amp;quot;. In der überwiegenden Mehrzahl der Fälle stellt sich dann heraus, daß es sich um ein Hardwareproblem handelt, wobei da wiederrum der Löwenanteil auf das Konto einer nicht korrekt eingestellten Taktrate geht: Der µC benutzt nicht einen angeschlossenen Quarz, so wie er auch im Programm eingetragen ist, sondern läuft immer noch mit dem internen RC-Takt. Daraus resultiert aber auch, daß der Baudraten Konfigurationswert falsch berechnet wird.&lt;br /&gt;
&lt;br /&gt;
Eine Checkliste zum Aufspüren solcher Fehler findet sich [[AVR_Checkliste#UART.2FUSART|hier]].&lt;br /&gt;
&lt;br /&gt;
= Analoge Ein- und Ausgabe =&lt;br /&gt;
&lt;br /&gt;
Analoge Eingangswerte werden in der Regel über den AVR Analog-Digital-Converter (AD-Wandler, ADC) eingelesen, der in vielen Typen verfügbar ist (typisch 10bit Auflösung). Durch diesen werden analogen Signale (Spannungen) in digitale Zahlenwerte gewandelt. Bei AVRs, die über keinen internen AD-Wandler verfügen (z.B. ATmega162), kann durch externe Beschaltung (R/C-Netzwerk und &amp;quot;Zeitmessung&amp;quot;) die Funktion des AD-Wandlers &amp;quot;emuliert&amp;quot; werden.&lt;br /&gt;
&lt;br /&gt;
Es existieren keine AVRs mit eingebautem Digital-Analog-Konverter (DAC). Diese Funktion muss durch externe Komponenten nachgebildet werden (z.B. PWM und &amp;quot;Glättung&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Unabhängig davon besteht natürlich immer die Möglichkeit, spezielle Bausteine zur Analog-Digital- bzw. Digital-Analog-Wandlung zu nutzen und diese über eine digitale Schnittstelle (z.b. SPI oder I2C) mit einem AVR anzusteuern.&lt;br /&gt;
&lt;br /&gt;
== AC (Analog Comparator) ==&lt;br /&gt;
&lt;br /&gt;
Der Comparator vergleicht 2 Spannungen an den Pins AIN0 und AIN1 und gibt einen Status aus welche der beiden Spannungen größer ist. AIN0 Dient dabei als Referenzspannung (Sollwert) und AIN1 als Vergleichsspannung (Istwert). Als Referenzspannung kann auch alternativ eine interne Referenzspannung ausgewählt werden.&amp;lt;BR&amp;gt;&lt;br /&gt;
&amp;lt;BR&amp;gt;&lt;br /&gt;
Liegt die Vergleichsspannung (IST) unter der der Referenzspannung (SOLL) gibt der Comperator eine logische 1 aus. Ist die Vergleichsspannung hingegen größer als die Referenzspannung wird eine logische 0 ausgegeben.&amp;lt;BR&amp;gt;&lt;br /&gt;
&amp;lt;BR&amp;gt;&lt;br /&gt;
Der Comperator arbeitet völlig autark bzw. parallel zum Prozessor. Für mobile Anwendungen empfiehlt es sich ihn abzuschalten sofern er nicht benötigt wird, da er ansonsten Strom benötigt. Der Comparator kann Interruptgesteuert abgefragt werden oder im Pollingbetrieb.&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Steuer- bzw. Statusregister ist wie folgt aufgebaut:&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ACSR (0x28) - Analog Comparator Status Register&amp;lt;BR&amp;gt;&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Bit&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 7&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 6&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 5&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 4&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 2&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Name&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ACD&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ACBG&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ACO&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ACI&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ACIE&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ACIC&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ACIS1&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ACIS0&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;R/W&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Initialwert&#039;&#039;&#039;&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; | n/a&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;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
Bit 7 ACD - Analog Comparator Disable: 0 = Comparator ein, 1 = Comparator aus. Wird dieses Bit geändert kann ein Interrupt ausgelöst werden. Soll dies vermieden werden muß das Bit 3 ACIE ggf. abgeschaltet werden.&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
Bit 6 ACBG - Analog Comparator Bandgap Select: Ermöglicht das umschalten zwischen interner und externer Referenzspannung. 1 = interne (~1,3 Volt), 0 = externe Referenzspannung (an Pin AIN0)&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
Bit 5 ACO - Analog Comparator Output: Hier wird das Ergebnis des Vergleichs angezeigt. Es liegt typischerweise nach 1-2 Taktzyklen vor. &amp;lt;BR&amp;gt;&lt;br /&gt;
Ergebnis: &amp;lt;BR&amp;gt;IST &amp;lt; SOLL --&amp;gt; 1&amp;lt;BR&amp;gt;&lt;br /&gt;
IST &amp;gt; SOLL --&amp;gt; 0&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
Bit 4 ACI - Analog Comparator Interrupt Flag: Dieses Bit wird von der Hardware gesetzt wenn ein Interruptereignis das in Bit 0 und 1 definiert ist eintritt. Dieses Bit löst noch keinen Interrupt aus! Die Interruptroutine wird nur dann ausgeführt wenn das Bit 3 ACIE gesetzt ist und global Interrupts erlaubt sind (I-Bit in SREG=1). Das Bit 4 ACI wird wieder gelöscht wenn die Interruptroutine ausgeführt wurde oder wenn manuell das Bit auf 1 gesetzt wird. Das Bit kann für Abfragen genutzt werden, steuert oder konfuguriert aber nicht den Comparator.&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
Bit 3 ACIE - Analog Comparator Interrupt Enable: Ist das Bit auf 1 gesetzt wird immer ein Interrupt ausgelöst wenn das Ereignis das in Bit 1 und 0 definiert ist eintritt.&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
Bit 2 ACIC - Analog Comparator Input Capture Enable: Wird das Bit gesetzt wird der Comparatorausgang intern mit dem Counter 1 verbunden. Es könnten damit z.b. die Anzahl der Vergleiche im Counter1 gezählt werden. Um den Comparator an den Timer1 Input Capture Interrupt zu verbinden muß im Timerregister das TICIE1 Bit auf 1 gesetzt werden. Der Trigger wird immer dann ausgelöst wenn das in Bit 1 und 0 definierte Ereignis eintritt.&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
Bit 1,0 ACIS1,ACIS0 - Analog Comparator Interrupt select: Hier wird definiert welche Ereignisse einen Interrupt auslösen sollen:&amp;lt;BR&amp;gt;&lt;br /&gt;
00 = Interrupt auslösen bei jedem Flankenwechsel&amp;lt;BR&amp;gt;&lt;br /&gt;
10 = Interrupt auslösen bei fallender Flanke&amp;lt;BR&amp;gt;&lt;br /&gt;
11 = Interrupt auslösen bei steigender Flanke&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
Werden diese Bit geändert kann ein Interrupt ausgelöst werden. Soll dies vermieden werden muß das Bit 3 gelöscht werden.&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== ADC (Analog Digital Converter) ==&lt;br /&gt;
&lt;br /&gt;
Der Analog-Digital-Konverter (ADC) wandelt analoge Signale in digitale Werte um, welche vom Controller interpretiert werden können. Einige AVR-Typen haben bereits einen mehrkanaligen Analog-Digital-Konverter eingebaut. Die Genauigkeit, mit welcher ein analoges Signal aufgelöst werden kann, wird durch die Auflösung des ADC in Anzahl Bits angegeben, man hört bzw. liest jeweils von 8-Bit-ADC oder 10-Bit-ADC oder noch höher. ADCs die in AVRs enthalten sind haben zur Zeit eine maximale Auflösung von 10-Bit.&lt;br /&gt;
&lt;br /&gt;
Ein ADC mit 8 Bit Auflösung kann somit das analoge Signal mit einer Genauigkeit von 1/256 des Maximalwertes darstellen. Wenn wir nun mal annehmen, wir hätten eine Spannung zwischen 0 und 5 Volt und eine Auflösung von 3 Bit, dann könnten&lt;br /&gt;
die Werte 0V, 0.625V, 1.25, 1.875V, 2.5V, 3.125V, 3.75, 4.375, 5V&lt;br /&gt;
daherkommen, siehe dazu folgende Tabelle:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div align=&amp;quot;center&amp;quot;&amp;gt;&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;Eingangsspannung am ADC&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;Entsprechender Messwert&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0...&amp;lt;0.625V&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0.625...&amp;lt;1.25V&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1.25...&amp;lt;1.875V&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 2&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1.875...&amp;lt;2.5V&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 2.5...&amp;lt;3.125V&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 4&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3.125...&amp;lt;3.75V&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 5&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3.75...&amp;lt;4.375V&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 6&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 4.375...5V&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 7&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Angaben sind natürlich nur ungefähr. Je höher nun die Auflösung des Analog-Digital-Konverters ist, also je mehr Bits er hat, um so genauer kann der Wert erfasst werden.&lt;br /&gt;
&lt;br /&gt;
=== Der interne ADC im AVR ===&lt;br /&gt;
&lt;br /&gt;
Wenn es einmal etwas genauer sein soll, dann müssen wir auf einen AVR mit eingebautem Analog-Digital-Wandler (ADC) zurückgreifen, die über mehrere Kanäle verfügen. Kanäle heißt in diesem Zusammenhang, dass zwar bis zu zehn analoge Eingänge am AVR verfügbar sind, aber nur ein &amp;quot;echter&amp;quot; Analog-Digital-Wandler zur Verfügung steht, vor der eigentlichen Messung ist also einzustellen, welcher Kanal (&amp;quot;Pin&amp;quot;) mit dem Wandler verbunden und gemessen wird.&lt;br /&gt;
&lt;br /&gt;
Die Umwandlung innerhalb des AVR basiert auf der schrittweisen Näherung. Beim AVR müssen die Pins &#039;&#039;&#039;AGND&#039;&#039;&#039; und &#039;&#039;&#039;AVCC&#039;&#039;&#039; beschaltet werden. Für genaue Messungen sollte AVCC über ein L-C Netzwerk mit VCC verbunden werden, um Spannungsspitzen und -einbrüche vom Analog-Digital-Wandler fernzuhalten. Im Datenblatt findet sich dazu eine Schaltung, die 10uH und 100nF vorsieht.&lt;br /&gt;
&lt;br /&gt;
Das Ergebnis der Analog-Digital-Wandlung wird auf eine Referenzspannung bezogen. Aktuelle AVRs bieten drei Möglichkeiten zur Wahl dieser Spannung:&lt;br /&gt;
&lt;br /&gt;
* Eine externe Referenzspannung von maximal &#039;&#039;&#039;Vcc&#039;&#039;&#039; am Anschlusspin &#039;&#039;&#039;AREF&#039;&#039;&#039;. Die minimale (externe) Referenzspannung darf jedoch nicht beliebig niedrig sein, vgl. dazu das (aktuellste) Datenblatt des verwendeten Controllers. &lt;br /&gt;
&lt;br /&gt;
* Verfügt der AVR über eine interne Referenzspannung, kann diese genutzt werden. Alle aktuellen AVRs mit internem AD-Wandler sollten damit ausgestattet sein (vgl. Datenblatt: 2,56V oder 1,1V je nach Typ). Das Datenblatt gibt auch über die Genauigkeit dieser Spannung Auskunft.&lt;br /&gt;
&lt;br /&gt;
* Die &#039;&#039;&#039;interne&#039;&#039;&#039; Referenzspannung wird auf &#039;&#039;&#039;Vcc&#039;&#039;&#039; bezogen, eine externe Referenzspannung auf &#039;&#039;&#039;GND (Masse)&#039;&#039;&#039;. Davon unabhängig werden digitalisierte Spannungen &#039;&#039;&#039;immer&#039;&#039;&#039; auf GND bezogen. Beim ATMEGA8 z.B. ist der Pin AREF über 32kOhm mit GND verbunden, d.h. man muss diese doch extrem niedrige Eingangsimpedanz mit in die Berechnung für einen Spannungsteiler einbeziehen, bzw. kann diesen Widerstand als R2 gleich mit benutzen. Formel für Spannungsteiler: Udiv = U / ((R1 + R2) / R2)&lt;br /&gt;
&lt;br /&gt;
Bei Nutzung von Vcc oder der internen Referenz wird empfohlen, einen Kondensator zwischen dem AREF-Pin und GND anzuordnen. Die Festlegung, welche Spannungsreferenz genutzt wird, erfolgt z.B. beim ATmega16 mit den Bits REFS1/REFS0 im ADMUX-Register. Die zu messende Spannung muss im Bereich zwischen &#039;&#039;&#039;AGND&#039;&#039;&#039; und &#039;&#039;&#039;AREF&#039;&#039;&#039; (egal ob intern oder extern) liegen. &lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;&#039;ADC&#039;&#039;&#039; kann in zwei verschiedenen Betriebsarten verwendet werden:&lt;br /&gt;
&lt;br /&gt;
; Einfache Wandlung (Single Conversion) : In dieser Betriebsart wird der Wandler bei Bedarf vom Programm angestoßen für jeweils eine Messung.&lt;br /&gt;
&lt;br /&gt;
; Frei laufend (Free Running) : In dieser Betriebsart erfasst der Wandler permanent die anliegende Spannung und schreibt diese in das &#039;&#039;&#039;ADC Data Register&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==== Die Register des ADC ====&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;&#039;ADC&#039;&#039;&#039; verfügt über eigene Register. Im Folgenden die Registerbeschreibung eines  ATMega16, welcher über 8 ADC-Kanäle verfügt. Die Register unterscheiden sich jedoch nicht erheblich von denen anderer AVRs (vgl. Datenblatt).&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;ADCSRA&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;ADC&#039;&#039;&#039; &#039;&#039;&#039;C&#039;&#039;&#039;ontrol and &#039;&#039;&#039;S&#039;&#039;&#039;tatus &#039;&#039;&#039;R&#039;&#039;&#039;egister A.&amp;lt;br /&amp;gt;&lt;br /&gt;
In diesem Register stellen wir ein, wie wir den &#039;&#039;&#039;ADC&#039;&#039;&#039; verwenden möchten.&amp;lt;br /&amp;gt;&lt;br /&gt;
Das Register ist wie folgt aufgebaut:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Bit&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 7&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 6&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 5&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 4&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 2&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Name&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ADEN&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ADSC&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ADFR&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ADIF&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ADIE&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ADPS2&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ADPS1&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ADPS0&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;R/W&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Initialwert&#039;&#039;&#039;&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;
| 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;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ADEN&#039;&#039;&#039; (&#039;&#039;&#039;AD&#039;&#039;&#039;C &#039;&#039;&#039;En&#039;&#039;&#039;able)&lt;br /&gt;
:Dieses Bit muss gesetzt werden, um den &#039;&#039;&#039; ADC&#039;&#039;&#039; überhaupt zu aktivieren. Wenn das Bit nicht gesetzt ist, können die Pins wie normale I/O-Pins verwendet werden.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ADSC&#039;&#039;&#039; (&#039;&#039;&#039;AD&#039;&#039;&#039;C &#039;&#039;&#039;S&#039;&#039;&#039;tart &#039;&#039;&#039;C&#039;&#039;&#039;onversion)&lt;br /&gt;
:Mit diesem Bit wird ein Messvorgang gestartet. In der frei laufenden Betriebsart muss das Bit gesetzt werden, um die kontinuierliche Messung zu aktivieren.&lt;br /&gt;
:Wenn das Bit nach dem Setzen des &#039;&#039;&#039;ADEN&#039;&#039;&#039;-Bits zum ersten Mal gesetzt wird, führt der Controller zuerst eine zusätzliche Wandlung und erst dann die eigentliche Wandlung aus. Diese zusätzliche Wandlung wird zu Initialisierungszwecken durchgeführt.&lt;br /&gt;
:Das Bit bleibt nun so lange auf 1, bis die Umwandlung abgeschlossen ist, im Initialisierungsfall entsprechend bis die zweite Umwandlung erfolgt ist und geht danach auf 0.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ADFR&#039;&#039;&#039; (&#039;&#039;&#039;AD&#039;&#039;&#039;C &#039;&#039;&#039;F&#039;&#039;&#039;ree &#039;&#039;&#039;R&#039;&#039;&#039;un select)&lt;br /&gt;
:Mit diesem Bit wird die Betriebsart eingestellt.&lt;br /&gt;
:Ist das Bit auf 1 gesetzt arbeitet der ADC im Freerunning Modus. Dabei wird das Datenregister permanent aktualisiert. Ist das Bit hingegen auf 0 gesetzt macht der ADC nur eine Single Conversion. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ADIF&#039;&#039;&#039; (&#039;&#039;&#039;AD&#039;&#039;&#039;C &#039;&#039;&#039;I&#039;&#039;&#039;nterrupt &#039;&#039;&#039;F&#039;&#039;&#039;lag)&lt;br /&gt;
:Dieses Bit wird vom &#039;&#039;&#039; ADC&#039;&#039;&#039; gesetzt, sobald eine Umwandlung erfolgt ist und das &#039;&#039;&#039;ADC Data Register&#039;&#039;&#039; aktualisiert wurde. Das Bit wird bei lesendem Zugriff auf &#039;&#039;&#039;ADC(L,H)&#039;&#039;&#039; automatisch (d.h. durch die Hardware) gelöscht.&lt;br /&gt;
:Wenn das &#039;&#039;&#039;ADIE&#039;&#039;&#039; Bit sowie das &#039;&#039;&#039;I-Bit&#039;&#039;&#039; im AVR &#039;&#039;&#039;Statusregister&#039;&#039;&#039; gesetzt ist, wird der &#039;&#039;&#039;ADC Interrupt&#039;&#039;&#039; ausgelöst und die Interrupt-Behandlungsroutine aufgerufen.&lt;br /&gt;
:Das Bit wird automatisch gelöscht, wenn die Interrupt-Behandlungsroutine aufgerufen wird. Es kann jedoch auch gelöscht werden, indem eine logische 1 in das Register geschrieben wird.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ADIE&#039;&#039;&#039; (&#039;&#039;&#039;AD&#039;&#039;&#039;C &#039;&#039;&#039;I&#039;&#039;&#039;nterrupt &#039;&#039;&#039;E&#039;&#039;&#039;nable)&lt;br /&gt;
:Wenn dieses Bit gesetzt ist und ebenso das &#039;&#039;&#039; I-Bit&#039;&#039;&#039; im Statusregister &#039;&#039;&#039;SREG&#039;&#039;&#039;, dann wird der &#039;&#039;&#039; ADC-Interrupt&#039;&#039;&#039; aktiviert.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ADPS2...ADPS0&#039;&#039;&#039; (&#039;&#039;&#039;AD&#039;&#039;&#039;C &#039;&#039;&#039;P&#039;&#039;&#039;rescaler &#039;&#039;&#039;S&#039;&#039;&#039;elect Bits)&lt;br /&gt;
:Diese Bits bestimmen den Teilungsfaktor zwischen der Taktfrequenz und dem Eingangstakt des &#039;&#039;&#039;ADC&#039;&#039;&#039;.&lt;br /&gt;
:Der &#039;&#039;&#039;ADC&#039;&#039;&#039; benötigt einen eigenen Takt, welchen er sich selber aus der CPU-Taktfreqenz erzeugt. Der &#039;&#039;&#039;ADC&#039;&#039;&#039;-Takt sollte zwischen 50 und 200kHz sein.&lt;br /&gt;
:Der Vorteiler muss also so eingestellt werden, dass die CPU-Taktfrequenz dividiert durch den Teilungsfaktor einen Wert zwischen 50-200kHz ergibt.&lt;br /&gt;
:Bei einer CPU-Taktfrequenz von 4MHz beispielsweise rechnen wir&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;&lt;br /&gt;
\begin{matrix}&lt;br /&gt;
TF_{min}=\frac{CLK}{200\,\mathrm{kHz}}=\frac{4000000}{200000}=\mathbf{20}&lt;br /&gt;
\\&lt;br /&gt;
\\&lt;br /&gt;
TF_{max}=\frac{CLK}{50\,\mathrm{kHz}}=\frac{4000000}{50000}=\mathbf{80}&lt;br /&gt;
\end{matrix}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Somit kann hier der Teilungsfaktor 32 oder 64 verwendet werden. Im Interesse der schnelleren Wandlungszeit werden wir hier den Faktor 32 einstellen.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&lt;br /&gt;
{| style=&amp;quot;&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ADPS2&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ADPS1&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ADPS0&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;Teilungsfaktor&#039;&#039;&#039;&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;
| align=&amp;quot;center&amp;quot; | 2&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;
| align=&amp;quot;center&amp;quot; | 2&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;
| align=&amp;quot;center&amp;quot; | 4&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;
| align=&amp;quot;center&amp;quot; | 8&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;
| align=&amp;quot;center&amp;quot; | 16&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;
| align=&amp;quot;center&amp;quot; | 32&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;
| align=&amp;quot;center&amp;quot; | 64&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;
| align=&amp;quot;center&amp;quot; | 128&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;ADCL&#039;&#039;&#039;&amp;lt;br /&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;ADCH&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;ADC &#039;&#039;&#039; Data Register&amp;lt;br /&amp;gt;&lt;br /&gt;
Wenn eine Umwandlung abgeschlossen ist, befindet sich der gemessene Wert in&lt;br /&gt;
diesen beiden Registern. Von &#039;&#039;&#039;ADCH&#039;&#039;&#039; werden nur die beiden niederwertigsten Bits verwendet. Es müssen immer beide Register ausgelesen werden, und zwar immer &#039;&#039;&#039;in der Reihenfolge: ADCL, ADCH&#039;&#039;&#039;. &lt;br /&gt;
Der effektive Messwert ergibt sich dann zu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
x = ADCL;       // mit uint16_t x&lt;br /&gt;
x += (ADCH&amp;lt;&amp;lt;8); // in zwei Zeilen (LSB/MSB-Reihenfolge und&lt;br /&gt;
                // C-Operatorpriorität sichergestellt)&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
oder &lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
x = ADCW; // je nach AVR auch x = ADC (siehe avr/ioxxx.h)&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;ADMUX&amp;amp;nbsp;&amp;amp;nbsp;&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;AD&#039;&#039;&#039;C &#039;&#039;&#039;Mu&#039;&#039;&#039;ltiple&#039;&#039;&#039;x&#039;&#039;&#039;er Select Register&amp;lt;br /&amp;gt;&lt;br /&gt;
Mit diesem Register wird der zu messende Kanal ausgewählt. Beim 90S8535&lt;br /&gt;
kann jeder Pin von Port A als &#039;&#039;&#039;ADC&#039;&#039;&#039;-Eingang verwendet werden (=8 Kanäle).&amp;lt;br /&amp;gt;&lt;br /&gt;
Das Register ist wie folgt aufgebaut:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Bit&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 7&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 6&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 5&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 4&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 2&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Name&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;REFS1&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;REFS0&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ADLAR&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;MUX4&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;MUX3&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;MUX2&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;MUX1&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;MUX0&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;R/W&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Initialwert&#039;&#039;&#039;&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;
| 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;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;REFS1...REFS0&#039;&#039;&#039; (&#039;&#039;&#039;Ref&#039;&#039;&#039;erence&#039;&#039;&#039;S&#039;&#039;&#039;election Bits)&lt;br /&gt;
:Mit diesen Bits kann die Referenzspannung eingestellt werden:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&lt;br /&gt;
{| style=&amp;quot;&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;REFS1&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;REFS0&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;Referenzspanung&#039;&#039;&#039;&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; | Externes AREF&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; | AVCC als Referenz&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; | Reserviert&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; | Interne 2,56 Volt&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ADLAR&#039;&#039;&#039; (&#039;&#039;&#039;ADC &#039;&#039;&#039; &#039;&#039;&#039;L&#039;&#039;&#039;eft &#039;&#039;&#039;A&#039;&#039;&#039;djust &#039;&#039;&#039;R&#039;&#039;&#039;esult)&lt;br /&gt;
:Das ADLAR Bit verändert das Aussehen des Ergebnisses der AD-Wandlung. Bei einer logischen 1 wird das Ergebnis linksbündig ausgegeben, bei einer 0 rechtsündig. Eine Änderung in diesem Bit beeinflusst das Ergebnis sofort, ganz egal ob bereits eine Wandlung läuft.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;MUX4...MUX0&#039;&#039;&#039;&lt;br /&gt;
:Mit diesen 5 Bits wird der zu messende Kanal bestimmt. Wenn man einen einfachen 1-kanaligen ADC verwendet wird einfach die entsprechende Pinnummer des Ports in die Bits 0...2 eingeschrieben.&lt;br /&gt;
:Wenn das Register beschrieben wird, während dem eine Umwandlung läuft, so wird zuerst die aktuelle Umwandlung auf dem bisherigen Kanal beendet. Dies ist vor allem beim frei laufenden Betrieb zu berücksichtigen.&lt;br /&gt;
&lt;br /&gt;
:Eine Empfehlung ist deswegen diese, dass der frei laufende Betrieb nur bei einem einzelnen zu verwendenden Analogeingang verwendet werden sollte, wenn man sich Probleme bei der Umschalterei ersparen will.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Aktivieren des ADC ====&lt;br /&gt;
&lt;br /&gt;
Um den &#039;&#039;&#039; ADC&#039;&#039;&#039; zu aktivieren, müssen wir das &#039;&#039;&#039;ADEN&#039;&#039;&#039;-Bit im &#039;&#039;&#039;ADCSR&#039;&#039;&#039;-Register&lt;br /&gt;
setzen. Im gleichen Schritt legen wir auch gleich die Betriebsart fest. &lt;br /&gt;
&lt;br /&gt;
Ein kleines Beispiel für den &amp;quot;single conversion&amp;quot;-Mode bei einem ATmega169 und Nutzung der internen Referenzspannung (beim &#039;169 1,1V bei anderen AVRs auch 2,56V). D.h. das Eingangssignal darf diese Spannung nicht überschreiten, gegebenenfalls mit Spannungsteiler einstellen. Ergebnis der Routine ist der ADC-Wert, also 0 für 0-Volt und 1023 für V_ref-Volt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
uint16_t ReadChannel(uint8_t mux)&lt;br /&gt;
{&lt;br /&gt;
  uint8_t i;&lt;br /&gt;
  uint16_t result;&lt;br /&gt;
&lt;br /&gt;
  ADMUX = mux;                      // Kanal waehlen&lt;br /&gt;
  ADMUX |= (1&amp;lt;&amp;lt;REFS1) | (1&amp;lt;&amp;lt;REFS0); // interne Referenzspannung nutzen&lt;br /&gt;
&lt;br /&gt;
  ADCSRA = (1&amp;lt;&amp;lt;ADEN) | (1&amp;lt;&amp;lt;ADPS1) | (1&amp;lt;&amp;lt;ADPS0);    // Frequenzvorteiler &lt;br /&gt;
                               // setzen auf 8 (1) und ADC aktivieren (1)&lt;br /&gt;
&lt;br /&gt;
  /* nach Aktivieren des ADC wird ein &amp;quot;Dummy-Readout&amp;quot; empfohlen, man liest&lt;br /&gt;
     also einen Wert und verwirft diesen, um den ADC &amp;quot;warmlaufen zu lassen&amp;quot; */&lt;br /&gt;
  ADCSRA |= (1&amp;lt;&amp;lt;ADSC);              // eine ADC-Wandlung &lt;br /&gt;
  while ( ADCSRA &amp;amp; (1&amp;lt;&amp;lt;ADSC) ) {&lt;br /&gt;
     ;     // auf Abschluss der Konvertierung warten &lt;br /&gt;
  }&lt;br /&gt;
  result = ADCW;  // ADCW muss einmal gelesen werden,&lt;br /&gt;
                  // sonst wird Ergebnis der nächsten Wandlung&lt;br /&gt;
                  // nicht übernommen.&lt;br /&gt;
&lt;br /&gt;
  /* Eigentliche Messung - Mittelwert aus 4 aufeinanderfolgenden Wandlungen */&lt;br /&gt;
  result = 0; &lt;br /&gt;
  for( i=0; i&amp;lt;4; i++ )&lt;br /&gt;
  {&lt;br /&gt;
    ADCSRA |= (1&amp;lt;&amp;lt;ADSC);            // eine Wandlung &amp;quot;single conversion&amp;quot;&lt;br /&gt;
    while ( ADCSRA &amp;amp; (1&amp;lt;&amp;lt;ADSC) ) {&lt;br /&gt;
      ;   // auf Abschluss der Konvertierung warten&lt;br /&gt;
    }&lt;br /&gt;
    result += ADCW;		    // Wandlungsergebnisse aufaddieren&lt;br /&gt;
  }&lt;br /&gt;
  ADCSRA &amp;amp;= ~(1&amp;lt;&amp;lt;ADEN);             // ADC deaktivieren (2)&lt;br /&gt;
&lt;br /&gt;
  result /= 4;                     // Summe durch vier teilen = arithm. Mittelwert&lt;br /&gt;
&lt;br /&gt;
  return result;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
/* Beispielaufrufe: */&lt;br /&gt;
&lt;br /&gt;
void foo(void)&lt;br /&gt;
{&lt;br /&gt;
  uint16_t adcval;&lt;br /&gt;
&lt;br /&gt;
  adcval = ReadChannel(0); /* MUX-Bits auf 0b0000 -&amp;gt; Channel 0 */&lt;br /&gt;
  ...&lt;br /&gt;
  adcval = ReadChannel(2); /* MUX-Bits auf 0b0010 -&amp;gt; Channel 2 */&lt;br /&gt;
  ...&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im Beispiel wird bei jedem Aufruf der ADC aktiviert und nach der Wandlung wieder abgeschaltet, das spart Strom. Will man dies nicht, verschiebt man die mit (1) gekennzeichneten Zeilen in eine Funktion adc_init() o.ä. und löscht die mit (2) markierten Zeilen. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- &lt;br /&gt;
Das Löschen des ADIF-Flags sollte, &#039;&#039;&#039;entgegen&#039;&#039;&#039; der [http://www.nongnu.org/avr-libc/user-manual/FAQ.html#faq_intbits FAQ], mit&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  ADCSRA |= (1&amp;lt;&amp;lt;ADIF);&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
erfolgen. Die Methode in der FAQ eignet sich nur für Register in denen &#039;&#039;&#039;nur&#039;&#039;&#039; Interrupt-Flags stehen.&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Analog-Digital-Wandlung ohne internen ADC ===&lt;br /&gt;
&lt;br /&gt;
==== Messen eines Widerstandes ====&lt;br /&gt;
&lt;br /&gt;
Analoge Werte lassen sich ohne Analog-Digital-Wandler auch indirekt ermitteln. Im Folgenden wird die Messung des an einem Potentiometer eingestellten Widerstands anhand der Ladekurve eines Kondensators erläutert. Bei dieser Methode wird nur ein Portpin benötigt, ein Analog-Digital-Wandler oder Analog-Comparator ist nicht erforderlich. Es wird dazu ein Kondensator und der Widerstand (das Potentiometer) in Reihe zwischen Vorsorgungsspannung und Masse/GND geschaltet (sogen. RC-Netzwerk). Zusätzlich wird eine Verbindung der Leitung zwischen Kondensator und Potentiometer zu einem Portpin des Controllers hergestellt. Die folgende Abbildung verdeutlicht die erforderliche Schaltung. &lt;br /&gt;
&lt;br /&gt;
[[Image:Poti.gif]]&lt;br /&gt;
&lt;br /&gt;
Wird der Portpin des Controllers auf Ausgang konfiguriert (im Beispiel &#039;&#039;DDRD&amp;amp;nbsp;|=&amp;amp;nbsp;(1&amp;lt;&amp;lt;PD2)&#039;&#039;) und dieser Ausgang auf Logisch 1 (&amp;quot;High&amp;quot;, &#039;&#039;PORTD&amp;amp;nbsp;|=&amp;amp;nbsp;(1&amp;lt;&amp;lt;PD2)&#039;&#039;) geschaltet, liegt an beiden &amp;quot;Platten&amp;quot; des Kondensators das gleiche Potential &#039;&#039;&#039;VCC&#039;&#039;&#039; an und der Kondensator somit entladen. (Klingt komisch, mit &#039;&#039;&#039; Vcc&#039;&#039;&#039; entladen, ist aber so, da an beiden Seiten des Kondensators das gleiche Potential anliegt und somit eine Potentialdifferenz von 0V besteht =&amp;gt; Kondensator ist entladen).&lt;br /&gt;
&lt;br /&gt;
Nach einer gewissen Zeit ist der Kondensator entladen und der Portpin wird als Eingang konfiguriert (&#039;&#039;DDRD&amp;amp;nbsp;&amp;amp;=&amp;amp;nbsp;~(1&amp;lt;&amp;lt;PD2); PORTD&amp;amp;nbsp;&amp;amp;=&amp;amp;nbsp;~(1&amp;lt;&amp;lt;PD2)&#039;&#039;), wodurch dieser hochohmig wird. Der Status des Eingangspin (in PIND) ist Logisch 1 (High). Der Kondensator lädt sich jetzt über das Poti auf, dabei steigt der Spannungsabfall über dem Kondensator und derjenige über dem Poti sinkt. Fällt nun der Spannungsabfall über dem Poti unter die Thresholdspannung des Eingangspins (2/5 Vcc, also ca. 2V), wird das Eingangssignal als LOW erkannt (Bit in PIND wird 0). Die Zeitspanne zwischen der Umschaltung von Entladung auf Aufladung und dem Wechsel des Eingangssignals von High auf Low ist ein Maß für den am Potentiometer eingestellten Widerstand. Zur Zeitmessung kann einer der im Controller vorhandenen Timer genutzt werden. Der 220 Ohm Widerstand dient dem Schutz des Controllers. Es würde sonst bei Maximaleinstellung des Potentionmeters (hier 0 Ohm) ein zu hoher Strom fließen, der die Ausgangsstufe des Controllers zerstört. &lt;br /&gt;
&lt;br /&gt;
Mit einem weiteren Eingangspin und ein wenig Software können wir auch eine Kalibrierung realisieren, um den Messwert in einen vernünftigen Bereich (z.B: 0...100 % oder so) umzurechnen. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- Link 404 =&amp;gt; auskommentiert, mthomas 9.2.2008 &lt;br /&gt;
Ein Beispielprogramm findet sich auf [http://www.mypage.bluewin.ch/ch_schifferle/ Christian Schifferles Web-Seite] im Archiv &#039;&#039;ATMEL.ZIP&#039;&#039;, welches unter den Titel &#039;&#039;Tutorial &amp;quot;Programmieren mit C für Atmel Mikrocontroller&#039;&#039; heruntergeladen werden kann. --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== ADC über Komparator ====&lt;br /&gt;
&lt;br /&gt;
Es gibt einen weiteren Weg, eine analoge Spannung mit Hilfe des&lt;br /&gt;
Komparators, welcher in fast jedem AVR integriert ist, zu messen. Siehe dazu&lt;br /&gt;
auch die Application Note AVR400 von Atmel.&lt;br /&gt;
&lt;br /&gt;
Dabei wird das zu messende Signal auf den invertierenden Eingang&lt;br /&gt;
des Komparators geführt. Zusätzlich wird ein Referenzsignal an den nicht&lt;br /&gt;
invertierenden Eingang des Komparators angeschlossen. Das Referenzsignal wird&lt;br /&gt;
hier auch wieder über ein RC-Glied erzeugt, allerdings mit festen Werten für R&lt;br /&gt;
und C.&lt;br /&gt;
&lt;br /&gt;
[[Image:ADC ueber Komparator.gif]]&lt;br /&gt;
&lt;br /&gt;
Das Prinzip der Messung ist nun dem vorhergehenden recht&lt;br /&gt;
ähnlich. Durch Anlegen eines LOW-Pegels an Pin 2 wird der Kondensator zuerst&lt;br /&gt;
einmal entladen. Auch hier muss darauf geachtet werden, dass der Entladevorgang&lt;br /&gt;
genügend lang dauert.&amp;lt;br /&amp;gt;&lt;br /&gt;
Nun wird Pin 2 auf HIGH gelegt. Der Kondensator wird geladen. Wenn die Spannung&lt;br /&gt;
über dem Kondensator die am Eingangspin anliegende Spannung erreicht hat&lt;br /&gt;
schaltet der Komparator durch. Die Zeit, welche benötigt wird, um den&lt;br /&gt;
Kondensator zu laden kann nun auch wieder als Maß für die Spannung an Pin 1&lt;br /&gt;
herangezogen werden.&lt;br /&gt;
&lt;br /&gt;
Ich habe es mir gespart, diese Schaltung auch aufzubauen und&lt;br /&gt;
zwar aus mehreren Gründen:&lt;br /&gt;
&lt;br /&gt;
# 3 Pins notwendig.&lt;br /&gt;
# Genauigkeit vergleichbar mit einfacherer Lösung.&lt;br /&gt;
# War einfach zu faul.&lt;br /&gt;
&lt;br /&gt;
Der Vorteil dieser Schaltung liegt allerdings darin, dass damit&lt;br /&gt;
direkt Spannungen gemessen werden können.&lt;br /&gt;
&lt;br /&gt;
== DAC (Digital Analog Converter) ==&lt;br /&gt;
&lt;br /&gt;
Mit Hilfe eines Digital-Analog-Konverters (&#039;&#039;&#039;DAC&#039;&#039;&#039;) können wir nun auch Analogsignale ausgeben. Es gibt hier mehrere Verfahren. &amp;lt;!-- Wenn wir beim ADC die Möglichkeit haben, mit externen Komponenten zu operieren, müssen wir bei der DAC-Wandlung mit dem auskommen, was der Controller selber zu bieten hat. --mt: hmm, richtig? verstaendlich? redundant? --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== DAC über mehrere digitale Ausgänge ===&lt;br /&gt;
&lt;br /&gt;
Wenn wir an den Ausgängen des Controllers ein entsprechendes&lt;br /&gt;
Widerstandsnetzwerk aufbauen haben wir die Möglichkeit, durch die Ansteuerung&lt;br /&gt;
der Ausgänge über den Widerständen einen Addierer aufzubauen, mit dessen&lt;br /&gt;
Hilfe wir eine dem Zahlenwert proportionale Spannung erzeugen können. Das&lt;br /&gt;
Schaltbild dazu kann etwa so aussehen:&lt;br /&gt;
&lt;br /&gt;
[[Image:DAC R2R.gif]]&lt;br /&gt;
&lt;br /&gt;
Es sollten selbstverständlich möglichst genaue Widerstände verwendet&lt;br /&gt;
werden, also nicht unbedingt solche mit einer Toleranz von 10% oder mehr.&lt;br /&gt;
Weiterhin empfiehlt es sich, je nach Anwendung den Ausgangsstrom über einen&lt;br /&gt;
Operationsverstärker zu verstärken.&lt;br /&gt;
&lt;br /&gt;
=== PWM (Pulsweitenmodulation) ===&lt;br /&gt;
&lt;br /&gt;
Wir kommen nun zu einem Thema, welches in aller Munde ist, aber viele&lt;br /&gt;
Anwender verstehen nicht ganz, wie &#039;&#039;&#039;[[PWM]]&#039;&#039;&#039; eigentlich funktioniert.&lt;br /&gt;
&lt;br /&gt;
Wie wir alle wissen, ist ein Mikrocontroller ein rein digitales Bauteil.&lt;br /&gt;
Definieren wir einen Pin als Ausgang, dann können wir diesen Ausgang entweder&lt;br /&gt;
auf HIGH setzen, worauf am Ausgang die Versorgungsspannung &#039;&#039;&#039; Vcc&#039;&#039;&#039; anliegt, oder aber wir setzen den Ausgang auf LOW, wonach dann &#039;&#039;&#039; 0V&#039;&#039;&#039; am Ausgang liegt. Was passiert aber nun, wenn wir periodisch mit einer festen Frequenz zwischen HIGH und LOW umschalten? - Richtig, wir erhalten eine Rechteckspannung, wie die folgende Abbildung zeigt:&lt;br /&gt;
&lt;br /&gt;
[[Image:PWM Theorie 1.gif]]&lt;br /&gt;
&lt;br /&gt;
Diese Rechteckspannung hat nun einen arithmetischen Mittelwert, &lt;br /&gt;
der je nach Pulsbreite kleiner oder größer ist.&lt;br /&gt;
&lt;br /&gt;
[[Image:PWM Theorie 2.gif]]&lt;br /&gt;
&lt;br /&gt;
Wenn wir nun diese pulsierende Ausgangsspannung noch über ein RC-Glied filtern/&amp;quot;glätten&amp;quot;, dann haben wir schon eine entsprechende Gleichspannung erzeugt.&lt;br /&gt;
&lt;br /&gt;
Mit den AVRs können wir direkt &#039;&#039;&#039;PWM&#039;&#039;&#039;-Signale erzeugen. &lt;br /&gt;
Dazu dient der 16-Bit Zähler, welcher im sogenannten &#039;&#039;&#039;PWM&#039;&#039;&#039;-Modus betrieben werden kann.&lt;br /&gt;
&lt;br /&gt;
Hinweis:&lt;br /&gt;
:In den folgenden Überlegungen wird als Controller der 90S2313 vorausgesetzt. Die Theorie ist bei anderen AVR-Controllern vergleichbar, die Pinbelegung allerdings nicht unbedingt, weshalb ein Blick ins entsprechende Datenblatt dringend angeraten wird.&lt;br /&gt;
&lt;br /&gt;
Um den &#039;&#039;&#039;PWM&#039;&#039;&#039;-Modus zu aktivieren, müssen im Timer/Counter1 Control&lt;br /&gt;
Register A &#039;&#039;&#039;TCCR1A&#039;&#039;&#039; die Pulsweiten-Modulatorbits &#039;&#039;&#039;PWM10&#039;&#039;&#039; bzw. &#039;&#039;&#039;PWM11&#039;&#039;&#039; entsprechend nachfolgender Tabelle gesetzt werden:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;PWM11&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;PWM10&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Bedeutung&#039;&#039;&#039;&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;
| PWM-Modus des Timers ist nicht aktiv.&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;
| 8-Bit PWM.&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;
| 9-Bit PWM.&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;
| 10-Bit PWM.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Der Timer/Counter zählt nun permanent von 0 bis zur Obergrenze&lt;br /&gt;
und wieder zurück, er wird also als sogenannter Auf-/Ab Zähler betrieben. &lt;br /&gt;
Die Obergrenze hängt davon ab, ob wir mit 8, 9 oder 10-Bit PWM arbeiten wollen:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;Auflösung&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;Obergrenze&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Frequenz&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 8&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 255&lt;br /&gt;
| f&amp;lt;sub&amp;gt;TC1&amp;lt;/sub&amp;gt; / 510&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 9&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 511&lt;br /&gt;
| f&amp;lt;sub&amp;gt;TC1&amp;lt;/sub&amp;gt; / 1022&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 10&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1023&lt;br /&gt;
| f&amp;lt;sub&amp;gt;TC1&amp;lt;/sub&amp;gt; / 2046&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Zusätzlich muss mit den Bits &#039;&#039;&#039;COM1A1&#039;&#039;&#039; und &#039;&#039;&#039;COM1A0&#039;&#039;&#039; desselben&lt;br /&gt;
Registers die gewünschte Ausgabeart des Signals definiert werden:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;COM1A1&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;COM1A0&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Bedeutung&#039;&#039;&#039;&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;
| Keine Wirkung, Pin wird nicht geschaltet.&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;
| Keine Wirkung, Pin wird nicht geschaltet.&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;
| Nicht invertierende PWM.&amp;lt;br /&amp;gt;&lt;br /&gt;
Der Ausgangspin wird gelöscht beim Hochzählen und gesetzt beim&lt;br /&gt;
Herunterzählen.&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;
| Invertierende PWM.&amp;lt;br /&amp;gt;&lt;br /&gt;
Der Ausgangspin wird gelöscht beim Herunterzählen und gesetzt beim&lt;br /&gt;
Hochzählen.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Der entsprechende Befehl, um beispielsweise den Timer/Counter als&lt;br /&gt;
nicht invertierenden 10-Bit PWM zu verwenden, heißt dann:&lt;br /&gt;
&lt;br /&gt;
alte Schreibweise (PWMxx wird nicht mehr akzeptiert)&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
TCCR1A = (1&amp;lt;&amp;lt;PWM11)|(1&amp;lt;&amp;lt;PWM10)|(1&amp;lt;&amp;lt;COM1A1);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
neue Schreibweise&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
TCCR1A = (1&amp;lt;&amp;lt;WGM11)|(1&amp;lt;&amp;lt;WGM10)|(1&amp;lt;&amp;lt;COM1A1);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Damit der Timer/Counter überhaupt läuft, müssen wir im Control&lt;br /&gt;
Register B &#039;&#039;&#039;TCCR1B&#039;&#039;&#039; noch den gewünschten Takt (Vorteiler) einstellen und&lt;br /&gt;
somit auch die Frequenz des &#039;&#039;&#039;PWM&#039;&#039;&#039;-Signals bestimmen.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;CS12&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;CS11&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;CS10&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Bedeutung&#039;&#039;&#039;&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;
| Stop. Der Timer/Counter wird gestoppt.&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;
| CK&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;
| CK / 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;
| CK / 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;
| CK / 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;
| CK / 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;
| Externer Pin 1, negative 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;
| Externer Pin 1, positive Flanke&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Also um einen Takt von CK / 1024 zu generieren, verwenden wir&lt;br /&gt;
folgenden Befehl:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
TCCR1B = (1&amp;lt;&amp;lt;CS12) | (1&amp;lt;&amp;lt;CS10);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jetzt muss nur noch der Vergleichswert festgelegt werden. Diesen&lt;br /&gt;
schreiben wir in das 16-Bit Timer/Counter Output Compare Register &#039;&#039;&#039;OCR1A&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
OCR1A = xxx;&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die folgende Grafik soll den Zusammenhang zwischen dem Vergleichswert und dem generierten &#039;&#039;&#039;PWM&#039;&#039;&#039;-Signal aufzeigen.&lt;br /&gt;
&lt;br /&gt;
[[Image:PWM Theorie 3.gif]]&lt;br /&gt;
&lt;br /&gt;
[[Image:PWM Theorie 4.gif]]&lt;br /&gt;
&lt;br /&gt;
Ach ja, fast hätte ich&#039;s vergessen. Das generierte &#039;&#039;&#039;PWM&#039;&#039;&#039;-Signal&lt;br /&gt;
wird am Output Compare Pin &#039;&#039;&#039;OC1&#039;&#039;&#039; des Timers ausgegeben und leider können wir&lt;br /&gt;
deshalb auch beim AT90S2313 nur ein einzelnes &#039;&#039;&#039;PWM&#039;&#039;&#039;-Signal mit dieser Methode generieren. Andere AVR-Typen verfügen über bis zu vier PWM-Ausgänge. Zu beachten ist außerdem, das wenn der OC Pin aktiviert ist, er nichtmehr wie üblich funktioniert und z.B. nicht einfach über PINx ausgelesen werden kann.&lt;br /&gt;
&lt;br /&gt;
Ein Programm, welches an einem ATMega8 den Fast-PWM Modus verwendet, den Modus 14, könnte so aussehen&lt;br /&gt;
&amp;lt;C&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
int main()&lt;br /&gt;
{&lt;br /&gt;
  // OC1A auf Ausgang&lt;br /&gt;
  DDRB = (1 &amp;lt;&amp;lt; PB1 );&lt;br /&gt;
&lt;br /&gt;
  //&lt;br /&gt;
  // Timer 1 einstellen&lt;br /&gt;
  //  &lt;br /&gt;
  // Modus 14:&lt;br /&gt;
  //    Fast PWM, Top von ICR1&lt;br /&gt;
  //&lt;br /&gt;
  //     WGM13    WGM12   WGM11    WGM10&lt;br /&gt;
  //      1        1       1        0&lt;br /&gt;
  //&lt;br /&gt;
  //    Timer Vorteiler: 1&lt;br /&gt;
  //     CS12     CS11    CS10&lt;br /&gt;
  //       0        0       1&lt;br /&gt;
  //&lt;br /&gt;
  //  Steuerung des Ausgangsport: Set at BOTTOM, Clear at match&lt;br /&gt;
  //     COM1A1   COM1A0&lt;br /&gt;
  //       1        0&lt;br /&gt;
 &lt;br /&gt;
  TCCR1A = (1&amp;lt;&amp;lt;COM1A1) | (1&amp;lt;&amp;lt;WGM11);&lt;br /&gt;
  TCCR1B = (1&amp;lt;&amp;lt;WGM13) | (1&amp;lt;&amp;lt;WGM12) | (1&amp;lt;&amp;lt;CS10);&lt;br /&gt;
 &lt;br /&gt;
  //&lt;br /&gt;
  //  den Endwert (TOP) für den Zähler setzen&lt;br /&gt;
  //  der Zähler zählt bis zu diesem Wert&lt;br /&gt;
&lt;br /&gt;
  ICR1 = 0x6FFF;&lt;br /&gt;
 &lt;br /&gt;
  //&lt;br /&gt;
  // der Compare Wert&lt;br /&gt;
  // Wenn der Zähler diesen Wert erreicht, wird mit&lt;br /&gt;
  // obiger Konfiguration der OC1A Ausgang abgeschaltet&lt;br /&gt;
  // Sobald der Zähler wieder bei 0 startet, wird der&lt;br /&gt;
  // Ausgang wieder auf 1 gesetzt&lt;br /&gt;
  //&lt;br /&gt;
  // Durch Verändern dieses Wertes, werden die unterschiedlichen&lt;br /&gt;
  // PWM Werte eingestellt.&lt;br /&gt;
&lt;br /&gt;
  OCR1A = 0x3FFF;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  while( 1 )&lt;br /&gt;
    ;  &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/C&amp;gt;&lt;br /&gt;
&lt;br /&gt;
PWM Mode Tabelle aus dem Datenblatt des Atmega 8515:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;Mode&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;WGM13&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;WGM12&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;WGM11&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;WGM10&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;Timer/Counter Mode of Operation&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;TOP&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;Update of OCR1x at&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;TOV1 Flag set on&#039;&#039;&#039;&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;
| 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; | Normal&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0xFFFF&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | Immediate&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | MAX&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;
| 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; | PWM, Phase Correct, 8-Bit&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0x00FF&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | TOP&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | BOTTOM&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 2&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;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | PWM, Phase Correct, 9-Bit&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0x01FF&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | TOP&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | BOTTOM&lt;br /&gt;
|-&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3&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;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | PWM, Phase Correct, 10-Bit&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0x03FF&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | TOP&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | BOTTOM&lt;br /&gt;
|-&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 4&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;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | CTC&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | OCR1A&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | Immediate&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | MAX&lt;br /&gt;
|-&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 5&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;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | Fast PWM, 8-Bit&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0x00FF&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | BOTTOM&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | TOP&lt;br /&gt;
|-&lt;br /&gt;
&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 6&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;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | Fast PWM, 9-Bit&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0x01FF&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | BOTTOM&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | TOP&lt;br /&gt;
|-&lt;br /&gt;
&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 7&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;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | Fast PWM, 10-Bit&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0x03FF&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | BOTTOM&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | TOP&lt;br /&gt;
|-&lt;br /&gt;
&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 8&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;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | PWM, Phase an Frequency Correct&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | ICR1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | BOTTOM&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | BOTTOM&lt;br /&gt;
|-    &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 9&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;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | PWM, Phase an Frequency Correct&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | OCR1A&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | BOTTOM&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | BOTTOM&lt;br /&gt;
|-&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 10&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;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | PWM, Phase Correct&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | ICR1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | TOP&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | BOTTOM&lt;br /&gt;
|-&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 11&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;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | PWM, Phase an Frequency Correct&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | OCR1A&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | TOP&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | BOTTOM&lt;br /&gt;
|-&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 12&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;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | CTC&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | ICR1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | Immediate&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | MAX&lt;br /&gt;
|-&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 13&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;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | Reserved&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | -&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | -&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | -&lt;br /&gt;
|-&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 14&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;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | Fast PWM&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | ICR1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | BOTTOM&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | TOP&lt;br /&gt;
|-&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 15&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;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | Fast PWM&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | OCR1A&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | BOTTOM&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | TOP&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Für Details der PWM Möglichkeiten, muß immer das jeweilge Datenblatt des Prozessors konsultiert werden, da sich die unterschiedlichen Prozessoren in ihren Möglichkeiten doch stark unterscheiden. Auch muß man aufpassen, welches zu setzende Bit in welchem Register sind. Auch hier kann es sein, dass gleichnamige Konfigurationsbits in unterschiedlichen Konfigurationsregistern (je nach konkretem Prozessortyp) sitzen.&lt;br /&gt;
&lt;br /&gt;
= LCD-Ansteuerung =&lt;br /&gt;
&lt;br /&gt;
==Das LCD und sein Controller==&lt;br /&gt;
&lt;br /&gt;
Die meisten Text-LCDs verwenden den Controller [[HD44780|&#039;&#039;&#039;HD44780&#039;&#039;&#039;]] oder einen kompatiblen (z.B. KS0070) und haben 14 oder 16 Pins. Die Pinbelegung an der LCD-Controller-Platine ist praktisch immer gleich: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;table width=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;th width=&amp;quot;50&amp;quot; align=&amp;quot;left&amp;quot;&amp;gt;Pin #&amp;lt;/th&amp;gt;&amp;lt;th  width=&amp;quot;70&amp;quot; align=&amp;quot;left&amp;quot;&amp;gt;Bezeichnung&amp;lt;/th&amp;gt;&amp;lt;th align=&amp;quot;left&amp;quot;&amp;gt;Funktion&amp;lt;/th&amp;gt;&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;1&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Vss&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;GND&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;2&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Vcc&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;5V&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;3&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Vee&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Kontrastspannung (0V bis 5V)&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;4&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;RS&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Register Select (Befehle/Daten)&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;5&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;RW&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Read/Write&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;6&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;E&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Enable&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;7&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;DB0&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Datenbit 0&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;8&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;DB1&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Datenbit 1&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;9&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;DB2&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Datenbit 2&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;10&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;DB3&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Datenbit 3&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;11&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;DB4&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Datenbit 4&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;12&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;DB5&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Datenbit 5&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;13&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;DB6&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Datenbit 6&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;14&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;DB7&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Datenbit 7&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;15&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;A&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;LED-Beleuchtung, Anode&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;16&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;K&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;LED-Beleuchtung, Kathode&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Achtung: Unbedingt von der richtigen Seite zu zählen anfangen! Meistens ist neben Pin 1 eine kleine 1 auf der LCD-Platine, ansonsten im Datenblatt nachschauen. &lt;br /&gt;
&lt;br /&gt;
Bei LCDs mit 16-poligem Anschluss sind die beiden letzten Pins für die Hintergrundbeleuchtung reserviert. Hier unbedingt das Datenblatt zu Rate ziehen, die beiden Anschlüsse sind je nach Hersteller verdreht beschaltet. Falls kein Datenblatt vorliegt, kann man mit einem Durchgangsprüfer feststellen, welcher Anschluss mit Masse (GND) verbunden ist.&lt;br /&gt;
&lt;br /&gt;
Vss wird ganz einfach an GND angeschlossen und Vcc an 5V. Vee kann man testweise auch an GND legen. Wenn das LCD dann zu dunkel sein sollte muss man ein 10k-Potentiometer zwischen GND und 5V schalten, mit dem Schleifer an Vee: &lt;br /&gt;
&lt;br /&gt;
[[Bild:LCD_Vee.gif]]&lt;br /&gt;
&lt;br /&gt;
Es gibt zwei verschiedene Möglichkeiten zur Ansteuerung eines solchen Displays: den &#039;&#039;&#039;8-bit-&#039;&#039;&#039; und den &#039;&#039;&#039;4-bit-&#039;&#039;&#039;Modus.&lt;br /&gt;
* Für den &#039;&#039;&#039;8-bit-Modus&#039;&#039;&#039; werden (wie der Name schon sagt) alle acht Datenleitungen zur Ansteuerung verwendet, somit kann durch einen Zugriff immer ein ganzes Byte übertragen werden.&lt;br /&gt;
* Der &#039;&#039;&#039;4-bit-Modus&#039;&#039;&#039; verwendet nur die oberen vier Datenleitungen (&#039;&#039;&#039;DB4-DB7&#039;&#039;&#039;). Um ein Byte zu übertragen braucht man somit zwei Zugriffe, wobei zuerst das höherwertige &#039;&#039;&#039;&amp;quot;Nibble&amp;quot;&#039;&#039;&#039; (= 4 Bits), also Bit 4 bis Bit 7 übertragen wird und dann das niederwertige, also Bit 0 bis Bit 3. Die unteren Datenleitungen des LCDs, die beim Lesezyklus Ausgänge sind, lässt man offen (siehe Datasheets, z.B. vom KS0070).&lt;br /&gt;
&lt;br /&gt;
Der 4-bit-Modus hat den Vorteil, dass man 4 IO-Pins weniger benötigt als beim 8-bit-Modus, weshalb ich mich hier für eine Ansteuerung mit 4bit entschieden habe. &lt;br /&gt;
&lt;br /&gt;
Neben den vier Datenleitungen (DB4, DB5, DB6 und DB7) werden noch die Anschlüsse &#039;&#039;&#039;RS&#039;&#039;&#039;, &#039;&#039;&#039;RW&#039;&#039;&#039; und &#039;&#039;&#039;E&#039;&#039;&#039; (ist in manchen Unterlagen auch &#039;&#039;&#039;EN&#039;&#039;&#039;  für &#039;&#039;Enable&#039;&#039; abgekürzt) benötigt. &lt;br /&gt;
&lt;br /&gt;
* Über &#039;&#039;&#039;RS&#039;&#039;&#039; wird ausgewählt, ob man einen Befehl oder ein Datenbyte an das LCD schicken möchte. Ist RS Low, dann wird das ankommende Byte als Befehl interpretiert, ist RS high, dann wird das Byte auf dem LCD angezeigt. &lt;br /&gt;
* &#039;&#039;&#039;RW&#039;&#039;&#039; legt fest, ob geschrieben oder gelesen werden soll. High bedeutet lesen, low bedeutet schreiben. Wenn man RW auf lesen einstellt und RS auf Befehl, dann kann man das &#039;&#039;&#039;Busy-Flag&#039;&#039;&#039; an DB7 lesen, das anzeigt, ob das LCD den vorhergehenden Befehl fertig verarbeitetet hat (diese Methode u.a. in der LCD-Library von Peter Fleury verwendet). Ist RS auf Daten eingestellt, dann kann man z.B. den Inhalt des Displays lesen - was jedoch nur in den wenigsten Fällen Sinn macht. Deshalb kann man RW dauerhaft auf low lassen (= an GND anschließen), so dass man noch ein IO-Pin am Controller einspart. Der Nachteil ist, dass man dann das Busy-Flag nicht lesen kann, weswegen man nach jedem Befehl vorsichtshalber ein paar Mikrosekunden warten sollte, um dem LCD Zeit zum Ausführen des Befehls zu geben. Dummerweise schwankt die Ausführungszeit von Display zu Display und ist auch von der Betriebsspannung abhängig. Für professionellere Sachen also lieber den IO-Pin opfern und Busy abfragen.&lt;br /&gt;
* Der &#039;&#039;&#039;E&#039;&#039;&#039; Anschluss schließlich signalisiert dem LCD, dass die übrigen Datenleitungen jetzt korrekte Pegel angenommen haben und es die gewünschten Daten von den Datenleitungen bzw. Kommandos von den Datenleitungen übernehmen kann.&lt;br /&gt;
&lt;br /&gt;
== Anschluss an den Controller ==&lt;br /&gt;
&lt;br /&gt;
Jetzt da wir wissen, welche Anschlüsse das LCDs benötigt, können wir das LCD mit dem Mikrocontroller verbinden: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;table width=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;th align=&amp;quot;left&amp;quot;&amp;gt;Pin #-LCD&amp;lt;/th&amp;gt;&amp;lt;th align=&amp;quot;left&amp;quot;&amp;gt;Bezeichnung-LCD&amp;lt;/th&amp;gt;&amp;lt;th align=&amp;quot;left&amp;quot;&amp;gt;Pin-µC&amp;lt;/th&amp;gt;&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;1&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Vss&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;GND&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;2&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Vcc&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;5V&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;3&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Vee&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;GND oder Poti (siehe oben)&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;4&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;RS&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;PD4 am AVR&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;5&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;RW&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;GND&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;6&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;E&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;PD5 am AVR&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;7&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;DB0&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;offen&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;8&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;DB1&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;offen&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;9&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;DB2&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;offen&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;10&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;DB3&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;offen&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;11&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;DB4&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;PD0 am AVR&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;12&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;DB5&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;PD1 am AVR&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;13&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;DB6&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;PD2 am AVR&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;14&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;DB7&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;PD3 am AVR&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn man die Steuerleitungen EN und RS auf Pins an einem anderen Port legen möchte, kann man so wie in diesem [http://www.mikrocontroller.net/topic/88543#751982 Forumsbeitrag] vorgehen.&lt;br /&gt;
&lt;br /&gt;
Ok, alles ist verbunden, wenn man jetzt den Strom einschaltet sollten ein oder zwei schwarze Balken auf dem Display angezeigt werden. Doch wie bekommt man jetzt die Befehle und Daten in das Display? &lt;br /&gt;
&lt;br /&gt;
== Programmierung ==&lt;br /&gt;
Datei &#039;&#039;&#039;lcd-routines.h&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
// Ansteuerung eines HD44780 kompatiblen LCD im 4-Bit-Interfacemodus&lt;br /&gt;
// http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial&lt;br /&gt;
//&lt;br /&gt;
void lcd_data(unsigned char temp1);&lt;br /&gt;
void lcd_string(char *data);&lt;br /&gt;
void lcd_command(unsigned char temp1);&lt;br /&gt;
void lcd_enable(void);&lt;br /&gt;
void lcd_init(void);&lt;br /&gt;
void lcd_home(void);&lt;br /&gt;
void lcd_clear(void);&lt;br /&gt;
void set_cursor(uint8_t x, uint8_t y);&lt;br /&gt;
&lt;br /&gt;
// Hier die verwendete Taktfrequenz in Hz eintragen, wichtig!&lt;br /&gt;
&lt;br /&gt;
#define F_CPU 8000000&lt;br /&gt;
&lt;br /&gt;
// LCD Befehle&lt;br /&gt;
&lt;br /&gt;
#define CLEAR_DISPLAY 0x01&lt;br /&gt;
#define CURSOR_HOME   0x02&lt;br /&gt;
&lt;br /&gt;
// Pinbelegung für das LCD, an verwendete Pins anpassen&lt;br /&gt;
&lt;br /&gt;
#define LCD_PORT      PORTD&lt;br /&gt;
#define LCD_DDR       DDRD&lt;br /&gt;
#define LCD_RS        PD4&lt;br /&gt;
#define LCD_EN        PD5&lt;br /&gt;
// DB4 bis DB7 des LCD sind mit PD0 bis PD3 des AVR verbunden&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Datei &#039;&#039;&#039;lcd-routines.c&#039;&#039;&#039;:&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
// Ansteuerung eines HD44780 kompatiblen LCD im 4-Bit-Interfacemodus&lt;br /&gt;
// http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial&lt;br /&gt;
//&lt;br /&gt;
// Die Pinbelegung ist über defines in lcd-routines.h einstellbar&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;quot;lcd-routines.h&amp;quot;&lt;br /&gt;
#include &amp;lt;util/delay.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
// sendet ein Datenbyte an das LCD&lt;br /&gt;
&lt;br /&gt;
void lcd_data(unsigned char temp1)&lt;br /&gt;
{&lt;br /&gt;
   unsigned char temp2 = temp1;&lt;br /&gt;
 &lt;br /&gt;
   LCD_PORT |= (1&amp;lt;&amp;lt;LCD_RS);        // RS auf 1 setzen&lt;br /&gt;
&lt;br /&gt;
   temp1 = temp1 &amp;gt;&amp;gt; 4;&lt;br /&gt;
   temp1 = temp1 &amp;amp; 0x0F;&lt;br /&gt;
   LCD_PORT &amp;amp;= 0xF0;&lt;br /&gt;
   LCD_PORT |= temp1;               // setzen&lt;br /&gt;
   lcd_enable();&lt;br /&gt;
 &lt;br /&gt;
   temp2 = temp2 &amp;amp; 0x0F;&lt;br /&gt;
   LCD_PORT &amp;amp;= 0xF0;&lt;br /&gt;
   LCD_PORT |= temp2;               // setzen&lt;br /&gt;
   lcd_enable();&lt;br /&gt;
   &lt;br /&gt;
   _delay_us(42);&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
// sendet einen Befehl an das LCD&lt;br /&gt;
&lt;br /&gt;
void lcd_command(unsigned char temp1)&lt;br /&gt;
{&lt;br /&gt;
   unsigned char temp2 = temp1;&lt;br /&gt;
 &lt;br /&gt;
   LCD_PORT &amp;amp;= ~(1&amp;lt;&amp;lt;LCD_RS);        // RS auf 0 setzen&lt;br /&gt;
&lt;br /&gt;
   temp1 = temp1 &amp;gt;&amp;gt; 4;              // oberes Nibble holen&lt;br /&gt;
   temp1 = temp1 &amp;amp; 0x0F;            // maskieren&lt;br /&gt;
   LCD_PORT &amp;amp;= 0xF0;&lt;br /&gt;
   LCD_PORT |= temp1;               // setzen&lt;br /&gt;
   lcd_enable();&lt;br /&gt;
 &lt;br /&gt;
   temp2 = temp2 &amp;amp; 0x0F;            // unteres Nibble holen und maskieren&lt;br /&gt;
   LCD_PORT &amp;amp;= 0xF0;&lt;br /&gt;
   LCD_PORT |= temp2;               // setzen&lt;br /&gt;
   lcd_enable();&lt;br /&gt;
   &lt;br /&gt;
   _delay_us(42);&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
// erzeugt den Enable-Puls&lt;br /&gt;
void lcd_enable(void)&lt;br /&gt;
{&lt;br /&gt;
   // Bei Problemen ggf. Pause gemäß Datenblatt des LCD Controllers einfügen&lt;br /&gt;
   // http://www.mikrocontroller.net/topic/81974#685882&lt;br /&gt;
   LCD_PORT |= (1&amp;lt;&amp;lt;LCD_EN);&lt;br /&gt;
    _delay_us(1);                   // kurze Pause&lt;br /&gt;
   // Bei Problemen ggf. Pause gemäß Datenblatt des LCD Controllers verlängern&lt;br /&gt;
   // http://www.mikrocontroller.net/topic/80900&lt;br /&gt;
   LCD_PORT &amp;amp;= ~(1&amp;lt;&amp;lt;LCD_EN);&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
// Initialisierung: &lt;br /&gt;
// Muss ganz am Anfang des Programms aufgerufen werden.&lt;br /&gt;
&lt;br /&gt;
void lcd_init(void)&lt;br /&gt;
{&lt;br /&gt;
   LCD_DDR = LCD_DDR | 0x0F | (1&amp;lt;&amp;lt;LCD_RS) | (1&amp;lt;&amp;lt;LCD_EN);   // Port auf Ausgang schalten&lt;br /&gt;
&lt;br /&gt;
   // muss 3mal hintereinander gesendet werden zur Initialisierung&lt;br /&gt;
&lt;br /&gt;
   _delay_ms(15);&lt;br /&gt;
   LCD_PORT &amp;amp;= 0xF0;&lt;br /&gt;
   LCD_PORT |= 0x03;            &lt;br /&gt;
   LCD_PORT &amp;amp;= ~(1&amp;lt;&amp;lt;LCD_RS);      // RS auf 0&lt;br /&gt;
   lcd_enable();&lt;br /&gt;
&lt;br /&gt;
   _delay_ms(5);&lt;br /&gt;
   lcd_enable();&lt;br /&gt;
&lt;br /&gt;
   _delay_ms(1);&lt;br /&gt;
   lcd_enable();&lt;br /&gt;
   _delay_ms(1);&lt;br /&gt;
&lt;br /&gt;
   // 4 Bit Modus aktivieren &lt;br /&gt;
   LCD_PORT &amp;amp;= 0xF0;&lt;br /&gt;
   LCD_PORT |= 0x02;&lt;br /&gt;
   lcd_enable();&lt;br /&gt;
   _delay_ms(1);&lt;br /&gt;
&lt;br /&gt;
   // 4Bit / 2 Zeilen / 5x7&lt;br /&gt;
   lcd_command(0x28);&lt;br /&gt;
    &lt;br /&gt;
   // Display ein / Cursor aus / kein Blinken&lt;br /&gt;
   lcd_command(0x0C); &lt;br /&gt;
 &lt;br /&gt;
   // inkrement / kein Scrollen&lt;br /&gt;
   lcd_command(0x06);&lt;br /&gt;
&lt;br /&gt;
   lcd_clear();&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
// Sendet den Befehl zur Löschung des Displays&lt;br /&gt;
&lt;br /&gt;
void lcd_clear(void)&lt;br /&gt;
{&lt;br /&gt;
   lcd_command(CLEAR_DISPLAY);&lt;br /&gt;
   _delay_ms(5);&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
// Sendet den Befehl: Cursor Home&lt;br /&gt;
&lt;br /&gt;
void lcd_home(void)&lt;br /&gt;
{&lt;br /&gt;
   lcd_command(CURSOR_HOME);&lt;br /&gt;
   _delay_ms(5);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// setzt den Cursor in Zeile y (1..4) Spalte x (0..15)&lt;br /&gt;
&lt;br /&gt;
void set_cursor(uint8_t x, uint8_t y)&lt;br /&gt;
{&lt;br /&gt;
  uint8_t tmp;&lt;br /&gt;
&lt;br /&gt;
  switch (y) {&lt;br /&gt;
    case 1: tmp=0x80+0x00+x; break;    // 1. Zeile&lt;br /&gt;
    case 2: tmp=0x80+0x40+x; break;    // 2. Zeile&lt;br /&gt;
    case 3: tmp=0x80+0x10+x; break;    // 3. Zeile&lt;br /&gt;
    case 4: tmp=0x80+0x50+x; break;    // 4. Zeile&lt;br /&gt;
    default: return;                   // für den Fall einer falschen Zeile&lt;br /&gt;
  }&lt;br /&gt;
  lcd_command(tmp);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Schreibt einen String auf das LCD&lt;br /&gt;
&lt;br /&gt;
void lcd_string(char *data)&lt;br /&gt;
{&lt;br /&gt;
    while(*data) {&lt;br /&gt;
        lcd_data(*data);&lt;br /&gt;
        data++;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein Hauptprogramm, welches die Funktionen benutzt, sieht zb. so aus:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
// &lt;br /&gt;
// Anpassungen im makefile:&lt;br /&gt;
//    ATMega8 =&amp;gt; MCU=atmega8 im makefile einstellen&lt;br /&gt;
//    lcd-routines.c in SRC = ... Zeile anhängen&lt;br /&gt;
// &lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;quot;lcd-routines.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
int main(void)&lt;br /&gt;
{&lt;br /&gt;
    lcd_init();&lt;br /&gt;
&lt;br /&gt;
    lcd_data(&#039;T&#039;);&lt;br /&gt;
    lcd_data(&#039;e&#039;);&lt;br /&gt;
    lcd_data(&#039;s&#039;);&lt;br /&gt;
    lcd_data(&#039;t&#039;);&lt;br /&gt;
&lt;br /&gt;
    set_cursor(0,2);&lt;br /&gt;
&lt;br /&gt;
    lcd_string(&amp;quot;Hello World!&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    while(1)&lt;br /&gt;
    {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wichtig ist dabei, dass die Optimierung bei der Compilierung eingeschaltet ist, sonst stimmen die Zeiten der Funktionen _delay_us() und _delay_ms() nicht und der Code wird wesentlich länger (Siehe Dokumentation der libc im WinAVR).&lt;br /&gt;
&lt;br /&gt;
Ein Hauptprogramm, welches eine Variable ausgibt, sieht zb. so aus.&lt;br /&gt;
Mittels der itoa() Funktion (itoa = &amp;lt;b&amp;gt;I&amp;lt;/b&amp;gt;nteger &amp;lt;b&amp;gt;To&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;A&amp;lt;/b&amp;gt;scii ) wird von einem Zahlenwert eine textuelle Repräsentierung ermittelt (sprich: ein String erzeugt) und dieser String mit der bereits vorhandenen Funktion lcd_string ausgegeben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
// &lt;br /&gt;
// Anpassungen im makefile:&lt;br /&gt;
//    ATMega8 =&amp;gt; MCU=atmega8 im makefile einstellen&lt;br /&gt;
//    lcd-routines.c in SRC = ... Zeile anhängen &lt;br /&gt;
// &lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
#include &amp;quot;lcd-routines.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
// Beispiel&lt;br /&gt;
int variable = 42;&lt;br /&gt;
&lt;br /&gt;
int main(void)&lt;br /&gt;
{&lt;br /&gt;
    lcd_init();&lt;br /&gt;
&lt;br /&gt;
    // Ausgabe des Zeichens dessen ASCII-Code gleich dem Variablenwert ist&lt;br /&gt;
    // (Im Beispiel entspricht der ASCII-Code 42 dem Zeichen *)&lt;br /&gt;
    // http://www.code-knacker.de/ascii.htm&lt;br /&gt;
    lcd_data(variable);&lt;br /&gt;
&lt;br /&gt;
    set_cursor(0,2);&lt;br /&gt;
 &lt;br /&gt;
    // Ausgabe der Variable als Text in dezimaler Schreibweise&lt;br /&gt;
    {&lt;br /&gt;
       // ... umwandeln siehe FAQ Artikel bei www.mikrocontroller.net&lt;br /&gt;
       // WinAVR hat eine itoa()-Funktion, das erfordert obiges #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
       char Buffer[20]; // in diesem {} lokal&lt;br /&gt;
       itoa( variable, Buffer, 10 ); &lt;br /&gt;
&lt;br /&gt;
       // ... ausgeben  &lt;br /&gt;
       lcd_string( Buffer );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    while(1)&lt;br /&gt;
    {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Beim Einrichten eines Projekts muss man zu der Datei mit dem Hauptprogramm auch die Datei lcd-routines.c in das Projekt aufnehmen. Dies geschieht beim AVR Studio unter Source Files im Fenster AVR GCC oder bei WinAVR im Makefile (z.B. durch SRC += lcd-routines.c).&lt;br /&gt;
&lt;br /&gt;
= Die Timer/Counter des AVR =&lt;br /&gt;
&lt;br /&gt;
Die heutigen Mikrocontroller und insbesondere die RISC-AVRs sind für viele Steuerungsaufgaben zu schnell. Wenn wir beispielsweise eine LED oder Lampe blinken lassen wollen, können wir selbstverständlich nicht die CPU-Frequenz verwenden, da ja dann nichts mehr vom Blinken zu bemerken wäre.&lt;br /&gt;
&lt;br /&gt;
Wir brauchen also eine Möglichkeit, Vorgänge in Zeitabständen durchzuführen, die geringer als die Taktfrequenz des Controllers sind. Selbstverständlich sollte die resultierende Frequenz auch noch möglichst genau und stabil sein.&lt;br /&gt;
&lt;br /&gt;
Hier kommen die im AVR vorhandenen Timer/Counter zum Einsatz.&lt;br /&gt;
&lt;br /&gt;
Ein Timer ist ganz einfach ein bestimmtes Register im µC, das völlig ohne Zutun des Programms, also per Hardware, hochgezählt wird. Das alleine wäre noch nicht allzu nützlich, wenn nicht dieses Hardwareregister bei bestimmten Zählerständen einen Interrupt auslösen könnte. Ein solches Ereignis ist der Overflow: Da die Bitbreite des Registers beschränkt ist, kommt es natürlich auch vor, dass der Zähler so hoch zählt, dass der nächste Zählerstand mit dieser Bitbreite nicht mehr darstellbar ist und der Zähler wieder auf 0 zurückgesetzt wird. Dieses Ereignis nennt man den Overflow und es ist möglich an dieses Ereignis einen Interrupt zu koppeln.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- Alternativvorschlag mthomas &lt;br /&gt;
Jeder Timer verfügt über ein Zählerregister im Mikrocontroller, das automatisch und ohne Zutun des Programms von der Hardware weitergezählt wird. In einem einfachen Anwendungsfall stellt man den Timer auf eine Zählgeschwindigkeit (Frequenz) und kann dann anhand des Zählerstands ermitteln, wie viel Zeit vergangen ist. Das eigentlich Nützliche an Timern ist jedoch, dass man  bestimmte Zählerstände mit Interrupts verknüpfen kann, so dass der Controller beim Auftreten automatisch eine vom Anwender geschriebene Routine aufruft. Eines dieser möglichen Ereignis ist der Overflow ((Zähler-)Überlauf), der dann auftritt, wenn der Wert des Zählerregisters (Timer/Counter-Register) den maximal möglichen Wert überschreitet. Der Maximalwert wird durch die Bitbreite des Zählerregisters bestimmt (z.B. 255 bei 8-Bit Timern). Beim Überlauf/Overflow wird der Zähler durch die Hardware auf 0 zurückgesetzt und die Zählung beginnt von neuem. Wurde vorher der Overflow-Interrupt für den Timer aktiviert (im Timer Control Register) unterbricht der Controller automatisch die Ausführung des Hauptprogramms und verzweigt in die Interrupt-Routine des Anwenders.&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein anderes Anwendungsgebiet ist die Zählung von Signalen, welche über einen I/O-Pin zugeführt werden können.&lt;br /&gt;
&lt;br /&gt;
Die folgenden Ausführungen beziehen sich auf den AT90S2313. Für andere Modelltypen müsst ihr euch die allenfalls notwendigen Anpassungen aus den Datenblättern der entsprechenden Controller herauslesen.&lt;br /&gt;
&lt;br /&gt;
Wir unterscheiden grundsätzlich zwischen 8-Bit Timern, welche eine Auflösung von 256 aufweisen und 16-Bit Timern mit (logischerweise) einer Auflösung von 65536. Als Eingangstakt für die Timer/Counter kann entweder die CPU-Taktfrequenz, der Vorteiler-Ausgang oder ein an einen I/O-Pin angelegtes Signal verwendet werden. Wenn ein externes Signal verwendet wird, so darf dessen Frequenz nicht höher sein als die Hälfte des CPU-Taktes.&lt;br /&gt;
&lt;br /&gt;
== Der Vorteiler (Prescaler) ==&lt;br /&gt;
&lt;br /&gt;
Der Vorteiler dient dazu, den CPU-Takt vorerst um einen einstellbaren Faktor zu reduzieren. Die so geteilte Frequenz wird den Eingängen der Timer zugeführt.&lt;br /&gt;
&lt;br /&gt;
Wenn wir mit einem CPU-Takt von 4 MHz arbeiten und den Vorteiler auf 1024 einstellen, wird also der Timer mit einer Frequenz von 4 MHz / 1024, also mit ca. 4 kHz versorgt. Wenn also der Timer läuft, so wird das Daten- bzw. Zählregister (TCNTx) mit dieser Frequenz inkrementiert.&lt;br /&gt;
&lt;br /&gt;
== 8-Bit Timer/Counter ==&lt;br /&gt;
&lt;br /&gt;
Alle AVR-Modelle verfügen über mindestens einen, teilweise sogar zwei, 8-Bit Timer.&lt;br /&gt;
&lt;br /&gt;
Der 8-Bit Timer wird z.B bei AT90S2313 über folgende Register angesprochen (bei anderen Typen weitestgehend analog):&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;TCCR0&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;T&#039;&#039;&#039;imer/&#039;&#039;&#039;C&#039;&#039;&#039;ounter &#039;&#039;&#039;C&#039;&#039;&#039;ontrol &#039;&#039;&#039;R&#039;&#039;&#039;egister&lt;br /&gt;
Timer &#039;&#039;&#039;0&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
In diesem Register stellen wir ein, wie wir den Timer/Counter verwenden möchten.&lt;br /&gt;
&lt;br /&gt;
Das Register ist wie folgt aufgebaut:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Bit&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 7&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 6&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 5&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 4&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 2&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Name&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;CS02&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;CS01&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;CS00&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;R/W&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Initialwert&#039;&#039;&#039;&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;
| 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;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;CS02, CS01, CS00&#039;&#039;&#039; (&#039;&#039;&#039;C&#039;&#039;&#039;lock &#039;&#039;&#039;S&#039;&#039;&#039;elect Bits)&lt;br /&gt;
:Diese 3 Bits bestimmen die Quelle für den Timer/Counter:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | CS02&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | CS01&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | CS00&lt;br /&gt;
| Resultat&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;
| Stopp, Der Timer/Counter wird 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;
| CPU-Takt&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;
| CPU-Takt / 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;
| CPU-Takt / 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;
| CPU-Takt / 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;
| CPU-Takt / 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;
| Externer Pin &#039;&#039;&#039;TO&#039;&#039;&#039;, 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;
| Externer Pin &#039;&#039;&#039;TO&#039;&#039;&#039;, steigende Flanke&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/dd&amp;gt;&lt;br /&gt;
&amp;lt;/dl&amp;gt;&lt;br /&gt;
:Wenn als Quelle der externe Pin &#039;&#039;&#039;TO&#039;&#039;&#039; verwendet wird, so wird ein Flankenwechsel auch erkannt, wenn der Pin &#039;&#039;&#039;TO&#039;&#039;&#039; als Ausgang geschaltet ist.&lt;br /&gt;
&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;TCNT0&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;T&#039;&#039;&#039;imer/&#039;&#039;&#039;C&#039;&#039;&#039;ou&#039;&#039;&#039;nt&#039;&#039;&#039;er Daten Register Timer &#039;&#039;&#039;0&#039;&#039;&#039;&amp;lt;br /&amp;gt;&lt;br /&gt;
Dieses ist als 8-Bit Aufwärtszähler mit Schreib- und Lesezugriff&lt;br /&gt;
realisiert. Wenn der Zähler den Wert 255 erreicht hat beginnt er beim&lt;br /&gt;
nächsten Zyklus wieder bei 0.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Bit&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 7&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 6&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 5&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 4&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 2&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Name&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;MSB&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;LSB&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;R/W&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Initialwert&#039;&#039;&#039;&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;
| 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;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Um nun also den Timer0 in Betrieb zu setzen und ihn mit einer Frequenz von 1/1024-tel des CPU-Taktes zählen zu lassen, schreiben wir die folgende Befehlszeile:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
    TCCR0 |= (1&amp;lt;&amp;lt;CS00)|(1&amp;lt;&amp;lt;CS02);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Zähler zählt nun aufwärts bis 255, um dann wieder bei 0 zu beginnen. Der aktuelle Zählerstand steht in TCNT0. Bei jedem Überlauf von 255 auf 0 wird das Timer Overflow Flag &#039;&#039;&#039;TOV0&#039;&#039;&#039; im Timer Interrupt Flag &#039;&#039;&#039;TIFR&#039;&#039;&#039;-Register gesetzt und, falls so konfiguriert, ein entsprechender Timer-Overflow-Interrupt ausgelöst und die daran gebundene Interrupt-Routine abgearbeitet. Das TOV Flag &lt;br /&gt;
lässt sich durch das Hineinschreiben einer 1 und nicht wie erwartet einer 0 wieder zurücksetzen.&lt;br /&gt;
&lt;br /&gt;
== 16-Bit Timer/Counter ==&lt;br /&gt;
&lt;br /&gt;
Viele AVR-Modelle besitzen außer den 8-Bit Timern auch 16-Bit Timer. Die 16-Bit Timer/Counter sind etwas komplexer aufgebaut als die 8-Bit Timer/Counter, bieten dafür aber auch viel mehr Möglichkeiten, als da sind:&lt;br /&gt;
&lt;br /&gt;
* Die [[PWM]]-Betriebsart Erzeugung eines pulsweitenmodulierten Ausgangssignals. &lt;br /&gt;
* Vergleichswert-Überprüfung mit Erzeugung eines Ausgangssignals (Output Compare Match).&lt;br /&gt;
* Einfangen eines Eingangssignals mit Speicherung des aktuellen Zählerwertes (Input Capturing), mit zuschaltbarer Rauschunterdrückung (Noise Filtering).&lt;br /&gt;
&lt;br /&gt;
Folgende Register sind dem Timer/Counter 1 zugeordnet:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;TCCR1A&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;T&#039;&#039;&#039;imer/&#039;&#039;&#039;C&#039;&#039;&#039;ounter &#039;&#039;&#039;C&#039;&#039;&#039;ontrol &#039;&#039;&#039;R&#039;&#039;&#039;egister &#039;&#039;&#039;A&#039;&#039;&#039; Timer &#039;&#039;&#039;1&#039;&#039;&#039;&amp;lt;br /&amp;gt;&lt;br /&gt;
In diesem und dem folgenden Register stellen wir ein, wie wir den Timer/Counter verwenden möchten.&amp;lt;br /&amp;gt;&lt;br /&gt;
Das Register ist wie folgt aufgebaut:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Bit&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 7&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 6&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 5&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 4&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 2&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Name&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;COM1A1&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;COM1A0&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;PWM11&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;PWM10&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;R/W&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Initialwert&#039;&#039;&#039;&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;
| 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;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;COM1A1&#039;&#039;&#039;, &#039;&#039;&#039;COM1A0&#039;&#039;&#039; (&#039;&#039;&#039;Co&#039;&#039;&#039;mpare &#039;&#039;&#039;M&#039;&#039;&#039;atch Control Bits)&lt;br /&gt;
:Diese 2 Bits bestimmen die Aktion, welche am Output-Pin &#039;&#039;&#039;OC1&#039;&#039;&#039; ausgeführt werden soll, wenn der Wert des Datenregisters des Timer/Counter 1 den Wert des Vergleichsregisters erreicht, also ein so genannter Compare Match auftritt.&lt;br /&gt;
:Der Pin &#039;&#039;&#039;OC1&#039;&#039;&#039; (&#039;&#039;&#039;PB3&#039;&#039;&#039; beim 2313) muss mit dem Datenrichtungsregister als Ausgang konfiguriert werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | COM1A1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | COM1A0&lt;br /&gt;
| Resultat&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;
| Output-Pin &#039;&#039;&#039;OC1&#039;&#039;&#039; wird nicht angesteuert.&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;
| Das Signal am Pin &#039;&#039;&#039;OC1&#039;&#039;&#039; wird invertiert (Toggle).&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;
| Der Output Pin &#039;&#039;&#039;OC1&#039;&#039;&#039; wird auf 0 gesetzt.&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;
| Der Output Pin &#039;&#039;&#039;OC1&#039;&#039;&#039; wird auf 1 gesetzt.&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&lt;br /&gt;
:In der PWM-Betriebsart haben diese Bits eine andere Funktion.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | COM1A1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | COM1A0&lt;br /&gt;
| Resultat&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;
| Output-Pin &#039;&#039;&#039;OC1&#039;&#039;&#039; wird nicht angesteuert.&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;
| Output-Pin &#039;&#039;&#039;OC1&#039;&#039;&#039; wird nicht angesteuert.&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;
| Wird beim Hochzählen der Wert im Vergleichsregister erreicht, so wird der Pin &#039;&#039;&#039;OC1&#039;&#039;&#039; auf 0 gesetzt.&lt;br /&gt;
Wird beim Herunterzählen der Wert im Vergleichsregister erreicht, so wird der Pin auf 1 gesetzt.&lt;br /&gt;
&lt;br /&gt;
Man nennt dies &#039;&#039;nicht invertierende PWM&#039;&#039;.&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;
| Wird beim Hochzählen der Wert im Vergleichsregister erreicht, so wird der Pin &#039;&#039;&#039;OC1&#039;&#039;&#039; auf 1 gesetzt.&lt;br /&gt;
Wird beim Herunterzählen der Wert im Vergleichsregister erreicht, so wird der Pin auf 0 gesetzt.&lt;br /&gt;
&lt;br /&gt;
Man nennt dies &#039;&#039;invertierende PWM&#039;&#039;.&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;PWM11&#039;&#039;&#039;, &#039;&#039;&#039;PWM10&#039;&#039;&#039; (&#039;&#039;&#039;PWM&#039;&#039;&#039; Mode Select Bits)&lt;br /&gt;
:Mit diesen 2 Bits wird die PWM-Betriebsart des Timer/Counter 1 gesteuert.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | PWM11&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | PWM10&lt;br /&gt;
| Resultat&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;
| Die PWM-Betriebsart ist nicht aktiviert. Timer/Counter 1 arbeitet als normaler Timer bzw. Zähler.&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;
| 8-Bit PWM Betriebsart aktivieren.&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;
| 9-Bit PWM Betriebsart aktivieren.&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;
| 10-Bit PWM Betriebsart aktivieren.&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;TCCR1B&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;T&#039;&#039;&#039;imer/&#039;&#039;&#039;C&#039;&#039;&#039;ounter &#039;&#039;&#039;C&#039;&#039;&#039;ontrol &#039;&#039;&#039;R&#039;&#039;&#039;egister &#039;&#039;&#039;B&#039;&#039;&#039; Timer &#039;&#039;&#039;1&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Bit&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 7&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 6&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 5&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 4&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 2&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Name&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ICNC1&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ICES1&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;WGM13&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;WGM12 (CTC1)&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;CS12&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;CS11&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;CS10&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;R/W&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Initialwert&#039;&#039;&#039;&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;
| 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;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ICNC1&#039;&#039;&#039; (&#039;&#039;&#039;I&#039;&#039;&#039;nput &#039;&#039;&#039;C&#039;&#039;&#039;apture &#039;&#039;&#039;N&#039;&#039;&#039;oise &#039;&#039;&#039;C&#039;&#039;&#039;anceler (4 CKs) Timer/Counter 1&lt;br /&gt;
:oder auf Deutsch Rauschunterdrückung des Eingangssignals.&lt;br /&gt;
:Wenn dieses Bit gesetzt ist und mit dem Input Capture Signal gearbeitet wird so werden nach der Triggerung des Signals mit der entsprechenden Flanke (steigend oder fallend) am Input Capture Pin &#039;&#039;&#039;ICP&#039;&#039;&#039; jeweils 4 Messungen mit der CPU-Frequenz des Eingangssignals abgefragt. Nur dann, wenn alle 4 Messungen den gleichen Zustand aufweisen gilt das Signal als erkannt.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ICES1&#039;&#039;&#039; (&#039;&#039;&#039;I&#039;&#039;&#039;nput &#039;&#039;&#039;C&#039;&#039;&#039;apture &#039;&#039;&#039;E&#039;&#039;&#039;dge &#039;&#039;&#039;S&#039;&#039;&#039;elect Timer/Counter &#039;&#039;&#039;1&#039;&#039;&#039;)&lt;br /&gt;
:Mit diesem Bit wird bestimmt, ob die steigende (&#039;&#039;&#039;ICES1&#039;&#039;&#039;=1) oder fallende (&#039;&#039;&#039;ICES1&#039;&#039;&#039;=0) Flanke zur Auswertung des Input Capture Signals an Pin &#039;&#039;&#039;ICP&#039;&#039;&#039; heran gezogen wird.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;CTC1&#039;&#039;&#039; (&#039;&#039;&#039;C&#039;&#039;&#039;lear &#039;&#039;&#039;T&#039;&#039;&#039;imer/&#039;&#039;&#039;C&#039;&#039;&#039;ounter on Compare Match Timer/Counter &#039;&#039;&#039;1&#039;&#039;&#039;)&lt;br /&gt;
:Wenn dieses Bit gesetzt ist, so wird nach einer Übereinstimmung des Datenregisters &#039;&#039;&#039;TCNT1H&#039;&#039;&#039;/&#039;&#039;&#039;TCNT1L&#039;&#039;&#039; mit dem Vergleichswert in &#039;&#039;&#039;OCR1H&#039;&#039;&#039;/&#039;&#039;&#039;OCR1L&#039;&#039;&#039; das Datenregister &#039;&#039;&#039;TCNT1H&#039;&#039;&#039;/&#039;&#039;&#039;TCNT1L&#039;&#039;&#039; auf 0 gesetzt.&lt;br /&gt;
:Da die Übereinstimmung im Takt nach dem Vergleich behandelt wird, ergibt sich je nach eingestelltem Vorteiler ein etwas anderes Zählverhalten:&lt;br /&gt;
:Wenn der Vorteiler auf 1 gestellt, und C der voreingestellte Vergleichswert ist, dann nimmt das Datenregister, im CPU-Takt betrachtet, folgende Werte an:&lt;br /&gt;
:... | C-2 | C-1 | C | 0 | 1 |...&lt;br /&gt;
:Wenn der Vorteiler z.B. auf 8 eingestellt ist, dann nimmt das Datenregister folgende Werte an:&lt;br /&gt;
:... | C-2, C-2, C-2, C-2, C-2, C-2, C-2, C-2 | C-1, C-1, C-1, C-1, C-1, C-1, C-1, C-1 | C, 0, 0, 0, 0, 0, 0, 0 |...&lt;br /&gt;
:In der PWM-Betriebsart hat dieses Bit keine Funktion.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;CS12&#039;&#039;&#039;, &#039;&#039;&#039;CS11&#039;&#039;&#039;, &#039;&#039;&#039;CS10&#039;&#039;&#039; (&#039;&#039;&#039;C&#039;&#039;&#039;lock &#039;&#039;&#039;S&#039;&#039;&#039;elect Bits)&lt;br /&gt;
:Diese 3 Bits bestimmen die Quelle für den Timer/Counter:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | CS12&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | CS11&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | CS10&lt;br /&gt;
| Resultat&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;
| Stopp, Der Timer/Counter wird 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;
| CPU-Takt&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;
| CPU-Takt / 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;
| CPU-Takt / 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;
| CPU-Takt / 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;
| CPU-Takt / 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;
| Externer 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;
| Externer Pin T1, steigende Flanke&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&lt;br /&gt;
:Wenn als Quelle der externe Pin T1 verwendet wird, so wird ein Flankenwechsel auch erkannt, wenn der Pin T1 als Ausgang geschaltet ist.&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;TCNT1H&#039;&#039;&#039;&amp;lt;br /&amp;gt;&#039;&#039;&#039;TCNT1L&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;T&#039;&#039;&#039;imer/&#039;&#039;&#039;C&#039;&#039;&#039;ou&#039;&#039;&#039;nt&#039;&#039;&#039;er Daten Register Timer/Counter &#039;&#039;&#039;1&#039;&#039;&#039;&lt;br /&gt;
Dieses ist als 16-Bit Aufwärtszähler mit Schreib- und Lesezugriff realisiert. Wenn der Zähler den Wert 65535 erreicht hat, beginnt er beim nächsten Zyklus wieder bei 0.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Bit&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 7&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 6&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 5&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 4&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 2&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; | &amp;amp;nbsp;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Name&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;MSB&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;TCNT1H&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Name&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;LSB&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;TCNT1L&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;R/W&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Initialwert&#039;&#039;&#039;&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;
| 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;
| 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; | &amp;amp;nbsp;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
In der PWM-Betriebsart wird das Register als Auf/Ab-Zähler verwendet, d.h. der Wert steigt zuerst von 0, bis er den Überlauf von 65535 auf 0 erreicht hat. Dann zählt das Register rückwärts wiederum bis 0.&lt;br /&gt;
&lt;br /&gt;
Zum Auslesen des Registers wird von der CPU ein internes TEMP-Register verwendet. Das gleiche Register wird auch verwendet, wenn auf &#039;&#039;&#039;OCR1&#039;&#039;&#039; oder &#039;&#039;&#039;ICR1&#039;&#039;&#039; zugegriffen wird.&lt;br /&gt;
&lt;br /&gt;
Deshalb müssen vor dem Zugriff auf eines dieser Register alle Interrupts gesperrt werden, weil sonst die Möglichkeit des gleichzeitigen Zugriffs auf das Temporärregister gegeben ist, was natürlich zu fehlerhaftem Verhalten des Programms führt.. Zudem muss zuerst &#039;&#039;&#039;TCNT1L&#039;&#039;&#039; und erst danach &#039;&#039;&#039;TCNT1H&#039;&#039;&#039; ausgelesen werden.&lt;br /&gt;
&lt;br /&gt;
Wenn in das Register geschrieben werden soll, müssen ebenfalls alle Interrrupts gesperrt werden. Dann muss zuerst das &#039;&#039;&#039;TCNT1H&#039;&#039;&#039;-Register und erst danach das &#039;&#039;&#039;TCNT1L&#039;&#039;&#039;-Register geschrieben werden, also genau die umgekehrte Reihenfolge wie beim Lesen des Registers.&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;OCR1H&#039;&#039;&#039;&amp;lt;br /&amp;gt;&#039;&#039;&#039;OCR1L&#039;&#039;&#039;&lt;br /&gt;
| Timer/Counter &#039;&#039;&#039;O&#039;&#039;&#039;utput &#039;&#039;&#039;C&#039;&#039;&#039;ompare &#039;&#039;&#039;R&#039;&#039;&#039;egister Timer/Counter &#039;&#039;&#039;1&#039;&#039;&#039;&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Bit&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 7&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 6&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 5&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 4&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 2&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; | &amp;amp;nbsp;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Name&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;MSB&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;OCR1H&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Name&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;LSB&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;OCR1L&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;R/W&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Initialwert&#039;&#039;&#039;&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;
| 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;
| 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; | &amp;amp;nbsp;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Der Wert im Output Compare Register wird ständig mit dem aktuellen Wert im Datenregister TCNT1H/TCNT1L verglichen. Stimmen die beiden Werte überein, so wird ein sogenannter Output Compare Match ausgelöst. Die entsprechenden Aktionen werden über die Timer/Counter 1 Control und Status Register eingestellt.&lt;br /&gt;
&lt;br /&gt;
Zum Auslesen des Registers wird von der CPU ein internes TEMP-Register verwendet. Das gleiche Register wird auch verwendet, wenn auf &#039;&#039;&#039;TCNT1&#039;&#039;&#039; oder &#039;&#039;&#039;ICR1&#039;&#039;&#039; zugegriffen wird.&lt;br /&gt;
Deshalb müssen vor dem Zugriff auf eines dieser Register alle Interrupts gesperrt werden, weil sonst die Möglichkeit des gleichzeitigen Zugriffs auf das Temporärregister gegeben ist, was natürlich zu fehlerhaftem Verhalten des Programms führt.. Zudem muss zuerst &#039;&#039;&#039;OCR1L&#039;&#039;&#039; und erst danach &#039;&#039;&#039;OCR1H&#039;&#039;&#039; ausgelesen werden.&lt;br /&gt;
&lt;br /&gt;
Wenn in das Register geschrieben werden soll, müssen ebenfalls alle Interrupts gesperrt werden. Dann muss zuerst das &#039;&#039;&#039;OCR1H&#039;&#039;&#039;-Register und erst danach das &#039;&#039;&#039;OCR1L&#039;&#039;&#039;-Register geschrieben werden, also genau die umgekehrte Reihenfolge wie beim Lesen des Registers.&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;ICR1H&#039;&#039;&#039;&amp;lt;br /&amp;gt;&#039;&#039;&#039;ICR1L&#039;&#039;&#039;&lt;br /&gt;
| Timer/Counter &#039;&#039;&#039;I&#039;&#039;&#039;nput &#039;&#039;&#039;C&#039;&#039;&#039;apture &#039;&#039;&#039;R&#039;&#039;&#039;egister Timer/Counter &#039;&#039;&#039;1&#039;&#039;&#039;&amp;lt;br /&amp;gt;&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Bit&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 7&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 6&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 5&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 4&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 2&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; | &amp;amp;nbsp;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Name&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;MSB&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ICR1&#039;&#039;&#039;&#039;&#039;&#039;H&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Name&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;LSB&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ICR1&#039;&#039;&#039;&#039;&#039;&#039;L&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;R/W&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Initialwert&#039;&#039;&#039;&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;
| 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;
| 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; | &amp;amp;nbsp;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Das Input Capture Register ist ein 16-Bit Register mit Lesezugriff. Es kann nicht beschrieben werden.&lt;br /&gt;
&lt;br /&gt;
Wenn am Input Capture Pin &#039;&#039;&#039;ICP&#039;&#039;&#039; die gemäß Einstellungen im &#039;&#039;&#039;TCCR1B&#039;&#039;&#039; definierte Flanke erkannt wird, so wird der aktuelle Inhalt des Datenregisters &#039;&#039;&#039;TCNT1H&#039;&#039;&#039;/&#039;&#039;&#039;TCNT1L&#039;&#039;&#039; sofort in dieses Register kopiert und das Input Capture Flag &#039;&#039;&#039;ICF1&#039;&#039;&#039; im Timer Interrupt Flag Register &#039;&#039;&#039;TIFR&#039;&#039;&#039; gesetzt.&lt;br /&gt;
&lt;br /&gt;
Wie bereits oben erwähnt, müssen vor dem Zugriff auf dieses Register alle Interrupts gesperrt werden. Zudem müssen Low- und Highbyte des Registers in der richtigen Reihenfolge bearbeitet werden:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;0&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| Lesen:&lt;br /&gt;
| &#039;&#039;&#039;ICR1L&#039;&#039;&#039; -&amp;gt; &#039;&#039;&#039;ICR1H&#039;&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Die PWM-Betriebsart ===&lt;br /&gt;
&lt;br /&gt;
Wenn der Timer/Counter 1 in der PWM-Betriebsart betrieben wird, so bilden das Datenregister &#039;&#039;&#039;TCNT1H&#039;&#039;&#039;/&#039;&#039;&#039;TCNT1L&#039;&#039;&#039; und das Vergleichsregister &#039;&#039;&#039;OCR1H&#039;&#039;&#039;/&#039;&#039;&#039;OCR1L&#039;&#039;&#039; einen 8-, 9- oder 10-Bit, frei laufenden PWM-Modulator, welcher als PWM-Signal am &#039;&#039;&#039;OC1&#039;&#039;&#039;-Pin (&#039;&#039;&#039;PB3&#039;&#039;&#039; beim 2313) abgegriffen werden kann. Das Datenregister &#039;&#039;&#039;TCNT1H&#039;&#039;&#039;/&#039;&#039;&#039;TCNT1L&#039;&#039;&#039; wird dabei als Auf-/Ab-Zähler betrieben, welcher von 0 an aufwärts zählt bis zur Obergrenze und danach wieder zurück auf 0.&lt;br /&gt;
Die Obergrenze ergibt sich daraus, ob 8-, 9- oder 10-Bit PWM verwendet wird, und zwar gemäß folgender Tabelle:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;Auflösung&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;Obergrenze&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Frequenz&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 8&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 255&lt;br /&gt;
| f&amp;lt;sub&amp;gt;TC1&amp;lt;/sub&amp;gt; / 510&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 9&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 511&lt;br /&gt;
| f&amp;lt;sub&amp;gt;TC1&amp;lt;/sub&amp;gt; / 1022&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 10&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1023&lt;br /&gt;
| f&amp;lt;sub&amp;gt;TC1&amp;lt;/sub&amp;gt; / 2046&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Wenn nun der Zählerwert im Datenregister den in &#039;&#039;&#039;OCR1H&#039;&#039;&#039;/&#039;&#039;&#039;OCR1L&#039;&#039;&#039; gespeicherten Wert erreicht, wird der Ausgabepin &#039;&#039;&#039;OC1&#039;&#039;&#039; gesetzt bzw. gelöscht, je nach Einstellung von &#039;&#039;&#039;COM1A1&#039;&#039;&#039; und &#039;&#039;&#039;COM1A0&#039;&#039;&#039; im &#039;&#039;&#039;TCCR1A&#039;&#039;&#039;-Register.&lt;br /&gt;
&lt;br /&gt;
Ich habe versucht, die entsprechenden Signale in der folgenden Grafik zusammenzufassen&lt;br /&gt;
&lt;br /&gt;
[[Image:PWM Theorie 3.gif]] [[Image:PWM Theorie 4.gif]]&lt;br /&gt;
&lt;br /&gt;
=== Vergleichswert-Überprüfung ===&lt;br /&gt;
&lt;br /&gt;
Hier wird in ein spezielles Vergleichswertregister (&#039;&#039;&#039;OCR1H&#039;&#039;&#039;/&#039;&#039;&#039;OCR1L&#039;&#039;&#039;) ein Wert eingeschrieben, welcher ständig mit dem aktuellen Zählerwert verglichen wird.&lt;br /&gt;
Erreicht der Zähler den in diesem Register eingetragenen Wert, so kann ein Signal (0 oder 1) am Pin &#039;&#039;&#039;OC1&#039;&#039;&#039; erzeugt und/oder ein Interrupt ausgelöst werden.&lt;br /&gt;
&lt;br /&gt;
=== Einfangen eines Eingangssignals (Input Capturing) ===&lt;br /&gt;
&lt;br /&gt;
Bei dieser Betriebsart wird an den Input Capturing Pin (ICP) des Controllers eine Signalquelle angeschlossen.&lt;br /&gt;
Nun kann je nach Konfiguration entweder ein Signalwechsel von 0 nach 1 (steigende Flanke) oder von 1 nach 0 (fallende Flanke) erkannt werden und der zu diesem Zeitpunkt aktuelle Zählerstand in ein spezielles Register abgelegt werden. Gleichzeitig kann auch ein entsprechender Interrupt ausgelöst werden.&lt;br /&gt;
Wenn die Signalquelle ein starkes Rauschen beinhaltet, kann die Rauschunterdrückung eingeschaltet werden. Dann wird beim Erkennen der konfigurierten Flanke über 4 Taktzyklen das Signal überwacht und nur dann, wenn alle 4 Messungen gleich sind, wird die entsprechende Aktion ausgelöst.&lt;br /&gt;
&lt;br /&gt;
== Gemeinsame Register ==&lt;br /&gt;
&lt;br /&gt;
Verschiedene Register beinhalten Zustände und Einstellungen, welche sowohl&lt;br /&gt;
für den 8-Bit, als auch für den 16-Bit Timer/Counter in ein und demselben&lt;br /&gt;
Register zu finden sind.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;TIMSK&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;T&#039;&#039;&#039;imer/Counter &#039;&#039;&#039;I&#039;&#039;&#039;nterrupt &#039;&#039;&#039;M&#039;&#039;&#039;a&#039;&#039;&#039;sk&#039;&#039;&#039;&lt;br /&gt;
Register&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Bit&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 7&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 6&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 5&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 4&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 2&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Name&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;TOIE1&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;OCIE1A&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;TICIE&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;TOIE0&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;R/W&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Initialwert&#039;&#039;&#039;&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;
| 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;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;TOIE1&#039;&#039;&#039; (&#039;&#039;&#039;T&#039;&#039;&#039;imer/Counter &#039;&#039;&#039;O&#039;&#039;&#039;verflow &#039;&#039;&#039;I&#039;&#039;&#039;nterrupt &#039;&#039;&#039;E&#039;&#039;&#039;nable Timer/Counter &#039;&#039;&#039;1&#039;&#039;&#039;)&lt;br /&gt;
:Wenn dieses Bit gesetzt ist, wird bei einem Überlauf des Datenregisters des Timer/Counter 1 ein Timer Overflow 1 Interrupt ausgelöst. Das Global Enable Interrupt Flag muss selbstverständlich auch gesetzt sein.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;OCIE1A&#039;&#039;&#039; (&#039;&#039;&#039;O&#039;&#039;&#039;utput &#039;&#039;&#039;C&#039;&#039;&#039;ompare Match &#039;&#039;&#039;I&#039;&#039;&#039;nterrupt &#039;&#039;&#039;E&#039;&#039;&#039;nable Timer/Counter &#039;&#039;&#039;1&#039;&#039;&#039;)&lt;br /&gt;
:Beim Timer/Counter 1 kann zusätzlich zum Überlauf ein Vergleichswert definiert werden.&lt;br /&gt;
&lt;br /&gt;
:Wenn dieses Bit gesetzt ist, wird beim Erreichen des Vergleichswertes ein Compare Match Interrupt ausgelöst. Das Global Enable Interrupt Flag muss selbstverständlich auch gesetzt sein.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;TICIE&#039;&#039;&#039; (&#039;&#039;&#039;T&#039;&#039;&#039;imer/Counter &#039;&#039;&#039;I&#039;&#039;&#039;nput &#039;&#039;&#039;C&#039;&#039;&#039;apture &#039;&#039;&#039;I&#039;&#039;&#039;nterrupt &#039;&#039;&#039;E&#039;&#039;&#039;nable)&lt;br /&gt;
:Wenn dieses Bit gesetzt ist, wird ein Capture Event Interrupt ausgelöst, wenn ein entsprechendes Signalereignis am Pin PD6(ICP) auftritt. Das Global Enable Interrupt Flag muss selbstverständlich auch gesetzt sein, wenn auch ein entsprechender Interrupt ausgelöst werden soll.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;TOIE0&#039;&#039;&#039; (&#039;&#039;&#039;T&#039;&#039;&#039;imer/Counter &#039;&#039;&#039;O&#039;&#039;&#039;verflow &#039;&#039;&#039;I&#039;&#039;&#039;nterrupt &#039;&#039;&#039;E&#039;&#039;&#039;nable Timer/Counter &#039;&#039;&#039;0&#039;&#039;&#039;)&lt;br /&gt;
:Wenn dieses Bit gesetzt ist, wird bei einem Überlauf des Datenregisters des Timer/Counter 0 ein Timer Overflow 0 Interrupt ausgelöst. Das Global Enable Interrupt Flag muss selbstverständlich auch gesetzt sein.&lt;br /&gt;
&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;TIFR&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;T&#039;&#039;&#039;imer/Counter &#039;&#039;&#039;I&#039;&#039;&#039;nterrupt &#039;&#039;&#039;F&#039;&#039;&#039;lag &#039;&#039;&#039;R&#039;&#039;&#039;egister&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Bit&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 7&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 6&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 5&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 4&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 2&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Name&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;TOV1&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;OCF1A&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ICF1&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;TOV0&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;R/W&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Initialwert&#039;&#039;&#039;&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;
| 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;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;TOV1&#039;&#039;&#039; (&#039;&#039;&#039;T&#039;&#039;&#039;imer/Counter &#039;&#039;&#039;O&#039;&#039;&#039;verflow Flag Timer/Counter &#039;&#039;&#039;1&#039;&#039;&#039;)&lt;br /&gt;
:Dieses Bit wird vom Controller gesetzt, wenn beim Timer 1 ein Überlauf des Datenregisters stattfindet.&lt;br /&gt;
&lt;br /&gt;
:In der PWM-Betriebsart wird das Bit gesetzt, wenn die Zählrichtung von auf- zu abwärts und umgekehrt geändert wird (Zählerwert = 0).&lt;br /&gt;
&lt;br /&gt;
:Das Flag wird automatisch gelöscht, wenn der zugehörige Interrupt-Vektor aufgerufen wird. Es kann jedoch auch gelöscht werden, indem eine logische 1 (!) in das entsprechende Bit geschrieben wird.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;OCF1A&#039;&#039;&#039; (&#039;&#039;&#039;O&#039;&#039;&#039;utput &#039;&#039;&#039;C&#039;&#039;&#039;ompare &#039;&#039;&#039;F&#039;&#039;&#039;lag Timer/Counter &#039;&#039;&#039;1&#039;&#039;&#039;)&lt;br /&gt;
:Dieses Bit wird gesetzt, wenn der aktuelle Wert des Datenregisters von Timer/Counter 1 mit demjenigen im Vergleichsregister &#039;&#039;&#039;OCR1&#039;&#039;&#039; übereinstimmt.&lt;br /&gt;
&lt;br /&gt;
:Das Flag wird automatisch gelöscht, wenn der zugehörige Interrupt-Vektor aufgerufen wird. Es kann jedoch auch gelöscht werden, indem eine logische 1 (!) in das entsprechende Bit geschrieben wird.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ICF1&#039;&#039;&#039; (&#039;&#039;&#039;I&#039;&#039;&#039;nput &#039;&#039;&#039;C&#039;&#039;&#039;apture &#039;&#039;&#039;F&#039;&#039;&#039;lag Timer/Counter &#039;&#039;&#039;1&#039;&#039;&#039;)&lt;br /&gt;
:Dieses Bit wird gesetzt, wenn ein Capture-Ereignis aufgetreten ist, welches anzeigt, dass der Wert des Datenregisters des  Timer/Counter 1 in das Input Capture Register ICR1 übertragen wurde.&lt;br /&gt;
&lt;br /&gt;
:Das Flag wird automatisch gelöscht, wenn der zugehörige Interrupt-Vektor aufgerufen wird. Es kann jedoch auch gelöscht werden, indem eine logische 1 (!) in das entsprechende Bit geschrieben wird.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;TOV0&#039;&#039;&#039; (&#039;&#039;&#039;T&#039;&#039;&#039;imer/Counter &#039;&#039;&#039;O&#039;&#039;&#039;verflow Flag Timer/Counter &#039;&#039;&#039;0&#039;&#039;&#039;)&lt;br /&gt;
:Dieses Bit wird vom Controller gesetzt, wenn beim Timer 0 ein Überlauf des Datenregisters stattfindet.&lt;br /&gt;
&lt;br /&gt;
:Das Flag wird automatisch gelöscht, wenn der zugehörige Interrupt-Vektor aufgerufen wird. Es kann jedoch auch gelöscht werden, indem eine logische 1 (!) in das entsprechende Bit geschrieben wird.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;amp;nbsp;&lt;br /&gt;
&lt;br /&gt;
= Warteschleifen (delay.h) =&lt;br /&gt;
&lt;br /&gt;
Der Programmablauf kann verschiedene Arten von Wartefunktionen erfordern:&lt;br /&gt;
&lt;br /&gt;
* Warten im Sinn von Zeitvertrödeln&lt;br /&gt;
* Warten auf einen bestimmten Zustand an den I/O-Pins&lt;br /&gt;
* Warten auf einen bestimmten Zeitpunkt (siehe Timer)&lt;br /&gt;
* Warten auf einen bestimmten Zählerstand (siehe Counter)&lt;br /&gt;
&lt;br /&gt;
Der einfachste Fall, das Zeitvertrödeln, kann in vielen Fällen und mit großer Genauigkeit anhand der avr-libc Bibliotheksfunktionen _delay_ms() und _delay_us() erledigt werden. Die Bibliotheksfunktionen sind einfachen Zählschleifen (Warteschleifen) vorzuziehen, da leere Zählschleifen ohne besondere Vorkehrungen sonst bei eingeschalteter Optimierung vom avr-gcc-Compiler wegoptimiert werden. Weiterhin sind die Bibliotheksfunktionen bereits darauf vorbereitet, die in F_CPU definierte Taktfrequenz zu verwenden. Ausserdem sind die Funktionen der Bibliothek wirklich getestet.&lt;br /&gt;
&lt;br /&gt;
Einfach!? Schon, aber während gewartet wird, macht der µC nichts anderes mehr. Die Wartefunktion blockiert den Programmablauf. Möchte man einerseits warten, um z.B. eine LED blinken zu lassen und gleichzeitig andere Aktionen ausführen z.B. weitere LED bedienen, sollten die Timer/Counter des AVR verwendet werden.&lt;br /&gt;
&lt;br /&gt;
Die Bibliotheksfunktionen funktionieren allerdings nur dann korrekt, wenn sie mit zur Übersetzungszeit (beim Compilieren) bekannten konstanten Werten aufgerufen werden. Der Quellcode muss mit eingeschalteter Optimierung übersetzt werden, sonst wird sehr viel Maschinencode erzeugt und die Wartezeiten stimmen nicht mehr mit dem Parameter überein.&lt;br /&gt;
&lt;br /&gt;
Abhängig von der Version der Bibliothek verhalten sich die Bibliotheksfunktionen etwas unterschiedlich.&lt;br /&gt;
&lt;br /&gt;
== avr-libc Versionen kleiner 1.6 ==&lt;br /&gt;
&lt;br /&gt;
Die Wartezeit der Funktion _delay_ms() ist auf 262,14ms/F_CPU (in MHz) begrenzt, d.h. bei 20 MHz kann man nur max. 13,1ms warten. Die Wartezeit der Funktion _delay_us() ist auf 768us/F_CPU (in MHz) begrenzt, d.h. bei 20 MHz kann man nur max. 38,4us warten. Längere Wartezeiten müssen dann über einen mehrfachen Aufruf in einer Schleife gelöst werden.&lt;br /&gt;
&lt;br /&gt;
Beispiel: Blinken einer LED an PORTB Pin PB0 im ca. 1s Rhythmus&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#ifndef F_CPU&lt;br /&gt;
/* Definiere F_CPU, wenn F_CPU nicht bereits vorher definiert &lt;br /&gt;
   (z.B. durch Übergabe als Parameter zum Compiler innerhalb &lt;br /&gt;
   des Makefiles). Zusätzlich Ausgabe einer Warnung, die auf die&lt;br /&gt;
   &amp;quot;nachträgliche&amp;quot; Definition hinweist */&lt;br /&gt;
#warning &amp;quot;F_CPU war noch nicht definiert, wird nun mit 3686400 definiert&amp;quot;&lt;br /&gt;
#define F_CPU 3686400UL     /* Quarz mit 3.6864 Mhz */&lt;br /&gt;
#endif&lt;br /&gt;
#include &amp;lt;util/delay.h&amp;gt;     /* in älteren avr-libc Versionen &amp;lt;avr/delay.h&amp;gt; */ &lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
 lange, variable Verzögerungszeit, Einheit in Millisekunden&lt;br /&gt;
&lt;br /&gt;
Die maximale Zeit pro Funktionsaufruf ist begrenzt auf &lt;br /&gt;
262.14 ms / F_CPU in MHz (im Beispiel: &lt;br /&gt;
262.1 / 3.6864 = max. 71 ms) &lt;br /&gt;
&lt;br /&gt;
Daher wird die kleine Warteschleife mehrfach aufgerufen,&lt;br /&gt;
um auf eine längere Wartezeit zu kommen. Die zusätzliche &lt;br /&gt;
Prüfung der Schleifenbedingung lässt die Wartezeit geringfügig&lt;br /&gt;
ungenau werden (macht hier vielleicht 2-3ms aus).&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
void long_delay(uint16_t ms) {&lt;br /&gt;
    for(; ms&amp;gt;0; ms--) _delay_ms(1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int main( void )&lt;br /&gt;
{&lt;br /&gt;
    DDRB = ( 1 &amp;lt;&amp;lt; PB0 );        // PB0 an PORTB als Ausgang setzen&lt;br /&gt;
&lt;br /&gt;
    while( 1 ) {                // Endlosschleife&lt;br /&gt;
        PORTB ^= ( 1 &amp;lt;&amp;lt; PB0 );  // Toggle PB0 z.B. angeschlossene LED&lt;br /&gt;
        long_delay(1000);       // Eine Sekunde warten...&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== avr-libc Versionen ab 1.6 ==&lt;br /&gt;
&lt;br /&gt;
_delay_ms() kann mit einem Argument bis 6553,5 ms (= 6,5535 Sekunden) benutzt werden. Wird die früher gültige Grenze von 262,14 ms/F_CPU (in MHz) überschritten, so arbeitet _delay_ms() einfach etwas ungenauer und zählt nur noch mit einer Auflösung von 1/10 ms. Eine Verzögerung von 1000,10 ms ließe sich nicht mehr von einer von 1000,19 ms unterscheiden. Ein Verlust, der sich im Allgemeinen verschmerzen lässt. Dem Programmierer wird keine Rückmeldung gegeben, dass die Funktion ggf. gröber arbeitet, d.h. wenn es darauf ankommt, bitte den Parameter wie bisher geschickt wählen.&lt;br /&gt;
&lt;br /&gt;
Die Funktion _delay_us() wurde ebenfalls erweitert. Wenn deren maximal als genau behandelbares Argument überschritten wird, benutzt diese intern _delay_ms(). Damit gelten in diesem Fall die _delay_ms() Einschränkungen.&lt;br /&gt;
&lt;br /&gt;
Beispiel: Blinken einer LED an PORTB Pin PB0 im ca. 1s Rhythmus, avr-libc ab Version 1.6&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#ifndef F_CPU&lt;br /&gt;
/* Definiere F_CPU, wenn F_CPU nicht bereits vorher definiert &lt;br /&gt;
   (z.B. durch Übergabe als Parameter zum Compiler innerhalb &lt;br /&gt;
   des Makefiles). Zusätzlich Ausgabe einer Warnung, die auf die&lt;br /&gt;
   &amp;quot;nachträgliche&amp;quot; Definition hinweist */&lt;br /&gt;
#warning &amp;quot;F_CPU war noch nicht definiert, wird nun mit 3686400 definiert&amp;quot;&lt;br /&gt;
#define F_CPU 3686400UL     /* Quarz mit 3.6864 Mhz */&lt;br /&gt;
#endif&lt;br /&gt;
#include &amp;lt;util/delay.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
int main( void )&lt;br /&gt;
{&lt;br /&gt;
    DDRB = ( 1 &amp;lt;&amp;lt; PB0 );        // PB0 an PORTB als Ausgang setzen&lt;br /&gt;
&lt;br /&gt;
    while( 1 ) {                // Endlosschleife&lt;br /&gt;
        PORTB ^= ( 1 &amp;lt;&amp;lt; PB0 );  // Toggle PB0 z.B. angeschlossene LED&lt;br /&gt;
        _delay_ms(1000);        // Eine Sekunde +/-1/10000 Sekunde warten...&lt;br /&gt;
                                // funktioniert nicht mit Bibliotheken vor 1.6&lt;br /&gt;
&lt;br /&gt;
    }&lt;br /&gt;
    return 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Der Watchdog =&lt;br /&gt;
&lt;br /&gt;
Und hier kommt das ultimative Mittel gegen die Unvollkommenheit von uns&lt;br /&gt;
Programmierern, der Watchdog.&lt;br /&gt;
&lt;br /&gt;
So sehr wir uns auch anstrengen, es wird uns kaum je gelingen, das absolut&lt;br /&gt;
perfekte und fehlerfreie Programm zu entwickeln.&lt;br /&gt;
&lt;br /&gt;
Der Watchdog kann uns zwar auch nicht zu besseren Programmen verhelfen aber er&lt;br /&gt;
kann dafür sorgen, dass unser Programm, wenn es sich wieder mal in&#039;s Nirwana&lt;br /&gt;
verabschiedet hat, neu gestartet wird, indem ein Reset des Controllers&lt;br /&gt;
ausgelöst wird.&lt;br /&gt;
&lt;br /&gt;
Betrachten wir doch einmal folgende Codesequenz:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
    uint8_t x;&lt;br /&gt;
&lt;br /&gt;
    x = 10;&lt;br /&gt;
&lt;br /&gt;
    while (x &amp;gt;= 0)&lt;br /&gt;
    {&lt;br /&gt;
      // tu was&lt;br /&gt;
&lt;br /&gt;
      x--;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn wir die Schleife mal genau anschauen sollte uns auffallen, dass dieselbe niemals beendet wird. Warum nicht? Ganz einfach, weil eine als &#039;&#039;&#039;&#039;&#039;unsigned&#039;&#039;&#039;&#039;&#039; deklarierte Variable niemals kleiner als Null werden kann (der Compiler sollte jedoch eine ensprechende Warnung ausgeben).&lt;br /&gt;
Das Programm würde sich also hier aufhängen und auf ewig in der Schleife drehen.&lt;br /&gt;
Und hier genau kommt der Watchdog zum Zug.&lt;br /&gt;
&lt;br /&gt;
== Wie funktioniert nun der Watchdog? ==&lt;br /&gt;
&lt;br /&gt;
Der Watchdog enthält einen separaten Timer/Counter, welcher mit einem intern erzeugten Takt von 1 MHz bei 5V Vcc getaktet wird. Einige Controller haben einen eigenen Watchdog Oszillator, z.B. der Tiny2313 mit 128kHz. Nachdem der Watchdog aktiviert und der gewünschte Vorteiler eingestellt wurde, beginnt der Counter von 0 an hochzuzählen. &lt;br /&gt;
Wenn nun die je nach Vorteiler eingestellte Anzahl Zyklen erreicht wurde, löst der Watchdog einen Reset aus. Um nun also im Normalbetrieb den Reset zu verhindern, müssen wir den Watchdog regelmäßig wieder neu starten bzw. rücksetzen (Watchdog Reset). &lt;br /&gt;
Dies sollte innerhalb unserer Hauptschleife passieren.&lt;br /&gt;
&lt;br /&gt;
Um ein unbeabsichtigtes Ausschalten des Watchdogs zu verhindern, muss ein spezielles Prozedere verwendet werden, um den WD auszuschalten. Es müssen zuerst die beiden Bits WDTOE und WDE in einer einzelnen Operation (also nicht mit sbi) auf 1 gesetzt werden. &lt;br /&gt;
Dann muss innerhalb der nächsten 4 Taktzyklen das Bit WDE auf 0 gesetzt werden.&lt;br /&gt;
&lt;br /&gt;
Das Watchdog Control Register:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;WDTCR&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;W&#039;&#039;&#039;atchog &#039;&#039;&#039;T&#039;&#039;&#039;imer&amp;amp;nbsp; &#039;&#039;&#039;C&#039;&#039;&#039;ontrol &#039;&#039;&#039;R&#039;&#039;&#039;egister&lt;br /&gt;
&lt;br /&gt;
In diesem Register stellen wir ein, wie wir den Watchdog verwenden möchten.&lt;br /&gt;
&lt;br /&gt;
Das Register ist wie folgt aufgebaut:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Bit&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 7&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 6&lt;br /&gt;
| align=&amp;amp;quot;center&amp;quot; | 5&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 4&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 2&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Name&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;WDTOE&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;WDE&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;WDP2&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;WDP1&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;WDP0&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;R/W&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Initialwert&#039;&#039;&#039;&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;
| 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;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;WDTOE&#039;&#039;&#039; (&#039;&#039;&#039;W&#039;&#039;&#039;atch&#039;&#039;&#039;d&#039;&#039;&#039;og &#039;&#039;&#039;T&#039;&#039;&#039;urn &#039;&#039;&#039;O&#039;&#039;&#039;ff &#039;&#039;&#039;E&#039;&#039;&#039;nable)&lt;br /&gt;
:Dieses Bit muss gesetzt sein, wenn das Bit &#039;&#039;&#039;WDE&#039;&#039;&#039; gelöscht wird, andernfalls wird der Watchdog nicht ausgeschaltet.&lt;br /&gt;
:Wenn das Bit einmal gesetzt ist, wird es von der Hardware nach 4 Taktzyklen automatisch wieder gelöscht.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;WDE&#039;&#039;&#039; (&#039;&#039;&#039;W&#039;&#039;&#039;atch&#039;&#039;&#039;d&#039;&#039;&#039;og &#039;&#039;&#039;E&#039;&#039;&#039;nable)&lt;br /&gt;
:Wenn dieses Bit gesetzt wird, so wird der Watchdog aktiviert.&lt;br /&gt;
:Das Bit kann nur gelöscht werden, solange das Bit &#039;&#039;&#039;WDTOE&#039;&#039;&#039; auf 1 steht.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;WDP2&#039;&#039;&#039;, &#039;&#039;&#039;WDP1&#039;&#039;&#039;, &#039;&#039;&#039;WDP0&#039;&#039;&#039; (&#039;&#039;&#039;W&#039;&#039;&#039;atch&#039;&#039;&#039;d&#039;&#039;&#039;og Timer &#039;&#039;&#039;P&#039;&#039;&#039;rescaler Bits)&lt;br /&gt;
:Diese 3 Bits bestimmen die Anzahl Oszillatorzyklen für den Watchdog, also, wie lange es dauert, bis ein Reset ausgelöst wird:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | WDP2&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | WDP1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | WDP0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | Anzahl Zyklen&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | Typ. Timeoutzeit bei Vcc = 3V&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | Typ. Timeoutzeit bei Vcc = 5V&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;
| align=&amp;quot;center&amp;quot; | 16K&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 47ms&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 15ms&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;
| align=&amp;quot;center&amp;quot; | 32K&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 94ms&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 30ms&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;
| align=&amp;quot;center&amp;quot; | 64K&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0.19s&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 60ms&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;
| align=&amp;quot;center&amp;quot; | 128K&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0.38s&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0.12s&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;
| align=&amp;quot;center&amp;quot; | 256K&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0.75s&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0.24s&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;
| align=&amp;quot;center&amp;quot; | 512K&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1.5s&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0.49s&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;
| align=&amp;quot;center&amp;quot; | 1024K&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3s&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0.97s&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;
| align=&amp;quot;center&amp;quot; | 2048K&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 6s&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1.9s&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Um den Watchdog mit dem AVR-GCC Compiler zu verwenden, muss die Headerdatei &#039;&#039;wdt.h&#039;&#039; (&#039;&#039;#include &amp;lt;avr/wdt.h&amp;gt;&#039;&#039;) in die Quelldatei eingebunden werden. &lt;br /&gt;
&amp;lt;!-- mt: das stimmt wohl nicht mehr?!:&lt;br /&gt;
Dadurch wird auch der Startup-Code entsprechend angepasst, so dass der Watchdog nach einem Reset automatisch gestartet wird. &lt;br /&gt;
Das WDTCR-Register wird dabei mit dem Wert 0 beschrieben. &lt;br /&gt;
Falls ein anderer Wert gewünscht ist, so kann dies im Makfile in den Linker-Optionen eingetragen werden. &lt;br /&gt;
Dazu muss in der Zeile LDFLAGS folgende Option angefügt werden:&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; --defsym __init_wdtcr__=0x1f&amp;lt;br /&amp;gt;&lt;br /&gt;
wenn beispielsweise der Wert des Registers auf 0x1f gestellt werden soll.&amp;lt;br /&amp;gt; --&amp;gt;&lt;br /&gt;
Danach können die folgenden Funktionen verwendet werden:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;wdt_enable(uint8_t timeout)&#039;&#039;&#039;&lt;br /&gt;
:Aktiviert den Watchdog und stellt den Vorteiler auf den gewünschten Wert ein bzw. der in timeout übergebene Wert wird in das WDTCR-Register eingetragen. Einige Timeout-Werte sind als Konstanten vordefiniert&lt;br /&gt;
:Mögliche Timeoutwerte:&lt;br /&gt;
&amp;lt;div align=&amp;quot;center&amp;quot;&amp;gt;&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
! Konstante&lt;br /&gt;
! Wert&lt;br /&gt;
! TimeOut&lt;br /&gt;
|- &lt;br /&gt;
| WDTO_15MS   &lt;br /&gt;
| 0&lt;br /&gt;
| 15 ms&lt;br /&gt;
|-&lt;br /&gt;
| WDTO_30MS   &lt;br /&gt;
| 1&lt;br /&gt;
| 30 ms&lt;br /&gt;
|-&lt;br /&gt;
| WDTO_60MS   &lt;br /&gt;
| 2&lt;br /&gt;
| 60 ms&lt;br /&gt;
|-&lt;br /&gt;
| WDTO_120MS   &lt;br /&gt;
| 3&lt;br /&gt;
| 120 ms&lt;br /&gt;
|-&lt;br /&gt;
| WDTO_250MS   &lt;br /&gt;
| 4&lt;br /&gt;
| 250 ms&lt;br /&gt;
|-&lt;br /&gt;
| WDTO_500MS   &lt;br /&gt;
| 5&lt;br /&gt;
| 500 ms&lt;br /&gt;
|-&lt;br /&gt;
| WDTO_1S   &lt;br /&gt;
| 6&lt;br /&gt;
| 1 s&lt;br /&gt;
|-&lt;br /&gt;
| WDTO_2S   &lt;br /&gt;
| 7&lt;br /&gt;
| 2 s&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;wdt_disable()&#039;&#039;&#039;&lt;br /&gt;
:Mit dieser Funktion kann der Watchdog ausgeschaltet werden. Dabei wird das notwendige Prozedere, wie oben beschrieben, automatisch ausgeführt.&lt;br /&gt;
* &#039;&#039;&#039;wdt_reset()&#039;&#039;&#039;&lt;br /&gt;
:Dies ist wohl die wichtigste der Watchdog-Funktionen. Sie erzeugt einen Watchdog-Reset, welcher periodisch, und zwar vor Ablauf der Timeoutzeit, ausgeführt werden muss, damit der Watchdog nicht den AVR zurücksetzt.&lt;br /&gt;
&lt;br /&gt;
Selbstverständlich kann das &#039;&#039;&#039;WDTCR&#039;&#039;&#039;-Register auch mit den uns bereits bekannten Funktionen für den Zugriff auf Register programmiert werden.&lt;br /&gt;
&lt;br /&gt;
== Watchdog-Anwendungshinweise ==&lt;br /&gt;
&lt;br /&gt;
Ob nun der Watchdog als Schutzfunktion überhaupt verwendet werden soll, hängt stark von der Anwendung, der genutzten Peripherie und dem Umfang und der Qualitätssicherung des Codes ab. Will man sicher gehen, dass ein Programm sich nicht in einer Endlosschleife verfängt, ist der Wachdog das geeignete Mittel dies zu verhindern. Weiterhin kann bei geschickter Programmierung der Watchdog dazu genutzt werden, bestimmte Stromsparfunktionen zu implementieren. Bei einigen neueren AVRs (z.B. dem ATTiny13) kann der Watchdog auch direkt als Timer genutzt werden, der den Controller aus einem Schlafmodus aufweckt. Auch dies kann im &#039;&#039;&#039;WDTCR&#039;&#039;&#039;-Register eingestellt werden. Außerdem bietet der WD die einzige Möglichkeit einen beabsichtigten System-Reset (ein &amp;quot;richtiger Reset&amp;quot;, kein &amp;quot;jmp 0x0000&amp;quot;) ohne externe Beschaltung auszulösen, was z.B. bei der Implementierung eines Bootloaders nützlich ist. Bei bestimmten Anwendungen kann die Nutzung des WD als &amp;quot;ultimative Deadlock-Sicherung für nicht bedachte Zustände&amp;quot; natürlich immer als zusätzliche Sicherung dienen. &lt;br /&gt;
&lt;br /&gt;
Es besteht die Möglichkeit herauszufinden, ob ein Reset durch den Watchdog ausgelöst wurde (beim ATmega16 z.B. Bit WDRF in MCUCSR). Diese Information sollte auch genutzt werden, falls ein WD-Reset in der Anwendung nicht planmäßig implementiert wurde. Zum Beispiel kann man eine LED an einen freien Pin hängen, die nur bei einem Reset durch den WD aufleuchtet oder aber das &amp;quot;Ereignis WD-Reset&amp;quot; im internen EEPROM des AVR absichern, um die Information später z.B. über UART oder ein Display auszugeben (oder einfach den EEPROM-Inhalt über die ISP/JTAG-Schnittstelle auslesen).&lt;br /&gt;
&lt;br /&gt;
Siehe auch: &lt;br /&gt;
* [http://www.nongnu.org/avr-libc/user-manual/index.html Dokumentation der avr-libc] Abschnitt Modules/Watchdog timer handling&lt;br /&gt;
* [http://www.mikrocontroller.net/topic/77273#642501 Bug in ATtiny2313?]&lt;br /&gt;
&lt;br /&gt;
= Programmieren mit Interrupts =&lt;br /&gt;
&lt;br /&gt;
Nachdem wir nun alles Wissenswerte für die serielle Programmerstellung&lt;br /&gt;
gelernt haben nehmen wir jetzt ein völlig anderes Thema in Angriff, nämlich&lt;br /&gt;
die Programmierung unter Zuhilfenahme der Interrupts des AVR.&lt;br /&gt;
&lt;br /&gt;
Als erstes wollen wir uns noch einmal den allgemeinen Programmablauf bei der&lt;br /&gt;
Interrupt-Programmierung zu Gemüte führen.&lt;br /&gt;
&lt;br /&gt;
[[Image:Interrupt Programme.gif]]&lt;br /&gt;
&lt;br /&gt;
Man sieht, dass die Interruptroutine quasi parallel zum Hauptprogramm&lt;br /&gt;
abläuft. Da wir nur eine CPU haben ist es natürlich keine echte Parallelität,&lt;br /&gt;
sondern das Hauptprogramm wird beim Eintreffen eines Interrupts unterbrochen,&lt;br /&gt;
die Interruptroutine wird ausgeführt und danach erst wieder zum Hauptprogramm&lt;br /&gt;
zurückgekehrt.&lt;br /&gt;
&lt;br /&gt;
[http://www.mikrocontroller.net/forum/read-1-235092.html#new Ausführlicher Thread im Forum]&lt;br /&gt;
&lt;br /&gt;
== Anforderungen an Interrupt-Routinen ==&lt;br /&gt;
&lt;br /&gt;
Um unliebsamen Überraschungen vorzubeugen, sollten einige Grundregeln bei der Implementierung der Interruptroutinen beachtet werden. Interruptroutinen soll möglichst kurz und schnell abarbeitbar sein, daraus folgt:&lt;br /&gt;
&lt;br /&gt;
* Keine umfangreichen Berechnungen innerhalb der Interruptroutine. (*)&lt;br /&gt;
* Keine langen Programmschleifen.&lt;br /&gt;
* Obwohl es möglich ist, während der Abarbeitung einer Interruptroutine andere oder sogar den gleichen Interrupt wieder zuzulassen, wird davon ohne genaue Kenntnis der internen Abläufe dringend abgeraten.&lt;br /&gt;
&lt;br /&gt;
Interruptroutinen (ISRs) sollten also möglichst kurz sein und keine Schleifen mit vielen Durchläufen enthalten. Längere Operationen können meist in einen &amp;quot;Interrupt-Teil&amp;quot; in einer ISR und einen &amp;quot;Arbeitsteil&amp;quot; im Hauptprogramm aufgetrennt werden. Z.B. Speichern des Zustands aller Eingänge im EEPROM in bestimmten Zeitabständen: ISR-Teil: Zeitvergleich (Timer,RTC) mit Logzeit/-intervall. Bei Übereinstimmung ein globales Flag setzen (volatile bei Flag-Deklaration nicht vergessen, s.u.). Dann im Hauptprogramm prüfen, ob das Flag gesetzt ist. Wenn ja: die Daten im EEPROM ablegen und Flag löschen.&lt;br /&gt;
&lt;br /&gt;
(*)&lt;br /&gt;
Hinweis: &lt;br /&gt;
Es gibt allerdings die seltene Situation, dass man gerade eingelesene&lt;br /&gt;
ADC-Werte sofort verarbeiten muss. Besonders dann, wenn man mehrere Werte sehr&lt;br /&gt;
schnell hintereinander bekommt. Dann bleibt einem nichts anderes übrig, als die&lt;br /&gt;
Werte noch in der ISR zu verarbeiten. Kommt aber sehr selten vor und sollte&lt;br /&gt;
durch geeignete Wahl des Systemtaktes bzw. Auswahl des Controllers vermieden werden!&lt;br /&gt;
&lt;br /&gt;
== Interrupt-Quellen ==&lt;br /&gt;
&lt;br /&gt;
Die folgenden Ereignisse können einen Interrupt auf einem AVR AT90S2313 auslösen, wobei die Reihenfolge der Auflistung auch die Priorität der Interrupts aufzeigt.&lt;br /&gt;
&lt;br /&gt;
* Reset&lt;br /&gt;
* Externer Interrupt 0&lt;br /&gt;
* Externer Interrupt 1&lt;br /&gt;
* Timer/Counter 1 Capture Ereignis&lt;br /&gt;
* Timer/Counter 1 Compare Match&lt;br /&gt;
* Timer/Counter 1 Überlauf&lt;br /&gt;
* Timer/Counter 0 Überlauf&lt;br /&gt;
* UART Zeichen empfangen&lt;br /&gt;
* UART Datenregister leer&lt;br /&gt;
* UART Zeichen gesendet&lt;br /&gt;
* Analoger Komparator&lt;br /&gt;
&lt;br /&gt;
Die Anzahl der möglichen Interruptquellen variiert zwischen den verschiedenen Typen. Im Zweifel hilft ein Blick ins Datenblatt (&amp;quot;Interrupt Vectors&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
== Register ==&lt;br /&gt;
&lt;br /&gt;
Der AT90S2313 verfügt über 2 Register die mit den&lt;br /&gt;
Interrupts zusammen hängen.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;GIMSK&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;G&#039;&#039;&#039;eneral &#039;&#039;&#039;I&#039;&#039;&#039;nterrupt &#039;&#039;&#039;M&#039;&#039;&#039;ask &#039;&#039;&#039;R&#039;&#039;&#039;egister.&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Bit&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 7&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 6&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 5&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 4&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 2&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Name&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;INT1&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;INT0&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;R/W&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Initialwert&#039;&#039;&#039;&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;
| 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;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;INT1&#039;&#039;&#039; (External &#039;&#039;&#039;Int&#039;&#039;&#039;errupt Request &#039;&#039;&#039;1&#039;&#039;&#039; Enable)&lt;br /&gt;
:Wenn dieses Bit gesetzt ist, wird ein Interrupt ausgelöst, wenn am &#039;&#039;&#039;INT1&#039;&#039;&#039;-Pin eine steigende oder fallende (je nach Konfiguration im &#039;&#039;&#039;MCUCR&#039;&#039;&#039;) Flanke erkannt wird.&lt;br /&gt;
:Das Global Enable Interrupt Flag muss selbstverständlich auch gesetzt sein.&lt;br /&gt;
:Der Interrupt wird auch ausgelöst, wenn der Pin als Ausgang geschaltet ist. Auf diese Weise bietet sich die Möglichkeit, Software-Interrupts zu realisieren.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;INT0&#039;&#039;&#039; (External &#039;&#039;&#039;Int&#039;&#039;&#039;errupt Request &#039;&#039;&#039;0&#039;&#039;&#039; Enable)&lt;br /&gt;
:Wenn dieses Bit gesetzt ist, wird ein Interrupt ausgelöst, wenn am &#039;&#039;&#039;INT0&#039;&#039;&#039;-Pin eine steigende oder fallende (je nach Konfiguration im &#039;&#039;&#039;MCUCR&#039;&#039;&#039;) Flanke erkannt wird.&lt;br /&gt;
:Das Global Enable Interrupt Flag muss selbstverständlich auch gesetzt sein.&lt;br /&gt;
:Der Interrupt wird auch ausgelöst, wenn der Pin als Ausgang geschaltet ist. Auf diese Weise bietet sich die Möglichkeit, Software-Interrupts zu realisieren.&lt;br /&gt;
&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;GIFR&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;G&#039;&#039;&#039;eneral &#039;&#039;&#039;I&#039;&#039;&#039;nterrupt &#039;&#039;&#039;F&#039;&#039;&#039;lag &#039;&#039;&#039;R&#039;&#039;&#039;egister.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Bit&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 7&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 6&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 5&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 4&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 2&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Name&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;INTF1&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;INTF0&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;R/W&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Initialwert&#039;&#039;&#039;&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;
| 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;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;INTF1&#039;&#039;&#039; (External &#039;&#039;&#039;Int&#039;&#039;&#039;errupt Flag &#039;&#039;&#039;1&#039;&#039;&#039;)&lt;br /&gt;
:Dieses Bit wird gesetzt, wenn am &#039;&#039;&#039;INT1&#039;&#039;&#039;-Pin eine Interrupt-Kondition, entsprechend der Konfiguration, erkannt wird. Wenn das Global Enable Interrupt Flag gesetzt ist, wird die Interruptroutine angesprungen.&lt;br /&gt;
:Das Flag wird automatisch gelöscht, wenn die Interruptroutine beendet ist. Alternativ kann das Flag gelöscht werden, indem der Wert &#039;&#039;&#039;1(!)&#039;&#039;&#039; eingeschrieben wird.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;INTF0&#039;&#039;&#039; (External &#039;&#039;&#039;Int&#039;&#039;&#039;errupt Flag &#039;&#039;&#039;0&#039;&#039;&#039;)&lt;br /&gt;
:Dieses Bit wird gesetzt, wenn am &#039;&#039;&#039;INT0&#039;&#039;&#039;-Pin eine Interrupt-Kondition, entsprechend der Konfiguration, erkannt wird. Wenn das Global Enable Interrupt Flag gesetzt ist, wird die Interruptroutine angesprungen.&lt;br /&gt;
:Das Flag wird automatisch gelöscht, wenn die Interruptroutine beendet ist. Alternativ kann das Flag gelöscht werden, indem der Wert &#039;&#039;&#039;1(!)&#039;&#039;&#039; eingeschrieben wird.&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;MCUCR&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;MCU&#039;&#039;&#039; &#039;&#039;&#039;C&#039;&#039;&#039;ontrol &#039;&#039;&#039;R&#039;&#039;&#039;egister.&lt;br /&gt;
&lt;br /&gt;
Das MCU Control Register enthält Kontrollbits für allgemeine&lt;br /&gt;
MCU-Funktionen.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Bit&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 7&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 6&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 5&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 4&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 2&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Name&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;SE&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;SM&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ISC11&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ISC10&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ISC01&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ISC00&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;R/W&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Initialwert&#039;&#039;&#039;&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;
| 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;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;SE&#039;&#039;&#039; (&#039;&#039;&#039;S&#039;&#039;&#039;leep &#039;&#039;&#039;E&#039;&#039;&#039;nable)&lt;br /&gt;
:Dieses Bit muss gesetzt sein, um den Controller mit dem &#039;&#039;&#039;SLEEP&#039;&#039;&#039;-Befehl in den Schlafzustand versetzen zu können.&lt;br /&gt;
:Um den Schlafmodus nicht irrtümlich einzuschalten, wird empfohlen, das Bit erst unmittelbar vor Ausführung des &#039;&#039;&#039;SLEEP&#039;&#039;&#039;-Befehls zu setzen.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;SM&#039;&#039;&#039; (&#039;&#039;&#039;S&#039;&#039;&#039;leep &#039;&#039;&#039;M&#039;&#039;&#039;ode)&lt;br /&gt;
:Dieses Bit bestimmt der Schlafmodus.&lt;br /&gt;
:Ist das Bit gelöscht, so wird der &#039;&#039;&#039;Idle&#039;&#039;&#039;-Modus ausgeführt. Ist das Bit gesetzt, so wird der &#039;&#039;&#039;Power-Down&#039;&#039;&#039;-Modus ausgeführt. (für andere AVR Controller siehe Abschnitt &amp;quot;Sleep-Mode&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ISC11&#039;&#039;&#039;, &#039;&#039;&#039;ISC10&#039;&#039;&#039; (&#039;&#039;&#039;I&#039;&#039;&#039;nterrupt &#039;&#039;&#039;S&#039;&#039;&#039;ense &#039;&#039;&#039;C&#039;&#039;&#039;ontrol &#039;&#039;&#039;1&#039;&#039;&#039; Bits)&lt;br /&gt;
:Diese beiden Bits bestimmen, ob die steigende oder die fallende Flanke für die Interrupterkennung am &#039;&#039;&#039;INT1&#039;&#039;&#039;-Pin ausgewertet wird.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ISC11&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ISC10&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Bedeutung&#039;&#039;&#039;&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;
| Low Level an &#039;&#039;&#039;INT1&#039;&#039;&#039; erzeugt einen Interrupt.&lt;br /&gt;
&lt;br /&gt;
In der Beschreibung heißt es, der Interrupt wird getriggert, solange der Pin auf 0 bleibt, also eigentlich unbrauchbar.&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;
| Reserviert&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;
| Die fallende Flanke an &#039;&#039;&#039;INT1&#039;&#039;&#039; erzeugt einen Interrupt.&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;
| Die steigende Flanke an &#039;&#039;&#039;INT1&#039;&#039;&#039; erzeugt einen Interrupt.&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;ISC01&#039;&#039;&#039;, &#039;&#039;&#039;ISC00&#039;&#039;&#039; (&#039;&#039;&#039;I&#039;&#039;&#039;nterrupt &#039;&#039;&#039;S&#039;&#039;&#039;ense &#039;&#039;&#039;C&#039;&#039;&#039;ontrol &#039;&#039;&#039;0&#039;&#039;&#039; Bits)&lt;br /&gt;
:Diese beiden Bits bestimmen, ob die steigende oder die fallende Flanke für die Interrupterkennung am &#039;&#039;&#039;INT0&#039;&#039;&#039;-Pin ausgewertet wird.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ISC01&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ISC00&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Bedeutung&#039;&#039;&#039;&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;
| Low Level an &#039;&#039;&#039;INT0&#039;&#039;&#039; erzeugt einen Interrupt.&lt;br /&gt;
&lt;br /&gt;
In der Beschreibung heißt es, der Interrupt wird getriggert, solange der Pin auf 0 bleibt, also eigentlich unbrauchbar.&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;
| Reserviert&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;
| Die fallende Flanke an &#039;&#039;&#039;INT0&#039;&#039;&#039; erzeugt einen Interrupt.&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;
| Die steigende Flanke an &#039;&#039;&#039;INT0&#039;&#039;&#039; erzeugt einen Interrupt.&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Allgemeines über die Interrupt-Abarbeitung ==&lt;br /&gt;
&lt;br /&gt;
Wenn ein Interrupt eintrifft, wird automatisch das &#039;&#039;&#039;Global Interrupt Enable&#039;&#039;&#039; Bit im Status Register &#039;&#039;&#039;SREG&#039;&#039;&#039; gelöscht und alle weiteren Interrupts unterbunden. Obwohl es möglich ist, zu diesem Zeitpunkt bereits wieder das GIE-bit zu setzen, rate ich dringend davon ab. Dieses wird nämlich automatisch gesetzt, wenn die Interruptroutine beendet wird. Wenn in der Zwischenzeit weitere Interrupts eintreffen, werden die zugehörigen Interrupt-Bits gesetzt und die Interrupts bei Beendigung der laufenden Interrupt-Routine in der Reihenfolge ihrer Priorität ausgeführt. Dies kann&lt;br /&gt;
eigentlich nur dann zu Problemen führen, wenn ein hoch priorisierter Interrupt ständig und in kurzer Folge auftritt. Dieser sperrt dann möglicherweise alle anderen Interrupts mit niedrigerer Priorität. Dies ist einer der Gründe, weshalb die Interrupt-Routinen sehr kurz gehalten werden sollen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- === Das Status-Register ===&lt;br /&gt;
&lt;br /&gt;
Es gilt auch zu beachten, dass das Status-Register während der Abarbeitung einer Interruptroutine nicht automatisch gesichert wird. Falls notwendig, muss dies vom Programmierer selber vorgesehen werden. --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Interrupts mit dem AVR GCC Compiler (WinAVR) ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- Selbstverständlich können alle interruptspezifischen Registerzugriffe wie gewohnt über I/O-Adressierung vorgenommen werden. Etwas einfacher geht es jedoch, wenn wir die vom Compiler zur Verfügung gestellten Mittel einsetzen.--&amp;gt;&lt;br /&gt;
Funktionen zur Interrupt-Verarbeitung werden in den Includedateien &#039;&#039;interrupt.h&#039;&#039;  der avr-libc zur Verfügung gestellt (bei älterem Quellcode zusätzlich &#039;&#039;signal.h&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
// fuer sei(), cli() und ISR():&lt;br /&gt;
#include &amp;lt;avr/interrupt.h&amp;gt;&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Makro &#039;&#039;&#039;sei()&#039;&#039;&#039; schaltet die Interrupts ein. Eigentlich wird nichts anderes gemacht, als das &#039;&#039;&#039;Global Interrupt Enable&#039;&#039;&#039; Bit im Status Register gesetzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
    sei();&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Makro &#039;&#039;&#039;cli()&#039;&#039;&#039; schaltet die Interrupts aus, oder anders gesagt, das &#039;&#039;&#039;Global Interrupt Enable&#039;&#039;&#039; Bit im Status Register wird gelöscht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
    cli();&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Oft steht man vor der Aufgabe, dass eine Codesequenz nicht unterbrochen werden darf. Es liegt dann nahe, zu Beginn dieser Sequenz ein cli() und am Ende ein sei() einzufügen. Dies ist jedoch ungünstig, wenn die Interrupts vor Aufruf der Sequenz deaktiviert waren und danach auch weiterhin deaktiviert bleiben sollen. Ein sei() würde ungeachtet des vorherigen  Zustands die Interrups aktivieren, was zu unerwünschten Seiteneffekten führen kann. Die aus dem folgenden Beispiel ersichtliche Vorgehensweise ist in solchen Fällen vorzuziehen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/interrupt.h&amp;gt;&lt;br /&gt;
#include &amp;lt;inttypes.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
void NichtUnterbrechenBitte(void)&lt;br /&gt;
{&lt;br /&gt;
   uint8_t tmp_sreg;  // temporaerer Speicher fuer das Statusregister&lt;br /&gt;
&lt;br /&gt;
   tmp_sreg = SREG;   // Statusregister (also auch das I-Flag darin) sichern&lt;br /&gt;
   cli();             // Interrupts global deaktivieren&lt;br /&gt;
&lt;br /&gt;
   /* hier &amp;quot;unterbrechnungsfreier&amp;quot; Code */&lt;br /&gt;
&lt;br /&gt;
   /* Beispiel Anfang&lt;br /&gt;
     JTAG-Interface eines ATmega16 per Software deaktivieren &lt;br /&gt;
     und damit die JTAG-Pins an PORTC für &amp;quot;general I/O&amp;quot; nutzbar machen&lt;br /&gt;
     ohne die JTAG-Fuse-Bit zu aendern. Dazu ist eine &amp;quot;timed sequence&amp;quot;&lt;br /&gt;
     einzuhalten (vgl Datenblatt ATmega16, Stand 10/04, S. 229): &lt;br /&gt;
     Das JTD-Bit muss zweimal innerhalb von 4 Taktzyklen geschrieben &lt;br /&gt;
     werden. Ein Interrupt zwischen den beiden Schreibzugriffen wuerde &lt;br /&gt;
     die erforderliche Sequenz &amp;quot;brechen&amp;quot;, das JTAG-Interface bliebe&lt;br /&gt;
     weiterhin aktiv und die IO-Pins weiterhin für JTAG reserviert. */&lt;br /&gt;
&lt;br /&gt;
   MCUCSR |= (1&amp;lt;&amp;lt;JTD);&lt;br /&gt;
   MCUCSR |= (1&amp;lt;&amp;lt;JTD); // 2 mal in Folge ,vgl. Datenblatt fuer mehr Information&lt;br /&gt;
&lt;br /&gt;
   /* Beispiel Ende */&lt;br /&gt;
  &lt;br /&gt;
   SREG = tmp_sreg;     // Status-Register wieder herstellen &lt;br /&gt;
                      // somit auch das I-Flag auf gesicherten Zustand setzen&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void NichtSoGut(void)&lt;br /&gt;
{&lt;br /&gt;
   cli();&lt;br /&gt;
   &lt;br /&gt;
   /* hier &amp;quot;unterbrechnungsfreier&amp;quot; Code */&lt;br /&gt;
   &lt;br /&gt;
   sei();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
int main(void)&lt;br /&gt;
{&lt;br /&gt;
   //...&lt;br /&gt;
&lt;br /&gt;
   cli();  &lt;br /&gt;
   // Interrupts global deaktiviert &lt;br /&gt;
&lt;br /&gt;
   NichtUnterbrechenBitte();&lt;br /&gt;
   // auch nach Aufruf der Funktion deaktiviert&lt;br /&gt;
&lt;br /&gt;
   sei();&lt;br /&gt;
   // Interrupts global aktiviert &lt;br /&gt;
&lt;br /&gt;
   NichtUnterbrechenBitte();&lt;br /&gt;
   // weiterhin aktiviert&lt;br /&gt;
   //...&lt;br /&gt;
&lt;br /&gt;
   /* Verdeutlichung der unguenstigen Vorgehensweise mit cli/sei: */&lt;br /&gt;
   cli();  &lt;br /&gt;
   // Interrupts jetzt global deaktiviert &lt;br /&gt;
&lt;br /&gt;
   NichtSoGut();&lt;br /&gt;
   // nach Aufruf der Funktion sind Interrupts global aktiviert &lt;br /&gt;
   // dies ist mglw. ungewollt!&lt;br /&gt;
   //...&lt;br /&gt;
   &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- mt: besser so nicht(?), lieber &amp;quot;datenblattkonform&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;font face=&amp;quot;Courier New&amp;quot;&amp;gt;&#039;&#039;&#039;timer_enable_int (unsigned char ints);&amp;lt;br /&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;/font&amp;gt;Schaltet Timerbezogene Interrupts ein bzw. aus.&amp;lt;br /&amp;gt;&lt;br /&gt;
Wenn als Argument &#039;&#039;&#039;ints&#039;&#039;&#039; der Wert 0 übergeben wird so werden alle&lt;br /&gt;
Timerinterrupts ausgeschaltet, ansonsten muss in &#039;&#039;&#039;ints&#039;&#039;&#039; angegeben werden,&lt;br /&gt;
welche Interrupts zu aktivieren sind. Dabei müssen einfach die entsprechend zu&lt;br /&gt;
setzenden Bits definiert werden.&amp;lt;br /&amp;gt;&lt;br /&gt;
Beispiel: &#039;&#039;&#039;&amp;lt;font face=&amp;quot;Courier New&amp;quot;&amp;gt;timer_enable_int (1 &amp;lt;&amp;lt; TOIE1));&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;/font&amp;gt;&#039;&#039;&#039;Achtung: Wenn ein Timerinterrupt eingeschaltet wird während ein&lt;br /&gt;
anderer Timerinterrupt bereits läuft, dann müssen beide Bits angegeben werden&lt;br /&gt;
sonst wird der andere Timerinterrupt versehentlich ausgeschaltet.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;font face=&amp;quot;Courier New&amp;quot;&amp;gt;&#039;&#039;&#039;enable_external_int (unsigned char ints);&amp;lt;br /&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;/font&amp;gt;Schaltet die externen Interrupts ein bzw. aus.&amp;lt;br /&amp;gt;&lt;br /&gt;
Wenn als Argument &#039;&#039;&#039;ints&#039;&#039;&#039; der Wert 0 übergeben wird so werden alle externen&lt;br /&gt;
Interrrups ausgeschaltet, ansonsten muss in &#039;&#039;&#039;ints&#039;&#039;&#039; angegeben werden, welche&lt;br /&gt;
Interrupts zu aktivieren sind. Dabei müssen einfach die entsprechend zu&lt;br /&gt;
setzenden Bits definiert werden.&amp;lt;br /&amp;gt;&lt;br /&gt;
Beispiel: &#039;&#039;&#039;&amp;lt;font face=&amp;quot;Courier New&amp;quot;&amp;gt;enable_external_int ((1&amp;lt;&lt;br /&gt;
&amp;lt;/font&amp;gt;&#039;&#039;&#039;Schaltet die externen Interrupts 0 und 1 ein.&lt;br /&gt;
&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nachdem nun die Interrupts aktiviert sind, braucht es selbstverständlich noch den auszuführenden Code, der ablaufen soll, wenn ein Interrupt eintrifft. Dazu existiert die Definition (ein Makro) &#039;&#039;&#039;ISR&#039;&#039;&#039;. SIGNAL sollte nicht mehr genutzt werden, zur Portierung von SIGNAL nach ISR siehe Abschnitt (TODO: verlinken) im Anhang.&lt;br /&gt;
&amp;lt;!--Dazu gibt es zwei Definitionen: &#039;&#039;&#039;SIGNAL&#039;&#039;&#039; und &#039;&#039;&#039;INTERRUPT&#039;&#039;&#039;, welche allerdings AVR-GCC spezifisch sind und bei anderen Compilern womöglich anders heissen können.--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== ISR ===&lt;br /&gt;
&lt;br /&gt;
(&#039;&#039;ISR()&#039;&#039; ersetzt bei neueren Versionen der avr-libc &#039;&#039;SIGNAL()&#039;&#039;. vgl. [[AVR-GCC-Tutorial#Anhang|Anhang]])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/signal.h&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
SIGNAL (siglabel)&lt;br /&gt;
{&lt;br /&gt;
    /* Interrupt Code */&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/interrupt.h&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
ISR(Vectorname) /* vormals: SIGNAL(siglabel) dabei Vectorname != siglabel ! */&lt;br /&gt;
{&lt;br /&gt;
    /* Interrupt Code */&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;ISR&#039;&#039; wird eine Funktion für die Bearbeitung eines Interrupts eingeleitet. Als Argument muss dabei die Benennung des entsprechenden Interruptvektors angegeben werden. Diese sind in den jeweiligen Includedateien IOxxxx.h zu finden. Die Bezeichnung entspricht dem Namen aus dem Datenblatt, bei dem die Leerzeichen durch Unterstriche ersetzt sind und ein &#039;&#039;_vect&#039;&#039; angehängt ist.&lt;br /&gt;
&lt;br /&gt;
Als Beispiel ein Ausschnitt aus der Datei für den ATmega8 (bei WinAVR Standardinstallation in C:\WinAVR\avr\include\avr\iom8.h) in der neben den aktuellen Namen für &#039;&#039;ISR&#039;&#039; (*_vect) noch die Bezeichnungen für das inzwischen nicht mehr aktuelle &#039;&#039;SIGNAL&#039;&#039; (SIG_*) enthalten sind.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
/* $Id: iom8.h,v 1.13 2005/10/30 22:11:23 joerg_wunsch Exp $ */&lt;br /&gt;
&lt;br /&gt;
/* avr/iom8.h - definitions for ATmega8 */&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
/* Interrupt vectors */&lt;br /&gt;
&lt;br /&gt;
/* External Interrupt Request 0 */&lt;br /&gt;
#define INT0_vect                       _VECTOR(1)&lt;br /&gt;
#define SIG_INTERRUPT0                  _VECTOR(1)&lt;br /&gt;
&lt;br /&gt;
/* External Interrupt Request 1 */&lt;br /&gt;
#define INT1_vect                       _VECTOR(2)&lt;br /&gt;
#define SIG_INTERRUPT1                  _VECTOR(2)&lt;br /&gt;
&lt;br /&gt;
/* Timer/Counter2 Compare Match */&lt;br /&gt;
#define TIMER2_COMP_vect                _VECTOR(3)&lt;br /&gt;
#define SIG_OUTPUT_COMPARE2             _VECTOR(3)&lt;br /&gt;
&lt;br /&gt;
/* Timer/Counter2 Overflow */&lt;br /&gt;
#define TIMER2_OVF_vect                 _VECTOR(4)&lt;br /&gt;
#define SIG_OVERFLOW2                   _VECTOR(4)&lt;br /&gt;
&lt;br /&gt;
/* Timer/Counter1 Capture Event */&lt;br /&gt;
#define TIMER1_CAPT_vect                _VECTOR(5)&lt;br /&gt;
#define SIG_INPUT_CAPTURE1              _VECTOR(5)&lt;br /&gt;
&lt;br /&gt;
/* Timer/Counter1 Compare Match A */&lt;br /&gt;
#define TIMER1_COMPA_vect               _VECTOR(6)&lt;br /&gt;
#define SIG_OUTPUT_COMPARE1A            _VECTOR(6)&lt;br /&gt;
&lt;br /&gt;
/* Timer/Counter1 Compare Match B */&lt;br /&gt;
#define TIMER1_COMPB_vect               _VECTOR(7)&lt;br /&gt;
#define SIG_OUTPUT_COMPARE1B            _VECTOR(7)&lt;br /&gt;
&lt;br /&gt;
//...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--Vor Nutzung von SIGNAL muss ebenfalls die Header-Datei signal.h eingebunden werden.--&amp;gt; &lt;br /&gt;
Mögliche Funktionsrümpfe für Interruptfunktionen sind zum Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/interrupt.h&amp;gt;&lt;br /&gt;
/* veraltet: #include &amp;lt;avr/signal.h&amp;gt; */&lt;br /&gt;
&lt;br /&gt;
ISR(INT0_vect)       /* veraltet: SIGNAL(SIG_INTERRUPT0) */&lt;br /&gt;
{&lt;br /&gt;
    /* Interrupt Code */&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
ISR(TIMER0_OVF_vect) /* veraltet: SIGNAL(SIG_OVERFLOW0) */&lt;br /&gt;
{&lt;br /&gt;
    /* Interrupt Code */&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
ISR(USART_RXC_vect) /* veraltet: SIGNAL(SIG_UART_RECV) */&lt;br /&gt;
{&lt;br /&gt;
    /* Interrupt Code */&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// und so weiter und so fort...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Auf die korrekte Schreibweise der Vektorbezeichnung ist zu achten. Der gcc-Compiler prüft erst ab Version 4.x, ob ein Signal/Interrupt der angegebenen Bezeichnung tatsächlich in der Includedatei definiert ist und gibt andernfalls eine Warnung aus. Bei WinAVR (ab 2/2005) wurde die Überprüfung auch in den mitgelieferten Compiler der Version 3.x integriert. Aus dem gcc-Quellcode Version 3.x selbst erstellte Compiler enthalten die Prüfung nicht (vgl. [[AVR-GCC]]). &lt;br /&gt;
&lt;br /&gt;
Während der Ausführung der Funktion sind alle weiteren Interrupts automatisch gesperrt. Beim Verlassen der Funktion werden die Interrupts wieder zugelassen.&lt;br /&gt;
&lt;br /&gt;
Sollte während der Abarbeitung der Interruptroutine ein weiterer Interrupt (gleiche oder andere Interruptquelle) auftreten, so wird das entsprechende Bit im zugeordneten Interrupt Flag Register gesetzt und die entsprechende Interruptroutine automatisch nach dem Beenden der aktuellen Funktion aufgerufen.&lt;br /&gt;
&lt;br /&gt;
Ein Problem ergibt sich eigentlich nur dann, wenn während der Abarbeitung der aktuellen Interruptroutine mehrere gleichartige Interrupts auftreten. Die entsprechende Interruptroutine wird im Nachhinein zwar aufgerufen jedoch wissen wir nicht, ob nun der entsprechende Interrupt einmal, zweimal oder gar noch öfter aufgetreten ist. Deshalb soll hier noch einmal betont werden, dass Interruptroutinen so schnell wie nur irgend möglich wieder verlassen werden sollten.&lt;br /&gt;
&lt;br /&gt;
=== Unterbrechbare Interruptroutinen ===&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Faustregel&amp;quot;: im Zweifel &#039;&#039;&#039;ISR&#039;&#039;&#039;. Die nachfolgend beschriebene Methode nur dann verwenden, wenn man sich über die unterschiedliche Funktionsweise im Klaren ist.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/interrupt.h&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
INTERRUPT (signame)&lt;br /&gt;
{&lt;br /&gt;
    /* Interrupt Code */&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/interrupt.h&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
void XXX_vect(void) __attribute__((interrupt));&lt;br /&gt;
void XXX_vect(void) {&lt;br /&gt;
  //...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hierbei steht XXX für den oben beschriebenen Namen des Vektors (also z.B. &#039;&#039;void TIMER0_OVF_vect(void)...&#039;&#039;). Der Unterschied im Vergleich zu ISR ist, dass hier beim Aufrufen der Funktion das &#039;&#039;&#039;Global Enable Interrupt&#039;&#039;&#039; Bit automatisch wieder gesetzt und somit weitere Interrupts zugelassen werden. Dies kann zu nicht unerheblichen Problemen von im einfachsten Fall einem Stack overflow bis zu sonstigen unerwarteten Effekten führen und sollte wirklich &#039;&#039;&#039;nur dann&#039;&#039;&#039; angewendet werden, wenn man sich absolut sicher ist, das Ganze auch im Griff zu haben.  &amp;lt;!--Vor Nutzung von INTERRUPT muss die Header-Datei interrupt.h eingebunden werden.--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
siehe auch: Hinweise in [[AVR-GCC]]&lt;br /&gt;
&lt;br /&gt;
siehe dazu: http://www.nongnu.org/avr-libc/user-manual/group__avr__interrupts.html&lt;br /&gt;
&lt;br /&gt;
== Datenaustausch mit Interrupt-Routinen ==&lt;br /&gt;
&lt;br /&gt;
Variablen die sowohl in Interrupt-Routinen (ISR = Interrupt Service Routine(s)), als auch vom übrigen Programmcode geschrieben oder gelesen werden, müssen mit einem &#039;&#039;&#039;volatile&#039;&#039;&#039; deklariert werden. Damit wird dem Compiler mitgeteilt, dass der Inhalt der Variablen vor jedem Lesezugriff aus dem Speicher gelesen und nach jedem Schreibzugriff in den Speicher geschrieben wird. Ansonsten könnte der Compiler den Code so optimieren, dass der Wert der Variablen nur &lt;br /&gt;
in Prozessorregistern zwischengespeichert wird, die nichts von der Änderung woanders mitbekommen.&lt;br /&gt;
&lt;br /&gt;
Zur Veranschaulichung ein Codefragment für eine Tastenentprellung mit Erkennung einer &amp;quot;lange gedrückten&amp;quot; Taste.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/interrupt.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
// Schwellwerte&lt;br /&gt;
// Entprellung: &lt;br /&gt;
#define CNTDEBOUNCE 10&lt;br /&gt;
// &amp;quot;lange gedrueckt:&amp;quot;&lt;br /&gt;
#define CNTREPEAT 200&lt;br /&gt;
&lt;br /&gt;
// hier z.B. Taste an Pin2 PortA &amp;quot;active low&amp;quot; = 0 wenn gedrueckt&lt;br /&gt;
#define KEY_PIN  PINA&lt;br /&gt;
#define KEY_PINNO PA2&lt;br /&gt;
&lt;br /&gt;
// beachte: volatile! &lt;br /&gt;
volatile uint8_t gKeyCounter;&lt;br /&gt;
&lt;br /&gt;
// Timer-Compare Interrupt ISR, wird z.B. alle 10ms ausgefuehrt&lt;br /&gt;
ISR(TIMER1_COMPA_vect)&lt;br /&gt;
{&lt;br /&gt;
   // hier wird gKeyCounter veraendert. Die übrigen&lt;br /&gt;
   // Programmteile müssen diese Aenderung &amp;quot;sehen&amp;quot;:&lt;br /&gt;
   // volatile -&amp;gt; aktuellen Wert immer in den Speicher schreiben&lt;br /&gt;
   if ( !(KEY_PIN &amp;amp; (1&amp;lt;&amp;lt;KEY_PINNO)) ) {&lt;br /&gt;
      if (gKeyCounter &amp;lt; CNTREPEAT) gKeyCounter++;&lt;br /&gt;
   }&lt;br /&gt;
   else {&lt;br /&gt;
      gKeyCounter = 0;&lt;br /&gt;
   }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
int main(void)&lt;br /&gt;
{&lt;br /&gt;
//...&lt;br /&gt;
    /* hier: Initialisierung der Ports und des Timer-Interrupts */&lt;br /&gt;
//... &lt;br /&gt;
   // hier wird auf gKeyCounter zugegriffen. Dazu muss der in der&lt;br /&gt;
   // ISR geschriebene Wert bekannt sein:&lt;br /&gt;
   // volatile -&amp;gt; aktuellen Wert immer aus dem Speicher lesen&lt;br /&gt;
   if ( gKeyCounter &amp;gt; CNTDEBOUNCE ) { // Taste mind. 10*10 ms &amp;quot;prellfrei&amp;quot;&lt;br /&gt;
       if (gKeyCounter == CNTREPEAT) {&lt;br /&gt;
          /* hier: Code fuer &amp;quot;Taste lange gedrueckt&amp;quot; */&lt;br /&gt;
       }&lt;br /&gt;
       else {&lt;br /&gt;
          /* hier: Code fuer &amp;quot;Taste kurz gedrueckt&amp;quot; */&lt;br /&gt;
       }&lt;br /&gt;
   }&lt;br /&gt;
//...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== volatile und Pointer ===&lt;br /&gt;
&lt;br /&gt;
Bei &#039;&#039;&#039;volatile&#039;&#039;&#039; in Verbindung mit Pointern ist zu beachten, ob der Pointer selbst oder die Variable auf die der Pointer zeigt &#039;&#039;&#039;volatile&#039;&#039;&#039; ist.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
volatile uint8_t *a;   // das Ziel von a ist volatile&lt;br /&gt;
&lt;br /&gt;
uint8_t *volatile a;   // a selbst ist volatile&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Variablen größer 1 Byte ===&lt;br /&gt;
&lt;br /&gt;
Bei Variablen größer ein Byte, auf die in Interrupt-Routinen und im Hauptprogramm zugegriffen wird, muss darauf geachtet werden, dass die Zugriffe auf die einzelnen Bytes außerhalb der ISR nicht durch einen Interrupt unterbrochen werden. (Allgemeinplatz: AVRs sind 8-bit Controller). Zur Veranschaulichung ein Codefragment:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
volatile uint16_t gMyCounter16bit;&lt;br /&gt;
//...&lt;br /&gt;
ISR(...)&lt;br /&gt;
{&lt;br /&gt;
//...&lt;br /&gt;
   gMyCounter16Bit++;&lt;br /&gt;
//...&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int main(void)&lt;br /&gt;
{&lt;br /&gt;
   uint16_t tmpCnt;&lt;br /&gt;
//...&lt;br /&gt;
   // nicht gut: Mglw. hier ein Fehler, wenn ein Byte von MyCounter &lt;br /&gt;
   // schon in tmpCnt kopiert ist aber vor dem Kopieren des zweiten Bytes &lt;br /&gt;
   // ein Interrupt auftritt, der den Inhalt von MyCounter verändert.&lt;br /&gt;
   tmpCnt = gMyCounter16bit; &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
   // besser: Änderungen &amp;quot;außerhalb&amp;quot; verhindern -&amp;gt; alle &amp;quot;Teilbytes&amp;quot;&lt;br /&gt;
   // bleiben konsistent&lt;br /&gt;
   cli();  // Interupts deaktivieren&lt;br /&gt;
   tmpCnt = gMyCounter16Bit;&lt;br /&gt;
   sei();  // wieder aktivieren&lt;br /&gt;
&lt;br /&gt;
   // oder: vorheriger Status des globalen Interrupt-Flags bleibt erhalten&lt;br /&gt;
   uint8_t sreg_tmp;&lt;br /&gt;
   sreg_tmp = SREG;    /* Sichern */&lt;br /&gt;
   cli()&lt;br /&gt;
   tmpCnt = gMyCounter16Bit;&lt;br /&gt;
   SREG = sreg_tmp;    /* Wiederherstellen */&lt;br /&gt;
&lt;br /&gt;
   // oder: mehrfach lesen, bis man konsistente Daten hat&lt;br /&gt;
   uint16_t count1 = gMyCounter16Bit;&lt;br /&gt;
   uint16_t count2 = gMyCounter16Bit;&lt;br /&gt;
   while (count1 != count2) {&lt;br /&gt;
       count1 = count2;&lt;br /&gt;
       count2 = gMyCounter16Bit;&lt;br /&gt;
   }&lt;br /&gt;
   tmpCnt = count1;&lt;br /&gt;
//...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Interrupt-Routinen und Registerzugriffe ==&lt;br /&gt;
&lt;br /&gt;
Falls Register sowohl im Hauptprogramm als auch in Interrupt-Routinen verändert werden, ist darauf zu achten, dass diese Zugriffe sich nicht überlappen. Nur wenige Anweisungen lassen sich in sogenannte &amp;quot;atomare&amp;quot; Zugriffe übersetzen, die nicht von Interrupt-Routinen unterbrochen werden können. &lt;br /&gt;
&lt;br /&gt;
Zur Veranschaulichung eine Anweisung, bei der ein Bit und im Anschluss drei Bits in einem Register gesetzt werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
int main(void)&lt;br /&gt;
{&lt;br /&gt;
//...&lt;br /&gt;
	PORTA |= (1&amp;lt;&amp;lt;PA0);&lt;br /&gt;
	&lt;br /&gt;
	PORTA |= (1&amp;lt;&amp;lt;PA2)|(1&amp;lt;&amp;lt;PA3)|(1&amp;lt;&amp;lt;PA4);&lt;br /&gt;
//...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Compiler übersetzt diese Anweisungen für einen ATmega128 bei Optimierungsstufe &amp;quot;S&amp;quot; nach:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;code&amp;quot;&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
        PORTA |= (1&amp;lt;&amp;lt;PA0);&lt;br /&gt;
  d2:	d8 9a       	sbi	0x1b, 0	; 27 (a)&lt;br /&gt;
	&lt;br /&gt;
        PORTA |= (1&amp;lt;&amp;lt;PA2)|(1&amp;lt;&amp;lt;PA3)|(1&amp;lt;&amp;lt;PA4);&lt;br /&gt;
  d4:	8b b3       	in	r24, 0x1b	; 27 (b)&lt;br /&gt;
  d6:	8c 61       	ori	r24, 0x1C	; 28 (c)&lt;br /&gt;
  d8:	8b bb       	out	0x1b, r24	; 27 (d)&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Setzen des einzelnen Bits wird bei eingeschalteter Optimierung für Register im unteren Speicherbereich in eine einzige Assembler-Anweisung (sbi) übersetzt und ist nicht anfällig für Unterbrechnungen durch Interrupts. Die Anweisung zum Setzen von drei Bits wird jedoch in drei abhängige Assembler-Anweisungen übersetzt und bietet damit zwei &amp;quot;Angriffspunkte&amp;quot; für Unterbrechnungen. Eine Interrupt-Routine könnte nach dem Laden des Ausgangszustands in den Zwischenspeicher (hier Register 24) den Wert des Registers ändern, z.B. ein Bit löschen. Damit würde der Zwischenspeicher nicht mehr mit dem tatsächlichen Zustand übereinstimmen aber dennoch nach der Bitoperation (hier ori) in das Register zurückgeschrieben. &lt;br /&gt;
&lt;br /&gt;
Beispiel: PORTA sei anfangs 0b00000000. Die erste Anweisung (a) setzt Bit 0, PORTA ist danach 0b00000001. Nun wird im ersten Teil der zweiten Anweisung der Portzustand in ein Register eingelesen (b). Unmittelbar darauf (vor (c)) &amp;quot;feuert&amp;quot; ein Interrupt, in dessen Interrupt-Routine Bit 0 von PORTA gelöscht wird. Nach Verlassen der Interrupt-Routine hat PORTA den Wert 0b00000000. In den beiden noch folgenden Anweisungen des Hauptprogramms wird nun der zwischengespeicherte &amp;quot;alte&amp;quot; Zustand 0b00000001 mit 0b00011100 logisch-oder-verknüft (c) und das Ergebnis 0b00011101 in PortA geschrieben (d). Obwohl zwischenzeitlich Bit 0 gelöscht wurde, ist es nach (d) wieder gesetzt. &lt;br /&gt;
&lt;br /&gt;
Lösungsmöglichkeiten:&lt;br /&gt;
* Register ohne besondere Vorkehrungen nicht in Interruptroutinen &#039;&#039;und&#039;&#039; im Hauptprogramm verändern.&lt;br /&gt;
* Interrupts vor Veränderungen in Registern, die auch in ISRs verändert werden, deaktivieren (&amp;quot;cli&amp;quot;).&lt;br /&gt;
* Bits einzeln löschen oder setzen. sbi und cbi können nicht unterbrochen werden. Vorsicht: nur Register im unteren Speicherbereich sind mittels sbi/cbi ansprechbar. Der Compiler kann nur für diese sbi/cbi-Anweisungen generieren. Für Register außerhalb dieses Adressbereichs (&amp;quot;Memory-Mapped&amp;quot;-Register) werden auch zur Manipulation einzelner Bits abhängige Anweisungen erzeugt (lds,...,sts).&lt;br /&gt;
&lt;br /&gt;
* siehe auch: [http://www.nongnu.org/avr-libc/user-manual/index.html Dokumentation der avr-libc] Frequently asked Questions/Fragen Nr. 1 und 8. (Stand: avr-libc Vers. 1.0.4)&lt;br /&gt;
&lt;br /&gt;
== Was macht das Hauptprogramm? ==&lt;br /&gt;
&lt;br /&gt;
Im einfachsten (Ausnahme-)Fall gar nichts mehr. Es ist also durchaus denkbar, ein Programm zu schreiben, welches in der main-Funktion lediglich noch die Interrupts aktiviert und dann in einer Endlosschleife verharrt. Sämtliche Funktionen werden dann in den ISRs abgearbeitet. Diese Vorgehensweise ist jedoch bei den meisten Anwendungen schlecht: man verschenkt eine Verarbeitungsebene und hat außerdem möglicherweise Probleme durch Interruptroutinen, die zu viel Verarbeitungszeit benötigen.&lt;br /&gt;
&lt;br /&gt;
Normalerweise wird man in den Interruptroutinen nur die bei Auftreten des jeweiligen Interruptereignisses unbedingt notwendigen Operationen ausführen lassen. Alle weniger kritischen Aufgaben werden dann im Hauptprogramm abgearbeitet.&lt;br /&gt;
&lt;br /&gt;
* siehe auch: [http://www.nongnu.org/avr-libc/user-manual/index.html Dokumentation der avr-libc] Abschnitt Modules/Interrupts and Signals&lt;br /&gt;
&lt;br /&gt;
= Sleep-Modes =&lt;br /&gt;
&lt;br /&gt;
AVR Controller verfügen über eine Reihe von sogenannten &#039;&#039;Sleep-Modes&#039;&#039; (&amp;quot;Schlaf-Modi&amp;quot;). Diese ermöglichen es, Teile des Controllers abzuschalten. Zum Einen kann damit besonders bei Batteriebetrieb Strom gespart werden, zum Anderen können Komponenten des Controllers deaktiviert werden, die die Genauigkeit des Analog-Digital-Wandlers bzw. des Analog-Comparators negativ beeinflussen. Der Controller wird durch Interrupts aus dem Schlaf geweckt. Welche Interrupts den jeweiligen Schlafmodus beenden, ist einer Tabelle im Datenblatt des jeweiligen Controllers zu entnehmen.&lt;br /&gt;
Die Funktionen (eigentlich Makros) der avr-libc stehen nach Einbinden der header-Datei &#039;&#039;sleep.h&#039;&#039; zur Verfügung.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;set_sleep_mode(uint8_t mode)&#039;&#039;&#039;&lt;br /&gt;
:Setzt den Schlafmodus, der bei Aufruf von sleep() aktiviert wird. In sleep.h sind einige Konstanten definiert (z.B. SLEEP_MODE_PWR_DOWN). Die definierten Modi werden jedoch nicht alle von sämtlichten AVR-Controllern unterstützt.&lt;br /&gt;
* &#039;&#039;&#039;sleep_enable()&#039;&#039;&#039;&lt;br /&gt;
:aktiviert den gesetzten Schlafmodus, versetzt den Controller aber noch nicht in den Schlafmodus&lt;br /&gt;
* &#039;&#039;&#039;sleep_cpu()&#039;&#039;&#039;&lt;br /&gt;
: Versetzt den Controller in den Schlafmodus (sleep_cpu wird im Prinzip durch die Assembler-Anweisung &#039;&#039;sleep&#039;&#039; ersetzt)&lt;br /&gt;
* &#039;&#039;&#039;sleep_disable()&#039;&#039;&#039;&lt;br /&gt;
:deaktiviert den gesetzten Schlafmodus&lt;br /&gt;
* &#039;&#039;&#039;sleep_mode()&#039;&#039;&#039;&lt;br /&gt;
:Versetzt den Controller in den mit set_sleep_mode gewählten Schlafmodus. Das Makro entspricht sleep_enable()+sleep_cpu()+sleep_disable(), beinhaltet also nicht die Aktivierung von Interrupts (besser nicht benutzen).&lt;br /&gt;
&lt;br /&gt;
Bei Anwendung von sleep_cpu() müssen Interrupts also bereits freigeben sein (sei()), da der Controller sonst nicht mehr &amp;quot;aufwachen&amp;quot; kann. sleep_mode() ist nicht geeignet für die Verwendung in ISR Interrupt-Service-Routinen, da bei deren Abarbeitung Interrupts global deaktiviert sind und somit auch die möglichen &amp;quot;Aufwachinterrupts&amp;quot;. Abhilfe: stattdessen sleep_enable(), sei(), sleep_cpu(), sleep_disable() und evtl. cli() verwenden (vgl. Dokumentation der avr-libc).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/sleep.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
int main(void)&lt;br /&gt;
{&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
   while (1) {&lt;br /&gt;
...&lt;br /&gt;
      set_sleep_mode(SLEEP_MODE_PWR_DOWN);&lt;br /&gt;
      sleep_mode();&lt;br /&gt;
   &lt;br /&gt;
      // Code hier wird erst nach Auftreten eines entsprechenden&lt;br /&gt;
      // &amp;quot;Aufwach-Interrupts&amp;quot; verarbeitet&lt;br /&gt;
...&lt;br /&gt;
   }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In älteren Versionenen der avr-libc wurden nicht alle AVR-Controller durch die sleep-Funktionen richtig angesteuert. Mit avr-libc 1.2.0 wurde die Anzahl der unterstützten Typen jedoch deutlich erweitert. Bei nicht-unterstützten Typen erreicht man die gewünschte Funktionalität durch direkte &amp;quot;[[Bitmanipulation]]&amp;quot; der entsprechenden Register (vgl. Datenblatt) und Aufruf des Sleep-Befehls via Inline-Assembler oder sleep_cpu():&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
   // Sleep-Mode &amp;quot;Power-Save&amp;quot; beim ATmega169 &amp;quot;manuell&amp;quot; aktivieren&lt;br /&gt;
   SMCR = (3&amp;lt;&amp;lt;SM0) | (1&amp;lt;&amp;lt;SE);&lt;br /&gt;
   asm volatile (&amp;quot;sleep&amp;quot;::); // alternativ sleep_cpu() aus sleep.h&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* siehe auch: [http://www.nongnu.org/avr-libc/user-manual/index.html Dokumentation der avr-libc] Abschnitt Modules/Power Management and Sleep-Modes&lt;br /&gt;
* [http://www.mikrocontroller.net/topic/96369#832712 Forenbeitrag] zur &amp;quot;Nichtverwendung&amp;quot; von sleep_mode in ISRs.&lt;br /&gt;
&lt;br /&gt;
= Speicherzugriffe =&lt;br /&gt;
&lt;br /&gt;
Atmel AVR-Controller verfügen typisch über drei Speicher:&lt;br /&gt;
&lt;br /&gt;
* [[RAM]]: Im RAM (genauer statisches RAM/SRAM) wird vom gcc-Compiler Platz für Variablen reserviert. Auch der Stack befindet sich im RAM. Dieser Speicher ist &amp;quot;flüchtig&amp;quot;, d.h. der Inhalt der Variablen geht beim Ausschalten oder einem Zusammenbruch der Spannungsversorgung verloren.&lt;br /&gt;
&lt;br /&gt;
* Programmspeicher: Ausgeführt als FLASH-Speicher, seitenweise wiederbeschreibbar. Darin ist das Anwendungsprogramm abgelegt.&lt;br /&gt;
&lt;br /&gt;
* [[EEPROM]]: Nichtflüchtiger Speicher, d.h. der einmal geschriebene Inhalt bleibt auch ohne Stromversorgung erhalten. Byte-weise schreib/lesbar. Im EEPROM werden typischerweise gerätespezifische Werte wie z.B. Kalibrierungswerte von Sensoren abgelegt.&lt;br /&gt;
&lt;br /&gt;
Einige AVRs besitzen keinen RAM-Speicher, lediglich die Register können als &amp;quot;Arbeitsvariablen&amp;quot;&lt;br /&gt;
genutzt werden. Da die Anwendung des avr-gcc auf solch &amp;quot;kleinen&amp;quot; Controllern ohnehin selten sinnvoll ist und auch nur bei einigen RAM-losen Typen nach [http://lightner.net/avr/ATtinyAvrGcc.html &amp;quot;Bastelarbeiten&amp;quot;] möglich ist, werden diese Controller hier nicht weiter berücksichtigt. Auch EEPROM-Speicher ist nicht auf allen Typen verfügbar. Generell sollten die nachfolgenden Erläuterungen auf alle ATmega-Controller und die größeren AT90-Typen übertragbar sein. Für die Typen ATtiny2313, ATtiny26 und viele weitere der &amp;quot;ATtiny-Reihe&amp;quot; gelten die Ausführungen ebenfalls.&lt;br /&gt;
&lt;br /&gt;
== RAM ==&lt;br /&gt;
&lt;br /&gt;
Die Verwaltung des RAM-Speichers erfolgt durch den Compiler, im Regelfall ist beim Zugriff auf Variablen im RAM nichts Besonderes zu beachten. Die Erläuterungen in jedem brauchbaren C-Buch gelten auch für den vom avr-gcc-Compiler erzeugten Code.&lt;br /&gt;
&lt;br /&gt;
Um Speicher dynamisch (während der Laufzeit) zu reservieren, kann &#039;&#039;&#039;malloc()&#039;&#039;&#039; verwendet werden. malloc(size) &amp;quot;allozieren&amp;quot; (~reserviert) einen gewissen Speicherblock mit &#039;&#039;&#039;size&#039;&#039;&#039; Bytes. Ist kein Platz für den neuen Block, wird NULL (0) zurückgegeben.&lt;br /&gt;
&lt;br /&gt;
Wird der angelegte Block zu klein (groß), kann die Größe mit realloc() verändert werden. Den allozierten Speicherbereich kann man mit free() wieder freigeben. Wenn das Freigeben eines Blocks vergessen wird spricht man von einem &amp;quot;Speicherleck&amp;quot; (memory leak).&lt;br /&gt;
&lt;br /&gt;
malloc() legt Speicherblöcke im &#039;&#039;&#039;Heap&#039;&#039;&#039; an, belegt man zuviel Platz, dann wächst der Heap zu weit nach oben und überschreibt den Stack, und der Controller kommt in Teufels Küche. Das kann leider nicht nur passieren wenn man insgesamt zu viel Speicher anfordert, sondern auch wenn man Blöcke unterschiedlicher Größe in ungünstiger Reihenfolge alloziert/freigibt (siehe Artikel [[Heap-Fragmentierung]]). Aus diesem Grund sollte man malloc() auf Mikrocontrollern sehr sparsam (am besten gar nicht) verwenden.&lt;br /&gt;
&lt;br /&gt;
Beispiel zur Verwendung von malloc():&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
void foo(void) {&lt;br /&gt;
  // neuen speicherbereich anlegen,&lt;br /&gt;
  // platz für 10 uint16&lt;br /&gt;
  uint16_t* pBuffer = malloc(10 * sizeof(uint16_t));&lt;br /&gt;
&lt;br /&gt;
  // darauf zugreifen, als wärs ein gewohnter Buffer&lt;br /&gt;
  pBuffer[2] = 5;&lt;br /&gt;
&lt;br /&gt;
  // Speicher (unbedingt!) wieder freigeben&lt;br /&gt;
  free(pBuffer);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn (wie in obigem Beispiel) dynamischer Speicher nur für die Dauer einer Funktion benötigt und am Ende wieder freigegeben wird, bietet es sich an, statt malloc() &#039;&#039;&#039;alloca()&#039;&#039;&#039; zu verwenden. Der Unterschied zu malloc() ist, dass der Speicher auf dem Stack reserviert wird, und beim Verlassen der Funktion automatisch wieder freigegeben wird. Es kann somit kein Speicherleck und keine Fragmentierung entstehen.&lt;br /&gt;
&lt;br /&gt;
siehe auch:&lt;br /&gt;
* http://www.nongnu.org/avr-libc/user-manual/malloc.html&lt;br /&gt;
&lt;br /&gt;
== Programmspeicher (Flash) ==&lt;br /&gt;
&lt;br /&gt;
Ein Zugriff auf Konstanten im Programmspeicher ist mittels avr-gcc nicht &amp;quot;transparent&amp;quot; möglich. D.h. es sind besondere Zugriffsfunktionen erforderlich, um Daten aus diesem Speicher zu lesen. Grundsätzlich basieren alle Zugriffsfunktionen auf der Assembler-Anweisung lpm (load program memory, bei AVR Controllern mit mehr als 64kB Flash auch elpm). Die Standard-Laufzeitbibliothek des avr-gcc (die avr-libc) stellt diese Funktionen nach Einbinden der Header-Datei pgmspace.h zur Verfügung. Mit diesen Funktionen können einzelne Bytes, Datenworte (16bit) und Datenblöcke gelesen werden. &lt;br /&gt;
&lt;br /&gt;
Deklarationen von Variablen im Flash-Speicher werden durch das &amp;quot;Attribut&amp;quot; PROGMEM ergänzt. Lokale Variablen (eigentlich Konstanten) innerhalb von Funktionen können ebenfalls im Programmspeicher abgelegt werden. Dazu ist bei der Definition jedoch ein &#039;&#039;static&#039;&#039; voranzustellen, da solche &amp;quot;Variablen&amp;quot; nicht auf dem Stack bzw. (bei Optimierung) in Registern verwaltet werden können. Der Compiler &amp;quot;wirft&amp;quot; eine Warnung falls static fehlt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/pgmspace.h&amp;gt;&lt;br /&gt;
#include &amp;lt;inttypes.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
/* Byte */&lt;br /&gt;
const uint8_t pgmFooByte PROGMEM = 123;&lt;br /&gt;
&lt;br /&gt;
/* Wort */&lt;br /&gt;
const uint16_t pgmFooWort PROGMEM = 12345;&lt;br /&gt;
&lt;br /&gt;
/* Byte-Feld */&lt;br /&gt;
const uint8_t pgmFooByteArray1[] PROGMEM = { 18, 3 ,70 };&lt;br /&gt;
const uint8_t pgmFooByteArray2[] PROGMEM = { 30, 7 ,79 };&lt;br /&gt;
&lt;br /&gt;
/* Zeiger */&lt;br /&gt;
const uint8_t *pgmPointerToArray1 PROGMEM = pgmFooByteArray1;&lt;br /&gt;
const uint8_t *pgmPointerArray[] PROGMEM = { pgmFooByteArray1, pgmFooByteArray2 };&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
void foo(void)&lt;br /&gt;
{&lt;br /&gt;
  static /*const*/ uint8_t pgmTestByteLocal PROGMEM = 0x55;&lt;br /&gt;
  static /*const*/ char pgmTestStringLocal[] PROGMEM = &amp;quot;im Flash&amp;quot;;&lt;br /&gt;
  // so nicht (static fehlt): char pgmTestStringLocalFalsch [] PROGMEM = &amp;quot;so nicht&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 // ...&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Byte lesen ===&lt;br /&gt;
&lt;br /&gt;
Mit der Funktion pgm_read_byte aus pgmspace.h erfolgt der Zugriff auf die Daten. Parameter der Funktion ist die Adresse des Bytes im Flash-Speicher.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
const uint8_t pgmFooByte PROGMEM = 123;&lt;br /&gt;
const uint8_t pgmFooByteArray1[] PROGMEM = { 18, 3 ,70 };&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    // Wert der Ram-Variablen myByte auf den Wert von pgmFooByte setzen:&lt;br /&gt;
    uint8_t myByte;&lt;br /&gt;
&lt;br /&gt;
    myByte = pgm_read_byte(&amp;amp;pgmFooByte);&lt;br /&gt;
    // myByte hat nun den Wert 123&lt;br /&gt;
&lt;br /&gt;
    //...&lt;br /&gt;
&lt;br /&gt;
    // Schleife ueber ein Array aus Byte-Werten im Flash&lt;br /&gt;
    uint8_t i;&lt;br /&gt;
&lt;br /&gt;
    for (i=0;i&amp;lt;3;i++) {&lt;br /&gt;
        myByte = pgm_read_byte(&amp;amp;pgmFooByteArray1[i]);&lt;br /&gt;
        // mach&#039; was mit myByte....&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Wort lesen ===&lt;br /&gt;
&lt;br /&gt;
Für &amp;quot;einfache&amp;quot; 16-bit breite Variablen erfolgt der Zugriff analog zum Byte-Beispiel, jedoch mit der Funktion pgm_read_word.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
const uint16_t pgmFooWort PROGMEM = 12345;&lt;br /&gt;
&lt;br /&gt;
    uint16_t myWord;&lt;br /&gt;
&lt;br /&gt;
    myWord = pgm_read_word(&amp;amp;pgmFooWort);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zeiger auf Werte im Flash sind ebenfalls 16 Bits &amp;quot;groß&amp;quot; (Stand avr-gcc 3.4.x). Damit ist der mögliche Speicherbereich für &amp;quot;Flash-Konstanten&amp;quot; auf 64kB begrenzt.  &amp;lt;!-- Einige avr-libc/pgmspace-Funktionen ermöglichen den Lesezugriff auf den gesamten Flash-Speicher) (intern via Assembler Anweisung ELPM). Die Initialisierungswerde des Speicherinhalts jenseits der 64kB-Marke müssen dann jedoch auf anderem Weg angelegt werden (nicht PROGMEM, evtl. eigene Section und Linker-Optionen - TODO) /// alt - und nicht ganz korrekt: (Die avr-libc pgmspace-Funktionen unterstützen nur die unteren 64kB Flash bei Controllern mit mehr als 64kB.)--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
    uint8_t *ptrToArray;&lt;br /&gt;
&lt;br /&gt;
    ptrToArray = (uint8_t*)(pgm_read_word(&amp;amp;pgmPointerToArray1));&lt;br /&gt;
    // ptrToArray enthält nun die Startadresse des Byte-Arrays pgmFooByteArray1&lt;br /&gt;
    // Allerdings würde ein direkter Zugriff mit diesem Pointer (z.B. temp=*ptrToArray)&lt;br /&gt;
    // &#039;&#039;&#039;nicht&#039;&#039;&#039; den Inhalt von pgmFooByteArray1[0] liefern, sondern von einer Speicherstelle&lt;br /&gt;
    // im &#039;&#039;&#039;RAM&#039;&#039;&#039;, die die gleiche Adresse hat wie pgmFooByteArray1[0]&lt;br /&gt;
    // Daher muss nun die Funktion pgm_read_byte() benutzt werden, die die in ptrToArray&lt;br /&gt;
    // enthaltene Adresse benutzt und auf das Flash zugreift.&lt;br /&gt;
&lt;br /&gt;
    for (i=0;i&amp;lt;3;i++) {&lt;br /&gt;
        myByte = pgm_read_byte(ptrToArray+i);&lt;br /&gt;
        // mach&#039; was mit myByte... (18, 3, 70)&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    ptrToArray = (uint8_t*)(pgm_read_word(&amp;amp;pgmPointerArray[1]));&lt;br /&gt;
    &lt;br /&gt;
    // ptrToArray enthält nun die Adresse des ersten Elements des Byte-Arrays pgmFooByteArray2&lt;br /&gt;
    // da im zweiten Element des Pointer-Arrays pgmPointerArray die Adresse&lt;br /&gt;
    // von pgmFooByteArray2 abgelegt ist&lt;br /&gt;
&lt;br /&gt;
    for (i=0;i&amp;lt;3;i++) {&lt;br /&gt;
        myByte = pgm_read_byte(ptrToArray+i);&lt;br /&gt;
        // mach&#039; was mit myByte... (30, 7, 79)&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Floats und Structs lesen ===&lt;br /&gt;
&lt;br /&gt;
Um komplexe Datentypen (structs), nicht-integer Datentypen (floats) aus dem Flash auszulesen, sind Hilfsfunktionen erforderlich. Einige Beispiele:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
/* Beispiel float aus Flash */&lt;br /&gt;
&lt;br /&gt;
float pgmFloatArray[3] PROGMEM = {1.1, 2.2, 3.3};&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
/* liest float von Flash-Addresse addr und gibt diese als return-value zurueck */&lt;br /&gt;
inline float pgm_read_float(const float *addr)&lt;br /&gt;
{	&lt;br /&gt;
	union&lt;br /&gt;
	{&lt;br /&gt;
		uint16_t i[2];	// 2 16-bit-Worte&lt;br /&gt;
		float f;&lt;br /&gt;
	} u;&lt;br /&gt;
	&lt;br /&gt;
	u.i[0]=pgm_read_word((PGM_P)addr);&lt;br /&gt;
	u.i[1]=pgm_read_word((PGM_P)addr+2);&lt;br /&gt;
	&lt;br /&gt;
	return u.f;&lt;br /&gt;
} &lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
void egal(void)&lt;br /&gt;
{&lt;br /&gt;
   int i;&lt;br /&gt;
   float f;&lt;br /&gt;
&lt;br /&gt;
   for (i=0;i&amp;lt;3;i++) {&lt;br /&gt;
      f = pgm_read_float(&amp;amp;pgmFloatArray[i]); // entspr. &amp;quot;f = pgmFloatArray[i];&amp;quot;&lt;br /&gt;
      // mach&#039; was mit f &lt;br /&gt;
   }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
TODO: Beispiele fuer structs und pointer aus flash auf struct im flash (menues, state-machines etc.)&lt;br /&gt;
&lt;br /&gt;
=== Array aus Zeichenketten im Flash-Speicher ===&lt;br /&gt;
&lt;br /&gt;
Felder aus Zeichenketten im Flash-Speicher werden in zwei Schritten angelegt: Zuerst die einzelnen Elemente des Arrays und im Anschluss ein Array, in dem die Addressen der Zeichenketten abgelegt werden. Zum Auslesen wird zuerst die Adresse des i-ten Elements aus dem Array im Flash-Speicher gelesen, die im Anschluss dazu genutzt wird, auf das Element (die Zeichenkette) selbst zuzugreifen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/pgmspace.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
const char str1[] PROGMEM = &amp;quot;first_A&amp;quot;;&lt;br /&gt;
const char str2[] PROGMEM = &amp;quot;second_A&amp;quot;;&lt;br /&gt;
const char str3[] PROGMEM = &amp;quot;third_A&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
const char *strarray1[] PROGMEM = {&lt;br /&gt;
	str1,&lt;br /&gt;
	str2,&lt;br /&gt;
	str3&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
int main(void)&lt;br /&gt;
{&lt;br /&gt;
	int i, j, l;&lt;br /&gt;
	const char *pstrflash;&lt;br /&gt;
	char work[20], work2[20];&lt;br /&gt;
	// fuer Simulation: per volatile Optimierung verhindern, &lt;br /&gt;
	//                  da c nicht genutzt&lt;br /&gt;
	volatile char c;&lt;br /&gt;
	&lt;br /&gt;
	for ( i = 0; i &amp;lt; (sizeof(strarray1)/sizeof(strarray1[0]) ); i++ ) {&lt;br /&gt;
&lt;br /&gt;
		// setze Pointer auf die Addresse des i-ten Elements des&lt;br /&gt;
		// &amp;quot;Flash-Arrays&amp;quot; (str1, str2, ...)&lt;br /&gt;
		pstrflash = (const char*)( pgm_read_word( &amp;amp;(strarray1[i]) ) );&lt;br /&gt;
		&lt;br /&gt;
		// kopiere den Inhalt der Zeichenkette von der&lt;br /&gt;
		// in pstrflash abgelegten Adresse in das work-Array&lt;br /&gt;
		// analog zu strcpy( work, strarray1[i]) wenn alles im RAM&lt;br /&gt;
		strcpy_P( work, pstrflash );&lt;br /&gt;
		// verkuerzt:&lt;br /&gt;
		strcpy_P( work2, (const char*)( pgm_read_word( &amp;amp;(strarray1[i]) ) ) );&lt;br /&gt;
		&lt;br /&gt;
&lt;br /&gt;
		// Zeichen-fuer-Zeichen&lt;br /&gt;
		l = strlen_P( pstrflash );&lt;br /&gt;
		for ( j=0; j &amp;lt; l; j++ ) {&lt;br /&gt;
			// analog zu c=strarray[i][j] wenn alles im RAM&lt;br /&gt;
			c = (char)( pgm_read_byte( pstrflash++ ) );&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	while (1) { ; }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Siehe dazu auch die avr-libc FAQ: &amp;quot;How do I put an array of strings completely in ROM?&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=== Vereinfachung für Zeichenketten (Strings) im Flash ===&lt;br /&gt;
&lt;br /&gt;
Zeichenketten können innerhalb des Quellcodes als &amp;quot;Flash-Konstanten&amp;quot; ausgewiesen werden. Dazu dient das Makro PSTR aus pgmspace.h. Dies erspart die getrennte Deklaration mit PROGMEM-Attribut.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/pgmspace.h&amp;gt;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#define MAXLEN 30&lt;br /&gt;
&lt;br /&gt;
char StringImFlash[] PROGMEM = &amp;quot;Erwin Lindemann&amp;quot;; // im &amp;quot;Flash&amp;quot;&lt;br /&gt;
char StringImRam[MAXLEN];&lt;br /&gt;
&lt;br /&gt;
//...&lt;br /&gt;
    strcpy(StringImRam, &amp;quot;Mueller-Luedenscheidt&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (!strncmp_P(StringImRam, StringImFlash, 5)) { &lt;br /&gt;
        // mach&#039; was, wenn die ersten 5 Zeichen identisch - hier nicht&lt;br /&gt;
    }&lt;br /&gt;
    else {&lt;br /&gt;
        // der Code hier wuerde ausgefuehrt &lt;br /&gt;
    } &lt;br /&gt;
&lt;br /&gt;
    if (!strncmp_P(StringImRam, PSTR(&amp;quot;Mueller-Schmitt&amp;quot;), 5)) {&lt;br /&gt;
        // der Code hier wuerde ausgefuehrt, die ersten 5 Zeichen stimmen ueberein&lt;br /&gt;
    }&lt;br /&gt;
    else {&lt;br /&gt;
        // wuerde bei nicht-Uebereinstimmung ausgefuehrt&lt;br /&gt;
    }&lt;br /&gt;
//...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Aber Vorsicht: Ersetzt man zum Beispiel&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
const char textImFlashOK[] PROGMEM = &amp;quot;mit[]&amp;quot;; &lt;br /&gt;
// = Daten im &amp;quot;Flash&amp;quot;, textImFlashOK* zeigt auf Flashadresse&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
durch&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
const char* textImFlashProblem PROGMEM = &amp;quot;mit*&amp;quot;;&lt;br /&gt;
// Konflikt: Daten im BSS (lies: RAM), textImFlashFAIL* zeigt auf Flashadresse&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
dann kann es zu Problemen mit AVR-GCC kommen. Zu erkennen daran, dass der Initialisierungsstring von &amp;quot;textImFlashProblem&amp;quot; zu den Konstanten ans Ende des Programmcodes gelegt wird (BSS), von dem aus er zur Benutzung eigentlich ins RAM kopiert werden sollte (und wird). Da der lesende Code (mittels pgm_read*) trotzdem an einer Stelle vorne im Flash sucht, wird Unsinn gelesen. Dies scheint ein weiters Problem des AVR-GCC (gesehen bei avr-gcc 3.4.1 und 3.4.2) bei der Anpassung an die Harvard-Architektur zu sein (konstanter Pointer auf variable Daten?!). Abhilfe (&amp;quot;Workaround&amp;quot;): Initialisierung bei Zeichenketten mit [] oder gleich im Code PSTR(&amp;quot;...&amp;quot;) nutzen.&lt;br /&gt;
&lt;br /&gt;
Übergibt man Zeichenketten (genauer: die Adresse des ersten Zeichens), die im Flash abglegt sind an eine Funktion, muss diese entsprechend programmiert sein. Die Funktion selbst hat keine Möglichkeit zu unterscheiden, ob es sich um eine Adresse im Flash oder im RAM handelt. Die avr-libc und viele andere avr-gcc-Bibliotheken halten sich an die Konvention, dass Namen von Funktionen die Flash-Adressen erwarten mit dem Suffix _p (oder _P) versehen sind.&lt;br /&gt;
&lt;br /&gt;
Eine Funktion, die einen im Flash abgelegten String z.B. an eine UART ausgibt, würde dann so aussehen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
void uart_puts_p(const char *text)&lt;br /&gt;
{&lt;br /&gt;
    char Zeichen;&lt;br /&gt;
&lt;br /&gt;
    while (Zeichen = pgm_read_byte(text))&lt;br /&gt;
    {   /* so lange, wie mittels pgm_read_byte ein Zeichen vom Flash gelesen&lt;br /&gt;
           werden konnte, welches nicht das &amp;quot;String-Endezeichen&amp;quot; darstellt */&lt;br /&gt;
&lt;br /&gt;
        /* Das gelesene Zeichen über die normalen Kanäle verschicken */&lt;br /&gt;
        uart_putc(Zeichen);&lt;br /&gt;
        text++;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Von einigen Bibliotheken werden Makros definiert, die &amp;quot;automatisch&amp;quot; ein PSTR bei Verwendung einer Funktion einfügen. Ein Blick in den Header-File der Bibliothek zeigt, ob dies der Fall ist. Ein Beispiel aus P. Fleurys lcd-Library:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
// Ausschnitt aus dem Header-File lcd.h der &amp;quot;Fleury-LCD-Lib.&amp;quot;&lt;br /&gt;
//...&lt;br /&gt;
extern void lcd_puts_p(const char *progmem_s);&lt;br /&gt;
#define lcd_puts_P(__s) lcd_puts_p(PSTR(__s))&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
// in einer Anwendung (wieauchimmmer.c)&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/pgmspace.h&amp;gt;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
#include &amp;quot;lcd.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
char StringImFlash[] PROGMEM = &amp;quot;Erwin Lindemann&amp;quot;; // im &amp;quot;Flash&amp;quot;&lt;br /&gt;
&lt;br /&gt;
//...&lt;br /&gt;
    lcd_puts_p(StringImFlash); &lt;br /&gt;
    lcd_puts_P(&amp;quot;Dr. Kloebner&amp;quot;); &lt;br /&gt;
    // daraus wird wg. #define lcd_put_P...:  lcd_puts_p( PSTR(&amp;quot;Dr. Kloebner&amp;quot;) );&lt;br /&gt;
//...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Flash in der Anwendung schreiben ===&lt;br /&gt;
&lt;br /&gt;
Bei AVRs mit &amp;quot;self-programming&amp;quot;-Option (auch bekannt als Bootloader-Support) können Teile des Flash-Speichers auch vom Anwendungsprogramm selbst beschrieben werden. Dies ist nur möglich, wenn die Schreibfunktionen in einem besonderen Speicherbereich (boot-section) des Programmspeichers/Flash abgelegt sind. Bei wenigen &amp;quot;kleinen&amp;quot; AVRs gibt es keine gesonderte Boot-Section, bei diesen kann der Flashspeicher von jeder Stelle des Programms geschrieben werden. Für Details sei hier auf das jeweilige Controller-Datenblatt und die Erläuterungen zum Modul boot.h der avr-libc verwiesen. Es existieren auch Application-Notes dazu bei atmel.com, die auf avr-gcc-Code übertragbar sind.&lt;br /&gt;
&lt;br /&gt;
=== Warum so kompliziert? ===&lt;br /&gt;
&lt;br /&gt;
Zu dem Thema, warum die Verabeitung von Werten aus dem Flash-Speicher so &amp;quot;kompliziert&amp;quot; ist, sei hier nur kurz erläutert: Die Harvard-Architektur des AVR weist getrennte Adressräume für Programm(Flash)- und Datenspeicher(RAM) auf. Der C-Standard und der gcc-Compiler sehen keine unterschiedlichen Adressräume vor. &lt;br /&gt;
Hat man zum Beispiel eine Funktion string_an_uart(const char* s) und übergibt an diese Funktion die Adresse einer Zeichenkette (einen Pointer, z.B. 0x01fe), &amp;quot;weiß&amp;quot; die Funktion nicht, ob die Adresse auf den Flash-Speicher oder den/das RAM zeigt. Allein aus dem Pointer-Wert (der Zahl) kann nicht geschlossen werden, ob ein &amp;quot;einfaches&amp;quot; zeichen_an_uart(s[i]) oder zeichen_an_uart(pgm_read_byte(&amp;amp;s[i]) genutzt werden muss, um das i-te Zeichen auszugeben.&lt;br /&gt;
&lt;br /&gt;
Einige AVR-Compiler &amp;quot;tricksen&amp;quot; etwas, in dem sie für einen Pointer nicht nur die Adresse anlegen, sondern zusätzlich zu jedem Pointer den Ablageort (Flash oder RAM) intern sichern. Bei Aufruf einer Funktion wird dann bei Pointer-Parametern neben der Adresse auch der Speicherbereich, auf den der Pointer zeigt, übergeben. Dies hat jedoch nicht nur Vorteile; Erläuterungen warum dies so ist, führen an dieser Stelle zu weit.&lt;br /&gt;
&lt;br /&gt;
* siehe auch: [http://www.nongnu.org/avr-libc/user-manual/index.html Dokumentation der avr-libc] Abschnitte Modules/Program Space String Utilities und Abschnitt Modules/Bootloader Support Utilities&lt;br /&gt;
&lt;br /&gt;
== EEPROM ==&lt;br /&gt;
&lt;br /&gt;
Man beachte, dass der EEPROM-Speicher nur eine begrenzte Anzahl von Schreibzugriffen zulässt. Beschreibt man eine EEPROM-Zelle öfter als die im Datenblatt zugesicherte Anzahl (typisch 100.000), wird die Funktion der Zelle nicht mehr garantiert. &lt;br /&gt;
Dies gilt für jede einzelne Zelle. Bei geschickter Programmierung (z.B. Ring-Puffer), bei der die zu beschreibenden Zellen regelmäßig gewechselt werden, kann man eine deutlich höhere Anzahl an Schreibzugriffen, bezogen auf den Gesamtspeicher, erreichen.&lt;br /&gt;
&lt;br /&gt;
Schreib- und Lesezugriffe auf den EEPROM-Speicher erfolgen über die im Modul eeprom.h definierten Funktionen. Mit diesen Funktionen können einzelne Bytes, Datenworte (16bit) und Datenblöcke geschrieben und gelesen werden. &lt;br /&gt;
&lt;br /&gt;
Bei Nutzung des EEPROMs ist zu beachten, dass vor dem Zugriff auf diesen Speicher abgefragt wird, ob der Controller die vorherige EEPROM-Operation abgeschlossen hat. Die avr-libc-Funktionen beinhalten diese Prüfung, man muss sie nicht selbst implementieren. Man sollte auch verhindern, dass der Zugriff durch die Abarbeitung einer Interrupt-Routine unterbrochen wird, da bestimme Befehlsabfolgen vorgegeben sind, die innerhalb weniger Taktzyklen aufeinanderfolgen müssen (&amp;quot;timed sequence&amp;quot;). Auch dies muss bei Nutzung der Funktionen aus der avr-libc/eeprom.h-Datei nicht selbst implementiert werden. Innerhalb der Funktionen werden Interrupts vor der &amp;quot;EEPROM-Sequenz&amp;quot; global deaktiviert und im Anschluss, falls vorher auch schon eingeschaltet, wieder aktiviert.&lt;br /&gt;
&lt;br /&gt;
Bei der Deklaration einer Variable im EEPROM, ist das Attribut für die Section &amp;quot;.eeprom&amp;quot; zu ergänzen. Siehe dazu folgendes Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/eeprom.h&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/interrupt.h&amp;gt;&lt;br /&gt;
#include &amp;lt;inttypes.h&amp;gt; // wird in aktuellen Versionen der avr-lib mit xx.h eingebunden&lt;br /&gt;
&lt;br /&gt;
// EEMEM wird bei aktuellen Versionen der avr-lib in eeprom.h definiert&lt;br /&gt;
// hier: definiere falls noch nicht bekannt (&amp;quot;alte&amp;quot; avr-libc)&lt;br /&gt;
#ifndef EEMEM&lt;br /&gt;
// alle Textstellen EEMEM im Quellcode durch __attribute__ ... ersetzen&lt;br /&gt;
#define EEMEM  __attribute__ ((section (&amp;quot;.eeprom&amp;quot;)))&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
/* Byte */&lt;br /&gt;
uint8_t eeFooByte EEMEM = 123;&lt;br /&gt;
&lt;br /&gt;
/* Wort */&lt;br /&gt;
uint16_t eeFooWord EEMEM = 12345;&lt;br /&gt;
&lt;br /&gt;
/* float */&lt;br /&gt;
float eeFooFloat EEMEM;&lt;br /&gt;
&lt;br /&gt;
/* Byte-Feld */&lt;br /&gt;
uint8_t eeFooByteArray1[] EEMEM = { 18, 3 ,70 };&lt;br /&gt;
uint8_t eeFooByteArray2[] EEMEM = { 30, 7 ,79 };&lt;br /&gt;
&lt;br /&gt;
/* 16-bit unsigned short feld */&lt;br /&gt;
uint16_t eeFooWordArray1[4] EEMEM;&lt;br /&gt;
//...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Bytes lesen/schreiben ===&lt;br /&gt;
&lt;br /&gt;
Die avr-libc Funktion zum Lesen eines Bytes heißt eeprom_read_byte. Parameter ist die Adresse des Bytes im EEPROM. Geschrieben wird über die Funktion eeprom_write_byte mit den Parametern Adresse und Inhalt. Anwendungsbeispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
    uint8_t myByte;&lt;br /&gt;
&lt;br /&gt;
    myByte = eeprom_read_byte(&amp;amp;eeFooByte); // lesen&lt;br /&gt;
    // myByte hat nun den Wert 123&lt;br /&gt;
//...&lt;br /&gt;
    myByte = 99;&lt;br /&gt;
    eeprom_write_byte(&amp;amp;eeFooByte, myByte); // schreiben&lt;br /&gt;
    // der Wert 99 wird im EEPROM an die Adresse der&lt;br /&gt;
    // &#039;Variablen&#039; eeFooByte geschrieben&lt;br /&gt;
//...&lt;br /&gt;
    myByte = eeprom_read_byte(&amp;amp;eeFooByteArray1[1]); &lt;br /&gt;
    // myByte hat nun den Wert 3&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
    // Beispiel zur &amp;quot;Sicherung&amp;quot; gegen leeres EEPROM nach &amp;quot;Chip Erase&amp;quot;&lt;br /&gt;
    // (z.B. wenn die .eep-Datei nach Programmierung einer neuen Version&lt;br /&gt;
    // des Programms nicht in den EEPROM uebertragen wurde und EESAVE&lt;br /&gt;
    // deaktiviert ist (unprogrammed/1)&lt;br /&gt;
    // &lt;br /&gt;
    // Vorsicht: wenn EESAVE &amp;quot;programmed&amp;quot; ist, hilft diese Sicherung nicht&lt;br /&gt;
    // weiter, da die Speicheraddressen in einem neuen/erweiterten Programm&lt;br /&gt;
    // moeglicherweise verschoben wurden. An der Stelle &amp;amp;eeFooByte steht&lt;br /&gt;
    // dann u.U. der Wert einer anderen Variable aus einer &amp;quot;alten&amp;quot; Version.&lt;br /&gt;
&lt;br /&gt;
    #define EEPROM_DEF 0xFF&lt;br /&gt;
    uint8_t fooByteDefault = 222;&lt;br /&gt;
    if ( ( myByte = eeprom_read_byte(&amp;amp;eeFooByte) ) == EEPROM_DEF ) {&lt;br /&gt;
        myByte = fooByteDefault;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Wort lesen/schreiben ===&lt;br /&gt;
&lt;br /&gt;
Schreiben und Lesen von Datenworten erfolgt analog zur Vorgehensweise bei Bytes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
    uint16_t myWord;&lt;br /&gt;
&lt;br /&gt;
    myWord = eeprom_read_word(&amp;amp;eeFooWord); // lesen&lt;br /&gt;
    // myWord hat nun den Wert 12345&lt;br /&gt;
//...&lt;br /&gt;
    myWord = 2222;&lt;br /&gt;
    eeprom_write_word(&amp;amp;eeFooWord, myWord); // schreiben&lt;br /&gt;
//...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Block lesen/schreiben ===&lt;br /&gt;
&lt;br /&gt;
Lesen und Schreiben von Datenblöcken erfolgt über die Funktionen &#039;&#039;eeprom_read_block()&#039;&#039; bzw. &#039;&#039;eeprom_write_block()&#039;&#039;. Die Funktionen erwarten drei Parameter: die Adresse der Quell- bzw. Zieldaten im RAM, die EEPROM-Addresse und die Länge des Datenblocks in Bytes (size_t).&lt;br /&gt;
&lt;br /&gt;
TODO: &#039;&#039;&#039;Vorsicht!&#039;&#039;&#039; die folgenden Beispiele sind noch nicht geprüft, erstmal nur als Hinweis auf &amp;quot;das Prinzip&amp;quot;. Evtl. fehlen &amp;quot;casts&amp;quot; und möglicherweise noch mehr.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
    uint8_t  myByteBuffer[3];&lt;br /&gt;
    uint16_t myWordBuffer[4];&lt;br /&gt;
&lt;br /&gt;
    /* Datenblock aus EEPROM LESEN  */&lt;br /&gt;
&lt;br /&gt;
    /* liest 3 Bytes ab der von eeFooByteArray1 definierten EEPROM-Adresse&lt;br /&gt;
       in das RAM-Array myByteBuffer */&lt;br /&gt;
    eeprom_read_block(myByteBuffer,eeFooByteArray1,3);&lt;br /&gt;
&lt;br /&gt;
    /* dito etwas anschaulicher aber &amp;quot;unnütze Tipparbeit&amp;quot;: */&lt;br /&gt;
    eeprom_read_block(&amp;amp;myByteBuffer[0],&amp;amp;eeFooByteArray[0],3);&lt;br /&gt;
&lt;br /&gt;
    /* dito mit etwas Absicherung betr. der Länge */&lt;br /&gt;
    eeprom_read_block(myByteBuffer,eeFooByteArray1,sizeof(myByteBuffer));&lt;br /&gt;
&lt;br /&gt;
    /* und nun mit &amp;quot;16bit&amp;quot; */&lt;br /&gt;
    eeprom_read_block(myWordBuffer,eeFooWordArray1,sizeof(myWordBuffer));&lt;br /&gt;
&lt;br /&gt;
    /* Datenlock in EEPROM SCHREIBEN */&lt;br /&gt;
    eeprom_write_block(eeFooByteArray1,myByteBuffer,sizeof(myByteBuffer));&lt;br /&gt;
    eeprom_write_block(eeFooWordArray1,myWordBuffer,sizeof(myWordBuffer));&lt;br /&gt;
//...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Nicht-Integer&amp;quot;-Datentypen wie z.B. Fließkommazahlen lassen sich recht praktisch über eine &#039;&#039;union&#039;&#039; in &amp;quot;Byte-Arrays&amp;quot; konvertieren und wieder &amp;quot;zurückwandeln&amp;quot;. Dies erweist sich hier (aber nicht nur hier) als nützlich.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
   float myFloat = 12.34;&lt;br /&gt;
&lt;br /&gt;
   union {&lt;br /&gt;
      float r;&lt;br /&gt;
      uint8_t i[sizeof(float)];&lt;br /&gt;
   } u;&lt;br /&gt;
&lt;br /&gt;
   u.r = myFloat;&lt;br /&gt;
   &lt;br /&gt;
   /* float in EEPROM */&lt;br /&gt;
   eeprom_write_block(&amp;amp;eeFooFloat,&amp;amp;(u.i),sizeof(float));&lt;br /&gt;
&lt;br /&gt;
   /* float aus EEPROM */&lt;br /&gt;
   eeprom_read_block(&amp;amp;(u.i),&amp;amp;eeFooFloat,sizeof(float));&lt;br /&gt;
   /* u.r wieder 12.34 */&lt;br /&gt;
//...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Auch zusammengesetzte Typen lassen sich mit den Block-Routinen verarbeiten.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
typedef struct {&lt;br /&gt;
    uint8_t   label[8];&lt;br /&gt;
    uint8_t   rom_code[8];&lt;br /&gt;
} tMyStruct;&lt;br /&gt;
&lt;br /&gt;
#define MAXSENSORS 3&lt;br /&gt;
tMyStruct eeMyStruct[MAXSENSORS] EEMEM;&lt;br /&gt;
&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
void egal(void)&lt;br /&gt;
{&lt;br /&gt;
   tMyStruct work;&lt;br /&gt;
   &lt;br /&gt;
   strcpy(work.label,&amp;quot;Flur&amp;quot;);&lt;br /&gt;
   GetRomCode(work.rom_code);     // Dummy zur Veranschaulichung - setzt rom-code&lt;br /&gt;
&lt;br /&gt;
   /* Sichern von &amp;quot;work&amp;quot; im EEPROM */&lt;br /&gt;
   eeprom_write_block(&amp;amp;eeMyStruct[0],&amp;amp;work,sizeof(tMyStruct)); // f. Index 0&lt;br /&gt;
   strcpy(work.label,&amp;quot;Bad&amp;quot;);&lt;br /&gt;
   GetRomCode(work.rom_code);&lt;br /&gt;
   eeprom_write_block(&amp;amp;eeMyStruct[1],&amp;amp;work,sizeof(tMyStruct)); // f. Index 1&lt;br /&gt;
//...&lt;br /&gt;
   /* Lesen der Daten EEPROM Index 0 in &amp;quot;work&amp;quot; */&lt;br /&gt;
   eeprom_read_block(&amp;amp;work,&amp;amp;eeMyStruct[0],sizeof(tMyStruct));&lt;br /&gt;
   // work.label hat nun den Inhalt &amp;quot;Flur&amp;quot;&lt;br /&gt;
//...&lt;br /&gt;
}&lt;br /&gt;
//...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== EEPROM-Speicherabbild in .eep-Datei ===&lt;br /&gt;
&lt;br /&gt;
Mit den zum Compiler gehörenden Werkzeugen kann der aus den Variablendeklaration abgeleiteten EEPROM-Inhalt in eine Datei geschrieben werden (übliche Dateiendung: .eep, Daten im Intel Hex-Format). Damit können recht elegant Standardwerte für den EEPROM-Inhalt im Quellcode definiert werden. Makefiles nach WinAVR/MFile-Vorlage enthalten bereits die notwendigen Einstellungen (siehe dazu die Erläuterungen im Abschnitt Exkurs: Makefiles). Der Inhalt der eep-Datei muss ebenfalls zum Mikrocontroller übertragen werden (Write EEPROM), wenn die Initialisierungswerte aus der Deklaration vom Programm erwartet werden. Ansonsten enthält der EEPROM-Speicher nach der Übertragung des Programmers mittels ISP abhängig von der Einstellung der EESAVE-Fuse (vgl. Datenblatt Abschnitt Fuse Bits) die vorherigen Daten (EESAVE programmed = 0), deren Position möglicherweise nicht mehr mit der Belegung im aktuellen Programm übereinstimmt oder den Standardwert nach &amp;quot;Chip Erase&amp;quot;: 0xFF (EESAVE unprogrammed = 1). Als Sicherung kann man im Programm nochmals die Standardwerte vorhalten, beim Lesen auf 0xFF prüfen und gegebenfalls einen Standardwert nutzen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--Eine besondere Funktion des avr-gcc ist, dass mit entsprechenden Optionen im Makefile aus den Initialisierungswerten der Variablen im Quellcode eine Datei erzeugt werden kann, die man auf den Controller programmieren kann (.eep-Datei). Damit können sehr elegant Standardwerte für den EEPROM-Inhalt im Quellcode definiert werden. Die Vorgehensweise wird aus dem WinAVR-Beispielmakefile ersichtlich. Siehe dazu die Erläuterungen im Abschnitt Exkurs: Makefiles.--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== EEPROM-Variable auf feste Adressen legen ===&lt;br /&gt;
&lt;br /&gt;
Gleich zu Beginn möchte ich darauf hinweisen, dass dieses Verfahren nur ein Workaround ist, mit dem man das Problem der anscheinend &amp;quot;zufälligen&amp;quot; Verteilung&lt;br /&gt;
der EEPROM-Variablen durch den Compiler etwas in den Griff bekommen kann.&lt;br /&gt;
&lt;br /&gt;
Hilfreich kann dies vor allem dann sein, wenn man z.B. über einen Kommandointerpreter (o.ä. Funktionen) direkt bestimmte EEPROM-Adressen manipulieren möchte. Auch wenn man über einen JTAG-Adapter (mk I oder mkII) den Programmablauf manipulieren möchte, indem man die EEPROM-Werte direkt ändert, kann diese Technik hilfreich sein.&lt;br /&gt;
&lt;br /&gt;
Im folgenden nun zwei Sourcelistings mit einem Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
/////////////////////////////////////////////////&lt;br /&gt;
// Datei &amp;quot;eeprom.h&amp;quot; eines eigenen Projektes&lt;br /&gt;
/////////////////////////////////////////////////&lt;br /&gt;
&lt;br /&gt;
#inlcude &amp;lt;avr/eeprom.h&amp;gt;     // Die EEPROM-Definitionen/Macros der avr-libc einbinden&lt;br /&gt;
&lt;br /&gt;
#define   EESIZE   512      // Maximale Größe des EEPROMS&lt;br /&gt;
&lt;br /&gt;
#define   EE_DUMMY   0x000  // Dummyelement (Adresse 0 sollte nicht genutzt werden)&lt;br /&gt;
#define   EE_VALUE1  0x001  // Eine Bytevariable  &lt;br /&gt;
#define   EE_WORD1L  0x002  // Eine Wordvariable (Lowbyte)&lt;br /&gt;
#define   EE_WORD1H  0x003  // Eine Wordvariable (Highbyte)&lt;br /&gt;
#define   EE_VALUE2  0x004  // Eine weitere Bytevariable&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit den Macros &#039;&#039;&#039;#define EE_VALUE1&#039;&#039;&#039; legt man den Namen und die Adresse der&lt;br /&gt;
&#039;Variablen&#039; fest.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;font color=$FF0000&amp;gt;WICHTIG:&amp;lt;/font&amp;gt;Die Adressen sollten fortlaufend, zumindest aber aufsteigend sortiert sein! Ansonsten besteht die Gefahr, daß man sehr schnell ein Durcheinander im EEPROM Speicher veranstaltet.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;font color=$FF0000&amp;gt;WICHTIG:&amp;lt;/font&amp;gt;Für den Compiler sind das lediglich Speicher-Adressen, über die auf das EEPROM zugegriffen wird. Der Compiler sieht nichts davon als eine echte Variable an und stößt sich daher auch nicht daran, wenn 2 Makros mit der gleichen Speicheradresse, bzw. überlappenden Speicherbereichen definiert werden. Es liegt einzig und alleine in der Hand des Programmierers, hier keinen Fehler zu machen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
/////////////////////////////////////////////////&lt;br /&gt;
// Datei &amp;quot;eeprom.c&amp;quot; eines eigenen Projektes&lt;br /&gt;
/////////////////////////////////////////////////&lt;br /&gt;
&lt;br /&gt;
#include &amp;quot;eeprom.h&amp;quot;          // Eigene EEPROM-Headerdatei einbinden&lt;br /&gt;
&lt;br /&gt;
uint8_t ee_mem[EESIZE] EEMEM =&lt;br /&gt;
{&lt;br /&gt;
   [EE_DUMMY]   = 0x00,&lt;br /&gt;
   [EE_VALUE1]  = 0x05,&lt;br /&gt;
   [EE_WORD1L]  = 0x01,   &lt;br /&gt;
   [EE_WORD1H]  = 0x00,&lt;br /&gt;
   [EE_VALUE2]  = 0xFF&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Durch die Verwendung eines Array, welches das gesammte EEPROM umfasst, bleibt&lt;br /&gt;
dem Compiler nicht anderes übrig, als das Array so zu platzieren, dass Element 0&lt;br /&gt;
des Arrays der Adresse 0 des EEPROMs entspricht. (&#039;&#039;Ich hoffe nur, dass die Compilerbauer daran nichts ändern!&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
Wie man in dem obigen Codelisting auch sehen kann, hat das Verfahren einen kleinen Haken. Variablen die größer sind als 1 Byte, müssen etwas umständlicher&lt;br /&gt;
definiert werden. Benötigt man keine Initialisierung durch das Programm (was der Normalfall sein dürfte), dann kann man das auch so machen:&lt;br /&gt;
&lt;br /&gt;
Möchte man im EEPROM hintereinander beispielsweise Variablen, mit den Namen &#039;&#039;&#039;Wert&#039;&#039;&#039;, &#039;&#039;&#039;Anzahl&#039;&#039;&#039;, &#039;&#039;&#039;Name&#039;&#039;&#039; und &#039;&#039;&#039;Wertigkeit&#039;&#039;&#039; definieren, wobei Wert und Wertigkeit 1 Byte belegen sollen, Anzahl als 1 Wort (also 2 Bytes) und Name mit 10 Bytes reserviert werden soll, so geht auch folgendes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#define EE_DUMMY      0x000&lt;br /&gt;
#define EE_WERT       ( 0x000 + sizeof( uint8_t ) )&lt;br /&gt;
#define EE_ANZAHL     ( EE_WERT + sizeof( uint8_t ) )&lt;br /&gt;
#define EE_NAME       ( EE_ANZAHL + sizeof( uint16_t ) )&lt;br /&gt;
#define EE_WERTIGKEIT ( EE_NAME + 10 * sizeof( uint8_t ) )&lt;br /&gt;
#define EE_LAST       ( EE_WERTIGKEIT + sizeof( uint8_t ) )&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jedes Makro definiert also seine Startadresse durch die Startadresse der unmittelbar vorhergehende &#039;Variablen&#039; plus der Anzahl der Bytes die von der vorhergehenden &#039;Variablen&#039; verbraucht werden. Dadurch ist man zumindest etwas auf der sicheren Seite, dass keine 2 &#039;Variablen&#039; im EEPROM überlappend definiert werden. Möchte man eine weitere &#039;Variable&#039; hinzufügen, so wird deren&lt;br /&gt;
Name, einfach anstelle der EE_LAST eingesetzt und eine neue Zeile für EE_LAST eingefügt, in der dann die Größe der &#039;Variablen&#039; festgelegt wird. Zb.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#define EE_DUMMY      0x000&lt;br /&gt;
#define EE_WERT       ( 0x000 + sizeof( uint8_t ) )&lt;br /&gt;
#define EE_ANZAHL     ( EE_WERT + sizeof( uint8_t ) )&lt;br /&gt;
#define EE_NAME       ( EE_ANZAHL + sizeof( uint16_t ) )&lt;br /&gt;
#define EE_WERTIGKEIT ( EE_NAME + 10 * sizeof( uint8_t ) )&lt;br /&gt;
#define EE_PROZENT    ( EE_WERTIGKEIT + sizeof( uint8_t ) )&lt;br /&gt;
#define EE_LAST       ( EE_WERTIGKEIT + sizeof( double ) )&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
EE_PROZENT legt die Startadresse für eine neue &#039;Variable&#039; des Datentyps double fest.&lt;br /&gt;
&lt;br /&gt;
Der Zugriff auf die EEPROM Werte kann dann z.B.so erfolgen:&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
uint8_t   temp1;&lt;br /&gt;
uint16_t  temp2;&lt;br /&gt;
&lt;br /&gt;
temp1 = eeprom_read_byte(EE_VALUE1);&lt;br /&gt;
temp2 = eeprom_read_word(EE_WORD1L);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ob die in der avr-libc vorhandenen Funktionen dafür verwendet werden können, weiß ich nicht. Aber in einigen Fällen muss man sich sowieso eigene Funktionen&lt;br /&gt;
bauen, welche die spezifischen Anforderungen (Interrupt - Atom Problem, etc.)&lt;br /&gt;
erfüllen.&lt;br /&gt;
&lt;br /&gt;
Die oben beschriebene Möglichkeit ist nur eine Möglichkeit, wie man dies realisieren kann. Sie bietet einem eine relativ einfache Art die EEPROM-Werte&lt;br /&gt;
auf beliebige Adressen zu legen oder Adressen zu ändern. Die Andere Möglichkeit besteht darin, die EEPROM-Werte wie folgt zu belegen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
/////////////////////////////////////////////////&lt;br /&gt;
// Datei &amp;quot;eeprom.c&amp;quot; eines eigenen Projektes&lt;br /&gt;
/////////////////////////////////////////////////&lt;br /&gt;
&lt;br /&gt;
#include &amp;quot;eeprom.h&amp;quot;          // Eigene EEPROM-Headerdatei einbinden&lt;br /&gt;
&lt;br /&gt;
uint8_t ee_mem[EESIZE] EEMEM =&lt;br /&gt;
{&lt;br /&gt;
  0x00,                     //  ee_dummy&lt;br /&gt;
  0x05,                     //  ee_value1&lt;br /&gt;
  0x01,                     //  ee_word1L&lt;br /&gt;
  0x00,                     // (ee_word1H)&lt;br /&gt;
  0xFF                      //  ee_value2&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hierbei kann man Variablen, die größer sind als 1 Byte einfacher definieren und&lt;br /&gt;
man muss nur die Highbyte- oder Lowbyte-Adresse in der &amp;quot;eeprom.h&amp;quot; definieren.&lt;br /&gt;
Allerdings muss man hier höllisch aufpassen, dass man nicht um eine oder mehrere&lt;br /&gt;
Positionen verrutscht!&lt;br /&gt;
&lt;br /&gt;
Welche der beiden Möglichkeiten man einsetzt, hängt vor allem davon ab, wieviele&lt;br /&gt;
Byte, Word und sonstige Variablen man benutzt. Gewöhnen sollte man sich an beide Varianten können ;)&lt;br /&gt;
&lt;br /&gt;
Kleine Schlussbemerkung:&lt;br /&gt;
&lt;br /&gt;
* Der avr-gcc unterstützt die Variante 1 und die Variante 2&lt;br /&gt;
* Der icc-avr Compiler unterstützt nur die Variante 2!&lt;br /&gt;
&lt;br /&gt;
=== Bekannte Probleme bei den EEPROM-Funktionen ===&lt;br /&gt;
&lt;br /&gt;
Vorsicht: Bei alten Versionen der avr-libc wurden nicht alle AVR Controller  untersützt. Z.B. bei der avr-libc Version 1.2.3 insbesondere bei AVRs &amp;quot;der neuen Generation&amp;quot; (ATmega48/88/168/169) funktionieren die Funktionen nicht korrekt (Ursache: unterschiedliche Speicheradressen der EEPROM-Register). In neueren Versionen (z.B. avr-libc 1.4.3 aus WinAVR 20050125) wurde die Zahl der unterstüzten Controller deutlich erweitert und eine Methode zur leichten Anpassung an zukünftige Controller eingeführt.&lt;br /&gt;
&lt;br /&gt;
In jedem Datenblatt zu AVR-Controllern mit EEPROM sind kurze Beispielecodes für den Schreib- und Lesezugriff enthalten. Will oder kann man nicht auf die neue Version aktualisieren, kann der dort gezeigte Code auch mit dem avr-gcc (ohne avr-libc/eeprom.h) genutzt werden (&amp;quot;copy/paste&amp;quot;, gegebenfalls Schutz vor Unterbrechnung/Interrupt ergänzen &#039;&#039;uint8_t sreg; sreg=SREG; cli(); [EEPROM-Code] ; SREG=sreg; return;&#039;&#039;, siehe Abschnitt Interrupts). Im Zweifel hilft ein Blick in den vom Compiler erzeugten Assembler-Code (lst/lss-Dateien).&lt;br /&gt;
&lt;br /&gt;
* siehe auch: [http://www.nongnu.org/avr-libc/user-manual/index.html Dokumentation der avr-libc] Abschnitt Modules/EEPROM handling&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== EEPROM Register ===&lt;br /&gt;
Um das EEPROM anzusteuern sind drei Register von Bedeutung.&amp;lt;BR&amp;gt;&lt;br /&gt;
&amp;lt;LI&amp;gt; EEAR Hier werden die Adressen eingetragen zum Schreiben oder Lesen. Dieses Register unterteilt sich nochmal in EEARH und EEARL da in einem 8 Bit Register keine 512 Adressen adressiert werden können&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
&amp;lt;LI&amp;gt; EEDR Hier werden die Daten eingetragen die geschrieben werden sollen bzw. es enthält die gelesenen Daten&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
&amp;lt;LI&amp;gt; EECR Ist das Kontrollregister für das EEPROM&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das EECR steuert den Zugriff auf das EEPROM und ist wie folgt aufgebaut:&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;TABLE BORDER=1&amp;gt;&lt;br /&gt;
&amp;lt;TR&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;Bit&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;&amp;amp;nbsp;&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;7&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;6&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;5&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;4&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;3&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;2&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;1&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;0&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;/TD&amp;gt;&lt;br /&gt;
&amp;lt;/TR&amp;gt;&lt;br /&gt;
&amp;lt;TR&amp;gt; &lt;br /&gt;
  &amp;lt;TD&amp;gt;Name&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;&amp;amp;nbsp;&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;-&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;-&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;-&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;-&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;EERIE&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;EEMWE&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;EEWE&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;EERE&amp;lt;/TD&amp;gt;&lt;br /&gt;
&amp;lt;/TR&amp;gt;&lt;br /&gt;
&amp;lt;TR&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;Read/Write&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;R&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;R&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;R&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;R&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;R/W&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;R/W&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;R/W&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;R/W&amp;lt;/TD&amp;gt;&lt;br /&gt;
&amp;lt;/TR&amp;gt;&lt;br /&gt;
&amp;lt;TR&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;Init Value&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;0&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;0&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;0&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;0&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;0&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;0&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;0&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;0&amp;lt;/TD&amp;gt;&lt;br /&gt;
&amp;lt;/TR&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/TABLE&amp;gt;&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;U&amp;gt;Bedeutung der Bits:&amp;lt;/U&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
Bit 4-7 nicht belegt.&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;U&amp;gt;Bit 3 (EERIE) - EEPROM Ready Interrupt Enable:&amp;lt;/U&amp;gt; Wenn das Bit gesetzt ist und globale Interrupts erlaubt sind in Register SREG (Bit 7) wird ein Interrupt ausgelöst nach Beendigung des Schreibzyklus (EEPROM Ready Interrupt). Ist einer der beiden Bits 0 wird kein Interrupt ausgelöst.&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;U&amp;gt;Bit 2(EEMWE) - EEPROM Master Write Enable:&amp;lt;/U&amp;gt; Dieses Bit bestimmt, daß wenn EEWE = 1 gesetzt wird (innerhalb von 4 Taktzyklen), das EEPROM beschrieben wird mit den Daten in EEDR bei Adresse EEAR. Wenn EEMWE =0 ist und EEWE = 1 gesetzt wird hat das keine Auswirkungen. Der Schreibvorgang wird dann nicht ausgelöst.&lt;br /&gt;
Nach 4 Taktzyklen wird das Bit EEMWE automatisch wieder auf 0 gesetzt. Dieses Bit löst den Schreibvorgang nicht aus, es dient sozusagen als Sicherungsbit für EEWE.&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;U&amp;gt;Bit 1 (EEWE) - EEPROM Write Enable:&amp;lt;/U&amp;gt; Dieses Bit löst den Schreibvorgang aus wenn es auf 1 gesetzt wird, sofern vorher EEMWE gesetzt wurde und seitdem nicht mehr als 4 Taktzyklen vergangen sind. Wenn der Schreibvorgang abgeschlossen ist wird dieses Bit automatisch wieder auf 0 gesetzt und sofern EERIE gesetzt ist ein Interrupt ausgelöst. &amp;lt;BR&amp;gt;&lt;br /&gt;
Ein Schreibvorgang sieht typischerweise wie folgt aus:&amp;lt;BR&amp;gt;&lt;br /&gt;
1. EEPROM Bereitschaft abwarten (EEWE=0) &lt;br /&gt;
2. Adresse übergeben an EEAR&amp;lt;BR&amp;gt;&lt;br /&gt;
3. Daten übergeben an EEDR&amp;lt;BR&amp;gt;&lt;br /&gt;
4. Schreibvorgang auslösen in EECR mit Bit EEMWE=1 und EEWE=1 &amp;lt;BR&amp;gt;&lt;br /&gt;
5. (Optinal) Warten bis Schreibvorgang abgeschlossen ist.&amp;lt;BR&amp;gt;&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
&amp;lt;U&amp;gt;Bit 0 EERE – EEPROM Read Enable:&amp;lt;/U&amp;gt; Wird dieses Bit auf 1 gesetzt wird das EEPROM an der Adresse in EEAR ausgelesen und die Daten in EEDR gespeichert. Das EEPROM kann nicht ausgelesen werden wenn bereits eine Schreiboperation gestartet wurde. Es ist daher zu empfehlen die Bereitschaft vorher zu prüfen. Das EEPROM ist lesebereit wenn das Bit EEWE=0 ist. ISt der LEsevorgang abgeschlossen wird das Bit wieder auf 0 gesetzt und das EEPROM ist für neue Lese/Schreibbefehle wieder bereit.&amp;lt;BR&amp;gt;&lt;br /&gt;
Ein typischer Lesevorgang kann wie folgt aufgebaut sein:&amp;lt;BR&amp;gt;&lt;br /&gt;
1. Bereitschaft zum lesen prüfen (EEWE=0)&amp;lt;BR&amp;gt;&lt;br /&gt;
2. Adresse übergeben an EEAR&amp;lt;BR&amp;gt;&lt;br /&gt;
3. Lesezyklus auslösen mit EERE = 1&amp;lt;BR&amp;gt;&lt;br /&gt;
4. Warten bis Lesevorgang abgeschlossen EERE = 0&amp;lt;BR&amp;gt;&lt;br /&gt;
5. Daten abholen aus EEDR&amp;lt;BR&amp;gt;&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Die Nutzung von printf =&lt;br /&gt;
&lt;br /&gt;
Um komfortabel Ausgaben auf ein Display oder die serielle Schnittstelle zu tätigen, bietet sich printf/sprintf an. &lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// ...&lt;br /&gt;
// nicht dargestellt: Implementierung von uart_puts (vgl. Abschnitt UART)&lt;br /&gt;
// ...&lt;br /&gt;
&lt;br /&gt;
uint16_t counter;&lt;br /&gt;
&lt;br /&gt;
void uart_puti( uint16_t value )&lt;br /&gt;
{&lt;br /&gt;
    uint8_t s[20];&lt;br /&gt;
&lt;br /&gt;
    sprintf( s, &amp;quot;Zählerstand: %d&amp;quot;, value );&lt;br /&gt;
    uart_puts( s );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int main()&lt;br /&gt;
{&lt;br /&gt;
  counter = 5;&lt;br /&gt;
&lt;br /&gt;
  uart_puti( counter );&lt;br /&gt;
  uart_puti( 42 );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Eine weitere elegante Möglichkeit besteht darin, die Ausgabe stdout auf eigene Ausgabefunktionen umzuleiten. Dazu wird dem Ausgabemechanismus eine neue Ausgabefunktion bekannt gemacht, deren Aufgabe es ist, ein einzelnes Zeichen auszugeben (wie auch immer die Ausgabe stattfindet). Alle anderen, höheren, Funktionen greifen letztendlich auf diese eine Ausgabefunktion zurück, die die Ausgabe eines einzelnen Zeichens vornimmt. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
void uart_init(void);&lt;br /&gt;
int uart_putchar(char c, FILE *stream);&lt;br /&gt;
&lt;br /&gt;
static FILE mystdout = FDEV_SETUP_STREAM( uart_putchar, NULL, _FDEV_SETUP_WRITE );&lt;br /&gt;
&lt;br /&gt;
void uart_init(void)&lt;br /&gt;
{&lt;br /&gt;
    /* hier µC spezifischen Code zur Initialisierung */&lt;br /&gt;
    /* des UART einfügen... s.o. im AVR-GCC-Tutorial */&lt;br /&gt;
&lt;br /&gt;
    // Beispiel: &lt;br /&gt;
    //&lt;br /&gt;
    // myAVR Board 1.5 mit externem Quarz Q1 3,6864 MHz&lt;br /&gt;
    // 9600 Baud 8N1&lt;br /&gt;
&lt;br /&gt;
#ifndef F_CPU&lt;br /&gt;
#define F_CPU 3686400&lt;br /&gt;
#endif&lt;br /&gt;
#define UART_BAUD_RATE 9600&lt;br /&gt;
&lt;br /&gt;
// Hilfsmakro zur UBRR-Berechnung (&amp;quot;Formel&amp;quot; laut Datenblatt)&lt;br /&gt;
#define UART_UBRR_CALC(BAUD_,FREQ_) ((FREQ_)/((BAUD_)*16L)-1)&lt;br /&gt;
&lt;br /&gt;
    UCSRB |= (1&amp;lt;&amp;lt;TXEN) | (1&amp;lt;&amp;lt;RXEN);    // UART TX und RX einschalten&lt;br /&gt;
    UCSRC |= (1&amp;lt;&amp;lt;URSEL)|(3&amp;lt;&amp;lt;UCSZ0);    // Asynchron 8N1 &lt;br /&gt;
 &lt;br /&gt;
    UBRRH = (uint8_t)( UART_UBRR_CALC( UART_BAUD_RATE, F_CPU ) &amp;gt;&amp;gt; 8 );&lt;br /&gt;
    UBRRL = (uint8_t)UART_UBRR_CALC( UART_BAUD_RATE, F_CPU );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int uart_putchar( char c, FILE *stream )&lt;br /&gt;
{&lt;br /&gt;
    if( c == &#039;\n&#039; )&lt;br /&gt;
        uart_putchar( &#039;\r&#039;, stream );&lt;br /&gt;
&lt;br /&gt;
    loop_until_bit_is_set( UCSRA, UDRE );&lt;br /&gt;
    UDR = c;&lt;br /&gt;
    return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int main(void)&lt;br /&gt;
{&lt;br /&gt;
    uart_init();&lt;br /&gt;
    stdout = &amp;amp;mystdout;&lt;br /&gt;
    printf( &amp;quot;Hello, world!\n&amp;quot; );&lt;br /&gt;
    return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Quelle: avr-libc-user-manual-1.4.3.pdf, S.74&lt;br /&gt;
//         + Ergänzungen&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Sollen Fließkommazahlen ausgegeben werden, muss im Makefile eine andere (größere) Version der [[FAQ#Aktivieren_der_Floating_Point_Version_von_sprintf_beim_WinAVR_mit_AVR-Studio|printflib]] eingebunden werden.&lt;br /&gt;
&lt;br /&gt;
Der Nachteil aller printf-Varianten: Sie sind recht speicherintensiv.&lt;br /&gt;
&lt;br /&gt;
= Assembler und Inline-Assembler =&lt;br /&gt;
&lt;br /&gt;
Gelegentlich erweist es sich als nützlich, C- und Assembler-Code in einer Anwendung zu nutzen. Typischerweise wird das Hauptprogramm in C verfasst und wenige, extrem zeitkritische oder hardwarenahe Operationen in Assembler.&lt;br /&gt;
&lt;br /&gt;
Die &amp;quot;gnu-Toolchain&amp;quot; bietet dazu zwei Möglichkeiten:&lt;br /&gt;
&lt;br /&gt;
* Inline-Assembler: Die Assembleranweisungen werden direkt in den C-Code integriert. Eine Quellcode-Datei enthält somit C- und Assembleranweisungen&lt;br /&gt;
* Assembler-Dateien: Der Assemblercode befindet sich in eigenen Quellcodedateien. Diese werden vom gnu-Assembler (avr-as) zu Object-Dateien assembliert (&amp;quot;compiliert&amp;quot;) und mit den aus dem C-Code erstellten Object-Dateien zusammengebunden (gelinkt).&lt;br /&gt;
&lt;br /&gt;
== Inline-Assembler ==&lt;br /&gt;
&lt;br /&gt;
Inline-Assembler bietet sich an, wenn nur wenig Assembleranweisungen benötigt werden. Typische Anwendung sind kurze Codesequenzen für zeitkritische Operationen in Interrupt-Routinen oder sehr präzise Warteschleifen (z.B. 1-Wire). Inline-Assembler wird mit &#039;&#039;&#039;asm volatile&#039;&#039;&#039; eingeleitet, die Assembler-Anweisungen werden in einer Zeichenkette zusammengefasst, die als &amp;quot;Parameter&amp;quot; übergeben wird. Durch Doppelpunkte getrennt werden die Ein- und Ausgaben sowie die &amp;quot;Clobber-Liste&amp;quot; angegeben.&lt;br /&gt;
&lt;br /&gt;
Ein einfaches Beispiel für Inline-Assembler ist das Einfügen einer NOP-Anweisung (NOP steht für No Operation). Dieser Assembler-Befehl benötigt genau einen Taktzyklus, ansonsten &amp;quot;tut sich nichts&amp;quot;. Sinnvolle Anwendungen für NOP sind genaue Delay(=Warte)-Funktionen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
    ...&lt;br /&gt;
   /* Verzögern der weiteren Programmausführung um&lt;br /&gt;
      genau 3 Taktzyklen */&lt;br /&gt;
    asm volatile (&amp;quot;nop&amp;quot;);&lt;br /&gt;
    asm volatile (&amp;quot;nop&amp;quot;);&lt;br /&gt;
    asm volatile (&amp;quot;nop&amp;quot;);&lt;br /&gt;
    ...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Weiterhin kann mit einem NOP verhindert werden, dass leere Schleifen, die als Warteschleifen gedacht sind, wegoptimiert werden. Der Compiler erkennt ansonsten die vermeintlich nutzlose Schleife und erzeugt dafür keinen Code im ausführbaren Programm.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
    ...&lt;br /&gt;
    uint16_t i;&lt;br /&gt;
&lt;br /&gt;
    /* leere Schleife - wird bei eingeschalteter Compiler-Optimierung   wegoptimiert */&lt;br /&gt;
    for (i = 0; i &amp;lt; 1000; i++)&lt;br /&gt;
      ;&lt;br /&gt;
&lt;br /&gt;
    ...&lt;br /&gt;
&lt;br /&gt;
    /* Schleife erzwingen (keine Optimierung): &amp;quot;NOP-Methode&amp;quot; */&lt;br /&gt;
    for (i = 0; i &amp;lt; 1000; i++)&lt;br /&gt;
      asm volatile(&amp;quot;NOP&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    ...&lt;br /&gt;
&lt;br /&gt;
    /* alternative Methode (keine Optimierung): */&lt;br /&gt;
    volatile uint16_t j;&lt;br /&gt;
    for (j = 0; j &amp;lt; 1000; j++)&lt;br /&gt;
      ;&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein weiterer nützlicher &amp;quot;Assembler-Einzeiler&amp;quot; ist der Aufruf von sleep (&#039;&#039;asm volatile (&amp;quot;sleep&amp;quot;);&#039;&#039;), da hierzu in älteren Versionen der avr-libc keine eigene Funktion existiert (in neueren Versionen &#039;&#039;sleep_cpu()&#039;&#039; aus sleep.h).&lt;br /&gt;
&lt;br /&gt;
Als Beispiel für mehrzeiligen Inline-Assembler eine präzise Delay-Funktion. Die Funktion erhält ein 16-bit Wort als Parameter, prüft den Parameter auf 0 und beendet die Funktion in diesem Fall oder durchläuft die folgende Schleife sooft wie im Wert des Parameters angegeben. Inline-Assembler hat hier den Vorteil, dass die Laufzeit unabhängig von der Optimierungsstufe (Parameter -O, vgl. makefile) und der Compiler-Version ist.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
static inline void delayloop16 (uint16_t count)&lt;br /&gt;
{&lt;br /&gt;
    asm volatile (&amp;quot;cp  %A0, __zero_reg__ \n\t&amp;quot;&lt;br /&gt;
                  &amp;quot;cpc %B0, __zero_reg__ \n\t&amp;quot;&lt;br /&gt;
                  &amp;quot;breq 2f               \n\t&amp;quot;&lt;br /&gt;
                  &amp;quot;1:                    \n\t&amp;quot;&lt;br /&gt;
                  &amp;quot;sbiw %0,1             \n\t&amp;quot;&lt;br /&gt;
                  &amp;quot;brne 1b               \n\t&amp;quot;&lt;br /&gt;
                  &amp;quot;2:                    &amp;quot;  &lt;br /&gt;
                  : &amp;quot;=w&amp;quot; (count)&lt;br /&gt;
	          : &amp;quot;0&amp;quot;  (count)&lt;br /&gt;
    );                            &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Jede Anweisung wird mit &#039;&#039;&#039;\n\t&#039;&#039;&#039; abgeschlossen. Der Zeilenumbruch teilt dem Assembler mit, dass ein neuer Befehl beginnt.&lt;br /&gt;
* Als Sprung-Marken (Labels) werden Ziffern verwendet. Diese speziellen Labels sind mehrfach im Code verwendbar. Gesprungen wird jeweils zurück (b) oder vorwärts (f) zum nächsten ausffindbaren Label.&lt;br /&gt;
&lt;br /&gt;
Das Resultat zeigt ein Blick in die Assembler-Datei, die der Compiler mit der option &amp;lt;tt&amp;gt;-save-temps&amp;lt;/tt&amp;gt; nicht löscht:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;avrasm&amp;gt;&lt;br /&gt;
	cp  r24, __zero_reg__ 	 ;  count&lt;br /&gt;
	cpc r25, __zero_reg__ 	 ;  count&lt;br /&gt;
	breq 2f               &lt;br /&gt;
	1:                    &lt;br /&gt;
	sbiw r24,1             	 ;  count&lt;br /&gt;
	brne 1b               &lt;br /&gt;
	2:&lt;br /&gt;
&amp;lt;/avrasm&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Detaillierte Ausführungen zum Thema Inline-Assembler finden sich in der Dokumentation der avr-libc im Abschnitt [http://www.nongnu.org/avr-libc/user-manual/inline_asm.html Related Pages/Inline Asm]. &lt;br /&gt;
&lt;br /&gt;
Siehe auch: &lt;br /&gt;
* [http://www.atmel.com/dyn/resources/prod_documents/doc0856.pdf AVR Assembler-Anweisungsliste]&lt;br /&gt;
* [http://www.roboternetz.de/wissen/index.php/Inline-Assembler_in_avr-gcc Deutsche Einführung in Inline-Assembler]&lt;br /&gt;
&lt;br /&gt;
== Assembler-Dateien ==&lt;br /&gt;
&lt;br /&gt;
Assembler-Dateien erhalten die Endung .S (&#039;&#039;grosses&#039;&#039; S) und werden im makefile nach WinAVR/mfile-Vorlage hinter &#039;&#039;ASRC=&#039;&#039; durch Leerzeichen getrennt aufgelistet.&lt;br /&gt;
&lt;br /&gt;
Wenn man mit dem AVR Studio arbeitet, kann alternativ auch das standardmäßig erstellte Makefile bearbeitet und folgende Zeilen eingefügt werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;code&amp;quot;&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
## Objects that must be built in order to link&lt;br /&gt;
OBJECTS = (alte Dateien...) useful.o&lt;br /&gt;
&lt;br /&gt;
## Compile&lt;br /&gt;
## Hier folgt eine Liste der gelinkten Dateien, darunter einfügen:&lt;br /&gt;
useful.o: ../useful.S&lt;br /&gt;
	$(CC) $(INCLUDES) $(ASMFLAGS) -c  $&amp;lt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
Das war es schon. Allerdings gilt es zu beachten, dass das makefile über &amp;quot;Project -&amp;gt; Configuration options&amp;quot; selbst einzubinden ist, sonst wird es natürlich wieder überschrieben.&lt;br /&gt;
&lt;br /&gt;
Im Beispiel eine Funktion &#039;&#039;superFunc&#039;&#039;, die alle Pins des Ports D auf &amp;quot;Ausgang&amp;quot; schaltet, eine Funktion &#039;&#039;ultraFunc&#039;&#039;, die die Ausgänge entsprechend des übergebenen Parameters schaltet, eine Funktion &#039;&#039;gigaFunc&#039;&#039;, die den Status von Port A zurückgibt und eine Funktion &#039;&#039;addFunc&#039;&#039;, die zwei Bytes zu einem 16-bit-Wort addiert. Die Zuweisungen im C-Code (PORTx = ...) verhindern, dass der Compiler die Aufrufe wegoptimiert und dienen nur zur Veranschaulichung der Parameterübergaben.&lt;br /&gt;
&lt;br /&gt;
Zuerst der Assembler-Code. Der Dateiname sei useful.S:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;avrasm&amp;gt;&lt;br /&gt;
#include &amp;quot;avr/io.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
//; Arbeitsregister (ohne &amp;quot;r&amp;quot;) &lt;br /&gt;
workreg  = 16&lt;br /&gt;
workreg2 = 17&lt;br /&gt;
&lt;br /&gt;
//; Konstante:&lt;br /&gt;
ALLOUT = 0xff&lt;br /&gt;
&lt;br /&gt;
//; ** Setze alle Pins von PortD auf Ausgang **&lt;br /&gt;
//; keine Parameter, keine Rückgabe&lt;br /&gt;
.global superFunc&lt;br /&gt;
.func superFunc&lt;br /&gt;
superFunc:&lt;br /&gt;
   push workreg&lt;br /&gt;
   ldi workreg, ALLOUT&lt;br /&gt;
   out  _SFR_IO_ADDR(DDRD), workreg  // beachte: _SFR_IO_ADDR()&lt;br /&gt;
   pop workreg&lt;br /&gt;
   ret&lt;br /&gt;
.endfunc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
//; ** Setze PORTD auf übergebenen Wert **&lt;br /&gt;
//; Parameter in r24 (LSB immer bei &amp;quot;graden&amp;quot; Nummern)&lt;br /&gt;
.global ultraFunc&lt;br /&gt;
.func ultraFunc&lt;br /&gt;
ultraFunc:&lt;br /&gt;
   out  _SFR_IO_ADDR(PORTD), 24&lt;br /&gt;
   ret&lt;br /&gt;
.endfunc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
//; ** Zustand von PINA zurückgeben **&lt;br /&gt;
//; Rückgabewerte in r24:r25 (LSB:MSB), hier nur LSB genutzt&lt;br /&gt;
.global gigaFunc&lt;br /&gt;
.func gigaFunc&lt;br /&gt;
gigaFunc:&lt;br /&gt;
   in 24, _SFR_IO_ADDR(PINA)&lt;br /&gt;
   ret&lt;br /&gt;
.endfunc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
//; ** Zwei Bytes addieren und 16-bit-Wort zurückgeben **&lt;br /&gt;
//; Parameter in r24 (Summand1) und r22 (Summand2) -&lt;br /&gt;
//;  Parameter sind Word-&amp;quot;aligned&amp;quot; d.h. LSB immer auf &amp;quot;graden&amp;quot;&lt;br /&gt;
//;  Registernummern. Bei 8-Bit und 16-Bit Paramtern somit &lt;br /&gt;
//;  beginnend bei r24 dann r22 dann r20 etc.&lt;br /&gt;
//; Rückgabewert in r24:r25&lt;br /&gt;
.global addFunc&lt;br /&gt;
.func addFunc&lt;br /&gt;
addFunc:&lt;br /&gt;
   push workreg&lt;br /&gt;
   push workreg2&lt;br /&gt;
   clr workreg2&lt;br /&gt;
   mov workreg, 22&lt;br /&gt;
   add workreg, 24&lt;br /&gt;
   adc workreg2, 1    // r1 - assumed to be always zero ...&lt;br /&gt;
   movw r24, workreg&lt;br /&gt;
   pop workreg2&lt;br /&gt;
   pop workreg&lt;br /&gt;
   ret&lt;br /&gt;
.endfunc&lt;br /&gt;
&lt;br /&gt;
//; oh je - sorry - Mein AVR-Assembler ist eingerostet, hoffe das stimmt so...&lt;br /&gt;
&lt;br /&gt;
.end&lt;br /&gt;
&amp;lt;/avrasm&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im Makefile ist der Name der Assembler-Quellcodedatei einzutragen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;code&amp;quot;&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
ASRC = useful.S&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Aufruf erfolgt dann im C-Code so:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
extern void superFunc(void);&lt;br /&gt;
extern void ultraFunc(uint8_t setVal);&lt;br /&gt;
extern uint8_t gigaFunc(void);&lt;br /&gt;
extern uint16_t addFunc(uint8_t w1, uint8_t w2);&lt;br /&gt;
&lt;br /&gt;
int main(void)&lt;br /&gt;
{&lt;br /&gt;
[...]&lt;br /&gt;
  superFunc();&lt;br /&gt;
  &lt;br /&gt;
  ultraFunc(0x55);&lt;br /&gt;
  &lt;br /&gt;
  PORTD = gigaFunc();&lt;br /&gt;
&lt;br /&gt;
  PORTA = (addFunc(0xF0, 0x11) &amp;amp; 0xff);&lt;br /&gt;
  PORTB = (addFunc(0xF0, 0x11) &amp;gt;&amp;gt; 8);&lt;br /&gt;
[...]&lt;br /&gt;
} &lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Ergebnis wird wieder in der lss-Datei ersichtlich:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;code&amp;quot;&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
[...]&lt;br /&gt;
   superFunc();&lt;br /&gt;
 148:	0e 94 f6 00 	call	0x1ec&lt;br /&gt;
  &lt;br /&gt;
  ultraFunc(0x55);&lt;br /&gt;
 14c:	85 e5       	ldi	r24, 0x55	; 85&lt;br /&gt;
 14e:	0e 94 fb 00 	call	0x1f6&lt;br /&gt;
  &lt;br /&gt;
  PORTD = gigaFunc();&lt;br /&gt;
 152:	0e 94 fd 00 	call	0x1fa&lt;br /&gt;
 156:	82 bb       	out	0x12, r24	; 18&lt;br /&gt;
  &lt;br /&gt;
  PORTA = (addFunc(0xF0, 0x11) &amp;amp; 0xff);&lt;br /&gt;
 158:	61 e1       	ldi	r22, 0x11	; 17&lt;br /&gt;
 15a:	80 ef       	ldi	r24, 0xF0	; 240&lt;br /&gt;
 15c:	0e 94 ff 00 	call	0x1fe&lt;br /&gt;
 160:	8b bb       	out	0x1b, r24	; 27&lt;br /&gt;
  PORTB = (addFunc(0xF0, 0x11) &amp;gt;&amp;gt; 8);&lt;br /&gt;
 162:	61 e1       	ldi	r22, 0x11	; 17&lt;br /&gt;
 164:	80 ef       	ldi	r24, 0xF0	; 240&lt;br /&gt;
 166:	0e 94 fc 00 	call	0x1f8&lt;br /&gt;
 16a:	89 2f       	mov	r24, r25&lt;br /&gt;
 16c:	99 27       	eor	r25, r25&lt;br /&gt;
 16e:	88 bb       	out	0x18, r24	; 24&lt;br /&gt;
&lt;br /&gt;
[...]&lt;br /&gt;
000001ec &amp;lt;superFunc&amp;gt;:&lt;br /&gt;
// setze alle Pins von PortD auf Ausgang&lt;br /&gt;
.global superFunc&lt;br /&gt;
.func superFunc&lt;br /&gt;
superFunc:&lt;br /&gt;
   push workreg&lt;br /&gt;
 1ec:	0f 93       	push	r16&lt;br /&gt;
   ldi workreg, ALLOUT&lt;br /&gt;
 1ee:	0f ef       	ldi	r16, 0xFF	; 255&lt;br /&gt;
   out  _SFR_IO_ADDR(DDRD), workreg&lt;br /&gt;
 1f0:	01 bb       	out	0x11, r16	; 17&lt;br /&gt;
   pop workreg&lt;br /&gt;
 1f2:	0f 91       	pop	r16&lt;br /&gt;
   ret&lt;br /&gt;
 1f4:	08 95       	ret&lt;br /&gt;
&lt;br /&gt;
000001f6 &amp;lt;ultraFunc&amp;gt;:&lt;br /&gt;
.endfunc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// setze PORTD auf übergebenen Wert&lt;br /&gt;
.global ultraFunc&lt;br /&gt;
.func ultraFunc&lt;br /&gt;
ultraFunc:&lt;br /&gt;
   out  _SFR_IO_ADDR(PORTD), 24&lt;br /&gt;
 1f6:	82 bb       	out	0x12, r24	; 18&lt;br /&gt;
   ret&lt;br /&gt;
 1f8:	08 95       	ret&lt;br /&gt;
&lt;br /&gt;
000001fa &amp;lt;gigaFunc&amp;gt;:&lt;br /&gt;
.endfunc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// Zustand von PINA zurückgeben&lt;br /&gt;
.global gigaFunc&lt;br /&gt;
.func gigaFunc&lt;br /&gt;
gigaFunc:&lt;br /&gt;
   in 24, _SFR_IO_ADDR(PINA)&lt;br /&gt;
 1fa:	89 b3       	in	r24, 0x19	; 25&lt;br /&gt;
   ret&lt;br /&gt;
 1fc:	08 95       	ret&lt;br /&gt;
&lt;br /&gt;
000001fe &amp;lt;addFunc&amp;gt;:&lt;br /&gt;
.endfunc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// zwei Bytes addieren und 16-bit-Wort zurückgeben&lt;br /&gt;
.global addFunc&lt;br /&gt;
.func addFunc&lt;br /&gt;
addFunc:&lt;br /&gt;
   push workreg&lt;br /&gt;
 1fe:	0f 93       	push	r16&lt;br /&gt;
   push workreg2&lt;br /&gt;
 200:	1f 93       	push	r17&lt;br /&gt;
   clr workreg2&lt;br /&gt;
 202:	11 27       	eor	r17, r17&lt;br /&gt;
   mov workreg, 22&lt;br /&gt;
 204:	06 2f       	mov	r16, r22&lt;br /&gt;
   add workreg, 24&lt;br /&gt;
 206:	08 0f       	add	r16, r24&lt;br /&gt;
   adc workreg2, 1    // r1 - assumed to be always zero ...&lt;br /&gt;
 208:	11 1d       	adc	r17, r1&lt;br /&gt;
   movw r24, workreg&lt;br /&gt;
 20a:	c8 01       	movw	r24, r16&lt;br /&gt;
   pop workreg2&lt;br /&gt;
 20c:	1f 91       	pop	r17&lt;br /&gt;
   pop workreg&lt;br /&gt;
 20e:	0f 91       	pop	r16&lt;br /&gt;
   ret&lt;br /&gt;
 210:	08 95       	ret&lt;br /&gt;
&lt;br /&gt;
[...]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Zuweisung von Registern zu Parameternummer und die Register für die Rückgabewerte sind in den &amp;quot;Register Usage Guidelines&amp;quot; der avr-libc-Dokumentation erläutert.&lt;br /&gt;
&lt;br /&gt;
Siehe auch:&lt;br /&gt;
* [http://www.nongnu.org/avr-libc/user-manual/assembler.html avr-libc-Dokumentation: Related Pages/avr-libc and assembler programs]&lt;br /&gt;
* [http://www.nongnu.org/avr-libc/user-manual/FAQ.html#faq_reg_usage avr-libc-Dokumentation: Related Pages/FAQ/&amp;quot;What registers are used by the C compiler?&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
== Globale Variablen für Datenaustausch ==&lt;br /&gt;
&lt;br /&gt;
Oftmals kommt man um globale Variablen nicht herum, z.B. um den Datenaustausch zwischen Hauptprogramm und Interrupt-Routinen zu realisieren. &lt;br /&gt;
Hierzu muss man im Assembler wissen, wo genau die Variable vom C-Compiler abgespeichert wird.&lt;br /&gt;
&lt;br /&gt;
Hierzu muss die Variable, hier &amp;quot;zaehler&amp;quot; genannt, zuerst im C-Code als Global definiert werden, z.B. so:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
volatile uint8_t zaehler;&lt;br /&gt;
&lt;br /&gt;
int16_t main (void)&lt;br /&gt;
{&lt;br /&gt;
    // irgendein Code, in dem zaehler benutzt werden kann&lt;br /&gt;
    &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im foldenden Assembler-Beispiel wird der Externe Interrupt0  verwendet, um den Zähler hochzuzählen. Es fehlen die Initialisierungen des Interrupts und die Interrupt-Freigabe, so richtig sinnvoll ist der Code auch nicht, aber er zeigt (hoffentlich) wie es geht.&lt;br /&gt;
&lt;br /&gt;
Im Umgang mit Interrupt-Vektoren gilt beim GCC-Assembler das Gleiche, wie bei C: Man muss die exakte Schreibweise beachten, ansonsten wird nicht der Interrupt-Vektor angelegt, sondern eine neue Funktion - und man wundert sich, dass nichts funktionert (vgl. das AVR-GCC-Handbuch).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;avrasm&amp;gt;&lt;br /&gt;
#include &amp;quot;avr/io.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
temp = 16&lt;br /&gt;
&lt;br /&gt;
.extern zaehler&lt;br /&gt;
&lt;br /&gt;
.global INT0_vect&lt;br /&gt;
INT0_vect:&lt;br /&gt;
&lt;br /&gt;
     push temp                      //; wichtig: Benutzte Register und das&lt;br /&gt;
     in temp,_SFR_IO_ADDR(SREG)     //; Status-Register (SREG) sichern!&lt;br /&gt;
     push temp&lt;br /&gt;
&lt;br /&gt;
     lds temp,zaehler               //; Wert aus dem Speicher lesen&lt;br /&gt;
     inc temp                       //; bearbeiten&lt;br /&gt;
     sts zaehler,temp               //; und wieder zurückschreiben&lt;br /&gt;
&lt;br /&gt;
     pop temp                       //; die benutzten Register wiederherstellen&lt;br /&gt;
     out _SFR_IO_ADDR(SREG),temp&lt;br /&gt;
     pop temp&lt;br /&gt;
     reti&lt;br /&gt;
&lt;br /&gt;
.end&lt;br /&gt;
&amp;lt;/avrasm&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Globale Variablen im Assemblerfile anlegen ===&lt;br /&gt;
&lt;br /&gt;
Alternativ können Variablen aber auch im Assemblerfile angelegt werden. Dadurch kann auf eine .c-Datei verzichtet werden. Für das obige Beispiel könnte der Quelltext dann die Dateien zaehl_asm.S und zaehl_asm.h abgelegt werden, so dass nur noch zaehl_asm.S mit kompiliert werden müsste.&lt;br /&gt;
&lt;br /&gt;
Anstatt im Assemblerfile über das Schlüsselwort &#039;&#039;.extern &#039;&#039; auf eine vorhandene Variable zu verweisen, wird dazu mit dem Schlüsselwort &#039;&#039;.comm&#039;&#039; die benötigte Anzahl von Bytes für eine Variable reserviert.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;zaehl_asm.S&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;avrasm&amp;gt;&lt;br /&gt;
#include &amp;quot;avr/io.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
temp = 16&lt;br /&gt;
&lt;br /&gt;
//; 1 Byte im RAM für den Zähler reservieren&lt;br /&gt;
.comm zaehler, 1&lt;br /&gt;
&lt;br /&gt;
.global INT0_vect&lt;br /&gt;
INT0_vect:&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/avrasm&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In der Headerdatei wird dann auf die Variable nur noch verwiesen (Schlüsselwort &#039;&#039;extern&#039;&#039;):&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;zaehl_asm.h&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#ifndef ZAEHL_ASM_H&lt;br /&gt;
#define ZAEHL_ASM_H&lt;br /&gt;
&lt;br /&gt;
extern volatile uint8_t zaehler;&lt;br /&gt;
&lt;br /&gt;
#endif&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im Gegensatz zu globalen Variablen in C werden so angelegte Variablen nicht automatisch mit dem Wert 0 initialisiert. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Variablen größer als 1 Byte ===&lt;br /&gt;
&lt;br /&gt;
Variablen, die größer als &#039;&#039;&#039;ein&#039;&#039;&#039; Byte sind, können in Assembler auf ähnliche Art angesprochen werden. Hierzu müssen nur genug Bytes angefordert werden, um die Variable aufzunehmen. Soll z.B. für den Zähler eine Variable vom Typ &#039;&#039;unsigned long&#039;&#039;, also &#039;&#039;uint32_t&#039;&#039; verwendet werden, so müssen 4 Bytes reserviert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;avrasm&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
// 4 Byte im RAM für den Zähler reservieren&lt;br /&gt;
.comm zaehler, 4&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/avrasm&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die dazugehörige Deklaration im Headerfile wäre dann:&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
extern volatile uint32_t zaehler;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bei Variablen, die größer als ein Byte sind, werden die Werte beginnend mit dem niederwertigsten Byte im RAM abgelegt. Das folgende Codeschnippsel zeigt, wie unter Assembler auf die einzelnen Bytes zugegriffen werden kann. Dazu wird im Interrupt nun ein 32-Bit Zähler erhöht:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;avrasm&amp;gt;&lt;br /&gt;
#include &amp;quot;avr/io.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
temp = 16&lt;br /&gt;
&lt;br /&gt;
// 4 Byte im RAM für den Zähler reservieren&lt;br /&gt;
.comm zaehler, 4&lt;br /&gt;
&lt;br /&gt;
.global INT0_vect&lt;br /&gt;
INT0_vect:&lt;br /&gt;
&lt;br /&gt;
     push temp                      // wichtig: Benutzte Register und das&lt;br /&gt;
     in temp,_SFR_IO_ADDR(SREG)     // Status-Register (SREG) sichern !&lt;br /&gt;
     push temp&lt;br /&gt;
&lt;br /&gt;
     // 32-Bit-Zähler incrementieren&lt;br /&gt;
     lds temp, (zaehler + 0)        // 0. Byte (niederwertigstes Byte)&lt;br /&gt;
     inc temp&lt;br /&gt;
     sts (zaehler + 0), temp&lt;br /&gt;
     brne RAUS&lt;br /&gt;
	&lt;br /&gt;
     lds temp, (zaehler + 1)        // 1. Byte&lt;br /&gt;
     inc temp&lt;br /&gt;
     sts (zaehler + 1), temp&lt;br /&gt;
     brne RAUS&lt;br /&gt;
&lt;br /&gt;
     lds temp, (zaehler + 2)        // 2. Byte&lt;br /&gt;
     inc temp&lt;br /&gt;
     sts (zaehler + 2), temp&lt;br /&gt;
     brne RAUS&lt;br /&gt;
&lt;br /&gt;
     lds temp, (zaehler + 3)        // 3. Byte (höchstwertigstes Byte)&lt;br /&gt;
     inc temp&lt;br /&gt;
     sts (zaehler + 3), temp&lt;br /&gt;
     brne RAUS&lt;br /&gt;
	&lt;br /&gt;
RAUS:&lt;br /&gt;
     pop temp                       // die benutzten Register wiederherstellen&lt;br /&gt;
     out _SFR_IO_ADDR(SREG),temp&lt;br /&gt;
     pop temp&lt;br /&gt;
     reti&lt;br /&gt;
&lt;br /&gt;
.end&lt;br /&gt;
&amp;lt;/avrasm&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;TODO:&#039;&#039;&#039; 16-Bit / 32-Bit Variablen, Zugriff auf Arrays (Strings)&lt;br /&gt;
&lt;br /&gt;
= Anhang =&lt;br /&gt;
&lt;br /&gt;
== Besonderheiten bei der Anpassung bestehenden Quellcodes ==&lt;br /&gt;
&lt;br /&gt;
Einige Funktionen, die in frühren Versionen der avr-libc vorhanden waren, werden inzwischen als veraltet angesehen. Sie sind nicht mehr vorhanden oder als &#039;&#039;deprecated&#039;&#039; (missbilligt) ausgewiesen und Definitionen in &amp;lt;compat/deprecated.h&amp;gt; verschoben. Es empfiehlt sich, vorhandenen Code zu portieren und die alten Funktionen nicht mehr zu nutzen, auch wenn diese noch zur Verfügung stehen.&lt;br /&gt;
&lt;br /&gt;
=== Veraltete Funktionen zur Deklaration von Interrupt-Routinen ===&lt;br /&gt;
&lt;br /&gt;
Die Funktionen (eigentlich Makros) &#039;&#039;SIGNAL&#039;&#039; und &#039;&#039;INTERRUPT&#039;&#039; zur Deklaration von Interruptroutinen sollten nicht mehr genutzt werden. &lt;br /&gt;
&lt;br /&gt;
In aktuellen Versionen der avr-libc (z.B. avr-libc 1.4.3 aus WinAVR 20060125) werden Interruptroutinen, die &#039;&#039;&#039;nicht&#039;&#039;&#039; durch andere Interrupts &#039;&#039;&#039;unterbrechbar&#039;&#039;&#039; sind, mit ISR deklariert (siehe Abschnitt im Hauptteil). Auch die Benennung wurden vereinheitlicht und an die üblichen Bezeichnungen in den AVR Datenblättern angepasst. In der Dokumentation der avr-libc sind alte und neue Bezeichnungen in der Tabelle gegenübergestellt. Die erforderlichen Schritte zur Portierung:&lt;br /&gt;
&lt;br /&gt;
* #include von avr/signal.h entfernen&lt;br /&gt;
* SIGNAL duch ISR ersetzen&lt;br /&gt;
* Name des Interrupt-Vektors anpassen (SIG_* durch entsprechendes *_vect)&lt;br /&gt;
&lt;br /&gt;
Als Beispiel für die Anpassung zuerst ein &amp;quot;alter&amp;quot; Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/interrupt.h&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/signal.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
/* Timer2 Output Compare bei einem ATmega8 */&lt;br /&gt;
SIGNAL(SIG_OUTPUT_COMPARE2)&lt;br /&gt;
{&lt;br /&gt;
   ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im Datenblatt wird der Vektor mit TIMER2 COMP bezeichnet. Die Bezeichnung in der avr-libc entspricht dem Namen im Datenblatt, Leerzeichen werden durch Unterstriche (_) ersetzt und ein _vect angehängt. &lt;br /&gt;
&lt;br /&gt;
Der neue Code sieht dann so aus:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/interrupt.h&amp;gt; &lt;br /&gt;
/* signal.h entfällt */&lt;br /&gt;
&lt;br /&gt;
ISR(TIMER2_COMP_vect)&lt;br /&gt;
{&lt;br /&gt;
   ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bei Unklarheiten bezüglich der neuen Vektorlabels hilft (noch) ein Blick in die Headerdatei des entsprechenden Controllers. Für das vorherige Beispiel also der Blick in die Datei iom8.h für den ATmega8, dort findet man die veraltete Bezeichnung unterhalb der aktuellen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
/* $Id: iom8.h,v 1.13 2005/10/30 22:11:23 joerg_wunsch Exp $ */&lt;br /&gt;
/* avr/iom8.h - definitions for ATmega8 */&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
/* Timer/Counter2 Compare Match */&lt;br /&gt;
#define TIMER2_COMP_vect		_VECTOR(3)&lt;br /&gt;
#define SIG_OUTPUT_COMPARE2		_VECTOR(3)&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- Nachfolgendes mit avr-libc 1.4.5 (in WinAVR 1/2007 behoben - noch eine Weile auskommentiert lassen und dann löschen.&lt;br /&gt;
Konnte in alten Versionen signal.h ohne interrupt.h eingebunden werden, erhält man bei Verwendung der avr-libc Version 1.4.3 (WinAVR 2/2005) beim Compilieren eine Fehlermeldung, da mit signal.h nicht die erforderlichen Definitionen eingebunden werden. Der Lösungsvorschlag in signal.h auch interrupt.h einzubinden, wurde von den avr-libc-Enwicklern akzeptiert und das Problem ist  im Quellcode (CVS) bereits behoben. Es ist aber noch keine avr-libc-&amp;quot;Release&amp;quot; bzw. noch kein WinAVR mit dieser avr-libc-Korrektur verfügbar (Stand 5.2.2006). Will oder kann man den Quellcode nicht aktualisieren, gibt es folgende Alternativen:&lt;br /&gt;
* in Quellcodedateien, in denen nur avr/signal.h eingebunden wird, interrupt.h einbinden (&#039;&#039;#include &amp;amp;lt;avr/interrupt.h&amp;amp;gt;&#039;&#039;). signal.h weiterhin einbinden, falls Kompatibiltät mit alten Versionen gewünscht ist.&lt;br /&gt;
* in der Datei signal.h (bein WinAVR in c:/WinAVR/avr/include/avr/signal.h) ein (&#039;&#039;#include &amp;amp;lt;avr/interrupt.h&amp;amp;gt;&#039;&#039;) ergänzen --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für &#039;&#039;&#039;unterbrechbare&#039;&#039;&#039; Interruptroutinen, die mittels &#039;&#039;INTERRUPT&#039;&#039; deklariert sind, gibt es keinen direkten Ersatz in Form eines Makros. Solche Routinen sind laut Dokumentation der avr-libc in folgender Form zu deklarieren:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
void XXX_vect(void) __attribute__((interrupt));&lt;br /&gt;
void XXX_vect(void) {&lt;br /&gt;
  ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
/* ** alt ** */&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/interrupt.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
INTERRUPT(SIG_OVERFLOW0)&lt;br /&gt;
{&lt;br /&gt;
   ...&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* ** neu: ** */&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
void TIMER0_OVF_vect(void) __attribute__((interrupt));&lt;br /&gt;
void TIMER0_OVF_vect(void) &lt;br /&gt;
{&lt;br /&gt;
   ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Will oder kann man den Code nicht portieren, ist zur weiteren Verwendung von &#039;&#039;INTERRUPT&#039;&#039; die Header-Datei &#039;&#039;compat/deprecated.h&#039;&#039; einzubinden. Man sollte bei dieser Gelegenheit jedoch nochmals überprüfen, ob die Funktionalität von &#039;&#039;INTERRUPT&#039;&#039; tatsächlich gewollt ist. In vielen Fällen wurde &#039;&#039;INTERRUPT&#039;&#039; dort genutzt, wo eigentlich &#039;&#039;SIGNAL&#039;&#039; (nunmehr &#039;&#039;ISR&#039;&#039;) hätte genutzt werden sollen.&lt;br /&gt;
&lt;br /&gt;
=== Veraltete Funktionen zum Portzugriff ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;inp&#039;&#039; und &#039;&#039;outp&#039;&#039; zum Einlesen bzw. Schreiben von Registern sind nicht mehr erforderlich, der Compiler unterstützt dies ohne diesen Umweg.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
unsigned char i, j;&lt;br /&gt;
&lt;br /&gt;
// alt:&lt;br /&gt;
  i = inp(PINA);&lt;br /&gt;
  j = 0xff;&lt;br /&gt;
  outp(PORTB, j);&lt;br /&gt;
&lt;br /&gt;
// neu (nicht mehr wirklich neu...):&lt;br /&gt;
  i = PINA&lt;br /&gt;
  j = 0xff;&lt;br /&gt;
  PORTB = j;&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Will oder kann man den Code nicht portieren, ist zur weiteren Verwendung von inp und outp die Header-Datei &#039;&#039;&#039;compat/deprecated.h&#039;&#039;&#039; einzubinden.&lt;br /&gt;
&lt;br /&gt;
=== Veraltete Funktionen zum Zugriff auf Bits in Registern ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;cbi&#039;&#039; und &#039;&#039;sbi&#039;&#039; zum Löschen und Setzen von Bits sind nicht mehr erforderlich, der Compiler unterstützt dies ohne diesen Umweg. Die Bezeichnung ist ohnehin irreführend da die Funktionen nur für Register mit Adressen im unteren Speicherbereich tatsächlich in die Assembleranweisungen cbi und sbi übersetzt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
// alt:&lt;br /&gt;
  sbi(PORTB, PB2);&lt;br /&gt;
  cbi(PORTC, PC1);&lt;br /&gt;
&lt;br /&gt;
// neu (auch nicht mehr wirklich neu...):&lt;br /&gt;
  PORTB |=  (1&amp;lt;&amp;lt;PB2);&lt;br /&gt;
  PORTC &amp;amp;= ~(1&amp;lt;&amp;lt;PC1);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Will oder kann man den Code nicht portieren, ist zur weiteren Verwendung von sbi und cbi die Header-Datei &#039;&#039;&#039;compat/deprecated.h&#039;&#039;&#039; einzubinden. Wer unbedingt will, kann sich natürlich eigene Makros mit aussagekräftigeren Namen definieren. Zum Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#define SET_BIT(PORT, BITNUM)    ((PORT) |=  (1&amp;lt;&amp;lt;(BITNUM)))&lt;br /&gt;
#define CLEAR_BIT(PORT, BITNUM)  ((PORT) &amp;amp;= ~(1&amp;lt;&amp;lt;(BITNUM)))&lt;br /&gt;
#define TOGGLE_BIT(PORT, BITNUM) ((PORT) ^=  (1&amp;lt;&amp;lt;(BITNUM)))&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Selbstdefinierte (nicht-standardisierte) ganzzahlige Datentypen ===&lt;br /&gt;
&lt;br /&gt;
Bei den im Folgenden genannten Typdefinitionen ist zu beachten, dass die Bezeichnungen für &amp;quot;Worte&amp;quot; teilweise je nach Prozessorplattform unterschiedlich verwendet werden. Die angegebenen Definitionen beziehen sich auf die im Zusammenhang mit AVR/8-bit-Controllern üblichen &amp;quot;Bit-Breiten&amp;quot; (In Erläuterungen zum ARM7TDMI z.B. werden oft 32-bit Integer mit &amp;quot;Wort&amp;quot; ohne weitere Ergänzung bezeichnet). Es empfiehlt sich, bei der Überarbeitung von altem Code die im Abschnitt &#039;&#039;standardisierten ganzzahligen Datentypen&#039;&#039; beschriebenen Datentypen zu nutzen (stdint.h) und damit &amp;quot;Missverständnissen&amp;quot; vorzubeugen, die z.B. bei der Portierung von C-Code zwischen verschiedenen Plattformen auftreten können.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
typedef unsigned char      BYTE;       // besser: uint8_t  aus &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
typedef unsigned short     WORD;       // besser: uint16_t aus &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
typedef unsigned long      DWORD;      // besser: uint32_t aus &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
typedef unsigned long long QWORD;      // besser: uint64_t aus &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; BYTE : Der Datentyp BYTE definiert eine Variable mit 8 Bit Breite zur Darstellung von ganzen Zahlen im Bereich zwischen 0 ... 255. &lt;br /&gt;
&lt;br /&gt;
; WORD : Der Datentyp WORD definiert eine Variable mit 16 Bit Breite zur Darstellung von ganzen Zahlen im Bereich zwischen 0 ... 65535. &lt;br /&gt;
&lt;br /&gt;
; DWORD : Der Datentyp DWORD (gesprochen: Double-Word) definiert eine Variable mit 32 Bit Breite zur Darstellung von ganzen Zahlen im Bereich zwischen 0 ... 4294967295.&lt;br /&gt;
&lt;br /&gt;
; QWORD : Der Datentyp QWORD (gesprochen: Quad-Word) definiert eine Variable mit 64 Bit Breite zur Darstellung von ganzen Zahlen im Bereich zwischen 0 ... 18446744073709551615.&lt;br /&gt;
&lt;br /&gt;
== Zusätzliche Funktionen im Makefile ==&lt;br /&gt;
&lt;br /&gt;
=== Bibliotheken (Libraries/.a-Dateien) hinzufügen ===&lt;br /&gt;
&lt;br /&gt;
Um Funktionen aus Bibliotheken (&amp;quot;echte&amp;quot; Libraries, *.a-Dateien) zu nutzen, sind dem Linker die Namen der Bibliotheken als Parameter zu übergeben. Dazu ist die Option -l (kleines L) vorgesehen, an die der Name der Library angehängt wird. &lt;br /&gt;
&lt;br /&gt;
Dabei ist zu beachten, dass der Name der Library und der Dateiname der Library nicht identisch sind. Der hinter -l angegebene Name entspricht dem Dateinamen der Library ohne die Zeichenfolge &#039;&#039;lib&#039;&#039; am Anfang des Dateinamens und ohne die Endung &#039;&#039;.a&#039;&#039;. Sollen z.B. Funktionen aus einer Library mit dem Dateinamen &#039;&#039;libefsl.a&#039;&#039; eingebunden (gelinkt) werden, lautet der entsprechende Parameter -lefsl (vergl. auch -lm zum Anbinden von libm.a). &lt;br /&gt;
&lt;br /&gt;
In Makefiles wird traditonell eine make-Variable LDLIBS genutzt, in die &amp;quot;l-Parameter&amp;quot; abgelegt werden. Die WinAVR-makefile-Vorlage enthält diese Variable zwar nicht, dies stellt jedoch keine Einschränkung dar, da alle in der make-Variable LDFLAGS abgelegten Parameter an den Linker weitergereicht werden. &lt;br /&gt;
&lt;br /&gt;
Beispiele:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;code&amp;quot;&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
# Einbinden von Funktionen aus einer Library efsl (Dateiname libefsl.a)&lt;br /&gt;
LDFLAGS += -lefsl&lt;br /&gt;
# Einbinden von Funktionen aus einer Library xyz (Dateiname libxyz.a)&lt;br /&gt;
LDFLAGS += -lxyz&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Liegen die Library-Dateien nicht im Standard Library-Suchpfad, sind die Pfade mittels Parameter &#039;&#039;-L&#039;&#039; ebenfalls anzugeben. (Der vordefinierte Suchpfad kann mittels &#039;&#039;avr-gcc --print-search-dirs&#039;&#039; angezeigt werden.)&lt;br /&gt;
&lt;br /&gt;
Als Beispiel ein Projekt (&amp;quot;superapp2&amp;quot;), in dem der Quellcode von zwei Libraries (efsl und xyz) und der Quellcode der eigentlichen Anwendung in verschiedenen Verzeichnissen mit der folgenden &amp;quot;Baumstruktur&amp;quot; abgelegt sind:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;code&amp;quot;&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
superapp2&lt;br /&gt;
|&lt;br /&gt;
+----- efslsource (darin libefsl.a)&lt;br /&gt;
|&lt;br /&gt;
+----- xyzsource (darin libxyz.a)&lt;br /&gt;
|&lt;br /&gt;
+----- firmware (darin Anwendungs-Quellcode und Makefile)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Daraus folgt, dass im Makefile die Verzeichnis efslsource und xyzsource in den Library-Suchpfad aufzunehmen sind:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;code&amp;quot;&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
LDFLAGS += -L../efslsource/ -L../xyzsource/&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Fuse-Bits ===&lt;br /&gt;
&lt;br /&gt;
Zur Berechnung der Fuse-Bits bietet sich neben dem Studium des Datenblattes auch der [http://palmavr.sourceforge.net/cgi-bin/fc.cgi AVR Fuse Calculator] an. Gewarnt werden muss vor der Benutzung von PonyProg, weil dort durch die negierte Darstellung gern Fehler gemacht werden.&lt;br /&gt;
&lt;br /&gt;
Soll die Programmierung von Fuse- und Lockbits automatisiert werden, kann man dies ebenfalls durch Einträge im Makefile vornehmen, die beim Aufruf von &amp;quot;make program&amp;quot; an die genutzte Programmiersoftware übergeben werden. In der makefile-Vorlage von WinAVR (und mfile) gibt es dafuer jedoch keine &amp;quot;Ausfüllhilfe&amp;quot; (Stand 9/2006). Die folgenden Ausführungen gelten für die Programmiersoftware [[AVRDUDE]] (Standard in der WinAVR-Vorlage), können jedoch sinngemäß auf andere Programmiersoftware übertragen werden, die die Angabe der Fuse- und Lockbits-Einstellungen per Kommandozeilenparameter unterstützt (z.B. stk500.exe). Im einfachsten Fall ergänzt man im Makefile einige Variablen, deren Werte natürlich vom verwendeten Controller und den gewünschten Einstellungen abhängen (vgl. Datenblatt Fuse-/Lockbits):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#---------------- Programming Options (avrdude) ----------------&lt;br /&gt;
&lt;br /&gt;
#...&lt;br /&gt;
#Beispiel! f. ATmega16 - nicht einfach uebernehmen! Zahlenwerte anhand&lt;br /&gt;
#--------- des Datenblatts nachvollziehen und gegebenenfalls aendern.&lt;br /&gt;
#&lt;br /&gt;
AVRDUDE_WRITE_LFUSE = -U lfuse:w:0xff:m&lt;br /&gt;
AVRDUDE_WRITE_HFUSE = -U hfuse:w:0xd8:m&lt;br /&gt;
AVRDUDE_WRITE_LOCK  = -U lock:w:0x2f:m&lt;br /&gt;
#...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Damit diese Variablen auch genutzt werden, ist der Aufruf von avrdude im Makefile entsprechend zu ergänzen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
# Program the device.  &lt;br /&gt;
program: $(TARGET).hex $(TARGET).eep&lt;br /&gt;
# ohne Fuse-/Lock-Einstellungen (nach WinAVR Vorlage Stand 4/2006)&lt;br /&gt;
#	$(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH) \&lt;br /&gt;
#        $(AVRDUDE_WRITE_EEPROM)&lt;br /&gt;
# mit Fuse-/Lock-Einstellungen&lt;br /&gt;
        $(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_LFUSE) \&lt;br /&gt;
        $(AVRDUDE_WRITE_HFUSE) $(AVRDUDE_WRITE_FLASH) \&lt;br /&gt;
        $(AVRDUDE_WRITE_EEPROM) $(AVRDUDE_WRITE_LOCK)&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Eine weiter Möglichkeit besteht darin, die Fuse- und Lockbit-Einstellungen vom Preprozessor/Compiler generieren zu lassen. Die Fuse-Bits werden dann bei Verwendung von AVRDUDE in eigene Hex-Files geschrieben. Hierzu kann man z.B. folgendes Konstrukt verwenden:&lt;br /&gt;
&lt;br /&gt;
In eine der C-Sourcen wird eine Variable je Fuse-Byte vom Typ &#039;&#039;unsigned char&#039;&#039; deklariert und in eine extra Section gepackt. Dies kann entweder in einem vorhandenen File passieren oder in ein neues (z.B. fuses.c) geschrieben werden. Das File muss im Makefile aber auf jeden Fall mit kompiliert und gelinkt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
// tiny 2313 fuses low byte&lt;br /&gt;
#define CKDIV8  7&lt;br /&gt;
#define CKOUT   6&lt;br /&gt;
#define SUT1    5&lt;br /&gt;
#define SUT0    4&lt;br /&gt;
#define CKSEL3  3&lt;br /&gt;
#define CKSEL2  2&lt;br /&gt;
#define CKSEL1  1&lt;br /&gt;
#define CKSEL0  0&lt;br /&gt;
&lt;br /&gt;
// tiny2313 fuses high byte&lt;br /&gt;
#define DWEN       7&lt;br /&gt;
#define EESAVE     6&lt;br /&gt;
#define SPIEN      5&lt;br /&gt;
#define WDTON      4&lt;br /&gt;
#define BODLEVEL2  3&lt;br /&gt;
#define BODLEVEL1  2&lt;br /&gt;
#define BODLEVEL0  1&lt;br /&gt;
#define RSTDISBL   0&lt;br /&gt;
&lt;br /&gt;
// tiny2313 fuses extended byte&lt;br /&gt;
#define SELFPRGEN  0&lt;br /&gt;
&lt;br /&gt;
#define LFUSE         __attribute__ ((section (&amp;quot;lfuses&amp;quot;)))&lt;br /&gt;
#define HFUSE         __attribute__ ((section (&amp;quot;hfuses&amp;quot;)))&lt;br /&gt;
#define EFUSE         __attribute__ ((section (&amp;quot;efuses&amp;quot;)))&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// select ext crystal 3-8Mhz&lt;br /&gt;
unsigned char lfuse LFUSE =&lt;br /&gt;
    ( (1&amp;lt;&amp;lt;CKDIV8) | (1&amp;lt;&amp;lt;CKOUT) | (1&amp;lt;&amp;lt;CKSEL3) | (1&amp;lt;&amp;lt;CKSEL2) | &lt;br /&gt;
      (0&amp;lt;&amp;lt;CKSEL1) | (1&amp;lt;&amp;lt;CKSEL0) | (0&amp;lt;&amp;lt;SUT1) | (1&amp;lt;&amp;lt;SUT0) );&lt;br /&gt;
unsigned char hfuse HFUSE =&lt;br /&gt;
    ( (1&amp;lt;&amp;lt;DWEN) | (1&amp;lt;&amp;lt;EESAVE) | (0&amp;lt;&amp;lt;SPIEN) | (1&amp;lt;&amp;lt;WDTON) | &lt;br /&gt;
      (1&amp;lt;&amp;lt;BODLEVEL2) | (1&amp;lt;&amp;lt;BODLEVEL1) | (0&amp;lt;&amp;lt;BODLEVEL0) | (1&amp;lt;&amp;lt;RSTDISBL) );&lt;br /&gt;
unsigned char efuse EFUSE =&lt;br /&gt;
    ((0&amp;lt;&amp;lt;SELFPRGEN));&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ACHTUNG: Die Bitpositionen wurden nicht vollständig getestet!&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Eine &amp;quot;1&amp;quot; bedeutet hier, dass das Fuse-Bit &#039;&#039;nicht&#039;&#039; programmiert wird - die Funktion also i.A. nicht aktiviert ist. Eine &amp;quot;0&amp;quot; hingegen aktiviert die meisten Funktionen. Dies ist wie im Datenblatt (1 = unprogrammed, 0 = programmed).&lt;br /&gt;
&lt;br /&gt;
Das Makefile muss nun noch um folgende Targets erweitert werden (mit Tabulator einrücken - nicht mit Leerzeichen):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;code&amp;quot;&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
lfuses: build&lt;br /&gt;
        -$(OBJCOPY) -j lfuses --change-section-address lfuses=0 \&lt;br /&gt;
          -O ihex $(TARGET).elf $(TARGET)-lfuse.hex&lt;br /&gt;
        @if [ -f $(TARGET)-lfuse.hex ]; then \&lt;br /&gt;
         $(AVRDUDE) $(AVRDUDE_FLAGS) -U lfuse:w:$(TARGET)-lfuse.hex; \&lt;br /&gt;
        fi;&lt;br /&gt;
&lt;br /&gt;
hfuses: build&lt;br /&gt;
        -$(OBJCOPY) -j hfuses --change-section-address hfuses=0 \&lt;br /&gt;
          -O ihex $(TARGET).elf $(TARGET)-hfuse.hex&lt;br /&gt;
        @if [ -f $(TARGET)-hfuse.hex ]; then \&lt;br /&gt;
         $(AVRDUDE) $(AVRDUDE_FLAGS) -U hfuse:w:$(TARGET)-hfuse.hex; \&lt;br /&gt;
        fi;&lt;br /&gt;
&lt;br /&gt;
efuses: build&lt;br /&gt;
        -$(OBJCOPY) -j efuses --change-section-address efuses=0 \&lt;br /&gt;
         -O ihex $(TARGET).elf $(TARGET)-efuse.hex&lt;br /&gt;
        @if [ -f $(TARGET)-efuse.hex ]; then \&lt;br /&gt;
         $(AVRDUDE) $(AVRDUDE_FLAGS) -U efuse:w:$(TARGET)-efuse.hex;&lt;br /&gt;
        fi;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Target &amp;quot;clean&amp;quot; muss noch um die Zeilen&lt;br /&gt;
&amp;lt;div class=&amp;quot;code&amp;quot;&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
        $(REMOVE) $(TARGET)-lfuse.hex&lt;br /&gt;
        $(REMOVE) $(TARGET)-hfuse.hex&lt;br /&gt;
        $(REMOVE) $(TARGET)-efuse.hex&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
erweitert werden, wenn auch die Fuse-Dateien gelöscht werden sollen.&lt;br /&gt;
&lt;br /&gt;
Um nun die Fusebits des angeschlossenen Controllers zu programmieren muss lediglichein &amp;quot;make lfuses&amp;quot;, &amp;quot;make hfuses&amp;quot; oder &amp;quot;make efuses&amp;quot; gestartet werden.&lt;br /&gt;
Bei den Fuse-Bits ist besondere Vorsicht geboten, da diese das Programmieren des Controllers unmöglich machen können. Also erst programmieren, wenn man einen HV-Programmierer hat oder ein paar Reserve-AVRs zur Hand ;-)&lt;br /&gt;
&lt;br /&gt;
Um weiterhin den &amp;quot;normalen&amp;quot; Flash beschreiben zu können, ist es wichtig, für das Target &amp;quot;*.hex&amp;quot; im Makefile nicht nur &amp;quot;-R .eeprom&amp;quot; als Parameter zu übergeben sondern zusätzlich noch &amp;quot;-R lfuses -R efuses -R hfuses&amp;quot;. Sonst bekommt AVRDUDE Probleme diese Sections in den Flash (wo sie ja nicht hingehören) zu schreiben.&lt;br /&gt;
&lt;br /&gt;
Siehe auch: [[AVR_Fuses#Vergleich_der_Fuses_bei_verschiedenen_Programmen|Vergleich der Fuses bei verschiedenen Programmen]]&lt;br /&gt;
&lt;br /&gt;
== Externe Referenzspannung des internen Analog-Digital-Wandlers ==&lt;br /&gt;
&lt;br /&gt;
Die minimale (externe) Referenzspannung des ADC darf nicht beliebig niedrig sein, vgl. dazu das (aktuellste) Datenblatt des verwendeten Controllers. z.B. beim ATMEGA8 darf sie laut Datenblatt (S.245, Tabelle 103, Zeile &amp;quot;VREF&amp;quot;) 2,0V nicht unterschreiten. HINWEIS: diese Information findet sich erst in der letzten Revision (Rev. 2486O-10/04) des Datenblatts.&lt;br /&gt;
&lt;br /&gt;
Meiner &amp;lt;!-- Wer? - es gibt inzwischen x Leute die mehr oder weniger viel in diesem Artikel geschrieben haben --&amp;gt; eigenen Erfahrung nach kann man aber (auf eigene Gefahr und natürlich nicht für Seriengeräte) durchaus noch ein klein wenig weiter heruntergehen, bei dem von mir unter die Lupe genommenen ATMEGA8L (also die Low-Voltage-Variante) funktioniert der ADC bei 5V Betriebsspannung mit bis zu VREF=1,15V hinunter korrekt, ab 1,1V und darunter digitalisiert er jedoch nur noch Blödsinn). Ich würde sicherheitshalber nicht unter 1,5V gehen und bei niedrigeren Betriebsspannungen mag sich die Untergrenze für VREF am Pin AREF ggf. nach oben&#039;&#039;&#039;(!)&#039;&#039;&#039; verschieben.&lt;br /&gt;
&lt;br /&gt;
In der letzten Revision des Datenblatts ist außerdem korrigiert, dass ADC4 und ADC5 sehr wohl 10 Bit Genauigkeit bieten (und nicht bloß 8 Bit, wie in älteren Revisionen irrtümlich angegeben.)&lt;br /&gt;
&lt;br /&gt;
= TODO =&lt;br /&gt;
* Aktualisierung Register- und Bitbeschreibungen an aktuelle AVR&lt;br /&gt;
* stdio.h, malloc() &lt;br /&gt;
* Code-Optimierungen (&amp;quot;tricks&amp;quot;), siehe auch Application Note [http://www.atmel.com/dyn/resources/prod_documents/doc1497.pdf AVR035: Efficient C Coding for AVR]&lt;br /&gt;
* &amp;quot;naked&amp;quot;-Funktionen&lt;br /&gt;
* SPI siehe [http://www.uni-koblenz.de/~physik/informatik/MCU/SPI.pdf SPI Bus mit Atmel AVR]&lt;br /&gt;
* I²C / TWI Bus [http://www.roboternetz.de/wissen/index.php/TWI]&lt;br /&gt;
* Bootloader (bez. auf boot.h)&lt;br /&gt;
* CAN-Bus&lt;br /&gt;
* Einsatz von einfachen Betriebssystemen auf dem AVR&lt;br /&gt;
* Übersicht zu den C bzw. GCC-predefined Makros (__DATE__, __TIME__,...)&lt;br /&gt;
[[Category:AVR]]&lt;br /&gt;
* ADC ; &lt;br /&gt;
* Timer&lt;br /&gt;
* USB ; Steuerung mit USB&lt;br /&gt;
* Multiplexen Siebensegment&lt;/div&gt;</summary>
		<author><name>Thymythos</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=AVR_RFM12&amp;diff=32604</id>
		<title>AVR RFM12</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=AVR_RFM12&amp;diff=32604"/>
		<updated>2008-11-20T14:07:22Z</updated>

		<summary type="html">&lt;p&gt;Thymythos: /* Platine */  Photo&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Schaltungen und Software für AVR und das Funkmodul [[RFM12]].&lt;br /&gt;
&lt;br /&gt;
== SVN ==&lt;br /&gt;
&lt;br /&gt;
svn://mikrocontroller.net/rfm12&lt;br /&gt;
&lt;br /&gt;
Wegen Zugangsdaten bitte bei [http://www.mikrocontroller.net/user/show/andreas Andreas Schwarz] melden.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Software ==&lt;br /&gt;
&lt;br /&gt;
=== Treiber ===&lt;br /&gt;
&lt;br /&gt;
[http://www.mikrocontroller.net/attachment/22473/rfm12_pc.zip Firmware v1.0.0] von Benedikt K.&lt;br /&gt;
&lt;br /&gt;
[http://www.mikrocontroller.net/attachment/23542/RMxx_Driver.tar.bz2 Firmware v2.0.1] von Jürgen Eckert&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot;&lt;br /&gt;
|+ Funktionalität&lt;br /&gt;
|-&lt;br /&gt;
!  || Beschreibung || Software&lt;br /&gt;
|-&lt;br /&gt;
!1. Stufe:&lt;br /&gt;
| Die Daten von der seriellen Schnittstelle werden über die Funkstrecke auf die serielle Schnittstelle der anderen Seite übertragen. (Wir freuen uns über jedes Byte das ankommt)&lt;br /&gt;
| [http://www.mikrocontroller.net/topic/67273#564945 Claude Schwarz], [http://www.mikrocontroller.net/topic/71682#584915 Benedikt K.] oder [http://www.mikrocontroller.net/attachment/36742/RFM12_V3.zip Manuel Stahl]&lt;br /&gt;
|-&lt;br /&gt;
! 2. Stufe:&lt;br /&gt;
| Es findet eine Fehlererkennung (z.B. mit CRC-Summen) statt. Fehlerhafte Daten werden erneut angefordert. Dadurch gehen auf der Funkstrecke keine Daten verloren und es werden keine Daten verfälscht.&lt;br /&gt;
| [http://www.mikrocontroller.net/topic/71682#585851 Benedikt K.]&lt;br /&gt;
|-&lt;br /&gt;
! 3. Stufe:&lt;br /&gt;
| Die Datenübertragung wird individualisiert. Dadurch können zwei Funkstrecken, die im gleichen Empfangsbereich liegen nebeneinander arbeiten, ohne sich zu beeinträchtigen.&lt;br /&gt;
| [[RFM12_Protokoll_Stack]]&lt;br /&gt;
|-&lt;br /&gt;
! 4. Stufe: &lt;br /&gt;
| Die Datenübertragung wird verschlüsselt und damit abhörsicher.&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
!5. Stufe:&lt;br /&gt;
| Neben den Daten der seriellen Schnittstelle werden auch Änderungen der Statusleitungen übertragen. Damit erhält man eine &amp;quot;RS232-Verlängerung&amp;quot; über eine Funkstrecke, die fehlerfrei arbeitet und zu einer Drahtverbindung weitestgehend kompatibel ist.&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== RS232 &amp;lt;-&amp;gt; RFM12 ===&lt;br /&gt;
&lt;br /&gt;
TODO&lt;br /&gt;
&lt;br /&gt;
=== USB &amp;lt;-&amp;gt; RFM12 ===&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;&#039;[http://www.obdev.at/products/avrusb/index.html avrusb]&#039;&#039;&#039; lässt sich ein USB-Slave in Software emulieren.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;[http://www.recursion.jp/avrcdc/ AVR-CDC]&#039;&#039;&#039; läuft mit Anpassung der USB-Pins. &#039;&#039;(Zumindest unter Windows an einem USB2.0-Port)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Adapter für &#039;&#039;&#039;[http://www.embedded-projects.net/?page_id=135 USBprog]:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Funktionierender Code liegt im oben genannten SVN&lt;br /&gt;
* Implementiert die USB-CDC-Klasse (kein Treiber nötig)&lt;br /&gt;
* Sicherung der Übertragung durch Hamming-Code&lt;br /&gt;
* Work in progress... (Manuel Stahl)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Hardware ==&lt;br /&gt;
&lt;br /&gt;
=== Basismodul V1.0 ===&lt;br /&gt;
&lt;br /&gt;
==== Prozessor ====&lt;br /&gt;
&lt;br /&gt;
ATmega8 TQFP32 (kompatibel ATmega48, ATmega88, ATmega168)&lt;br /&gt;
&lt;br /&gt;
==== Schnittstellen ====&lt;br /&gt;
&lt;br /&gt;
* RS232&lt;br /&gt;
* I²C:&lt;br /&gt;
* USB&lt;br /&gt;
* GPIO&lt;br /&gt;
&lt;br /&gt;
==== Platine ====&lt;br /&gt;
&lt;br /&gt;
[[Bild:AVR RFM12 Schematic.png|200px|ATmega48 + USB]]&lt;br /&gt;
[[Bild:AVR RFM12 Board TOP.png|220px|2-lagig top]]&lt;br /&gt;
[[Bild:AVR RFM12 Board BOTTOM.png|240px|2-lagig bottom]]&lt;br /&gt;
[[Bild:AVR_RFM12_Photo.jpg|240px|Photo]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Bauteile:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Größe: SMD 0603&lt;br /&gt;
&lt;br /&gt;
* R1, R2: 68R (nur USB)&lt;br /&gt;
* R3, R4: 10k&lt;br /&gt;
* R5: 1k5 (nur USB)&lt;br /&gt;
* C1, C2: 22pF&lt;br /&gt;
* C3 - C9: 100nF&lt;br /&gt;
* Q1: 12Mhz (nur USB)&lt;br /&gt;
* D1, D2: beliebig, Minimelf&lt;br /&gt;
* IC3: MAX3221CUE&lt;br /&gt;
&lt;br /&gt;
==== Bugs / Erweiterungen ====&lt;br /&gt;
&lt;br /&gt;
* Der 1,5k Widerstand muss direkt an den VCC-Pin angelötet werden (Pad ist nicht verbunden)&lt;br /&gt;
* Beim Fertigen wurde das Polygon, welches das VCC-Signal durch die eine Ecke des ATmega48 leitet, unterbrochen. Hier hilft nur eine Drahtbrücke.&lt;br /&gt;
* Unter den RFM12 und unter das Quarz am Besten Isolierband kleben!&lt;br /&gt;
* Beim Programmieren sollte der SEL des RFM12 (J1 der zweite Pin vom RS232 aus) auf VCC gelegt werden&lt;br /&gt;
&lt;br /&gt;
==== Fertigung ====&lt;br /&gt;
&lt;br /&gt;
Kosten:&lt;br /&gt;
&lt;br /&gt;
* MiniUSB SMD: &#039;&#039;&#039;1,25€&#039;&#039;&#039;&lt;br /&gt;
* HF-Buchse MMCX: &#039;&#039;&#039;4,25€&#039;&#039;&#039;&lt;br /&gt;
* ATmega48: &#039;&#039;&#039;2,85€&#039;&#039;&#039;&lt;br /&gt;
* MAX3221CUE: &#039;&#039;&#039;1,10€&#039;&#039;&#039;&lt;br /&gt;
* Quarz 12Mhz 30ppm: &#039;&#039;&#039;1,19€&#039;&#039;&#039;&lt;br /&gt;
* Kleinkram: &#039;&#039;&#039;&amp;lt; 1,10€&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* habe ein verbindliches Angebot für 24 Stück von http://mme-pcb.de/: &#039;&#039;&#039;4,00€ pro Platine&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[http://www.mikrocontroller.net/attachment/24012/RFM12.brd Board]:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Board bottom bestuecken.png|200px|bottom]]&lt;br /&gt;
[[Bild:AVR RFM12 Board top bestuecken.png|200px|top]]&lt;br /&gt;
&lt;br /&gt;
=== USBprogRFM12 ===&lt;br /&gt;
&lt;br /&gt;
Da der USBprog genau das SPI-Interface des ATmega32 zur Verfügung stellt, eignet er sich perfekt als USB-RFM12-Adapter.&lt;br /&gt;
&lt;br /&gt;
[[Bild:USBprogRFM12_schematic.png|200px|USBprogRFM12]] [[Bild:USBprogRFM12_board.png|200px|USBprogRFM12]]&lt;br /&gt;
&lt;br /&gt;
[[Bild:USBprogRFM12.jpg|400px|USBprogRFM12]]&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
* [http://www.mikrocontroller.net/topic/65984 Allgemeine Diskussion]&lt;br /&gt;
* [http://www.mikrocontroller.net/topic/71682  bidirektionale RS232 Funkbrücke mit RFM12]&lt;br /&gt;
* [http://www.das-labor.org/wiki/Datenfunk_mit_dem_AVR Datenfunk mit dem AVR] bei das-labor.org&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Projekte]]&lt;br /&gt;
[[Kategorie:AVR]]&lt;br /&gt;
[[Kategorie:Funk]]&lt;/div&gt;</summary>
		<author><name>Thymythos</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=Datei:AVR_RFM12_Photo.jpg&amp;diff=32603</id>
		<title>Datei:AVR RFM12 Photo.jpg</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=Datei:AVR_RFM12_Photo.jpg&amp;diff=32603"/>
		<updated>2008-11-20T14:06:31Z</updated>

		<summary type="html">&lt;p&gt;Thymythos: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Thymythos</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=RFM12_Protokoll_Stack&amp;diff=32578</id>
		<title>RFM12 Protokoll Stack</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=RFM12_Protokoll_Stack&amp;diff=32578"/>
		<updated>2008-11-18T21:59:04Z</updated>

		<summary type="html">&lt;p&gt;Thymythos: /* Kanalzuordnung */ Baudrate&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Bild:RFM12 Stack.svg|right]]&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel beschreibt einen [http://de.wikipedia.org/wiki/ISO/OSI ISO/OSI] Protokoll [http://de.wikipedia.org/wiki/Protokollstack Stack] für den [[RFM12]] Funkchip.&amp;lt;br/&amp;gt;&lt;br /&gt;
Einige Hardwarebeispiele finden sich in [[AVR RFM12]].&amp;lt;br/&amp;gt;&lt;br /&gt;
Fehler und Anregungen können gerne auf der [[Diskussion:RFM12_Protokoll_Stack|Diskussionsseite]] besprochen werden.&lt;br /&gt;
&lt;br /&gt;
Eine Referenz-Implementierung für den [[AVR]] wird bereitgestellt:&lt;br /&gt;
{| style=&amp;quot;border:1px dashed green&amp;quot;&lt;br /&gt;
|&#039;&#039;svn://mikrocontroller.net/rfm12/trunk/RFM12_Stack&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
;Implementierungskriterien&lt;br /&gt;
* Wo möglich werden [http://de.wikipedia.org/wiki/R%C3%BCckruffunktion Callback]-Funktionen anstatt [http://de.wikipedia.org/wiki/First_In_%E2%80%93_First_Out FIFOs] verwendet um RAM zu sparen.&lt;br /&gt;
* Interruptgesteuerter Ablauf des Stacks&lt;br /&gt;
* Funktionen sollten nicht blockieren&lt;br /&gt;
&lt;br /&gt;
== Layer 1: Physical ==&lt;br /&gt;
&lt;br /&gt;
[[Bild:RFM12 PHY StateMachine.svg|thumb|320px|Layer1 State Diagram]]&lt;br /&gt;
&lt;br /&gt;
Der Physical-Layer kümmert sich um die direkte Ansteuerung des RFM12. Alle Funktionen des Chips werden als Software-API bereitgestellt.&lt;br /&gt;
&lt;br /&gt;
Folgende Eigenschaften sind bereits vom RFM12 vorgegeben:&lt;br /&gt;
&lt;br /&gt;
* [http://de.wikipedia.org/wiki/ISM-Band 70cm Band (433MHz)]&lt;br /&gt;
* [http://de.wikipedia.org/wiki/Frequenzumtastung FSK]-Modulation&lt;br /&gt;
* Sync-Erkennung auf &#039;&#039;0x2D 0xD4&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Definiert werden muss jedoch noch:&lt;br /&gt;
&lt;br /&gt;
* Baudrate (Vorschlag: feste Kanal-Baudraten-Zuordnung)&lt;br /&gt;
* Zuordnung von Frequenzen zu [[#Kanalzuordnung|Kanälen]]&lt;br /&gt;
* Bandbreite der Kanäle&lt;br /&gt;
* Management der Sendeleistung/Empfangsempfindlichkeit&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;API&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
void RFM12_PHY_modeTX(void);&lt;br /&gt;
&lt;br /&gt;
void RFM12_PHY_modeRX(void);&lt;br /&gt;
&lt;br /&gt;
bool RFM12_PHY_busy(void);&lt;br /&gt;
&lt;br /&gt;
void RFM12_setBaudrate(uint32_t baud);&lt;br /&gt;
&lt;br /&gt;
void RFM12_setCenterFrequency(uint16_t freq);&lt;br /&gt;
&lt;br /&gt;
void RFM12_setDataFilter(bool autoLock, bool fastMode, bool analog, uint8_t dqdThres);&lt;br /&gt;
&lt;br /&gt;
void RFM12_setReceiverBandwidth(RFM12_VDI_t vdi, RFM12_RxBW_t bandwidth, RFM12_GAIN_t gain, RFM12_RSSI_t drssi);&lt;br /&gt;
&lt;br /&gt;
void RFM12_setPowerManagement(bool enRX, bool enBB, bool startTX, bool enSynth, bool enOSC, bool enBat, bool enWkT, bool clkOff);&lt;br /&gt;
&lt;br /&gt;
void RFM12_setTransmitPower(RFM12_Power_t power, RFM12_TxDev_t deviation);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Layer 2: Data Link ==&lt;br /&gt;
&lt;br /&gt;
=== Media Access Control (MAC) ===&lt;br /&gt;
&lt;br /&gt;
Hier noch ein paar Anregungen zur Verbesserung des MAC: [http://www.comsoc.org/livepubs/surveys/public/2q00issue/gummalla.html]&lt;br /&gt;
&lt;br /&gt;
Der MAC-Layer ist sehr einfach gehalten und regelt den Zugriff auf das Medium. Hier soll ein [http://de.wikipedia.org/wiki/CSMA-CA CSMA/CA] Verfahren eingesetzt werden.&lt;br /&gt;
&lt;br /&gt;
# Im Grundzustand befindet sich der RFM12 im Empfangsmodus und wartet auf eine SYNC-Sequenz.&lt;br /&gt;
# Kommt eine Sendeanforderung, wird so lange gewartet bis das Medium frei ist, dann darf nach Ablauf einer (pseudo) zufälligen Zeitspanne gesendet werden.&lt;br /&gt;
# Wurde gerade ein Paket empfangen, darf sofort ein ACK gesendet werden.&lt;br /&gt;
&lt;br /&gt;
Der Frameaufbau ist teilweise vom RFM12 vorgegeben (SYNC-Erkennung). Der Start-Of-Frame (SOF) dient der Synchronisation. Als End-Of-Frame (EOF) wird ebenfalls die Sequenz &#039;&#039;0xAA&#039;&#039; verwendet. Diese darf im Datenteil nicht vorkommen!&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|+ MAC Frameaufbau&lt;br /&gt;
|-&lt;br /&gt;
!&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; | SOF&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; | Sync&lt;br /&gt;
! &#039;&#039;n Byte Daten&#039;&#039;&lt;br /&gt;
! EOF&lt;br /&gt;
|----&lt;br /&gt;
! Bits&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; | 16 || colspan=&amp;quot;2&amp;quot; | 16 || 0 - 512    || 8&lt;br /&gt;
|----&lt;br /&gt;
! Wert&lt;br /&gt;
| 0xAA || 0xAA     || 0x2D || 0xD4     || &#039;&#039;Daten&#039;&#039;  || 0xAA&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;API&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
void RFM12_MAC_setChannel(uint8_t channel);&lt;br /&gt;
&lt;br /&gt;
bool RFM12_MAC_isReceiving(void);&lt;br /&gt;
&lt;br /&gt;
bool RFM12_MAC_mediaBusy(void);&lt;br /&gt;
&lt;br /&gt;
void RFM12_MAC_startCtrlTransmission(void);&lt;br /&gt;
&lt;br /&gt;
void RFM12_MAC_endCtrlTransmission(void);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Logical Link Control (LLC) ===&lt;br /&gt;
&lt;br /&gt;
Der LLC-Layer kümmert sich um die Sicherung der zu übertragenden Daten.&lt;br /&gt;
Außerdem können Geräte direkt mit ihrer Adresse (8-Bit) angesprochen werden.&lt;br /&gt;
&lt;br /&gt;
;[http://de.wikipedia.org/wiki/Vorw%C3%A4rtsfehlerkorrektur FEC]&lt;br /&gt;
:Alle Bytes werden auf eine [[#Hamming-Tabelle|16-Bit Hamming-Sequenz]] erweitert, wodurch die Datenrate halbiert wird.&lt;br /&gt;
:Dies erlaubt es einzelne Bitfehler zu korrigieren.&lt;br /&gt;
:Bei zu vielen Fehlern können diese jedoch nicht erkannt werden.&lt;br /&gt;
:Im Hamming-Code kommt die Sequenz &#039;&#039;0xAA&#039;&#039; nicht vor (siehe MAC-Layer).&lt;br /&gt;
:Die FEC sorgt außerdem dafür, dass genügend 0-1 Transitionen vorkommen. So kann der Empfänger den Takt auch bei langen Paketen besser halten.&lt;br /&gt;
&lt;br /&gt;
;[http://de.wikipedia.org/wiki/Cyclic_Redundancy_Check CRC]&lt;br /&gt;
:Der gesamte Frame wird nochmals durch eine Checksumme gesichert. (CRC-8: &#039;&#039;x&amp;lt;sup&amp;gt;8&amp;lt;/sup&amp;gt; + x&amp;lt;sup&amp;gt;5&amp;lt;/sup&amp;gt; + x&amp;lt;sup&amp;gt;4&amp;lt;/sup&amp;gt; + 1&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Es werden mehrere Frame-Typen zur Verfügung gestellt:&lt;br /&gt;
&lt;br /&gt;
* Broadcast an alle Geräte (immer ohne ACK)&lt;br /&gt;
* Nachricht an ein bestimmtes Gerät (mit oder ohne ACK)&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|+ LLC Frameaufbau&lt;br /&gt;
|-&lt;br /&gt;
!&lt;br /&gt;
! Empfänger&lt;br /&gt;
! Sender&lt;br /&gt;
! need ACK&lt;br /&gt;
! is ACK&lt;br /&gt;
!&lt;br /&gt;
!&lt;br /&gt;
! TypeID&lt;br /&gt;
! &#039;&#039;0-28 Byte Daten&#039;&#039;&lt;br /&gt;
! CRC-8&lt;br /&gt;
|----&lt;br /&gt;
! Bits (vor FEC)&lt;br /&gt;
| 8      || 8      || 1 || 1 || 1 || 1 || 4 || 0-224 || 8&lt;br /&gt;
|-&lt;br /&gt;
! Bits (nach FEC)&lt;br /&gt;
| 16     || 16     || 2 || 2 || 2 || 2 || 8 || 0-448 || 16&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039; API &#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
void RFM12_LLC_registerType(RFM12_ProtocolID_t typeID, RFM12_L3_Protocol_t proto);&lt;br /&gt;
&lt;br /&gt;
uint8_t RFM12_LLC_sendFrame(RFM12_ProtocolID_t proto, uint8_t receiver, bool requireACK);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Layer 3: Network ==&lt;br /&gt;
&lt;br /&gt;
Für den Network-Layer werden nur einige Beispiele angeführt. Ab hier können beliebige eigene Protokolle eingesetzt werden. Das verwendete Protokoll wird durch die &#039;&#039;TypeID&#039;&#039; im LLC-Layer angegeben. Die Layer-3-Protokolle sollten nach Möglichkeit nur über die LLC-API mit dem Rest des Stacks kommunizieren.&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;TypeID&#039;&#039;s sind wie folgt definiert:&lt;br /&gt;
&lt;br /&gt;
=== Typ 0: Management ===&lt;br /&gt;
&lt;br /&gt;
Management Protokoll: Beacons etc.&lt;br /&gt;
&lt;br /&gt;
* Sollte ähnliche Funktionen bieten wie das Service Discovery Protocol (SDP) bei Bluetooth&lt;br /&gt;
&lt;br /&gt;
=== Typ 1: Bytestream ===&lt;br /&gt;
&lt;br /&gt;
Die Einteilung in Pakete wird aufgehoben. Daten kommen 1:1 in der Reihenfolge an, wie sie gesendet wurden.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;API&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
void RFM12_Serial_setPeer(uint8_t peer);&lt;br /&gt;
&lt;br /&gt;
bool RFM12_Serial_txAvailable(void);&lt;br /&gt;
&lt;br /&gt;
void RFM12_Serial_txData(uint8_t data);&lt;br /&gt;
&lt;br /&gt;
bool RFM12_Serial_rxAvailable(void);&lt;br /&gt;
&lt;br /&gt;
uint8_t RFM12_Serial_rxData(void);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Typ 3: IPv4 ===&lt;br /&gt;
&lt;br /&gt;
z.B. [http://www.sics.se/~adam/uip/index.php/Main_Page uIP TCP/IP Stack] von Adam Dunkels &amp;lt;adam@dunkels.com&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Anhänge ==&lt;br /&gt;
&lt;br /&gt;
=== Sequenzdiagramme ===&lt;br /&gt;
&lt;br /&gt;
Empfang:&lt;br /&gt;
[[Bild:RFM12 RX Sequence.svg|center|800px|RX Sequenz]]&lt;br /&gt;
&lt;br /&gt;
Senden:&lt;br /&gt;
[[Bild:RFM12 TX Sequence.svg|center|800px|TX Sequenz]]&lt;br /&gt;
&lt;br /&gt;
=== Frames ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Beachte:&#039;&#039;&#039; Durch die Hamming-Codierung sind alle Bytes innerhalb des MAC-Layer doppelt so lang wie angegeben!&lt;br /&gt;
{|&lt;br /&gt;
! bgcolor=&amp;quot;#9fffa8&amp;quot; | MAC || bgcolor=&amp;quot;#a9f3f2&amp;quot; | LLC || bgcolor=&amp;quot;#d28787&amp;quot; | L3&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; align=&amp;quot;center&amp;quot; style=&amp;quot;text-align:center&amp;quot;&lt;br /&gt;
|+ Frameaufbau&lt;br /&gt;
|-&lt;br /&gt;
!&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; bgcolor=&amp;quot;#9fffa8&amp;quot; | SOF&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; bgcolor=&amp;quot;#9fffa8&amp;quot; | Sync&lt;br /&gt;
! bgcolor=&amp;quot;#a9f3f2&amp;quot; | Empfänger&lt;br /&gt;
! bgcolor=&amp;quot;#a9f3f2&amp;quot; | Sender&lt;br /&gt;
! bgcolor=&amp;quot;#a9f3f2&amp;quot; | need ACK | is ACK | | | TypeID&lt;br /&gt;
! bgcolor=&amp;quot;#d28787&amp;quot; | &#039;&#039;0-28 Byte Daten&#039;&#039;&lt;br /&gt;
! bgcolor=&amp;quot;#a9f3f2&amp;quot; | CRC-8&lt;br /&gt;
! bgcolor=&amp;quot;#9fffa8&amp;quot; | EOF&lt;br /&gt;
|----&lt;br /&gt;
! Bits&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; bgcolor=&amp;quot;#9fffa8&amp;quot; | 16 || colspan=&amp;quot;2&amp;quot; bgcolor=&amp;quot;#9fffa8&amp;quot; | 16&lt;br /&gt;
| bgcolor=&amp;quot;#a9f3f2&amp;quot; | 8 || bgcolor=&amp;quot;#a9f3f2&amp;quot; | 8 || bgcolor=&amp;quot;#a9f3f2&amp;quot; | &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; 1 &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; | &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; 1 &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; |1|1| &amp;amp;nbsp;&amp;amp;nbsp; 4 &amp;amp;nbsp;&amp;amp;nbsp;&lt;br /&gt;
| bgcolor=&amp;quot;#d28787&amp;quot; | 0-224&lt;br /&gt;
| bgcolor=&amp;quot;#a9f3f2&amp;quot; | 8&lt;br /&gt;
| bgcolor=&amp;quot;#9fffa8&amp;quot; | 8&lt;br /&gt;
|----&lt;br /&gt;
! Wert&lt;br /&gt;
| bgcolor=&amp;quot;#9fffa8&amp;quot; | 0xAA || bgcolor=&amp;quot;#9fffa8&amp;quot; | 0xAA || bgcolor=&amp;quot;#9fffa8&amp;quot; | 0x2D || bgcolor=&amp;quot;#9fffa8&amp;quot; | 0xD4&lt;br /&gt;
| bgcolor=&amp;quot;#a9f3f2&amp;quot; | || bgcolor=&amp;quot;#a9f3f2&amp;quot; | || bgcolor=&amp;quot;#a9f3f2&amp;quot; | &lt;br /&gt;
| bgcolor=&amp;quot;#d28787&amp;quot; | &lt;br /&gt;
| bgcolor=&amp;quot;#a9f3f2&amp;quot; |&lt;br /&gt;
| bgcolor=&amp;quot;#9fffa8&amp;quot; | 0xAA&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Kanalzuordnung ===&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; align=&amp;quot;center&amp;quot; style=&amp;quot;text-align:right;&amp;quot;&lt;br /&gt;
|+ 433MHz Band&lt;br /&gt;
|-&lt;br /&gt;
! Kanal&lt;br /&gt;
| 0 || 1 || 2 || 3 || 4 || 5 || 6 || 7 || 8 || 9 || 10 || 11 || 12 || 13 || 14 || 15&lt;br /&gt;
|-&lt;br /&gt;
! Mittenfrequenz&lt;br /&gt;
|  431.0 || 431.5 || 432.0 || 432.5 || 433.0 || 433.5 || 434.0 || 434.5 || 435.0 || 435.5 || 436.0 || 436.5 || 437.0 || 437.5 || 438.0 || 438.5&lt;br /&gt;
|-&lt;br /&gt;
! Baudrate&lt;br /&gt;
|   9.6k || 19.2k || 115.2k||  9.6k || 19.2k || 115.2k||  9.6k || 19.2k ||115.2k ||  9.6k || 19.2k || 115.2k||  9.6k || 19.2k || 115.2k||  9.6k&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Hamming-Tabelle ===&lt;br /&gt;
&lt;br /&gt;
==== Encodieren ====&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;3&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|&lt;br /&gt;
! colspan=&amp;quot;4&amp;quot; | Algorithmus&lt;br /&gt;
! colspan=&amp;quot;4&amp;quot; | Beispiel&lt;br /&gt;
|-&lt;br /&gt;
| 1:&lt;br /&gt;
| width=&amp;quot;80&amp;quot; |&lt;br /&gt;
| width=&amp;quot;160&amp;quot; colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 8-Bit Wert&lt;br /&gt;
| width=&amp;quot;160&amp;quot; colspan=&amp;quot;2&amp;quot; |&lt;br /&gt;
| width=&amp;quot;160&amp;quot; colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 10010110&lt;br /&gt;
| width=&amp;quot;80&amp;quot; |&lt;br /&gt;
|-&lt;br /&gt;
| 2: || || align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 4-7 ||  align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 0-3 || colspan=&amp;quot;2&amp;quot; | ||  align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 1001 || align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 0110 || &lt;br /&gt;
|-&lt;br /&gt;
| 3:&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | HammingE[(4-7)]&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | HammingE[(0-3)]&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 0xC7&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 0x38&lt;br /&gt;
|-&lt;br /&gt;
| 4:&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | high&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | low&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 11000111&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 00111000&lt;br /&gt;
|-&lt;br /&gt;
| 5:&lt;br /&gt;
| colspan=&amp;quot;4&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 16-Bit Codewort&lt;br /&gt;
| colspan=&amp;quot;4&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 11000111 00111000&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;3&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|+ HammingE&lt;br /&gt;
|-&lt;br /&gt;
!  0 || 1 || 2  || 3 || 4 || 5 || 6 || 7 || 8 || 9 || A || B || C || D || E || F&lt;br /&gt;
|-&lt;br /&gt;
|bgcolor=&amp;quot;#ff0000&amp;quot;|0x15||bgcolor=&amp;quot;#ff1111&amp;quot;|0x02||bgcolor=&amp;quot;#ff2222&amp;quot;|0x49||bgcolor=&amp;quot;#ff3333&amp;quot;|0x5E||bgcolor=&amp;quot;#ff4444&amp;quot;|0x64||bgcolor=&amp;quot;#ff5555&amp;quot;|0x73||bgcolor=&amp;quot;#ff6666&amp;quot;|0x38||bgcolor=&amp;quot;#ff7777&amp;quot;|0x2F||bgcolor=&amp;quot;#ff8888&amp;quot;|0xD0||bgcolor=&amp;quot;#ff9999&amp;quot;|0xC7||bgcolor=&amp;quot;#ffaaaa&amp;quot;|0x8C||bgcolor=&amp;quot;#ffbbbb&amp;quot;|0x9B||bgcolor=&amp;quot;#ffcccc&amp;quot;|0xA1||bgcolor=&amp;quot;#ffdddd&amp;quot;|0xB6||bgcolor=&amp;quot;#ffeeee&amp;quot;|0xFD||bgcolor=&amp;quot;#ffffff&amp;quot;|0xEA&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Die Einträge in der Tabelle sind so gewählt, dass der Code den maximalen [http://de.wikipedia.org/wiki/Hamming-Abstand#Hamming-Abstand_eines_Codes Hamming-Abstand] von 4 Bit hat.&lt;br /&gt;
&lt;br /&gt;
==== Dekodieren ====&lt;br /&gt;
&lt;br /&gt;
In der Tabelle &#039;&#039;HammingD&#039;&#039; stehen nur 4-Bit breite Werte. Um einen 8-Bit Wert zu erhalten müssen also 2 Einträge aus der Tabelle ausgewählt werden.&lt;br /&gt;
&lt;br /&gt;
Wird nun ein 16-Bit Wert empfangen, bestimmt das High-Byte den ersten Eintrag, das Low-Byte den zweiten.&lt;br /&gt;
&lt;br /&gt;
Es können bis zu zwei gekippte Bits im High- und im Low-Byte korrigiert werden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;3&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|&lt;br /&gt;
! colspan=&amp;quot;4&amp;quot; | Algorithmus || colspan=&amp;quot;4&amp;quot; | Beispiel (mit Bitfehlern)&lt;br /&gt;
|-&lt;br /&gt;
| 1:&lt;br /&gt;
| colspan=&amp;quot;4&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 16-Bit Codewort&lt;br /&gt;
| colspan=&amp;quot;4&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 110&#039;&#039;&#039;1&#039;&#039;&#039;0111 001&#039;&#039;&#039;0&#039;&#039;&#039;100&#039;&#039;&#039;1&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 2:&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | high&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | low&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 110&#039;&#039;&#039;1&#039;&#039;&#039;0111&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 001&#039;&#039;&#039;0&#039;&#039;&#039;100&#039;&#039;&#039;1&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 3:&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | HammingD[high]&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | HammingD[low]&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 0x09&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 0x06&lt;br /&gt;
|-&lt;br /&gt;
| 4: || || align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 4-7&lt;br /&gt;
| align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 0-3 || &lt;br /&gt;
| || align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 1001&lt;br /&gt;
| align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 0110 || &lt;br /&gt;
|-&lt;br /&gt;
| 5:&lt;br /&gt;
| width=&amp;quot;80&amp;quot; |&lt;br /&gt;
| width=&amp;quot;160&amp;quot; colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 8-Bit Wert&lt;br /&gt;
| width=&amp;quot;80&amp;quot; | || width=&amp;quot;80&amp;quot; |&lt;br /&gt;
| width=&amp;quot;160&amp;quot; colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 10010110&lt;br /&gt;
| width=&amp;quot;80&amp;quot; |&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;3&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|+ HammingD&lt;br /&gt;
|-&lt;br /&gt;
!  || 0 || 1 || 2  || 3 || 4 || 5 || 6 || 7 || 8 || 9 || A || B || C || D || E || F&lt;br /&gt;
|-&lt;br /&gt;
! 0&lt;br /&gt;
|bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ffaaAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07&lt;br /&gt;
|-&lt;br /&gt;
! 1&lt;br /&gt;
|bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03&lt;br /&gt;
|-&lt;br /&gt;
! 2&lt;br /&gt;
|bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07&lt;br /&gt;
|-&lt;br /&gt;
! 3&lt;br /&gt;
|bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07&lt;br /&gt;
|-&lt;br /&gt;
! 4&lt;br /&gt;
|bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03&lt;br /&gt;
|-&lt;br /&gt;
! 5&lt;br /&gt;
|bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03&lt;br /&gt;
|-&lt;br /&gt;
! 6&lt;br /&gt;
|bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07&lt;br /&gt;
|-&lt;br /&gt;
! 7&lt;br /&gt;
|bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07&lt;br /&gt;
|-&lt;br /&gt;
! 8&lt;br /&gt;
|bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B&lt;br /&gt;
|-&lt;br /&gt;
! 9&lt;br /&gt;
|bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B&lt;br /&gt;
|-&lt;br /&gt;
! A&lt;br /&gt;
|bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07&lt;br /&gt;
|-&lt;br /&gt;
! B&lt;br /&gt;
|bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F&lt;br /&gt;
|-&lt;br /&gt;
! C&lt;br /&gt;
|bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09&lt;br /&gt;
|-&lt;br /&gt;
! D&lt;br /&gt;
|bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B&lt;br /&gt;
|-&lt;br /&gt;
! E&lt;br /&gt;
|bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F&lt;br /&gt;
|-&lt;br /&gt;
! F&lt;br /&gt;
|bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Funk]]&lt;br /&gt;
[[Kategorie:Wettbewerb]]&lt;/div&gt;</summary>
		<author><name>Thymythos</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=RFM12_Protokoll_Stack&amp;diff=32577</id>
		<title>RFM12 Protokoll Stack</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=RFM12_Protokoll_Stack&amp;diff=32577"/>
		<updated>2008-11-18T21:53:19Z</updated>

		<summary type="html">&lt;p&gt;Thymythos: /* Layer 1: Physical */ Baudrate&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Bild:RFM12 Stack.svg|right]]&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel beschreibt einen [http://de.wikipedia.org/wiki/ISO/OSI ISO/OSI] Protokoll [http://de.wikipedia.org/wiki/Protokollstack Stack] für den [[RFM12]] Funkchip.&amp;lt;br/&amp;gt;&lt;br /&gt;
Einige Hardwarebeispiele finden sich in [[AVR RFM12]].&amp;lt;br/&amp;gt;&lt;br /&gt;
Fehler und Anregungen können gerne auf der [[Diskussion:RFM12_Protokoll_Stack|Diskussionsseite]] besprochen werden.&lt;br /&gt;
&lt;br /&gt;
Eine Referenz-Implementierung für den [[AVR]] wird bereitgestellt:&lt;br /&gt;
{| style=&amp;quot;border:1px dashed green&amp;quot;&lt;br /&gt;
|&#039;&#039;svn://mikrocontroller.net/rfm12/trunk/RFM12_Stack&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
;Implementierungskriterien&lt;br /&gt;
* Wo möglich werden [http://de.wikipedia.org/wiki/R%C3%BCckruffunktion Callback]-Funktionen anstatt [http://de.wikipedia.org/wiki/First_In_%E2%80%93_First_Out FIFOs] verwendet um RAM zu sparen.&lt;br /&gt;
* Interruptgesteuerter Ablauf des Stacks&lt;br /&gt;
* Funktionen sollten nicht blockieren&lt;br /&gt;
&lt;br /&gt;
== Layer 1: Physical ==&lt;br /&gt;
&lt;br /&gt;
[[Bild:RFM12 PHY StateMachine.svg|thumb|320px|Layer1 State Diagram]]&lt;br /&gt;
&lt;br /&gt;
Der Physical-Layer kümmert sich um die direkte Ansteuerung des RFM12. Alle Funktionen des Chips werden als Software-API bereitgestellt.&lt;br /&gt;
&lt;br /&gt;
Folgende Eigenschaften sind bereits vom RFM12 vorgegeben:&lt;br /&gt;
&lt;br /&gt;
* [http://de.wikipedia.org/wiki/ISM-Band 70cm Band (433MHz)]&lt;br /&gt;
* [http://de.wikipedia.org/wiki/Frequenzumtastung FSK]-Modulation&lt;br /&gt;
* Sync-Erkennung auf &#039;&#039;0x2D 0xD4&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Definiert werden muss jedoch noch:&lt;br /&gt;
&lt;br /&gt;
* Baudrate (Vorschlag: feste Kanal-Baudraten-Zuordnung)&lt;br /&gt;
* Zuordnung von Frequenzen zu [[#Kanalzuordnung|Kanälen]]&lt;br /&gt;
* Bandbreite der Kanäle&lt;br /&gt;
* Management der Sendeleistung/Empfangsempfindlichkeit&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;API&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
void RFM12_PHY_modeTX(void);&lt;br /&gt;
&lt;br /&gt;
void RFM12_PHY_modeRX(void);&lt;br /&gt;
&lt;br /&gt;
bool RFM12_PHY_busy(void);&lt;br /&gt;
&lt;br /&gt;
void RFM12_setBaudrate(uint32_t baud);&lt;br /&gt;
&lt;br /&gt;
void RFM12_setCenterFrequency(uint16_t freq);&lt;br /&gt;
&lt;br /&gt;
void RFM12_setDataFilter(bool autoLock, bool fastMode, bool analog, uint8_t dqdThres);&lt;br /&gt;
&lt;br /&gt;
void RFM12_setReceiverBandwidth(RFM12_VDI_t vdi, RFM12_RxBW_t bandwidth, RFM12_GAIN_t gain, RFM12_RSSI_t drssi);&lt;br /&gt;
&lt;br /&gt;
void RFM12_setPowerManagement(bool enRX, bool enBB, bool startTX, bool enSynth, bool enOSC, bool enBat, bool enWkT, bool clkOff);&lt;br /&gt;
&lt;br /&gt;
void RFM12_setTransmitPower(RFM12_Power_t power, RFM12_TxDev_t deviation);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Layer 2: Data Link ==&lt;br /&gt;
&lt;br /&gt;
=== Media Access Control (MAC) ===&lt;br /&gt;
&lt;br /&gt;
Hier noch ein paar Anregungen zur Verbesserung des MAC: [http://www.comsoc.org/livepubs/surveys/public/2q00issue/gummalla.html]&lt;br /&gt;
&lt;br /&gt;
Der MAC-Layer ist sehr einfach gehalten und regelt den Zugriff auf das Medium. Hier soll ein [http://de.wikipedia.org/wiki/CSMA-CA CSMA/CA] Verfahren eingesetzt werden.&lt;br /&gt;
&lt;br /&gt;
# Im Grundzustand befindet sich der RFM12 im Empfangsmodus und wartet auf eine SYNC-Sequenz.&lt;br /&gt;
# Kommt eine Sendeanforderung, wird so lange gewartet bis das Medium frei ist, dann darf nach Ablauf einer (pseudo) zufälligen Zeitspanne gesendet werden.&lt;br /&gt;
# Wurde gerade ein Paket empfangen, darf sofort ein ACK gesendet werden.&lt;br /&gt;
&lt;br /&gt;
Der Frameaufbau ist teilweise vom RFM12 vorgegeben (SYNC-Erkennung). Der Start-Of-Frame (SOF) dient der Synchronisation. Als End-Of-Frame (EOF) wird ebenfalls die Sequenz &#039;&#039;0xAA&#039;&#039; verwendet. Diese darf im Datenteil nicht vorkommen!&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|+ MAC Frameaufbau&lt;br /&gt;
|-&lt;br /&gt;
!&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; | SOF&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; | Sync&lt;br /&gt;
! &#039;&#039;n Byte Daten&#039;&#039;&lt;br /&gt;
! EOF&lt;br /&gt;
|----&lt;br /&gt;
! Bits&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; | 16 || colspan=&amp;quot;2&amp;quot; | 16 || 0 - 512    || 8&lt;br /&gt;
|----&lt;br /&gt;
! Wert&lt;br /&gt;
| 0xAA || 0xAA     || 0x2D || 0xD4     || &#039;&#039;Daten&#039;&#039;  || 0xAA&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;API&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
void RFM12_MAC_setChannel(uint8_t channel);&lt;br /&gt;
&lt;br /&gt;
bool RFM12_MAC_isReceiving(void);&lt;br /&gt;
&lt;br /&gt;
bool RFM12_MAC_mediaBusy(void);&lt;br /&gt;
&lt;br /&gt;
void RFM12_MAC_startCtrlTransmission(void);&lt;br /&gt;
&lt;br /&gt;
void RFM12_MAC_endCtrlTransmission(void);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Logical Link Control (LLC) ===&lt;br /&gt;
&lt;br /&gt;
Der LLC-Layer kümmert sich um die Sicherung der zu übertragenden Daten.&lt;br /&gt;
Außerdem können Geräte direkt mit ihrer Adresse (8-Bit) angesprochen werden.&lt;br /&gt;
&lt;br /&gt;
;[http://de.wikipedia.org/wiki/Vorw%C3%A4rtsfehlerkorrektur FEC]&lt;br /&gt;
:Alle Bytes werden auf eine [[#Hamming-Tabelle|16-Bit Hamming-Sequenz]] erweitert, wodurch die Datenrate halbiert wird.&lt;br /&gt;
:Dies erlaubt es einzelne Bitfehler zu korrigieren.&lt;br /&gt;
:Bei zu vielen Fehlern können diese jedoch nicht erkannt werden.&lt;br /&gt;
:Im Hamming-Code kommt die Sequenz &#039;&#039;0xAA&#039;&#039; nicht vor (siehe MAC-Layer).&lt;br /&gt;
:Die FEC sorgt außerdem dafür, dass genügend 0-1 Transitionen vorkommen. So kann der Empfänger den Takt auch bei langen Paketen besser halten.&lt;br /&gt;
&lt;br /&gt;
;[http://de.wikipedia.org/wiki/Cyclic_Redundancy_Check CRC]&lt;br /&gt;
:Der gesamte Frame wird nochmals durch eine Checksumme gesichert. (CRC-8: &#039;&#039;x&amp;lt;sup&amp;gt;8&amp;lt;/sup&amp;gt; + x&amp;lt;sup&amp;gt;5&amp;lt;/sup&amp;gt; + x&amp;lt;sup&amp;gt;4&amp;lt;/sup&amp;gt; + 1&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Es werden mehrere Frame-Typen zur Verfügung gestellt:&lt;br /&gt;
&lt;br /&gt;
* Broadcast an alle Geräte (immer ohne ACK)&lt;br /&gt;
* Nachricht an ein bestimmtes Gerät (mit oder ohne ACK)&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|+ LLC Frameaufbau&lt;br /&gt;
|-&lt;br /&gt;
!&lt;br /&gt;
! Empfänger&lt;br /&gt;
! Sender&lt;br /&gt;
! need ACK&lt;br /&gt;
! is ACK&lt;br /&gt;
!&lt;br /&gt;
!&lt;br /&gt;
! TypeID&lt;br /&gt;
! &#039;&#039;0-28 Byte Daten&#039;&#039;&lt;br /&gt;
! CRC-8&lt;br /&gt;
|----&lt;br /&gt;
! Bits (vor FEC)&lt;br /&gt;
| 8      || 8      || 1 || 1 || 1 || 1 || 4 || 0-224 || 8&lt;br /&gt;
|-&lt;br /&gt;
! Bits (nach FEC)&lt;br /&gt;
| 16     || 16     || 2 || 2 || 2 || 2 || 8 || 0-448 || 16&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039; API &#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
void RFM12_LLC_registerType(RFM12_ProtocolID_t typeID, RFM12_L3_Protocol_t proto);&lt;br /&gt;
&lt;br /&gt;
uint8_t RFM12_LLC_sendFrame(RFM12_ProtocolID_t proto, uint8_t receiver, bool requireACK);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Layer 3: Network ==&lt;br /&gt;
&lt;br /&gt;
Für den Network-Layer werden nur einige Beispiele angeführt. Ab hier können beliebige eigene Protokolle eingesetzt werden. Das verwendete Protokoll wird durch die &#039;&#039;TypeID&#039;&#039; im LLC-Layer angegeben. Die Layer-3-Protokolle sollten nach Möglichkeit nur über die LLC-API mit dem Rest des Stacks kommunizieren.&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;TypeID&#039;&#039;s sind wie folgt definiert:&lt;br /&gt;
&lt;br /&gt;
=== Typ 0: Management ===&lt;br /&gt;
&lt;br /&gt;
Management Protokoll: Beacons etc.&lt;br /&gt;
&lt;br /&gt;
* Sollte ähnliche Funktionen bieten wie das Service Discovery Protocol (SDP) bei Bluetooth&lt;br /&gt;
&lt;br /&gt;
=== Typ 1: Bytestream ===&lt;br /&gt;
&lt;br /&gt;
Die Einteilung in Pakete wird aufgehoben. Daten kommen 1:1 in der Reihenfolge an, wie sie gesendet wurden.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;API&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
void RFM12_Serial_setPeer(uint8_t peer);&lt;br /&gt;
&lt;br /&gt;
bool RFM12_Serial_txAvailable(void);&lt;br /&gt;
&lt;br /&gt;
void RFM12_Serial_txData(uint8_t data);&lt;br /&gt;
&lt;br /&gt;
bool RFM12_Serial_rxAvailable(void);&lt;br /&gt;
&lt;br /&gt;
uint8_t RFM12_Serial_rxData(void);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Typ 3: IPv4 ===&lt;br /&gt;
&lt;br /&gt;
z.B. [http://www.sics.se/~adam/uip/index.php/Main_Page uIP TCP/IP Stack] von Adam Dunkels &amp;lt;adam@dunkels.com&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Anhänge ==&lt;br /&gt;
&lt;br /&gt;
=== Sequenzdiagramme ===&lt;br /&gt;
&lt;br /&gt;
Empfang:&lt;br /&gt;
[[Bild:RFM12 RX Sequence.svg|center|800px|RX Sequenz]]&lt;br /&gt;
&lt;br /&gt;
Senden:&lt;br /&gt;
[[Bild:RFM12 TX Sequence.svg|center|800px|TX Sequenz]]&lt;br /&gt;
&lt;br /&gt;
=== Frames ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Beachte:&#039;&#039;&#039; Durch die Hamming-Codierung sind alle Bytes innerhalb des MAC-Layer doppelt so lang wie angegeben!&lt;br /&gt;
{|&lt;br /&gt;
! bgcolor=&amp;quot;#9fffa8&amp;quot; | MAC || bgcolor=&amp;quot;#a9f3f2&amp;quot; | LLC || bgcolor=&amp;quot;#d28787&amp;quot; | L3&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; align=&amp;quot;center&amp;quot; style=&amp;quot;text-align:center&amp;quot;&lt;br /&gt;
|+ Frameaufbau&lt;br /&gt;
|-&lt;br /&gt;
!&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; bgcolor=&amp;quot;#9fffa8&amp;quot; | SOF&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; bgcolor=&amp;quot;#9fffa8&amp;quot; | Sync&lt;br /&gt;
! bgcolor=&amp;quot;#a9f3f2&amp;quot; | Empfänger&lt;br /&gt;
! bgcolor=&amp;quot;#a9f3f2&amp;quot; | Sender&lt;br /&gt;
! bgcolor=&amp;quot;#a9f3f2&amp;quot; | need ACK | is ACK | | | TypeID&lt;br /&gt;
! bgcolor=&amp;quot;#d28787&amp;quot; | &#039;&#039;0-28 Byte Daten&#039;&#039;&lt;br /&gt;
! bgcolor=&amp;quot;#a9f3f2&amp;quot; | CRC-8&lt;br /&gt;
! bgcolor=&amp;quot;#9fffa8&amp;quot; | EOF&lt;br /&gt;
|----&lt;br /&gt;
! Bits&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; bgcolor=&amp;quot;#9fffa8&amp;quot; | 16 || colspan=&amp;quot;2&amp;quot; bgcolor=&amp;quot;#9fffa8&amp;quot; | 16&lt;br /&gt;
| bgcolor=&amp;quot;#a9f3f2&amp;quot; | 8 || bgcolor=&amp;quot;#a9f3f2&amp;quot; | 8 || bgcolor=&amp;quot;#a9f3f2&amp;quot; | &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; 1 &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; | &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; 1 &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; |1|1| &amp;amp;nbsp;&amp;amp;nbsp; 4 &amp;amp;nbsp;&amp;amp;nbsp;&lt;br /&gt;
| bgcolor=&amp;quot;#d28787&amp;quot; | 0-224&lt;br /&gt;
| bgcolor=&amp;quot;#a9f3f2&amp;quot; | 8&lt;br /&gt;
| bgcolor=&amp;quot;#9fffa8&amp;quot; | 8&lt;br /&gt;
|----&lt;br /&gt;
! Wert&lt;br /&gt;
| bgcolor=&amp;quot;#9fffa8&amp;quot; | 0xAA || bgcolor=&amp;quot;#9fffa8&amp;quot; | 0xAA || bgcolor=&amp;quot;#9fffa8&amp;quot; | 0x2D || bgcolor=&amp;quot;#9fffa8&amp;quot; | 0xD4&lt;br /&gt;
| bgcolor=&amp;quot;#a9f3f2&amp;quot; | || bgcolor=&amp;quot;#a9f3f2&amp;quot; | || bgcolor=&amp;quot;#a9f3f2&amp;quot; | &lt;br /&gt;
| bgcolor=&amp;quot;#d28787&amp;quot; | &lt;br /&gt;
| bgcolor=&amp;quot;#a9f3f2&amp;quot; |&lt;br /&gt;
| bgcolor=&amp;quot;#9fffa8&amp;quot; | 0xAA&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Kanalzuordnung ===&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|+ 433MHz Band&lt;br /&gt;
|-&lt;br /&gt;
! Kanal&lt;br /&gt;
| 0 || 1 || 2 || 3 || 4 || 5 || 6 || 7 || 8 || 9 || 10 || 11 || 12 || 13 || 14 || 15&lt;br /&gt;
|-&lt;br /&gt;
! Mittenfrequenz&lt;br /&gt;
|  431.0 || 431.5 || 432.0 || 432.5 || 433.0 || 433.5 || 434.0 || 434.5 || 435.0 || 435.5 || 436.0 || 436.5 || 437.0 || 437.5 || 438.0 || 438.5&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Hamming-Tabelle ===&lt;br /&gt;
&lt;br /&gt;
==== Encodieren ====&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;3&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|&lt;br /&gt;
! colspan=&amp;quot;4&amp;quot; | Algorithmus&lt;br /&gt;
! colspan=&amp;quot;4&amp;quot; | Beispiel&lt;br /&gt;
|-&lt;br /&gt;
| 1:&lt;br /&gt;
| width=&amp;quot;80&amp;quot; |&lt;br /&gt;
| width=&amp;quot;160&amp;quot; colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 8-Bit Wert&lt;br /&gt;
| width=&amp;quot;160&amp;quot; colspan=&amp;quot;2&amp;quot; |&lt;br /&gt;
| width=&amp;quot;160&amp;quot; colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 10010110&lt;br /&gt;
| width=&amp;quot;80&amp;quot; |&lt;br /&gt;
|-&lt;br /&gt;
| 2: || || align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 4-7 ||  align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 0-3 || colspan=&amp;quot;2&amp;quot; | ||  align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 1001 || align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 0110 || &lt;br /&gt;
|-&lt;br /&gt;
| 3:&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | HammingE[(4-7)]&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | HammingE[(0-3)]&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 0xC7&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 0x38&lt;br /&gt;
|-&lt;br /&gt;
| 4:&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | high&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | low&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 11000111&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 00111000&lt;br /&gt;
|-&lt;br /&gt;
| 5:&lt;br /&gt;
| colspan=&amp;quot;4&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 16-Bit Codewort&lt;br /&gt;
| colspan=&amp;quot;4&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 11000111 00111000&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;3&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|+ HammingE&lt;br /&gt;
|-&lt;br /&gt;
!  0 || 1 || 2  || 3 || 4 || 5 || 6 || 7 || 8 || 9 || A || B || C || D || E || F&lt;br /&gt;
|-&lt;br /&gt;
|bgcolor=&amp;quot;#ff0000&amp;quot;|0x15||bgcolor=&amp;quot;#ff1111&amp;quot;|0x02||bgcolor=&amp;quot;#ff2222&amp;quot;|0x49||bgcolor=&amp;quot;#ff3333&amp;quot;|0x5E||bgcolor=&amp;quot;#ff4444&amp;quot;|0x64||bgcolor=&amp;quot;#ff5555&amp;quot;|0x73||bgcolor=&amp;quot;#ff6666&amp;quot;|0x38||bgcolor=&amp;quot;#ff7777&amp;quot;|0x2F||bgcolor=&amp;quot;#ff8888&amp;quot;|0xD0||bgcolor=&amp;quot;#ff9999&amp;quot;|0xC7||bgcolor=&amp;quot;#ffaaaa&amp;quot;|0x8C||bgcolor=&amp;quot;#ffbbbb&amp;quot;|0x9B||bgcolor=&amp;quot;#ffcccc&amp;quot;|0xA1||bgcolor=&amp;quot;#ffdddd&amp;quot;|0xB6||bgcolor=&amp;quot;#ffeeee&amp;quot;|0xFD||bgcolor=&amp;quot;#ffffff&amp;quot;|0xEA&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Die Einträge in der Tabelle sind so gewählt, dass der Code den maximalen [http://de.wikipedia.org/wiki/Hamming-Abstand#Hamming-Abstand_eines_Codes Hamming-Abstand] von 4 Bit hat.&lt;br /&gt;
&lt;br /&gt;
==== Dekodieren ====&lt;br /&gt;
&lt;br /&gt;
In der Tabelle &#039;&#039;HammingD&#039;&#039; stehen nur 4-Bit breite Werte. Um einen 8-Bit Wert zu erhalten müssen also 2 Einträge aus der Tabelle ausgewählt werden.&lt;br /&gt;
&lt;br /&gt;
Wird nun ein 16-Bit Wert empfangen, bestimmt das High-Byte den ersten Eintrag, das Low-Byte den zweiten.&lt;br /&gt;
&lt;br /&gt;
Es können bis zu zwei gekippte Bits im High- und im Low-Byte korrigiert werden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;3&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|&lt;br /&gt;
! colspan=&amp;quot;4&amp;quot; | Algorithmus || colspan=&amp;quot;4&amp;quot; | Beispiel (mit Bitfehlern)&lt;br /&gt;
|-&lt;br /&gt;
| 1:&lt;br /&gt;
| colspan=&amp;quot;4&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 16-Bit Codewort&lt;br /&gt;
| colspan=&amp;quot;4&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 110&#039;&#039;&#039;1&#039;&#039;&#039;0111 001&#039;&#039;&#039;0&#039;&#039;&#039;100&#039;&#039;&#039;1&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 2:&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | high&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | low&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 110&#039;&#039;&#039;1&#039;&#039;&#039;0111&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 001&#039;&#039;&#039;0&#039;&#039;&#039;100&#039;&#039;&#039;1&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 3:&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | HammingD[high]&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | HammingD[low]&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 0x09&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 0x06&lt;br /&gt;
|-&lt;br /&gt;
| 4: || || align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 4-7&lt;br /&gt;
| align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 0-3 || &lt;br /&gt;
| || align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 1001&lt;br /&gt;
| align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 0110 || &lt;br /&gt;
|-&lt;br /&gt;
| 5:&lt;br /&gt;
| width=&amp;quot;80&amp;quot; |&lt;br /&gt;
| width=&amp;quot;160&amp;quot; colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 8-Bit Wert&lt;br /&gt;
| width=&amp;quot;80&amp;quot; | || width=&amp;quot;80&amp;quot; |&lt;br /&gt;
| width=&amp;quot;160&amp;quot; colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 10010110&lt;br /&gt;
| width=&amp;quot;80&amp;quot; |&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;3&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|+ HammingD&lt;br /&gt;
|-&lt;br /&gt;
!  || 0 || 1 || 2  || 3 || 4 || 5 || 6 || 7 || 8 || 9 || A || B || C || D || E || F&lt;br /&gt;
|-&lt;br /&gt;
! 0&lt;br /&gt;
|bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ffaaAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07&lt;br /&gt;
|-&lt;br /&gt;
! 1&lt;br /&gt;
|bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03&lt;br /&gt;
|-&lt;br /&gt;
! 2&lt;br /&gt;
|bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07&lt;br /&gt;
|-&lt;br /&gt;
! 3&lt;br /&gt;
|bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07&lt;br /&gt;
|-&lt;br /&gt;
! 4&lt;br /&gt;
|bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03&lt;br /&gt;
|-&lt;br /&gt;
! 5&lt;br /&gt;
|bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03&lt;br /&gt;
|-&lt;br /&gt;
! 6&lt;br /&gt;
|bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07&lt;br /&gt;
|-&lt;br /&gt;
! 7&lt;br /&gt;
|bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07&lt;br /&gt;
|-&lt;br /&gt;
! 8&lt;br /&gt;
|bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B&lt;br /&gt;
|-&lt;br /&gt;
! 9&lt;br /&gt;
|bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B&lt;br /&gt;
|-&lt;br /&gt;
! A&lt;br /&gt;
|bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07&lt;br /&gt;
|-&lt;br /&gt;
! B&lt;br /&gt;
|bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F&lt;br /&gt;
|-&lt;br /&gt;
! C&lt;br /&gt;
|bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09&lt;br /&gt;
|-&lt;br /&gt;
! D&lt;br /&gt;
|bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B&lt;br /&gt;
|-&lt;br /&gt;
! E&lt;br /&gt;
|bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F&lt;br /&gt;
|-&lt;br /&gt;
! F&lt;br /&gt;
|bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Funk]]&lt;br /&gt;
[[Kategorie:Wettbewerb]]&lt;/div&gt;</summary>
		<author><name>Thymythos</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=RFM12_Protokoll_Stack&amp;diff=32565</id>
		<title>RFM12 Protokoll Stack</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=RFM12_Protokoll_Stack&amp;diff=32565"/>
		<updated>2008-11-18T09:04:15Z</updated>

		<summary type="html">&lt;p&gt;Thymythos: /* Logical Link Control (LLC) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Bild:RFM12 Stack.svg|right]]&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel beschreibt einen [http://de.wikipedia.org/wiki/ISO/OSI ISO/OSI] Protokoll [http://de.wikipedia.org/wiki/Protokollstack Stack] für den [[RFM12]] Funkchip.&amp;lt;br/&amp;gt;&lt;br /&gt;
Einige Hardwarebeispiele finden sich in [[AVR RFM12]].&amp;lt;br/&amp;gt;&lt;br /&gt;
Fehler und Anregungen können gerne auf der [[Diskussion:RFM12_Protokoll_Stack|Diskussionsseite]] besprochen werden.&lt;br /&gt;
&lt;br /&gt;
Eine Referenz-Implementierung für den [[AVR]] wird bereitgestellt:&lt;br /&gt;
{| style=&amp;quot;border:1px dashed green&amp;quot;&lt;br /&gt;
|&#039;&#039;svn://mikrocontroller.net/rfm12/trunk/RFM12_Stack&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
;Implementierungskriterien&lt;br /&gt;
* Wo möglich werden [http://de.wikipedia.org/wiki/R%C3%BCckruffunktion Callback]-Funktionen anstatt [http://de.wikipedia.org/wiki/First_In_%E2%80%93_First_Out FIFOs] verwendet um RAM zu sparen.&lt;br /&gt;
* Interruptgesteuerter Ablauf des Stacks&lt;br /&gt;
* Funktionen sollten nicht blockieren&lt;br /&gt;
&lt;br /&gt;
== Layer 1: Physical ==&lt;br /&gt;
&lt;br /&gt;
[[Bild:RFM12 PHY StateMachine.svg|thumb|320px|Layer1 State Diagram]]&lt;br /&gt;
&lt;br /&gt;
Der Physical-Layer kümmert sich um die direkte Ansteuerung des RFM12. Alle Funktionen des Chips werden als Software-API bereitgestellt.&lt;br /&gt;
&lt;br /&gt;
Folgende Eigenschaften sind bereits vom RFM12 vorgegeben:&lt;br /&gt;
&lt;br /&gt;
* [http://de.wikipedia.org/wiki/ISM-Band 70cm Band (433MHz)]&lt;br /&gt;
* [http://de.wikipedia.org/wiki/Frequenzumtastung FSK]-Modulation&lt;br /&gt;
* Sync-Erkennung auf &#039;&#039;0x2D 0xD4&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Definiert werden muss jedoch noch:&lt;br /&gt;
&lt;br /&gt;
* Baudrate&lt;br /&gt;
* Zuordnung von Frequenzen zu [[#Kanalzuordnung|Kanälen]]&lt;br /&gt;
* Bandbreite der Kanäle&lt;br /&gt;
* Management der Sendeleistung/Empfangsempfindlichkeit&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;API&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
void RFM12_PHY_modeTX(void);&lt;br /&gt;
&lt;br /&gt;
void RFM12_PHY_modeRX(void);&lt;br /&gt;
&lt;br /&gt;
bool RFM12_PHY_busy(void);&lt;br /&gt;
&lt;br /&gt;
void RFM12_setBaudrate(uint32_t baud);&lt;br /&gt;
&lt;br /&gt;
void RFM12_setCenterFrequency(uint16_t freq);&lt;br /&gt;
&lt;br /&gt;
void RFM12_setDataFilter(bool autoLock, bool fastMode, bool analog, uint8_t dqdThres);&lt;br /&gt;
&lt;br /&gt;
void RFM12_setReceiverBandwidth(RFM12_VDI_t vdi, RFM12_RxBW_t bandwidth, RFM12_GAIN_t gain, RFM12_RSSI_t drssi);&lt;br /&gt;
&lt;br /&gt;
void RFM12_setPowerManagement(bool enRX, bool enBB, bool startTX, bool enSynth, bool enOSC, bool enBat, bool enWkT, bool clkOff);&lt;br /&gt;
&lt;br /&gt;
void RFM12_setTransmitPower(RFM12_Power_t power, RFM12_TxDev_t deviation);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Layer 2: Data Link ==&lt;br /&gt;
&lt;br /&gt;
=== Media Access Control (MAC) ===&lt;br /&gt;
&lt;br /&gt;
Hier noch ein paar Anregungen zur Verbesserung des MAC: [http://www.comsoc.org/livepubs/surveys/public/2q00issue/gummalla.html]&lt;br /&gt;
&lt;br /&gt;
Der MAC-Layer ist sehr einfach gehalten und regelt den Zugriff auf das Medium. Hier soll ein [http://de.wikipedia.org/wiki/CSMA-CA CSMA/CA] Verfahren eingesetzt werden.&lt;br /&gt;
&lt;br /&gt;
# Im Grundzustand befindet sich der RFM12 im Empfangsmodus und wartet auf eine SYNC-Sequenz.&lt;br /&gt;
# Kommt eine Sendeanforderung, wird so lange gewartet bis das Medium frei ist, dann darf nach Ablauf einer (pseudo) zufälligen Zeitspanne gesendet werden.&lt;br /&gt;
# Wurde gerade ein Paket empfangen, darf sofort ein ACK gesendet werden.&lt;br /&gt;
&lt;br /&gt;
Der Frameaufbau ist teilweise vom RFM12 vorgegeben (SYNC-Erkennung). Der Start-Of-Frame (SOF) dient der Synchronisation. Als End-Of-Frame (EOF) wird ebenfalls die Sequenz &#039;&#039;0xAA&#039;&#039; verwendet. Diese darf im Datenteil nicht vorkommen!&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|+ MAC Frameaufbau&lt;br /&gt;
|-&lt;br /&gt;
!&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; | SOF&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; | Sync&lt;br /&gt;
! &#039;&#039;n Byte Daten&#039;&#039;&lt;br /&gt;
! EOF&lt;br /&gt;
|----&lt;br /&gt;
! Bits&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; | 16 || colspan=&amp;quot;2&amp;quot; | 16 || 0 - 512    || 8&lt;br /&gt;
|----&lt;br /&gt;
! Wert&lt;br /&gt;
| 0xAA || 0xAA     || 0x2D || 0xD4     || &#039;&#039;Daten&#039;&#039;  || 0xAA&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;API&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
void RFM12_MAC_setChannel(uint8_t channel);&lt;br /&gt;
&lt;br /&gt;
bool RFM12_MAC_isReceiving(void);&lt;br /&gt;
&lt;br /&gt;
bool RFM12_MAC_mediaBusy(void);&lt;br /&gt;
&lt;br /&gt;
void RFM12_MAC_startCtrlTransmission(void);&lt;br /&gt;
&lt;br /&gt;
void RFM12_MAC_endCtrlTransmission(void);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Logical Link Control (LLC) ===&lt;br /&gt;
&lt;br /&gt;
Der LLC-Layer kümmert sich um die Sicherung der zu übertragenden Daten.&lt;br /&gt;
Außerdem können Geräte direkt mit ihrer Adresse (8-Bit) angesprochen werden.&lt;br /&gt;
&lt;br /&gt;
;[http://de.wikipedia.org/wiki/Vorw%C3%A4rtsfehlerkorrektur FEC]&lt;br /&gt;
:Alle Bytes werden auf eine [[#Hamming-Tabelle|16-Bit Hamming-Sequenz]] erweitert, wodurch die Datenrate halbiert wird.&lt;br /&gt;
:Dies erlaubt es einzelne Bitfehler zu korrigieren.&lt;br /&gt;
:Bei zu vielen Fehlern können diese jedoch nicht erkannt werden.&lt;br /&gt;
:Im Hamming-Code kommt die Sequenz &#039;&#039;0xAA&#039;&#039; nicht vor (siehe MAC-Layer).&lt;br /&gt;
:Die FEC sorgt außerdem dafür, dass genügend 0-1 Transitionen vorkommen. So kann der Empfänger den Takt auch bei langen Paketen besser halten.&lt;br /&gt;
&lt;br /&gt;
;[http://de.wikipedia.org/wiki/Cyclic_Redundancy_Check CRC]&lt;br /&gt;
:Der gesamte Frame wird nochmals durch eine Checksumme gesichert. (CRC-8: &#039;&#039;x&amp;lt;sup&amp;gt;8&amp;lt;/sup&amp;gt; + x&amp;lt;sup&amp;gt;5&amp;lt;/sup&amp;gt; + x&amp;lt;sup&amp;gt;4&amp;lt;/sup&amp;gt; + 1&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Es werden mehrere Frame-Typen zur Verfügung gestellt:&lt;br /&gt;
&lt;br /&gt;
* Broadcast an alle Geräte (immer ohne ACK)&lt;br /&gt;
* Nachricht an ein bestimmtes Gerät (mit oder ohne ACK)&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|+ LLC Frameaufbau&lt;br /&gt;
|-&lt;br /&gt;
!&lt;br /&gt;
! Empfänger&lt;br /&gt;
! Sender&lt;br /&gt;
! need ACK&lt;br /&gt;
! is ACK&lt;br /&gt;
!&lt;br /&gt;
!&lt;br /&gt;
! TypeID&lt;br /&gt;
! &#039;&#039;0-28 Byte Daten&#039;&#039;&lt;br /&gt;
! CRC-8&lt;br /&gt;
|----&lt;br /&gt;
! Bits (vor FEC)&lt;br /&gt;
| 8      || 8      || 1 || 1 || 1 || 1 || 4 || 0-224 || 8&lt;br /&gt;
|-&lt;br /&gt;
! Bits (nach FEC)&lt;br /&gt;
| 16     || 16     || 2 || 2 || 2 || 2 || 8 || 0-448 || 16&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039; API &#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
void RFM12_LLC_registerType(RFM12_ProtocolID_t typeID, RFM12_L3_Protocol_t proto);&lt;br /&gt;
&lt;br /&gt;
uint8_t RFM12_LLC_sendFrame(RFM12_ProtocolID_t proto, uint8_t receiver, bool requireACK);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Layer 3: Network ==&lt;br /&gt;
&lt;br /&gt;
Für den Network-Layer werden nur einige Beispiele angeführt. Ab hier können beliebige eigene Protokolle eingesetzt werden. Das verwendete Protokoll wird durch die &#039;&#039;TypeID&#039;&#039; im LLC-Layer angegeben. Die Layer-3-Protokolle sollten nach Möglichkeit nur über die LLC-API mit dem Rest des Stacks kommunizieren.&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;TypeID&#039;&#039;s sind wie folgt definiert:&lt;br /&gt;
&lt;br /&gt;
=== Typ 0: Management ===&lt;br /&gt;
&lt;br /&gt;
Management Protokoll: Beacons etc.&lt;br /&gt;
&lt;br /&gt;
* Sollte ähnliche Funktionen bieten wie das Service Discovery Protocol (SDP) bei Bluetooth&lt;br /&gt;
&lt;br /&gt;
=== Typ 1: Bytestream ===&lt;br /&gt;
&lt;br /&gt;
Die Einteilung in Pakete wird aufgehoben. Daten kommen 1:1 in der Reihenfolge an, wie sie gesendet wurden.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;API&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
void RFM12_Serial_setPeer(uint8_t peer);&lt;br /&gt;
&lt;br /&gt;
bool RFM12_Serial_txAvailable(void);&lt;br /&gt;
&lt;br /&gt;
void RFM12_Serial_txData(uint8_t data);&lt;br /&gt;
&lt;br /&gt;
bool RFM12_Serial_rxAvailable(void);&lt;br /&gt;
&lt;br /&gt;
uint8_t RFM12_Serial_rxData(void);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Typ 3: IPv4 ===&lt;br /&gt;
&lt;br /&gt;
z.B. [http://www.sics.se/~adam/uip/index.php/Main_Page uIP TCP/IP Stack] von Adam Dunkels &amp;lt;adam@dunkels.com&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Anhänge ==&lt;br /&gt;
&lt;br /&gt;
=== Sequenzdiagramme ===&lt;br /&gt;
&lt;br /&gt;
Empfang:&lt;br /&gt;
[[Bild:RFM12 RX Sequence.svg|center|800px|RX Sequenz]]&lt;br /&gt;
&lt;br /&gt;
Senden:&lt;br /&gt;
[[Bild:RFM12 TX Sequence.svg|center|800px|TX Sequenz]]&lt;br /&gt;
&lt;br /&gt;
=== Frames ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Beachte:&#039;&#039;&#039; Durch die Hamming-Codierung sind alle Bytes innerhalb des MAC-Layer doppelt so lang wie angegeben!&lt;br /&gt;
{|&lt;br /&gt;
! bgcolor=&amp;quot;#9fffa8&amp;quot; | MAC || bgcolor=&amp;quot;#a9f3f2&amp;quot; | LLC || bgcolor=&amp;quot;#d28787&amp;quot; | L3&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; align=&amp;quot;center&amp;quot; style=&amp;quot;text-align:center&amp;quot;&lt;br /&gt;
|+ Frameaufbau&lt;br /&gt;
|-&lt;br /&gt;
!&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; bgcolor=&amp;quot;#9fffa8&amp;quot; | SOF&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; bgcolor=&amp;quot;#9fffa8&amp;quot; | Sync&lt;br /&gt;
! bgcolor=&amp;quot;#a9f3f2&amp;quot; | Empfänger&lt;br /&gt;
! bgcolor=&amp;quot;#a9f3f2&amp;quot; | Sender&lt;br /&gt;
! bgcolor=&amp;quot;#a9f3f2&amp;quot; | need ACK | is ACK | | | TypeID&lt;br /&gt;
! bgcolor=&amp;quot;#d28787&amp;quot; | &#039;&#039;0-28 Byte Daten&#039;&#039;&lt;br /&gt;
! bgcolor=&amp;quot;#a9f3f2&amp;quot; | CRC-8&lt;br /&gt;
! bgcolor=&amp;quot;#9fffa8&amp;quot; | EOF&lt;br /&gt;
|----&lt;br /&gt;
! Bits&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; bgcolor=&amp;quot;#9fffa8&amp;quot; | 16 || colspan=&amp;quot;2&amp;quot; bgcolor=&amp;quot;#9fffa8&amp;quot; | 16&lt;br /&gt;
| bgcolor=&amp;quot;#a9f3f2&amp;quot; | 8 || bgcolor=&amp;quot;#a9f3f2&amp;quot; | 8 || bgcolor=&amp;quot;#a9f3f2&amp;quot; | &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; 1 &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; | &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; 1 &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; |1|1| &amp;amp;nbsp;&amp;amp;nbsp; 4 &amp;amp;nbsp;&amp;amp;nbsp;&lt;br /&gt;
| bgcolor=&amp;quot;#d28787&amp;quot; | 0-224&lt;br /&gt;
| bgcolor=&amp;quot;#a9f3f2&amp;quot; | 8&lt;br /&gt;
| bgcolor=&amp;quot;#9fffa8&amp;quot; | 8&lt;br /&gt;
|----&lt;br /&gt;
! Wert&lt;br /&gt;
| bgcolor=&amp;quot;#9fffa8&amp;quot; | 0xAA || bgcolor=&amp;quot;#9fffa8&amp;quot; | 0xAA || bgcolor=&amp;quot;#9fffa8&amp;quot; | 0x2D || bgcolor=&amp;quot;#9fffa8&amp;quot; | 0xD4&lt;br /&gt;
| bgcolor=&amp;quot;#a9f3f2&amp;quot; | || bgcolor=&amp;quot;#a9f3f2&amp;quot; | || bgcolor=&amp;quot;#a9f3f2&amp;quot; | &lt;br /&gt;
| bgcolor=&amp;quot;#d28787&amp;quot; | &lt;br /&gt;
| bgcolor=&amp;quot;#a9f3f2&amp;quot; |&lt;br /&gt;
| bgcolor=&amp;quot;#9fffa8&amp;quot; | 0xAA&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Kanalzuordnung ===&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|+ 433MHz Band&lt;br /&gt;
|-&lt;br /&gt;
! Kanal&lt;br /&gt;
| 0 || 1 || 2 || 3 || 4 || 5 || 6 || 7 || 8 || 9 || 10 || 11 || 12 || 13 || 14 || 15&lt;br /&gt;
|-&lt;br /&gt;
! Mittenfrequenz&lt;br /&gt;
|  431.0 || 431.5 || 432.0 || 432.5 || 433.0 || 433.5 || 434.0 || 434.5 || 435.0 || 435.5 || 436.0 || 436.5 || 437.0 || 437.5 || 438.0 || 438.5&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Hamming-Tabelle ===&lt;br /&gt;
&lt;br /&gt;
==== Encodieren ====&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;3&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|&lt;br /&gt;
! colspan=&amp;quot;4&amp;quot; | Algorithmus&lt;br /&gt;
! colspan=&amp;quot;4&amp;quot; | Beispiel&lt;br /&gt;
|-&lt;br /&gt;
| 1:&lt;br /&gt;
| width=&amp;quot;80&amp;quot; |&lt;br /&gt;
| width=&amp;quot;160&amp;quot; colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 8-Bit Wert&lt;br /&gt;
| width=&amp;quot;160&amp;quot; colspan=&amp;quot;2&amp;quot; |&lt;br /&gt;
| width=&amp;quot;160&amp;quot; colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 10010110&lt;br /&gt;
| width=&amp;quot;80&amp;quot; |&lt;br /&gt;
|-&lt;br /&gt;
| 2: || || align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 4-7 ||  align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 0-3 || colspan=&amp;quot;2&amp;quot; | ||  align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 1001 || align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 0110 || &lt;br /&gt;
|-&lt;br /&gt;
| 3:&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | HammingE[(4-7)]&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | HammingE[(0-3)]&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 0xC7&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 0x38&lt;br /&gt;
|-&lt;br /&gt;
| 4:&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | high&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | low&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 11000111&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 00111000&lt;br /&gt;
|-&lt;br /&gt;
| 5:&lt;br /&gt;
| colspan=&amp;quot;4&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 16-Bit Codewort&lt;br /&gt;
| colspan=&amp;quot;4&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 11000111 00111000&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;3&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|+ HammingE&lt;br /&gt;
|-&lt;br /&gt;
!  0 || 1 || 2  || 3 || 4 || 5 || 6 || 7 || 8 || 9 || A || B || C || D || E || F&lt;br /&gt;
|-&lt;br /&gt;
|bgcolor=&amp;quot;#ff0000&amp;quot;|0x15||bgcolor=&amp;quot;#ff1111&amp;quot;|0x02||bgcolor=&amp;quot;#ff2222&amp;quot;|0x49||bgcolor=&amp;quot;#ff3333&amp;quot;|0x5E||bgcolor=&amp;quot;#ff4444&amp;quot;|0x64||bgcolor=&amp;quot;#ff5555&amp;quot;|0x73||bgcolor=&amp;quot;#ff6666&amp;quot;|0x38||bgcolor=&amp;quot;#ff7777&amp;quot;|0x2F||bgcolor=&amp;quot;#ff8888&amp;quot;|0xD0||bgcolor=&amp;quot;#ff9999&amp;quot;|0xC7||bgcolor=&amp;quot;#ffaaaa&amp;quot;|0x8C||bgcolor=&amp;quot;#ffbbbb&amp;quot;|0x9B||bgcolor=&amp;quot;#ffcccc&amp;quot;|0xA1||bgcolor=&amp;quot;#ffdddd&amp;quot;|0xB6||bgcolor=&amp;quot;#ffeeee&amp;quot;|0xFD||bgcolor=&amp;quot;#ffffff&amp;quot;|0xEA&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Die Einträge in der Tabelle sind so gewählt, dass der Code den maximalen [http://de.wikipedia.org/wiki/Hamming-Abstand#Hamming-Abstand_eines_Codes Hamming-Abstand] von 4 Bit hat.&lt;br /&gt;
&lt;br /&gt;
==== Dekodieren ====&lt;br /&gt;
&lt;br /&gt;
In der Tabelle &#039;&#039;HammingD&#039;&#039; stehen nur 4-Bit breite Werte. Um einen 8-Bit Wert zu erhalten müssen also 2 Einträge aus der Tabelle ausgewählt werden.&lt;br /&gt;
&lt;br /&gt;
Wird nun ein 16-Bit Wert empfangen, bestimmt das High-Byte den ersten Eintrag, das Low-Byte den zweiten.&lt;br /&gt;
&lt;br /&gt;
Es können bis zu zwei gekippte Bits im High- und im Low-Byte korrigiert werden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;3&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|&lt;br /&gt;
! colspan=&amp;quot;4&amp;quot; | Algorithmus || colspan=&amp;quot;4&amp;quot; | Beispiel (mit Bitfehlern)&lt;br /&gt;
|-&lt;br /&gt;
| 1:&lt;br /&gt;
| colspan=&amp;quot;4&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 16-Bit Codewort&lt;br /&gt;
| colspan=&amp;quot;4&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 110&#039;&#039;&#039;1&#039;&#039;&#039;0111 001&#039;&#039;&#039;0&#039;&#039;&#039;100&#039;&#039;&#039;1&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 2:&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | high&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | low&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 110&#039;&#039;&#039;1&#039;&#039;&#039;0111&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 001&#039;&#039;&#039;0&#039;&#039;&#039;100&#039;&#039;&#039;1&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 3:&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | HammingD[high]&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | HammingD[low]&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 0x09&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 0x06&lt;br /&gt;
|-&lt;br /&gt;
| 4: || || align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 4-7&lt;br /&gt;
| align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 0-3 || &lt;br /&gt;
| || align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 1001&lt;br /&gt;
| align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 0110 || &lt;br /&gt;
|-&lt;br /&gt;
| 5:&lt;br /&gt;
| width=&amp;quot;80&amp;quot; |&lt;br /&gt;
| width=&amp;quot;160&amp;quot; colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 8-Bit Wert&lt;br /&gt;
| width=&amp;quot;80&amp;quot; | || width=&amp;quot;80&amp;quot; |&lt;br /&gt;
| width=&amp;quot;160&amp;quot; colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 10010110&lt;br /&gt;
| width=&amp;quot;80&amp;quot; |&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;3&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|+ HammingD&lt;br /&gt;
|-&lt;br /&gt;
!  || 0 || 1 || 2  || 3 || 4 || 5 || 6 || 7 || 8 || 9 || A || B || C || D || E || F&lt;br /&gt;
|-&lt;br /&gt;
! 0&lt;br /&gt;
|bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ffaaAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07&lt;br /&gt;
|-&lt;br /&gt;
! 1&lt;br /&gt;
|bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03&lt;br /&gt;
|-&lt;br /&gt;
! 2&lt;br /&gt;
|bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07&lt;br /&gt;
|-&lt;br /&gt;
! 3&lt;br /&gt;
|bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07&lt;br /&gt;
|-&lt;br /&gt;
! 4&lt;br /&gt;
|bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03&lt;br /&gt;
|-&lt;br /&gt;
! 5&lt;br /&gt;
|bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03&lt;br /&gt;
|-&lt;br /&gt;
! 6&lt;br /&gt;
|bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07&lt;br /&gt;
|-&lt;br /&gt;
! 7&lt;br /&gt;
|bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07&lt;br /&gt;
|-&lt;br /&gt;
! 8&lt;br /&gt;
|bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B&lt;br /&gt;
|-&lt;br /&gt;
! 9&lt;br /&gt;
|bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B&lt;br /&gt;
|-&lt;br /&gt;
! A&lt;br /&gt;
|bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07&lt;br /&gt;
|-&lt;br /&gt;
! B&lt;br /&gt;
|bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F&lt;br /&gt;
|-&lt;br /&gt;
! C&lt;br /&gt;
|bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09&lt;br /&gt;
|-&lt;br /&gt;
! D&lt;br /&gt;
|bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B&lt;br /&gt;
|-&lt;br /&gt;
! E&lt;br /&gt;
|bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F&lt;br /&gt;
|-&lt;br /&gt;
! F&lt;br /&gt;
|bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Funk]]&lt;br /&gt;
[[Kategorie:Wettbewerb]]&lt;/div&gt;</summary>
		<author><name>Thymythos</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=RFM12_Protokoll_Stack&amp;diff=32564</id>
		<title>RFM12 Protokoll Stack</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=RFM12_Protokoll_Stack&amp;diff=32564"/>
		<updated>2008-11-18T08:51:48Z</updated>

		<summary type="html">&lt;p&gt;Thymythos: /* Frames */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Bild:RFM12 Stack.svg|right]]&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel beschreibt einen [http://de.wikipedia.org/wiki/ISO/OSI ISO/OSI] Protokoll [http://de.wikipedia.org/wiki/Protokollstack Stack] für den [[RFM12]] Funkchip.&amp;lt;br/&amp;gt;&lt;br /&gt;
Einige Hardwarebeispiele finden sich in [[AVR RFM12]].&amp;lt;br/&amp;gt;&lt;br /&gt;
Fehler und Anregungen können gerne auf der [[Diskussion:RFM12_Protokoll_Stack|Diskussionsseite]] besprochen werden.&lt;br /&gt;
&lt;br /&gt;
Eine Referenz-Implementierung für den [[AVR]] wird bereitgestellt:&lt;br /&gt;
{| style=&amp;quot;border:1px dashed green&amp;quot;&lt;br /&gt;
|&#039;&#039;svn://mikrocontroller.net/rfm12/trunk/RFM12_Stack&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
;Implementierungskriterien&lt;br /&gt;
* Wo möglich werden [http://de.wikipedia.org/wiki/R%C3%BCckruffunktion Callback]-Funktionen anstatt [http://de.wikipedia.org/wiki/First_In_%E2%80%93_First_Out FIFOs] verwendet um RAM zu sparen.&lt;br /&gt;
* Interruptgesteuerter Ablauf des Stacks&lt;br /&gt;
* Funktionen sollten nicht blockieren&lt;br /&gt;
&lt;br /&gt;
== Layer 1: Physical ==&lt;br /&gt;
&lt;br /&gt;
[[Bild:RFM12 PHY StateMachine.svg|thumb|320px|Layer1 State Diagram]]&lt;br /&gt;
&lt;br /&gt;
Der Physical-Layer kümmert sich um die direkte Ansteuerung des RFM12. Alle Funktionen des Chips werden als Software-API bereitgestellt.&lt;br /&gt;
&lt;br /&gt;
Folgende Eigenschaften sind bereits vom RFM12 vorgegeben:&lt;br /&gt;
&lt;br /&gt;
* [http://de.wikipedia.org/wiki/ISM-Band 70cm Band (433MHz)]&lt;br /&gt;
* [http://de.wikipedia.org/wiki/Frequenzumtastung FSK]-Modulation&lt;br /&gt;
* Sync-Erkennung auf &#039;&#039;0x2D 0xD4&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Definiert werden muss jedoch noch:&lt;br /&gt;
&lt;br /&gt;
* Baudrate&lt;br /&gt;
* Zuordnung von Frequenzen zu [[#Kanalzuordnung|Kanälen]]&lt;br /&gt;
* Bandbreite der Kanäle&lt;br /&gt;
* Management der Sendeleistung/Empfangsempfindlichkeit&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;API&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
void RFM12_PHY_modeTX(void);&lt;br /&gt;
&lt;br /&gt;
void RFM12_PHY_modeRX(void);&lt;br /&gt;
&lt;br /&gt;
bool RFM12_PHY_busy(void);&lt;br /&gt;
&lt;br /&gt;
void RFM12_setBaudrate(uint32_t baud);&lt;br /&gt;
&lt;br /&gt;
void RFM12_setCenterFrequency(uint16_t freq);&lt;br /&gt;
&lt;br /&gt;
void RFM12_setDataFilter(bool autoLock, bool fastMode, bool analog, uint8_t dqdThres);&lt;br /&gt;
&lt;br /&gt;
void RFM12_setReceiverBandwidth(RFM12_VDI_t vdi, RFM12_RxBW_t bandwidth, RFM12_GAIN_t gain, RFM12_RSSI_t drssi);&lt;br /&gt;
&lt;br /&gt;
void RFM12_setPowerManagement(bool enRX, bool enBB, bool startTX, bool enSynth, bool enOSC, bool enBat, bool enWkT, bool clkOff);&lt;br /&gt;
&lt;br /&gt;
void RFM12_setTransmitPower(RFM12_Power_t power, RFM12_TxDev_t deviation);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Layer 2: Data Link ==&lt;br /&gt;
&lt;br /&gt;
=== Media Access Control (MAC) ===&lt;br /&gt;
&lt;br /&gt;
Hier noch ein paar Anregungen zur Verbesserung des MAC: [http://www.comsoc.org/livepubs/surveys/public/2q00issue/gummalla.html]&lt;br /&gt;
&lt;br /&gt;
Der MAC-Layer ist sehr einfach gehalten und regelt den Zugriff auf das Medium. Hier soll ein [http://de.wikipedia.org/wiki/CSMA-CA CSMA/CA] Verfahren eingesetzt werden.&lt;br /&gt;
&lt;br /&gt;
# Im Grundzustand befindet sich der RFM12 im Empfangsmodus und wartet auf eine SYNC-Sequenz.&lt;br /&gt;
# Kommt eine Sendeanforderung, wird so lange gewartet bis das Medium frei ist, dann darf nach Ablauf einer (pseudo) zufälligen Zeitspanne gesendet werden.&lt;br /&gt;
# Wurde gerade ein Paket empfangen, darf sofort ein ACK gesendet werden.&lt;br /&gt;
&lt;br /&gt;
Der Frameaufbau ist teilweise vom RFM12 vorgegeben (SYNC-Erkennung). Der Start-Of-Frame (SOF) dient der Synchronisation. Als End-Of-Frame (EOF) wird ebenfalls die Sequenz &#039;&#039;0xAA&#039;&#039; verwendet. Diese darf im Datenteil nicht vorkommen!&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|+ MAC Frameaufbau&lt;br /&gt;
|-&lt;br /&gt;
!&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; | SOF&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; | Sync&lt;br /&gt;
! &#039;&#039;n Byte Daten&#039;&#039;&lt;br /&gt;
! EOF&lt;br /&gt;
|----&lt;br /&gt;
! Bits&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; | 16 || colspan=&amp;quot;2&amp;quot; | 16 || 0 - 512    || 8&lt;br /&gt;
|----&lt;br /&gt;
! Wert&lt;br /&gt;
| 0xAA || 0xAA     || 0x2D || 0xD4     || &#039;&#039;Daten&#039;&#039;  || 0xAA&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;API&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
void RFM12_MAC_setChannel(uint8_t channel);&lt;br /&gt;
&lt;br /&gt;
bool RFM12_MAC_isReceiving(void);&lt;br /&gt;
&lt;br /&gt;
bool RFM12_MAC_mediaBusy(void);&lt;br /&gt;
&lt;br /&gt;
void RFM12_MAC_startCtrlTransmission(void);&lt;br /&gt;
&lt;br /&gt;
void RFM12_MAC_endCtrlTransmission(void);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Logical Link Control (LLC) ===&lt;br /&gt;
&lt;br /&gt;
Der LLC-Layer kümmert sich um die Sicherung der zu übertragenden Daten.&lt;br /&gt;
Außerdem können Geräte direkt mit ihrer Adresse (8-Bit) angesprochen werden.&lt;br /&gt;
&lt;br /&gt;
;[http://de.wikipedia.org/wiki/Vorw%C3%A4rtsfehlerkorrektur FEC]&lt;br /&gt;
:Alle Bytes werden auf eine [[#Hamming-Tabelle|16-Bit Hamming-Sequenz]] erweitert, wodurch die Datenrate halbiert wird.&lt;br /&gt;
:Dies erlaubt es einzelne Bitfehler zu korrigieren.&lt;br /&gt;
:Bei zu vielen Fehlern können diese jedoch nicht erkannt werden.&lt;br /&gt;
:Im Hamming-Code kommt die Sequenz &#039;&#039;0xAA&#039;&#039; nicht vor (siehe MAC-Layer).&lt;br /&gt;
&lt;br /&gt;
;[http://de.wikipedia.org/wiki/Cyclic_Redundancy_Check CRC]&lt;br /&gt;
:Der gesamte Frame wird nochmals durch eine Checksumme gesichert. (CRC-8: &#039;&#039;x&amp;lt;sup&amp;gt;8&amp;lt;/sup&amp;gt; + x&amp;lt;sup&amp;gt;5&amp;lt;/sup&amp;gt; + x&amp;lt;sup&amp;gt;4&amp;lt;/sup&amp;gt; + 1&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Es werden mehrere Frame-Typen zur Verfügung gestellt:&lt;br /&gt;
&lt;br /&gt;
* Broadcast an alle Geräte (immer ohne ACK)&lt;br /&gt;
* Nachricht an ein bestimmtes Gerät (mit oder ohne ACK)&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|+ LLC Frameaufbau&lt;br /&gt;
|-&lt;br /&gt;
!&lt;br /&gt;
! Empfänger&lt;br /&gt;
! Sender&lt;br /&gt;
! need ACK&lt;br /&gt;
! is ACK&lt;br /&gt;
!&lt;br /&gt;
!&lt;br /&gt;
! TypeID&lt;br /&gt;
! &#039;&#039;0-28 Byte Daten&#039;&#039;&lt;br /&gt;
! CRC-8&lt;br /&gt;
|----&lt;br /&gt;
! Bits (vor FEC)&lt;br /&gt;
| 8      || 8      || 1 || 1 || 1 || 1 || 4 || 0-224 || 8&lt;br /&gt;
|-&lt;br /&gt;
! Bits (nach FEC)&lt;br /&gt;
| 16     || 16     || 2 || 2 || 2 || 2 || 8 || 0-448 || 16&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039; API &#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
void RFM12_LLC_registerType(RFM12_ProtocolID_t typeID, RFM12_L3_Protocol_t proto);&lt;br /&gt;
&lt;br /&gt;
uint8_t RFM12_LLC_sendFrame(RFM12_ProtocolID_t proto, uint8_t receiver, bool requireACK);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Layer 3: Network ==&lt;br /&gt;
&lt;br /&gt;
Für den Network-Layer werden nur einige Beispiele angeführt. Ab hier können beliebige eigene Protokolle eingesetzt werden. Das verwendete Protokoll wird durch die &#039;&#039;TypeID&#039;&#039; im LLC-Layer angegeben. Die Layer-3-Protokolle sollten nach Möglichkeit nur über die LLC-API mit dem Rest des Stacks kommunizieren.&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;TypeID&#039;&#039;s sind wie folgt definiert:&lt;br /&gt;
&lt;br /&gt;
=== Typ 0: Management ===&lt;br /&gt;
&lt;br /&gt;
Management Protokoll: Beacons etc.&lt;br /&gt;
&lt;br /&gt;
* Sollte ähnliche Funktionen bieten wie das Service Discovery Protocol (SDP) bei Bluetooth&lt;br /&gt;
&lt;br /&gt;
=== Typ 1: Bytestream ===&lt;br /&gt;
&lt;br /&gt;
Die Einteilung in Pakete wird aufgehoben. Daten kommen 1:1 in der Reihenfolge an, wie sie gesendet wurden.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;API&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
void RFM12_Serial_setPeer(uint8_t peer);&lt;br /&gt;
&lt;br /&gt;
bool RFM12_Serial_txAvailable(void);&lt;br /&gt;
&lt;br /&gt;
void RFM12_Serial_txData(uint8_t data);&lt;br /&gt;
&lt;br /&gt;
bool RFM12_Serial_rxAvailable(void);&lt;br /&gt;
&lt;br /&gt;
uint8_t RFM12_Serial_rxData(void);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Typ 3: IPv4 ===&lt;br /&gt;
&lt;br /&gt;
z.B. [http://www.sics.se/~adam/uip/index.php/Main_Page uIP TCP/IP Stack] von Adam Dunkels &amp;lt;adam@dunkels.com&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Anhänge ==&lt;br /&gt;
&lt;br /&gt;
=== Sequenzdiagramme ===&lt;br /&gt;
&lt;br /&gt;
Empfang:&lt;br /&gt;
[[Bild:RFM12 RX Sequence.svg|center|800px|RX Sequenz]]&lt;br /&gt;
&lt;br /&gt;
Senden:&lt;br /&gt;
[[Bild:RFM12 TX Sequence.svg|center|800px|TX Sequenz]]&lt;br /&gt;
&lt;br /&gt;
=== Frames ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Beachte:&#039;&#039;&#039; Durch die Hamming-Codierung sind alle Bytes innerhalb des MAC-Layer doppelt so lang wie angegeben!&lt;br /&gt;
{|&lt;br /&gt;
! bgcolor=&amp;quot;#9fffa8&amp;quot; | MAC || bgcolor=&amp;quot;#a9f3f2&amp;quot; | LLC || bgcolor=&amp;quot;#d28787&amp;quot; | L3&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; align=&amp;quot;center&amp;quot; style=&amp;quot;text-align:center&amp;quot;&lt;br /&gt;
|+ Frameaufbau&lt;br /&gt;
|-&lt;br /&gt;
!&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; bgcolor=&amp;quot;#9fffa8&amp;quot; | SOF&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; bgcolor=&amp;quot;#9fffa8&amp;quot; | Sync&lt;br /&gt;
! bgcolor=&amp;quot;#a9f3f2&amp;quot; | Empfänger&lt;br /&gt;
! bgcolor=&amp;quot;#a9f3f2&amp;quot; | Sender&lt;br /&gt;
! bgcolor=&amp;quot;#a9f3f2&amp;quot; | need ACK | is ACK | | | TypeID&lt;br /&gt;
! bgcolor=&amp;quot;#d28787&amp;quot; | &#039;&#039;0-28 Byte Daten&#039;&#039;&lt;br /&gt;
! bgcolor=&amp;quot;#a9f3f2&amp;quot; | CRC-8&lt;br /&gt;
! bgcolor=&amp;quot;#9fffa8&amp;quot; | EOF&lt;br /&gt;
|----&lt;br /&gt;
! Bits&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; bgcolor=&amp;quot;#9fffa8&amp;quot; | 16 || colspan=&amp;quot;2&amp;quot; bgcolor=&amp;quot;#9fffa8&amp;quot; | 16&lt;br /&gt;
| bgcolor=&amp;quot;#a9f3f2&amp;quot; | 8 || bgcolor=&amp;quot;#a9f3f2&amp;quot; | 8 || bgcolor=&amp;quot;#a9f3f2&amp;quot; | &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; 1 &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; | &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; 1 &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; |1|1| &amp;amp;nbsp;&amp;amp;nbsp; 4 &amp;amp;nbsp;&amp;amp;nbsp;&lt;br /&gt;
| bgcolor=&amp;quot;#d28787&amp;quot; | 0-224&lt;br /&gt;
| bgcolor=&amp;quot;#a9f3f2&amp;quot; | 8&lt;br /&gt;
| bgcolor=&amp;quot;#9fffa8&amp;quot; | 8&lt;br /&gt;
|----&lt;br /&gt;
! Wert&lt;br /&gt;
| bgcolor=&amp;quot;#9fffa8&amp;quot; | 0xAA || bgcolor=&amp;quot;#9fffa8&amp;quot; | 0xAA || bgcolor=&amp;quot;#9fffa8&amp;quot; | 0x2D || bgcolor=&amp;quot;#9fffa8&amp;quot; | 0xD4&lt;br /&gt;
| bgcolor=&amp;quot;#a9f3f2&amp;quot; | || bgcolor=&amp;quot;#a9f3f2&amp;quot; | || bgcolor=&amp;quot;#a9f3f2&amp;quot; | &lt;br /&gt;
| bgcolor=&amp;quot;#d28787&amp;quot; | &lt;br /&gt;
| bgcolor=&amp;quot;#a9f3f2&amp;quot; |&lt;br /&gt;
| bgcolor=&amp;quot;#9fffa8&amp;quot; | 0xAA&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Kanalzuordnung ===&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|+ 433MHz Band&lt;br /&gt;
|-&lt;br /&gt;
! Kanal&lt;br /&gt;
| 0 || 1 || 2 || 3 || 4 || 5 || 6 || 7 || 8 || 9 || 10 || 11 || 12 || 13 || 14 || 15&lt;br /&gt;
|-&lt;br /&gt;
! Mittenfrequenz&lt;br /&gt;
|  431.0 || 431.5 || 432.0 || 432.5 || 433.0 || 433.5 || 434.0 || 434.5 || 435.0 || 435.5 || 436.0 || 436.5 || 437.0 || 437.5 || 438.0 || 438.5&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Hamming-Tabelle ===&lt;br /&gt;
&lt;br /&gt;
==== Encodieren ====&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;3&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|&lt;br /&gt;
! colspan=&amp;quot;4&amp;quot; | Algorithmus&lt;br /&gt;
! colspan=&amp;quot;4&amp;quot; | Beispiel&lt;br /&gt;
|-&lt;br /&gt;
| 1:&lt;br /&gt;
| width=&amp;quot;80&amp;quot; |&lt;br /&gt;
| width=&amp;quot;160&amp;quot; colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 8-Bit Wert&lt;br /&gt;
| width=&amp;quot;160&amp;quot; colspan=&amp;quot;2&amp;quot; |&lt;br /&gt;
| width=&amp;quot;160&amp;quot; colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 10010110&lt;br /&gt;
| width=&amp;quot;80&amp;quot; |&lt;br /&gt;
|-&lt;br /&gt;
| 2: || || align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 4-7 ||  align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 0-3 || colspan=&amp;quot;2&amp;quot; | ||  align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 1001 || align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 0110 || &lt;br /&gt;
|-&lt;br /&gt;
| 3:&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | HammingE[(4-7)]&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | HammingE[(0-3)]&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 0xC7&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 0x38&lt;br /&gt;
|-&lt;br /&gt;
| 4:&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | high&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | low&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 11000111&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 00111000&lt;br /&gt;
|-&lt;br /&gt;
| 5:&lt;br /&gt;
| colspan=&amp;quot;4&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 16-Bit Codewort&lt;br /&gt;
| colspan=&amp;quot;4&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 11000111 00111000&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;3&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|+ HammingE&lt;br /&gt;
|-&lt;br /&gt;
!  0 || 1 || 2  || 3 || 4 || 5 || 6 || 7 || 8 || 9 || A || B || C || D || E || F&lt;br /&gt;
|-&lt;br /&gt;
|bgcolor=&amp;quot;#ff0000&amp;quot;|0x15||bgcolor=&amp;quot;#ff1111&amp;quot;|0x02||bgcolor=&amp;quot;#ff2222&amp;quot;|0x49||bgcolor=&amp;quot;#ff3333&amp;quot;|0x5E||bgcolor=&amp;quot;#ff4444&amp;quot;|0x64||bgcolor=&amp;quot;#ff5555&amp;quot;|0x73||bgcolor=&amp;quot;#ff6666&amp;quot;|0x38||bgcolor=&amp;quot;#ff7777&amp;quot;|0x2F||bgcolor=&amp;quot;#ff8888&amp;quot;|0xD0||bgcolor=&amp;quot;#ff9999&amp;quot;|0xC7||bgcolor=&amp;quot;#ffaaaa&amp;quot;|0x8C||bgcolor=&amp;quot;#ffbbbb&amp;quot;|0x9B||bgcolor=&amp;quot;#ffcccc&amp;quot;|0xA1||bgcolor=&amp;quot;#ffdddd&amp;quot;|0xB6||bgcolor=&amp;quot;#ffeeee&amp;quot;|0xFD||bgcolor=&amp;quot;#ffffff&amp;quot;|0xEA&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Die Einträge in der Tabelle sind so gewählt, dass der Code den maximalen [http://de.wikipedia.org/wiki/Hamming-Abstand#Hamming-Abstand_eines_Codes Hamming-Abstand] von 4 Bit hat.&lt;br /&gt;
&lt;br /&gt;
==== Dekodieren ====&lt;br /&gt;
&lt;br /&gt;
In der Tabelle &#039;&#039;HammingD&#039;&#039; stehen nur 4-Bit breite Werte. Um einen 8-Bit Wert zu erhalten müssen also 2 Einträge aus der Tabelle ausgewählt werden.&lt;br /&gt;
&lt;br /&gt;
Wird nun ein 16-Bit Wert empfangen, bestimmt das High-Byte den ersten Eintrag, das Low-Byte den zweiten.&lt;br /&gt;
&lt;br /&gt;
Es können bis zu zwei gekippte Bits im High- und im Low-Byte korrigiert werden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;3&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|&lt;br /&gt;
! colspan=&amp;quot;4&amp;quot; | Algorithmus || colspan=&amp;quot;4&amp;quot; | Beispiel (mit Bitfehlern)&lt;br /&gt;
|-&lt;br /&gt;
| 1:&lt;br /&gt;
| colspan=&amp;quot;4&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 16-Bit Codewort&lt;br /&gt;
| colspan=&amp;quot;4&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 110&#039;&#039;&#039;1&#039;&#039;&#039;0111 001&#039;&#039;&#039;0&#039;&#039;&#039;100&#039;&#039;&#039;1&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 2:&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | high&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | low&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 110&#039;&#039;&#039;1&#039;&#039;&#039;0111&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 001&#039;&#039;&#039;0&#039;&#039;&#039;100&#039;&#039;&#039;1&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 3:&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | HammingD[high]&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | HammingD[low]&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 0x09&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 0x06&lt;br /&gt;
|-&lt;br /&gt;
| 4: || || align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 4-7&lt;br /&gt;
| align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 0-3 || &lt;br /&gt;
| || align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 1001&lt;br /&gt;
| align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 0110 || &lt;br /&gt;
|-&lt;br /&gt;
| 5:&lt;br /&gt;
| width=&amp;quot;80&amp;quot; |&lt;br /&gt;
| width=&amp;quot;160&amp;quot; colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 8-Bit Wert&lt;br /&gt;
| width=&amp;quot;80&amp;quot; | || width=&amp;quot;80&amp;quot; |&lt;br /&gt;
| width=&amp;quot;160&amp;quot; colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 10010110&lt;br /&gt;
| width=&amp;quot;80&amp;quot; |&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;3&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|+ HammingD&lt;br /&gt;
|-&lt;br /&gt;
!  || 0 || 1 || 2  || 3 || 4 || 5 || 6 || 7 || 8 || 9 || A || B || C || D || E || F&lt;br /&gt;
|-&lt;br /&gt;
! 0&lt;br /&gt;
|bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ffaaAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07&lt;br /&gt;
|-&lt;br /&gt;
! 1&lt;br /&gt;
|bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03&lt;br /&gt;
|-&lt;br /&gt;
! 2&lt;br /&gt;
|bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07&lt;br /&gt;
|-&lt;br /&gt;
! 3&lt;br /&gt;
|bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07&lt;br /&gt;
|-&lt;br /&gt;
! 4&lt;br /&gt;
|bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03&lt;br /&gt;
|-&lt;br /&gt;
! 5&lt;br /&gt;
|bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03&lt;br /&gt;
|-&lt;br /&gt;
! 6&lt;br /&gt;
|bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07&lt;br /&gt;
|-&lt;br /&gt;
! 7&lt;br /&gt;
|bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07&lt;br /&gt;
|-&lt;br /&gt;
! 8&lt;br /&gt;
|bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B&lt;br /&gt;
|-&lt;br /&gt;
! 9&lt;br /&gt;
|bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B&lt;br /&gt;
|-&lt;br /&gt;
! A&lt;br /&gt;
|bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07&lt;br /&gt;
|-&lt;br /&gt;
! B&lt;br /&gt;
|bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F&lt;br /&gt;
|-&lt;br /&gt;
! C&lt;br /&gt;
|bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09&lt;br /&gt;
|-&lt;br /&gt;
! D&lt;br /&gt;
|bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B&lt;br /&gt;
|-&lt;br /&gt;
! E&lt;br /&gt;
|bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F&lt;br /&gt;
|-&lt;br /&gt;
! F&lt;br /&gt;
|bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Funk]]&lt;br /&gt;
[[Kategorie:Wettbewerb]]&lt;/div&gt;</summary>
		<author><name>Thymythos</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=RFM12_Protokoll_Stack&amp;diff=32563</id>
		<title>RFM12 Protokoll Stack</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=RFM12_Protokoll_Stack&amp;diff=32563"/>
		<updated>2008-11-18T08:50:39Z</updated>

		<summary type="html">&lt;p&gt;Thymythos: /* Logical Link Control (LLC) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Bild:RFM12 Stack.svg|right]]&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel beschreibt einen [http://de.wikipedia.org/wiki/ISO/OSI ISO/OSI] Protokoll [http://de.wikipedia.org/wiki/Protokollstack Stack] für den [[RFM12]] Funkchip.&amp;lt;br/&amp;gt;&lt;br /&gt;
Einige Hardwarebeispiele finden sich in [[AVR RFM12]].&amp;lt;br/&amp;gt;&lt;br /&gt;
Fehler und Anregungen können gerne auf der [[Diskussion:RFM12_Protokoll_Stack|Diskussionsseite]] besprochen werden.&lt;br /&gt;
&lt;br /&gt;
Eine Referenz-Implementierung für den [[AVR]] wird bereitgestellt:&lt;br /&gt;
{| style=&amp;quot;border:1px dashed green&amp;quot;&lt;br /&gt;
|&#039;&#039;svn://mikrocontroller.net/rfm12/trunk/RFM12_Stack&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
;Implementierungskriterien&lt;br /&gt;
* Wo möglich werden [http://de.wikipedia.org/wiki/R%C3%BCckruffunktion Callback]-Funktionen anstatt [http://de.wikipedia.org/wiki/First_In_%E2%80%93_First_Out FIFOs] verwendet um RAM zu sparen.&lt;br /&gt;
* Interruptgesteuerter Ablauf des Stacks&lt;br /&gt;
* Funktionen sollten nicht blockieren&lt;br /&gt;
&lt;br /&gt;
== Layer 1: Physical ==&lt;br /&gt;
&lt;br /&gt;
[[Bild:RFM12 PHY StateMachine.svg|thumb|320px|Layer1 State Diagram]]&lt;br /&gt;
&lt;br /&gt;
Der Physical-Layer kümmert sich um die direkte Ansteuerung des RFM12. Alle Funktionen des Chips werden als Software-API bereitgestellt.&lt;br /&gt;
&lt;br /&gt;
Folgende Eigenschaften sind bereits vom RFM12 vorgegeben:&lt;br /&gt;
&lt;br /&gt;
* [http://de.wikipedia.org/wiki/ISM-Band 70cm Band (433MHz)]&lt;br /&gt;
* [http://de.wikipedia.org/wiki/Frequenzumtastung FSK]-Modulation&lt;br /&gt;
* Sync-Erkennung auf &#039;&#039;0x2D 0xD4&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Definiert werden muss jedoch noch:&lt;br /&gt;
&lt;br /&gt;
* Baudrate&lt;br /&gt;
* Zuordnung von Frequenzen zu [[#Kanalzuordnung|Kanälen]]&lt;br /&gt;
* Bandbreite der Kanäle&lt;br /&gt;
* Management der Sendeleistung/Empfangsempfindlichkeit&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;API&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
void RFM12_PHY_modeTX(void);&lt;br /&gt;
&lt;br /&gt;
void RFM12_PHY_modeRX(void);&lt;br /&gt;
&lt;br /&gt;
bool RFM12_PHY_busy(void);&lt;br /&gt;
&lt;br /&gt;
void RFM12_setBaudrate(uint32_t baud);&lt;br /&gt;
&lt;br /&gt;
void RFM12_setCenterFrequency(uint16_t freq);&lt;br /&gt;
&lt;br /&gt;
void RFM12_setDataFilter(bool autoLock, bool fastMode, bool analog, uint8_t dqdThres);&lt;br /&gt;
&lt;br /&gt;
void RFM12_setReceiverBandwidth(RFM12_VDI_t vdi, RFM12_RxBW_t bandwidth, RFM12_GAIN_t gain, RFM12_RSSI_t drssi);&lt;br /&gt;
&lt;br /&gt;
void RFM12_setPowerManagement(bool enRX, bool enBB, bool startTX, bool enSynth, bool enOSC, bool enBat, bool enWkT, bool clkOff);&lt;br /&gt;
&lt;br /&gt;
void RFM12_setTransmitPower(RFM12_Power_t power, RFM12_TxDev_t deviation);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Layer 2: Data Link ==&lt;br /&gt;
&lt;br /&gt;
=== Media Access Control (MAC) ===&lt;br /&gt;
&lt;br /&gt;
Hier noch ein paar Anregungen zur Verbesserung des MAC: [http://www.comsoc.org/livepubs/surveys/public/2q00issue/gummalla.html]&lt;br /&gt;
&lt;br /&gt;
Der MAC-Layer ist sehr einfach gehalten und regelt den Zugriff auf das Medium. Hier soll ein [http://de.wikipedia.org/wiki/CSMA-CA CSMA/CA] Verfahren eingesetzt werden.&lt;br /&gt;
&lt;br /&gt;
# Im Grundzustand befindet sich der RFM12 im Empfangsmodus und wartet auf eine SYNC-Sequenz.&lt;br /&gt;
# Kommt eine Sendeanforderung, wird so lange gewartet bis das Medium frei ist, dann darf nach Ablauf einer (pseudo) zufälligen Zeitspanne gesendet werden.&lt;br /&gt;
# Wurde gerade ein Paket empfangen, darf sofort ein ACK gesendet werden.&lt;br /&gt;
&lt;br /&gt;
Der Frameaufbau ist teilweise vom RFM12 vorgegeben (SYNC-Erkennung). Der Start-Of-Frame (SOF) dient der Synchronisation. Als End-Of-Frame (EOF) wird ebenfalls die Sequenz &#039;&#039;0xAA&#039;&#039; verwendet. Diese darf im Datenteil nicht vorkommen!&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|+ MAC Frameaufbau&lt;br /&gt;
|-&lt;br /&gt;
!&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; | SOF&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; | Sync&lt;br /&gt;
! &#039;&#039;n Byte Daten&#039;&#039;&lt;br /&gt;
! EOF&lt;br /&gt;
|----&lt;br /&gt;
! Bits&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; | 16 || colspan=&amp;quot;2&amp;quot; | 16 || 0 - 512    || 8&lt;br /&gt;
|----&lt;br /&gt;
! Wert&lt;br /&gt;
| 0xAA || 0xAA     || 0x2D || 0xD4     || &#039;&#039;Daten&#039;&#039;  || 0xAA&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;API&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
void RFM12_MAC_setChannel(uint8_t channel);&lt;br /&gt;
&lt;br /&gt;
bool RFM12_MAC_isReceiving(void);&lt;br /&gt;
&lt;br /&gt;
bool RFM12_MAC_mediaBusy(void);&lt;br /&gt;
&lt;br /&gt;
void RFM12_MAC_startCtrlTransmission(void);&lt;br /&gt;
&lt;br /&gt;
void RFM12_MAC_endCtrlTransmission(void);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Logical Link Control (LLC) ===&lt;br /&gt;
&lt;br /&gt;
Der LLC-Layer kümmert sich um die Sicherung der zu übertragenden Daten.&lt;br /&gt;
Außerdem können Geräte direkt mit ihrer Adresse (8-Bit) angesprochen werden.&lt;br /&gt;
&lt;br /&gt;
;[http://de.wikipedia.org/wiki/Vorw%C3%A4rtsfehlerkorrektur FEC]&lt;br /&gt;
:Alle Bytes werden auf eine [[#Hamming-Tabelle|16-Bit Hamming-Sequenz]] erweitert, wodurch die Datenrate halbiert wird.&lt;br /&gt;
:Dies erlaubt es einzelne Bitfehler zu korrigieren.&lt;br /&gt;
:Bei zu vielen Fehlern können diese jedoch nicht erkannt werden.&lt;br /&gt;
:Im Hamming-Code kommt die Sequenz &#039;&#039;0xAA&#039;&#039; nicht vor (siehe MAC-Layer).&lt;br /&gt;
&lt;br /&gt;
;[http://de.wikipedia.org/wiki/Cyclic_Redundancy_Check CRC]&lt;br /&gt;
:Der gesamte Frame wird nochmals durch eine Checksumme gesichert. (CRC-8: &#039;&#039;x&amp;lt;sup&amp;gt;8&amp;lt;/sup&amp;gt; + x&amp;lt;sup&amp;gt;5&amp;lt;/sup&amp;gt; + x&amp;lt;sup&amp;gt;4&amp;lt;/sup&amp;gt; + 1&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Es werden mehrere Frame-Typen zur Verfügung gestellt:&lt;br /&gt;
&lt;br /&gt;
* Broadcast an alle Geräte (immer ohne ACK)&lt;br /&gt;
* Nachricht an ein bestimmtes Gerät (mit oder ohne ACK)&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|+ LLC Frameaufbau&lt;br /&gt;
|-&lt;br /&gt;
!&lt;br /&gt;
! Empfänger&lt;br /&gt;
! Sender&lt;br /&gt;
! need ACK&lt;br /&gt;
! is ACK&lt;br /&gt;
!&lt;br /&gt;
!&lt;br /&gt;
! TypeID&lt;br /&gt;
! &#039;&#039;0-28 Byte Daten&#039;&#039;&lt;br /&gt;
! CRC-8&lt;br /&gt;
|----&lt;br /&gt;
! Bits (vor FEC)&lt;br /&gt;
| 8      || 8      || 1 || 1 || 1 || 1 || 4 || 0-224 || 8&lt;br /&gt;
|-&lt;br /&gt;
! Bits (nach FEC)&lt;br /&gt;
| 16     || 16     || 2 || 2 || 2 || 2 || 8 || 0-448 || 16&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039; API &#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
void RFM12_LLC_registerType(RFM12_ProtocolID_t typeID, RFM12_L3_Protocol_t proto);&lt;br /&gt;
&lt;br /&gt;
uint8_t RFM12_LLC_sendFrame(RFM12_ProtocolID_t proto, uint8_t receiver, bool requireACK);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Layer 3: Network ==&lt;br /&gt;
&lt;br /&gt;
Für den Network-Layer werden nur einige Beispiele angeführt. Ab hier können beliebige eigene Protokolle eingesetzt werden. Das verwendete Protokoll wird durch die &#039;&#039;TypeID&#039;&#039; im LLC-Layer angegeben. Die Layer-3-Protokolle sollten nach Möglichkeit nur über die LLC-API mit dem Rest des Stacks kommunizieren.&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;TypeID&#039;&#039;s sind wie folgt definiert:&lt;br /&gt;
&lt;br /&gt;
=== Typ 0: Management ===&lt;br /&gt;
&lt;br /&gt;
Management Protokoll: Beacons etc.&lt;br /&gt;
&lt;br /&gt;
* Sollte ähnliche Funktionen bieten wie das Service Discovery Protocol (SDP) bei Bluetooth&lt;br /&gt;
&lt;br /&gt;
=== Typ 1: Bytestream ===&lt;br /&gt;
&lt;br /&gt;
Die Einteilung in Pakete wird aufgehoben. Daten kommen 1:1 in der Reihenfolge an, wie sie gesendet wurden.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;API&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
void RFM12_Serial_setPeer(uint8_t peer);&lt;br /&gt;
&lt;br /&gt;
bool RFM12_Serial_txAvailable(void);&lt;br /&gt;
&lt;br /&gt;
void RFM12_Serial_txData(uint8_t data);&lt;br /&gt;
&lt;br /&gt;
bool RFM12_Serial_rxAvailable(void);&lt;br /&gt;
&lt;br /&gt;
uint8_t RFM12_Serial_rxData(void);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Typ 3: IPv4 ===&lt;br /&gt;
&lt;br /&gt;
z.B. [http://www.sics.se/~adam/uip/index.php/Main_Page uIP TCP/IP Stack] von Adam Dunkels &amp;lt;adam@dunkels.com&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Anhänge ==&lt;br /&gt;
&lt;br /&gt;
=== Sequenzdiagramme ===&lt;br /&gt;
&lt;br /&gt;
Empfang:&lt;br /&gt;
[[Bild:RFM12 RX Sequence.svg|center|800px|RX Sequenz]]&lt;br /&gt;
&lt;br /&gt;
Senden:&lt;br /&gt;
[[Bild:RFM12 TX Sequence.svg|center|800px|TX Sequenz]]&lt;br /&gt;
&lt;br /&gt;
=== Frames ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Beachte:&#039;&#039;&#039; Durch die Hamming-Codierung sind alle Bytes innerhalb des MAC-Layer doppelt so lang wie angegeben!&lt;br /&gt;
{|&lt;br /&gt;
! bgcolor=&amp;quot;#9fffa8&amp;quot; | MAC || bgcolor=&amp;quot;#a9f3f2&amp;quot; | LLC || bgcolor=&amp;quot;#d28787&amp;quot; | L3&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; align=&amp;quot;center&amp;quot; style=&amp;quot;text-align:center&amp;quot;&lt;br /&gt;
|+ Frameaufbau&lt;br /&gt;
|-&lt;br /&gt;
!&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; bgcolor=&amp;quot;#9fffa8&amp;quot; | SOF&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; bgcolor=&amp;quot;#9fffa8&amp;quot; | Sync&lt;br /&gt;
! bgcolor=&amp;quot;#a9f3f2&amp;quot; | Empfänger&lt;br /&gt;
! bgcolor=&amp;quot;#a9f3f2&amp;quot; | Sender&lt;br /&gt;
! bgcolor=&amp;quot;#a9f3f2&amp;quot; | need ACK | is ACK | | | TypeID&lt;br /&gt;
! bgcolor=&amp;quot;#d28787&amp;quot; | &#039;&#039;n Byte Daten&#039;&#039;&lt;br /&gt;
! bgcolor=&amp;quot;#a9f3f2&amp;quot; | CRC-8&lt;br /&gt;
! bgcolor=&amp;quot;#9fffa8&amp;quot; | EOF&lt;br /&gt;
|----&lt;br /&gt;
! Bits&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; bgcolor=&amp;quot;#9fffa8&amp;quot; | 16 || colspan=&amp;quot;2&amp;quot; bgcolor=&amp;quot;#9fffa8&amp;quot; | 16&lt;br /&gt;
| bgcolor=&amp;quot;#a9f3f2&amp;quot; | 8 || bgcolor=&amp;quot;#a9f3f2&amp;quot; | 8 || bgcolor=&amp;quot;#a9f3f2&amp;quot; | &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; 1 &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; | &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; 1 &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; |1|1| &amp;amp;nbsp;&amp;amp;nbsp; 4 &amp;amp;nbsp;&amp;amp;nbsp;&lt;br /&gt;
| bgcolor=&amp;quot;#d28787&amp;quot; | 0-480&lt;br /&gt;
| bgcolor=&amp;quot;#a9f3f2&amp;quot; | 8&lt;br /&gt;
| bgcolor=&amp;quot;#9fffa8&amp;quot; | 8&lt;br /&gt;
|----&lt;br /&gt;
! Wert&lt;br /&gt;
| bgcolor=&amp;quot;#9fffa8&amp;quot; | 0xAA || bgcolor=&amp;quot;#9fffa8&amp;quot; | 0xAA || bgcolor=&amp;quot;#9fffa8&amp;quot; | 0x2D || bgcolor=&amp;quot;#9fffa8&amp;quot; | 0xD4&lt;br /&gt;
| bgcolor=&amp;quot;#a9f3f2&amp;quot; | || bgcolor=&amp;quot;#a9f3f2&amp;quot; | || bgcolor=&amp;quot;#a9f3f2&amp;quot; | &lt;br /&gt;
| bgcolor=&amp;quot;#d28787&amp;quot; | &lt;br /&gt;
| bgcolor=&amp;quot;#a9f3f2&amp;quot; |&lt;br /&gt;
| bgcolor=&amp;quot;#9fffa8&amp;quot; | 0xAA&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Kanalzuordnung ===&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|+ 433MHz Band&lt;br /&gt;
|-&lt;br /&gt;
! Kanal&lt;br /&gt;
| 0 || 1 || 2 || 3 || 4 || 5 || 6 || 7 || 8 || 9 || 10 || 11 || 12 || 13 || 14 || 15&lt;br /&gt;
|-&lt;br /&gt;
! Mittenfrequenz&lt;br /&gt;
|  431.0 || 431.5 || 432.0 || 432.5 || 433.0 || 433.5 || 434.0 || 434.5 || 435.0 || 435.5 || 436.0 || 436.5 || 437.0 || 437.5 || 438.0 || 438.5&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Hamming-Tabelle ===&lt;br /&gt;
&lt;br /&gt;
==== Encodieren ====&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;3&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|&lt;br /&gt;
! colspan=&amp;quot;4&amp;quot; | Algorithmus&lt;br /&gt;
! colspan=&amp;quot;4&amp;quot; | Beispiel&lt;br /&gt;
|-&lt;br /&gt;
| 1:&lt;br /&gt;
| width=&amp;quot;80&amp;quot; |&lt;br /&gt;
| width=&amp;quot;160&amp;quot; colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 8-Bit Wert&lt;br /&gt;
| width=&amp;quot;160&amp;quot; colspan=&amp;quot;2&amp;quot; |&lt;br /&gt;
| width=&amp;quot;160&amp;quot; colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 10010110&lt;br /&gt;
| width=&amp;quot;80&amp;quot; |&lt;br /&gt;
|-&lt;br /&gt;
| 2: || || align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 4-7 ||  align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 0-3 || colspan=&amp;quot;2&amp;quot; | ||  align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 1001 || align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 0110 || &lt;br /&gt;
|-&lt;br /&gt;
| 3:&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | HammingE[(4-7)]&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | HammingE[(0-3)]&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 0xC7&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 0x38&lt;br /&gt;
|-&lt;br /&gt;
| 4:&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | high&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | low&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 11000111&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 00111000&lt;br /&gt;
|-&lt;br /&gt;
| 5:&lt;br /&gt;
| colspan=&amp;quot;4&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 16-Bit Codewort&lt;br /&gt;
| colspan=&amp;quot;4&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 11000111 00111000&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;3&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|+ HammingE&lt;br /&gt;
|-&lt;br /&gt;
!  0 || 1 || 2  || 3 || 4 || 5 || 6 || 7 || 8 || 9 || A || B || C || D || E || F&lt;br /&gt;
|-&lt;br /&gt;
|bgcolor=&amp;quot;#ff0000&amp;quot;|0x15||bgcolor=&amp;quot;#ff1111&amp;quot;|0x02||bgcolor=&amp;quot;#ff2222&amp;quot;|0x49||bgcolor=&amp;quot;#ff3333&amp;quot;|0x5E||bgcolor=&amp;quot;#ff4444&amp;quot;|0x64||bgcolor=&amp;quot;#ff5555&amp;quot;|0x73||bgcolor=&amp;quot;#ff6666&amp;quot;|0x38||bgcolor=&amp;quot;#ff7777&amp;quot;|0x2F||bgcolor=&amp;quot;#ff8888&amp;quot;|0xD0||bgcolor=&amp;quot;#ff9999&amp;quot;|0xC7||bgcolor=&amp;quot;#ffaaaa&amp;quot;|0x8C||bgcolor=&amp;quot;#ffbbbb&amp;quot;|0x9B||bgcolor=&amp;quot;#ffcccc&amp;quot;|0xA1||bgcolor=&amp;quot;#ffdddd&amp;quot;|0xB6||bgcolor=&amp;quot;#ffeeee&amp;quot;|0xFD||bgcolor=&amp;quot;#ffffff&amp;quot;|0xEA&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Die Einträge in der Tabelle sind so gewählt, dass der Code den maximalen [http://de.wikipedia.org/wiki/Hamming-Abstand#Hamming-Abstand_eines_Codes Hamming-Abstand] von 4 Bit hat.&lt;br /&gt;
&lt;br /&gt;
==== Dekodieren ====&lt;br /&gt;
&lt;br /&gt;
In der Tabelle &#039;&#039;HammingD&#039;&#039; stehen nur 4-Bit breite Werte. Um einen 8-Bit Wert zu erhalten müssen also 2 Einträge aus der Tabelle ausgewählt werden.&lt;br /&gt;
&lt;br /&gt;
Wird nun ein 16-Bit Wert empfangen, bestimmt das High-Byte den ersten Eintrag, das Low-Byte den zweiten.&lt;br /&gt;
&lt;br /&gt;
Es können bis zu zwei gekippte Bits im High- und im Low-Byte korrigiert werden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;3&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|&lt;br /&gt;
! colspan=&amp;quot;4&amp;quot; | Algorithmus || colspan=&amp;quot;4&amp;quot; | Beispiel (mit Bitfehlern)&lt;br /&gt;
|-&lt;br /&gt;
| 1:&lt;br /&gt;
| colspan=&amp;quot;4&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 16-Bit Codewort&lt;br /&gt;
| colspan=&amp;quot;4&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 110&#039;&#039;&#039;1&#039;&#039;&#039;0111 001&#039;&#039;&#039;0&#039;&#039;&#039;100&#039;&#039;&#039;1&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 2:&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | high&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | low&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 110&#039;&#039;&#039;1&#039;&#039;&#039;0111&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 001&#039;&#039;&#039;0&#039;&#039;&#039;100&#039;&#039;&#039;1&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 3:&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | HammingD[high]&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | HammingD[low]&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 0x09&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 0x06&lt;br /&gt;
|-&lt;br /&gt;
| 4: || || align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 4-7&lt;br /&gt;
| align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 0-3 || &lt;br /&gt;
| || align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 1001&lt;br /&gt;
| align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 0110 || &lt;br /&gt;
|-&lt;br /&gt;
| 5:&lt;br /&gt;
| width=&amp;quot;80&amp;quot; |&lt;br /&gt;
| width=&amp;quot;160&amp;quot; colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 8-Bit Wert&lt;br /&gt;
| width=&amp;quot;80&amp;quot; | || width=&amp;quot;80&amp;quot; |&lt;br /&gt;
| width=&amp;quot;160&amp;quot; colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 10010110&lt;br /&gt;
| width=&amp;quot;80&amp;quot; |&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;3&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|+ HammingD&lt;br /&gt;
|-&lt;br /&gt;
!  || 0 || 1 || 2  || 3 || 4 || 5 || 6 || 7 || 8 || 9 || A || B || C || D || E || F&lt;br /&gt;
|-&lt;br /&gt;
! 0&lt;br /&gt;
|bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ffaaAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07&lt;br /&gt;
|-&lt;br /&gt;
! 1&lt;br /&gt;
|bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03&lt;br /&gt;
|-&lt;br /&gt;
! 2&lt;br /&gt;
|bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07&lt;br /&gt;
|-&lt;br /&gt;
! 3&lt;br /&gt;
|bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07&lt;br /&gt;
|-&lt;br /&gt;
! 4&lt;br /&gt;
|bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03&lt;br /&gt;
|-&lt;br /&gt;
! 5&lt;br /&gt;
|bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03&lt;br /&gt;
|-&lt;br /&gt;
! 6&lt;br /&gt;
|bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07&lt;br /&gt;
|-&lt;br /&gt;
! 7&lt;br /&gt;
|bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07&lt;br /&gt;
|-&lt;br /&gt;
! 8&lt;br /&gt;
|bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B&lt;br /&gt;
|-&lt;br /&gt;
! 9&lt;br /&gt;
|bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B&lt;br /&gt;
|-&lt;br /&gt;
! A&lt;br /&gt;
|bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07&lt;br /&gt;
|-&lt;br /&gt;
! B&lt;br /&gt;
|bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F&lt;br /&gt;
|-&lt;br /&gt;
! C&lt;br /&gt;
|bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09&lt;br /&gt;
|-&lt;br /&gt;
! D&lt;br /&gt;
|bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B&lt;br /&gt;
|-&lt;br /&gt;
! E&lt;br /&gt;
|bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F&lt;br /&gt;
|-&lt;br /&gt;
! F&lt;br /&gt;
|bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Funk]]&lt;br /&gt;
[[Kategorie:Wettbewerb]]&lt;/div&gt;</summary>
		<author><name>Thymythos</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=NesC&amp;diff=32516</id>
		<title>NesC</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=NesC&amp;diff=32516"/>
		<updated>2008-11-15T16:23:09Z</updated>

		<summary type="html">&lt;p&gt;Thymythos: Die Seite wurde neu angelegt: NesC ist eine Auszeichnungssprache für C, ähnlich dem C-Präprozessor. Der nesC Compiler &amp;#039;&amp;#039;ncc&amp;#039;&amp;#039; erweitert die Toolchain und wird als erstes aufgerufen. Er erzeugt au...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;NesC ist eine Auszeichnungssprache für C, ähnlich dem C-Präprozessor. Der nesC Compiler &#039;&#039;ncc&#039;&#039; erweitert die Toolchain und wird als erstes aufgerufen. Er erzeugt aus &#039;&#039;*.nc&#039;&#039; Dateien C-Quellcode.&lt;br /&gt;
&lt;br /&gt;
NesC wird im Betriebssystem [http://www.tinyos.net TinyOS] verwendet.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Beispiel:&#039;&#039;&#039; TimerMilliP.nc&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
// $Id: TimerMilliP.nc,v 1.5 2008/06/11 00:46:27 razvanm Exp $&lt;br /&gt;
/*&lt;br /&gt;
 * &amp;quot;Copyright (c) 2005 The Regents of the University  of California.  &lt;br /&gt;
 * All rights reserved.&lt;br /&gt;
 *&lt;br /&gt;
 * Permission to use, copy, modify, and distribute this software and its&lt;br /&gt;
 * documentation for any purpose, without fee, and without written agreement is&lt;br /&gt;
 * hereby granted, provided that the above copyright notice, the following&lt;br /&gt;
 * two paragraphs and the author appear in all copies of this software.&lt;br /&gt;
 * &lt;br /&gt;
 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR&lt;br /&gt;
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT&lt;br /&gt;
 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF&lt;br /&gt;
 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.&lt;br /&gt;
 * &lt;br /&gt;
 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,&lt;br /&gt;
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY&lt;br /&gt;
 * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS&lt;br /&gt;
 * ON AN &amp;quot;AS IS&amp;quot; BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO&lt;br /&gt;
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.&amp;quot;&lt;br /&gt;
 *&lt;br /&gt;
 */&lt;br /&gt;
/**&lt;br /&gt;
 * Components should never wire to this component. This is the&lt;br /&gt;
 * underlying configuration of virtualized millisecond timers. &lt;br /&gt;
 * It auto-wires wires the timer&lt;br /&gt;
 * implementation (TimerC) to the boot sequence and exports the&lt;br /&gt;
 * various Timer interfaces.&lt;br /&gt;
 *&lt;br /&gt;
 * @author Philip Levis&lt;br /&gt;
 * @author Cory Sharp&lt;br /&gt;
 * @date   May 16 2005&lt;br /&gt;
 */ &lt;br /&gt;
&lt;br /&gt;
#include &amp;quot;Timer.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
configuration TimerMilliP {&lt;br /&gt;
  provides interface Timer&amp;lt;TMilli&amp;gt; as TimerMilli[uint8_t id];&lt;br /&gt;
}&lt;br /&gt;
implementation {&lt;br /&gt;
  components HilTimerMilliC, MainC;&lt;br /&gt;
  MainC.SoftwareInit -&amp;gt; HilTimerMilliC;&lt;br /&gt;
  TimerMilli = HilTimerMilliC;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
* Sourceforge: [http://sf.net/projects/nescc]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Programmiersprachen]]&lt;/div&gt;</summary>
		<author><name>Thymythos</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=RFM12_Protokoll_Stack&amp;diff=32488</id>
		<title>RFM12 Protokoll Stack</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=RFM12_Protokoll_Stack&amp;diff=32488"/>
		<updated>2008-11-12T17:42:42Z</updated>

		<summary type="html">&lt;p&gt;Thymythos: /* Layer 2: Data Link */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Bild:RFM12 Stack.svg|right]]&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel beschreibt einen [http://de.wikipedia.org/wiki/ISO/OSI ISO/OSI] Protokoll [http://de.wikipedia.org/wiki/Protokollstack Stack] für den [[RFM12]] Funkchip.&amp;lt;br/&amp;gt;&lt;br /&gt;
Einige Hardwarebeispiele finden sich in [[AVR RFM12]].&amp;lt;br/&amp;gt;&lt;br /&gt;
Fehler und Anregungen können gerne auf der [[Diskussion:RFM12_Protokoll_Stack|Diskussionsseite]] besprochen werden.&lt;br /&gt;
&lt;br /&gt;
Eine Referenz-Implementierung für den [[AVR]] wird bereitgestellt:&lt;br /&gt;
{| style=&amp;quot;border:1px dashed green&amp;quot;&lt;br /&gt;
|&#039;&#039;svn://mikrocontroller.net/rfm12/trunk/RFM12_Stack&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
;Implementierungskriterien&lt;br /&gt;
* Wo möglich werden [http://de.wikipedia.org/wiki/R%C3%BCckruffunktion Callback]-Funktionen anstatt [http://de.wikipedia.org/wiki/First_In_%E2%80%93_First_Out FIFOs] verwendet um RAM zu sparen.&lt;br /&gt;
* Interruptgesteuerter Ablauf des Stacks&lt;br /&gt;
* Funktionen sollten nicht blockieren&lt;br /&gt;
&lt;br /&gt;
== Layer 1: Physical ==&lt;br /&gt;
&lt;br /&gt;
[[Bild:RFM12 PHY StateMachine.svg|thumb|320px|Layer1 State Diagram]]&lt;br /&gt;
&lt;br /&gt;
Der Physical-Layer kümmert sich um die direkte Ansteuerung des RFM12. Alle Funktionen des Chips werden als Software-API bereitgestellt.&lt;br /&gt;
&lt;br /&gt;
Folgende Eigenschaften sind bereits vom RFM12 vorgegeben:&lt;br /&gt;
&lt;br /&gt;
* [http://de.wikipedia.org/wiki/ISM-Band 70cm Band (433MHz)]&lt;br /&gt;
* [http://de.wikipedia.org/wiki/Frequenzumtastung FSK]-Modulation&lt;br /&gt;
* Sync-Erkennung auf &#039;&#039;0x2D 0xD4&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Definiert werden muss jedoch noch:&lt;br /&gt;
&lt;br /&gt;
* Baudrate&lt;br /&gt;
* Zuordnung von Frequenzen zu [[#Kanalzuordnung|Kanälen]]&lt;br /&gt;
* Bandbreite der Kanäle&lt;br /&gt;
* Management der Sendeleistung/Empfangsempfindlichkeit&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;API&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
void RFM12_PHY_modeTX(void);&lt;br /&gt;
&lt;br /&gt;
void RFM12_PHY_modeRX(void);&lt;br /&gt;
&lt;br /&gt;
bool RFM12_PHY_busy(void);&lt;br /&gt;
&lt;br /&gt;
void RFM12_setBaudrate(uint32_t baud);&lt;br /&gt;
&lt;br /&gt;
void RFM12_setCenterFrequency(uint16_t freq);&lt;br /&gt;
&lt;br /&gt;
void RFM12_setDataFilter(bool autoLock, bool fastMode, bool analog, uint8_t dqdThres);&lt;br /&gt;
&lt;br /&gt;
void RFM12_setReceiverBandwidth(RFM12_VDI_t vdi, RFM12_RxBW_t bandwidth, RFM12_GAIN_t gain, RFM12_RSSI_t drssi);&lt;br /&gt;
&lt;br /&gt;
void RFM12_setPowerManagement(bool enRX, bool enBB, bool startTX, bool enSynth, bool enOSC, bool enBat, bool enWkT, bool clkOff);&lt;br /&gt;
&lt;br /&gt;
void RFM12_setTransmitPower(RFM12_Power_t power, RFM12_TxDev_t deviation);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Layer 2: Data Link ==&lt;br /&gt;
&lt;br /&gt;
=== Media Access Control (MAC) ===&lt;br /&gt;
&lt;br /&gt;
Hier noch ein paar Anregungen zur Verbesserung des MAC: [http://www.comsoc.org/livepubs/surveys/public/2q00issue/gummalla.html]&lt;br /&gt;
&lt;br /&gt;
Der MAC-Layer ist sehr einfach gehalten und regelt den Zugriff auf das Medium. Hier soll ein [http://de.wikipedia.org/wiki/CSMA-CA CSMA/CA] Verfahren eingesetzt werden.&lt;br /&gt;
&lt;br /&gt;
# Im Grundzustand befindet sich der RFM12 im Empfangsmodus und wartet auf eine SYNC-Sequenz.&lt;br /&gt;
# Kommt eine Sendeanforderung, wird so lange gewartet bis das Medium frei ist, dann darf nach Ablauf einer (pseudo) zufälligen Zeitspanne gesendet werden.&lt;br /&gt;
# Wurde gerade ein Paket empfangen, darf sofort ein ACK gesendet werden.&lt;br /&gt;
&lt;br /&gt;
Der Frameaufbau ist teilweise vom RFM12 vorgegeben (SYNC-Erkennung). Der Start-Of-Frame (SOF) dient der Synchronisation. Als End-Of-Frame (EOF) wird ebenfalls die Sequenz &#039;&#039;0xAA&#039;&#039; verwendet. Diese darf im Datenteil nicht vorkommen!&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|+ MAC Frameaufbau&lt;br /&gt;
|-&lt;br /&gt;
!&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; | SOF&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; | Sync&lt;br /&gt;
! &#039;&#039;n Byte Daten&#039;&#039;&lt;br /&gt;
! EOF&lt;br /&gt;
|----&lt;br /&gt;
! Bits&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; | 16 || colspan=&amp;quot;2&amp;quot; | 16 || 0 - 512    || 8&lt;br /&gt;
|----&lt;br /&gt;
! Wert&lt;br /&gt;
| 0xAA || 0xAA     || 0x2D || 0xD4     || &#039;&#039;Daten&#039;&#039;  || 0xAA&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;API&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
void RFM12_MAC_setChannel(uint8_t channel);&lt;br /&gt;
&lt;br /&gt;
bool RFM12_MAC_isReceiving(void);&lt;br /&gt;
&lt;br /&gt;
bool RFM12_MAC_mediaBusy(void);&lt;br /&gt;
&lt;br /&gt;
void RFM12_MAC_startCtrlTransmission(void);&lt;br /&gt;
&lt;br /&gt;
void RFM12_MAC_endCtrlTransmission(void);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Logical Link Control (LLC) ===&lt;br /&gt;
&lt;br /&gt;
Der LLC-Layer kümmert sich um die Sicherung der zu übertragenden Daten.&lt;br /&gt;
Außerdem können Geräte direkt mit ihrer Adresse (8-Bit) angesprochen werden.&lt;br /&gt;
&lt;br /&gt;
;[http://de.wikipedia.org/wiki/Vorw%C3%A4rtsfehlerkorrektur FEC]&lt;br /&gt;
:Alle Bytes werden auf eine [[#Hamming-Tabelle|16-Bit Hamming-Sequenz]] erweitert, wodurch die Datenrate halbiert wird.&lt;br /&gt;
:Dies erlaubt es einzelne Bitfehler zu korrigieren.&lt;br /&gt;
:Bei zu vielen Fehlern können diese jedoch nicht erkannt werden.&lt;br /&gt;
:Im Hamming-Code kommt die Sequenz &#039;&#039;0xAA&#039;&#039; nicht vor (siehe MAC-Layer).&lt;br /&gt;
&lt;br /&gt;
;[http://de.wikipedia.org/wiki/Cyclic_Redundancy_Check CRC]&lt;br /&gt;
:Der gesamte Frame wird nochmals durch eine Checksumme gesichert. (CRC-8: &#039;&#039;x&amp;lt;sup&amp;gt;8&amp;lt;/sup&amp;gt; + x&amp;lt;sup&amp;gt;5&amp;lt;/sup&amp;gt; + x&amp;lt;sup&amp;gt;4&amp;lt;/sup&amp;gt; + 1&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Es werden mehrere Frame-Typen zur Verfügung gestellt:&lt;br /&gt;
&lt;br /&gt;
* Broadcast an alle Geräte (immer ohne ACK)&lt;br /&gt;
* Nachricht an ein bestimmtes Gerät (mit oder ohne ACK)&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|+ LLC Frameaufbau&lt;br /&gt;
|-&lt;br /&gt;
!&lt;br /&gt;
! Empfänger&lt;br /&gt;
! Sender&lt;br /&gt;
! need ACK&lt;br /&gt;
! is ACK&lt;br /&gt;
!&lt;br /&gt;
!&lt;br /&gt;
! TypeID&lt;br /&gt;
! &#039;&#039;n Byte Daten&#039;&#039;&lt;br /&gt;
! CRC-8&lt;br /&gt;
|----&lt;br /&gt;
! Bits&lt;br /&gt;
| 8      || 8      || 1 || 1 || 1 || 1 || 4 || 0-480 || 8&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039; API &#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
void RFM12_LLC_registerType(RFM12_ProtocolID_t typeID, RFM12_L3_Protocol_t proto);&lt;br /&gt;
&lt;br /&gt;
uint8_t RFM12_LLC_sendFrame(RFM12_ProtocolID_t proto, uint8_t receiver, bool requireACK);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Layer 3: Network ==&lt;br /&gt;
&lt;br /&gt;
Für den Network-Layer werden nur einige Beispiele angeführt. Ab hier können beliebige eigene Protokolle eingesetzt werden. Das verwendete Protokoll wird durch die &#039;&#039;TypeID&#039;&#039; im LLC-Layer angegeben. Die Layer-3-Protokolle sollten nach Möglichkeit nur über die LLC-API mit dem Rest des Stacks kommunizieren.&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;TypeID&#039;&#039;s sind wie folgt definiert:&lt;br /&gt;
&lt;br /&gt;
=== Typ 0: Management ===&lt;br /&gt;
&lt;br /&gt;
Management Protokoll: Beacons etc.&lt;br /&gt;
&lt;br /&gt;
* Sollte ähnliche Funktionen bieten wie das Service Discovery Protocol (SDP) bei Bluetooth&lt;br /&gt;
&lt;br /&gt;
=== Typ 1: Bytestream ===&lt;br /&gt;
&lt;br /&gt;
Die Einteilung in Pakete wird aufgehoben. Daten kommen 1:1 in der Reihenfolge an, wie sie gesendet wurden.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;API&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
void RFM12_Serial_setPeer(uint8_t peer);&lt;br /&gt;
&lt;br /&gt;
bool RFM12_Serial_txAvailable(void);&lt;br /&gt;
&lt;br /&gt;
void RFM12_Serial_txData(uint8_t data);&lt;br /&gt;
&lt;br /&gt;
bool RFM12_Serial_rxAvailable(void);&lt;br /&gt;
&lt;br /&gt;
uint8_t RFM12_Serial_rxData(void);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Typ 3: IPv4 ===&lt;br /&gt;
&lt;br /&gt;
z.B. [http://www.sics.se/~adam/uip/index.php/Main_Page uIP TCP/IP Stack] von Adam Dunkels &amp;lt;adam@dunkels.com&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Anhänge ==&lt;br /&gt;
&lt;br /&gt;
=== Sequenzdiagramme ===&lt;br /&gt;
&lt;br /&gt;
Empfang:&lt;br /&gt;
[[Bild:RFM12 RX Sequence.svg|center|800px|RX Sequenz]]&lt;br /&gt;
&lt;br /&gt;
Senden:&lt;br /&gt;
[[Bild:RFM12 TX Sequence.svg|center|800px|TX Sequenz]]&lt;br /&gt;
&lt;br /&gt;
=== Frames ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Beachte:&#039;&#039;&#039; Durch die Hamming-Codierung sind alle Bytes innerhalb des MAC-Layer doppelt so lang wie angegeben!&lt;br /&gt;
{|&lt;br /&gt;
! bgcolor=&amp;quot;#9fffa8&amp;quot; | MAC || bgcolor=&amp;quot;#a9f3f2&amp;quot; | LLC || bgcolor=&amp;quot;#d28787&amp;quot; | L3&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; align=&amp;quot;center&amp;quot; style=&amp;quot;text-align:center&amp;quot;&lt;br /&gt;
|+ Frameaufbau&lt;br /&gt;
|-&lt;br /&gt;
!&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; bgcolor=&amp;quot;#9fffa8&amp;quot; | SOF&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; bgcolor=&amp;quot;#9fffa8&amp;quot; | Sync&lt;br /&gt;
! bgcolor=&amp;quot;#a9f3f2&amp;quot; | Empfänger&lt;br /&gt;
! bgcolor=&amp;quot;#a9f3f2&amp;quot; | Sender&lt;br /&gt;
! bgcolor=&amp;quot;#a9f3f2&amp;quot; | need ACK | is ACK | | | TypeID&lt;br /&gt;
! bgcolor=&amp;quot;#d28787&amp;quot; | &#039;&#039;n Byte Daten&#039;&#039;&lt;br /&gt;
! bgcolor=&amp;quot;#a9f3f2&amp;quot; | CRC-8&lt;br /&gt;
! bgcolor=&amp;quot;#9fffa8&amp;quot; | EOF&lt;br /&gt;
|----&lt;br /&gt;
! Bits&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; bgcolor=&amp;quot;#9fffa8&amp;quot; | 16 || colspan=&amp;quot;2&amp;quot; bgcolor=&amp;quot;#9fffa8&amp;quot; | 16&lt;br /&gt;
| bgcolor=&amp;quot;#a9f3f2&amp;quot; | 8 || bgcolor=&amp;quot;#a9f3f2&amp;quot; | 8 || bgcolor=&amp;quot;#a9f3f2&amp;quot; | &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; 1 &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; | &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; 1 &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; |1|1| &amp;amp;nbsp;&amp;amp;nbsp; 4 &amp;amp;nbsp;&amp;amp;nbsp;&lt;br /&gt;
| bgcolor=&amp;quot;#d28787&amp;quot; | 0-480&lt;br /&gt;
| bgcolor=&amp;quot;#a9f3f2&amp;quot; | 8&lt;br /&gt;
| bgcolor=&amp;quot;#9fffa8&amp;quot; | 8&lt;br /&gt;
|----&lt;br /&gt;
! Wert&lt;br /&gt;
| bgcolor=&amp;quot;#9fffa8&amp;quot; | 0xAA || bgcolor=&amp;quot;#9fffa8&amp;quot; | 0xAA || bgcolor=&amp;quot;#9fffa8&amp;quot; | 0x2D || bgcolor=&amp;quot;#9fffa8&amp;quot; | 0xD4&lt;br /&gt;
| bgcolor=&amp;quot;#a9f3f2&amp;quot; | || bgcolor=&amp;quot;#a9f3f2&amp;quot; | || bgcolor=&amp;quot;#a9f3f2&amp;quot; | &lt;br /&gt;
| bgcolor=&amp;quot;#d28787&amp;quot; | &lt;br /&gt;
| bgcolor=&amp;quot;#a9f3f2&amp;quot; |&lt;br /&gt;
| bgcolor=&amp;quot;#9fffa8&amp;quot; | 0xAA&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Kanalzuordnung ===&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|+ 433MHz Band&lt;br /&gt;
|-&lt;br /&gt;
! Kanal&lt;br /&gt;
| 0 || 1 || 2 || 3 || 4 || 5 || 6 || 7 || 8 || 9 || 10 || 11 || 12 || 13 || 14 || 15&lt;br /&gt;
|-&lt;br /&gt;
! Mittenfrequenz&lt;br /&gt;
|  431.0 || 431.5 || 432.0 || 432.5 || 433.0 || 433.5 || 434.0 || 434.5 || 435.0 || 435.5 || 436.0 || 436.5 || 437.0 || 437.5 || 438.0 || 438.5&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Hamming-Tabelle ===&lt;br /&gt;
&lt;br /&gt;
==== Encodieren ====&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;3&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|&lt;br /&gt;
! colspan=&amp;quot;4&amp;quot; | Algorithmus&lt;br /&gt;
! colspan=&amp;quot;4&amp;quot; | Beispiel&lt;br /&gt;
|-&lt;br /&gt;
| 1:&lt;br /&gt;
| width=&amp;quot;80&amp;quot; |&lt;br /&gt;
| width=&amp;quot;160&amp;quot; colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 8-Bit Wert&lt;br /&gt;
| width=&amp;quot;160&amp;quot; colspan=&amp;quot;2&amp;quot; |&lt;br /&gt;
| width=&amp;quot;160&amp;quot; colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 10010110&lt;br /&gt;
| width=&amp;quot;80&amp;quot; |&lt;br /&gt;
|-&lt;br /&gt;
| 2: || || align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 4-7 ||  align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 0-3 || colspan=&amp;quot;2&amp;quot; | ||  align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 1001 || align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 0110 || &lt;br /&gt;
|-&lt;br /&gt;
| 3:&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | HammingE[(4-7)]&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | HammingE[(0-3)]&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 0xC7&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 0x38&lt;br /&gt;
|-&lt;br /&gt;
| 4:&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | high&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | low&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 11000111&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 00111000&lt;br /&gt;
|-&lt;br /&gt;
| 5:&lt;br /&gt;
| colspan=&amp;quot;4&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 16-Bit Codewort&lt;br /&gt;
| colspan=&amp;quot;4&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 11000111 00111000&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;3&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|+ HammingE&lt;br /&gt;
|-&lt;br /&gt;
!  0 || 1 || 2  || 3 || 4 || 5 || 6 || 7 || 8 || 9 || A || B || C || D || E || F&lt;br /&gt;
|-&lt;br /&gt;
|bgcolor=&amp;quot;#ff0000&amp;quot;|0x15||bgcolor=&amp;quot;#ff1111&amp;quot;|0x02||bgcolor=&amp;quot;#ff2222&amp;quot;|0x49||bgcolor=&amp;quot;#ff3333&amp;quot;|0x5E||bgcolor=&amp;quot;#ff4444&amp;quot;|0x64||bgcolor=&amp;quot;#ff5555&amp;quot;|0x73||bgcolor=&amp;quot;#ff6666&amp;quot;|0x38||bgcolor=&amp;quot;#ff7777&amp;quot;|0x2F||bgcolor=&amp;quot;#ff8888&amp;quot;|0xD0||bgcolor=&amp;quot;#ff9999&amp;quot;|0xC7||bgcolor=&amp;quot;#ffaaaa&amp;quot;|0x8C||bgcolor=&amp;quot;#ffbbbb&amp;quot;|0x9B||bgcolor=&amp;quot;#ffcccc&amp;quot;|0xA1||bgcolor=&amp;quot;#ffdddd&amp;quot;|0xB6||bgcolor=&amp;quot;#ffeeee&amp;quot;|0xFD||bgcolor=&amp;quot;#ffffff&amp;quot;|0xEA&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Die Einträge in der Tabelle sind so gewählt, dass der Code den maximalen [http://de.wikipedia.org/wiki/Hamming-Abstand#Hamming-Abstand_eines_Codes Hamming-Abstand] von 4 Bit hat.&lt;br /&gt;
&lt;br /&gt;
==== Dekodieren ====&lt;br /&gt;
&lt;br /&gt;
In der Tabelle &#039;&#039;HammingD&#039;&#039; stehen nur 4-Bit breite Werte. Um einen 8-Bit Wert zu erhalten müssen also 2 Einträge aus der Tabelle ausgewählt werden.&lt;br /&gt;
&lt;br /&gt;
Wird nun ein 16-Bit Wert empfangen, bestimmt das High-Byte den ersten Eintrag, das Low-Byte den zweiten.&lt;br /&gt;
&lt;br /&gt;
Es können bis zu zwei gekippte Bits im High- und im Low-Byte korrigiert werden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;3&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|&lt;br /&gt;
! colspan=&amp;quot;4&amp;quot; | Algorithmus || colspan=&amp;quot;4&amp;quot; | Beispiel (mit Bitfehlern)&lt;br /&gt;
|-&lt;br /&gt;
| 1:&lt;br /&gt;
| colspan=&amp;quot;4&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 16-Bit Codewort&lt;br /&gt;
| colspan=&amp;quot;4&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 110&#039;&#039;&#039;1&#039;&#039;&#039;0111 001&#039;&#039;&#039;0&#039;&#039;&#039;100&#039;&#039;&#039;1&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 2:&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | high&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | low&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 110&#039;&#039;&#039;1&#039;&#039;&#039;0111&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 001&#039;&#039;&#039;0&#039;&#039;&#039;100&#039;&#039;&#039;1&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 3:&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | HammingD[high]&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | HammingD[low]&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 0x09&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 0x06&lt;br /&gt;
|-&lt;br /&gt;
| 4: || || align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 4-7&lt;br /&gt;
| align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 0-3 || &lt;br /&gt;
| || align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 1001&lt;br /&gt;
| align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 0110 || &lt;br /&gt;
|-&lt;br /&gt;
| 5:&lt;br /&gt;
| width=&amp;quot;80&amp;quot; |&lt;br /&gt;
| width=&amp;quot;160&amp;quot; colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 8-Bit Wert&lt;br /&gt;
| width=&amp;quot;80&amp;quot; | || width=&amp;quot;80&amp;quot; |&lt;br /&gt;
| width=&amp;quot;160&amp;quot; colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 10010110&lt;br /&gt;
| width=&amp;quot;80&amp;quot; |&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;3&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|+ HammingD&lt;br /&gt;
|-&lt;br /&gt;
!  || 0 || 1 || 2  || 3 || 4 || 5 || 6 || 7 || 8 || 9 || A || B || C || D || E || F&lt;br /&gt;
|-&lt;br /&gt;
! 0&lt;br /&gt;
|bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ffaaAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07&lt;br /&gt;
|-&lt;br /&gt;
! 1&lt;br /&gt;
|bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03&lt;br /&gt;
|-&lt;br /&gt;
! 2&lt;br /&gt;
|bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07&lt;br /&gt;
|-&lt;br /&gt;
! 3&lt;br /&gt;
|bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07&lt;br /&gt;
|-&lt;br /&gt;
! 4&lt;br /&gt;
|bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03&lt;br /&gt;
|-&lt;br /&gt;
! 5&lt;br /&gt;
|bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03&lt;br /&gt;
|-&lt;br /&gt;
! 6&lt;br /&gt;
|bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07&lt;br /&gt;
|-&lt;br /&gt;
! 7&lt;br /&gt;
|bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07&lt;br /&gt;
|-&lt;br /&gt;
! 8&lt;br /&gt;
|bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B&lt;br /&gt;
|-&lt;br /&gt;
! 9&lt;br /&gt;
|bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B&lt;br /&gt;
|-&lt;br /&gt;
! A&lt;br /&gt;
|bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07&lt;br /&gt;
|-&lt;br /&gt;
! B&lt;br /&gt;
|bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F&lt;br /&gt;
|-&lt;br /&gt;
! C&lt;br /&gt;
|bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09&lt;br /&gt;
|-&lt;br /&gt;
! D&lt;br /&gt;
|bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B&lt;br /&gt;
|-&lt;br /&gt;
! E&lt;br /&gt;
|bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F&lt;br /&gt;
|-&lt;br /&gt;
! F&lt;br /&gt;
|bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Funk]]&lt;br /&gt;
[[Kategorie:Wettbewerb]]&lt;/div&gt;</summary>
		<author><name>Thymythos</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=RFM12&amp;diff=32482</id>
		<title>RFM12</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=RFM12&amp;diff=32482"/>
		<updated>2008-11-12T16:02:22Z</updated>

		<summary type="html">&lt;p&gt;Thymythos: /* Kommunikation mit RFM funktioniert nur sporadisch */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Beschreibung der Funkmodule RFM01, RFM02 und RFM12.&lt;br /&gt;
&lt;br /&gt;
Benötigt werden in der Minimal-Version im FIFO-Modus nur die Anschlüsse nSEL, SDO, SDI und SCK, eben das komplette SPI-Interface. Der Zugriff auf das Sende- und Empfangs-FIFO ist per Software möglich, ebenso die Abfrage der Statusbits. Deshalb werden z.B. nIRQ und nFFS nicht unbedingt benötigt. nIRQ signalisiert unter anderem, dass das Modul bereit ist Daten zu empfangen. Wenn Daten empfangen wurden, kann dies über den FFIT-Pin abgefragt werden (falls die Füllschwelle eingestellt wurde). nFFS dient dazu das FIFO direkt anzusprechen (es ist quasi der Chipselect für das FIFO), davon wird in der Minimalversion aber kein Gebrauch gemacht. Der Pin muss daher auf high-Pegel gelegt werden!&lt;br /&gt;
An CLK kann eine Frequenz von 1MHz bis 10MHz eingestellt werden. Hiermit kann dann z.B. der Mikrocontroller versorgt werden.&lt;br /&gt;
Reset ist ein Open-Collector-Ausgang und gleichzeitig der Reset-Eingang. Er sollte daher entweder gar nicht, oder aber hochohmig angeschlossen werden.&lt;br /&gt;
&lt;br /&gt;
Im FIFO-Mode kann das Modul konfiguriert werden mit dem Empfang zu warten, bis die Daten 0x2DD4 empfangen wurden. Sobald dieses Bitmuster empfangen wurde, werden Daten in das FIFO geschrieben, bis man das FIFO abschaltet und die Mustererkennung neu startet.&lt;br /&gt;
&lt;br /&gt;
Als weitere Modi stehen unter anderem ein synchroner Modus zur Verfügung (no FIFO mode), in dem der Sender/Empfänger den Bittakt ausgibt, und synchron dazu die zu sendenden Daten einliest bzw. die empfangenen Daten ausgibt. Der SPI Bus ist trotzdem zur Initialisierung des Moduls notwendig.&lt;br /&gt;
&lt;br /&gt;
== FAQ ==&lt;br /&gt;
&lt;br /&gt;
=== SPI Interface ===&lt;br /&gt;
&lt;br /&gt;
* Maximale Datenrate: 2,5MHz (10MHz Quarz / 4)&lt;br /&gt;
&lt;br /&gt;
=== CLK-Ausgang bleibt bei 1 MHz ===&lt;br /&gt;
&lt;br /&gt;
* Vor dem Umschalten (mit 0xC0E0) länger warten.&lt;br /&gt;
&lt;br /&gt;
=== RFM12 empfängt ein paar Bytes, dann nur Müll ===&lt;br /&gt;
&lt;br /&gt;
* Es wird zu langsam gesendet (TX FIFO underrun)&lt;br /&gt;
* Es wird zu langsam empfangen (RX FIFO overrun)&lt;br /&gt;
&lt;br /&gt;
Die Status-Bits helfen hier beim Debuggen. SPI sollte auf maximaler Transferrate stehen.&lt;br /&gt;
&lt;br /&gt;
=== RFM empfängt nur Müll ===&lt;br /&gt;
&lt;br /&gt;
http://www.mikrocontroller.net/topic/73560#605528&lt;br /&gt;
&lt;br /&gt;
Deine Module verhalten sich normal. Man muß mit den Gain- und AFC-Bits&lt;br /&gt;
eine ganze Weile spielen, bis die Module korrekt laufen (kommt auf die&lt;br /&gt;
Anwendung an). Fakt ist: der Empfänger empfängt ständig Datenmüll als&lt;br /&gt;
Rauschen. Wenn der FIFO durch die Präambel getriggert wird, sind die&lt;br /&gt;
Daten im FIFO ziemlich korrekt, wenn alles &amp;quot;gut&amp;quot; eingestellt ist. Der&lt;br /&gt;
FIFO sollte per Interrupt dann auch sofort abgeholt werden, da sonst das&lt;br /&gt;
nächste Byte das alte direkt überschreibt. Jeder zusammenhängende&lt;br /&gt;
Datensatz (mehrere Bytes an einem Stück) muß von einer Präambel&lt;br /&gt;
eingeleitet werden. Nach dem kompletten Einlesen eines Datensatzes muß&lt;br /&gt;
der FIFO abgeschaltet, wieder eingeschaltet und für den Empfang der&lt;br /&gt;
nächsten Präambel neu scharf gemacht werden.&lt;br /&gt;
&lt;br /&gt;
=== RFM hängt sich auf ===&lt;br /&gt;
&lt;br /&gt;
Wenn man die AFC nicht begrenzt, also keinen Wertebereich vorgibt, die eine maximale Abweichung korrigiert wird passiert es nach einer Weile, dass sich der Empfänger aufhängt, die Offsetbits im Status werden maximal und dann geht gar nichts mehr, er hängt fest.&lt;br /&gt;
&lt;br /&gt;
Siehe auch &lt;br /&gt;
* Forenbeitrag [http://www.mikrocontroller.net/topic/82456#689660 RFM12: Erfahrungen ]&lt;br /&gt;
&lt;br /&gt;
=== Kommunikation mit RFM funktioniert nur sporadisch ===&lt;br /&gt;
&lt;br /&gt;
* Ist die Versorgungsspannung stabil? (evtl. Kondensator einbauen)&lt;br /&gt;
&lt;br /&gt;
== Register ==&lt;br /&gt;
&lt;br /&gt;
Von https://www.mikrocontroller.net/attachment/24947/RFM12.txt&lt;br /&gt;
&lt;br /&gt;
Dieses Dokument beschreibt die Nutzung des RFM12 TRX Moduls!&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039; WICHTIG &#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Dieses Dokument wurde aus mehreren Quellen zusammengestellt, und kann Fehler enthalten!&lt;br /&gt;
Es können Abweichungen in Bezug auf RF01 / RF02 / RF12 / RFM01 / RFM02 und andere Module auftreten!&lt;br /&gt;
Es wurde das Datenblatt vom RFM12B und RF12 von www.hoperf.com als Basis genuzt. Zusätzlich wurden diese Informationen mit Hilfe von Forums-Nutzern (https://www.mikrocontroller.net/topic/71682) weiter vervollständigt!&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039; WICHTIG &#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Hinweis:&#039;&#039;&#039; Die LNA-Eingangsimpedanz beträgt 250 Ohm, und muss beim Anschluss einer 50-Ohm-Antenne entsprechend angepasst werden, um das Rauschen zu minimieren! &#039;&#039; -- (Auf den Pollin-Modulen bereits vorhanden)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configuration Setting ===&lt;br /&gt;
 Hex = 80 &amp;amp; xx&lt;br /&gt;
 Bit-Syntax: 10000000 | el | ef | b1 | b0 | x3 | x2 | x1 | x0&lt;br /&gt;
 el (TX FIFO) = Sendepuffer für Datentransfer nutzen (1 = An / 0 = Aus)&lt;br /&gt;
 ef (RX FIFO) = Empfangspuffer für Datenspeicherung nutzen (1 = An / 0 = Aus)&lt;br /&gt;
 b... = Zu nutzende Basisfrequenz (00=315MHz / 01=433MHz / 10=868MHz / 11=915MHz)&lt;br /&gt;
 x... = Interner Clock des Chips kann durch verschieben einer Kondensator-Anpass-Stufe bestimmt werden.&lt;br /&gt;
        0,5pF pro Schritt. Basis ist 8,5pF -&amp;gt; (0000=8,5 / 0001=9,0 / 0010=9,5 / ...)&lt;br /&gt;
&lt;br /&gt;
=== Power-Managment ===&lt;br /&gt;
 Hex = 82 &amp;amp; xx&lt;br /&gt;
 Bit-Syntax: 10000010 | er | ebb | et | es | ex | eb | ew | dc&lt;br /&gt;
 er = Empfänger einschalten (1 = an / 0 = Aus)&lt;br /&gt;
 ebb = ... (Synthesizer muss aktiv sein!) (1 = an / 0 = aus)&lt;br /&gt;
 et = Sender einschalten (1 = an / 0 = Aus) (Wenn das TX-Register aktiv und mit Daten gefüllt ist/wurde,&lt;br /&gt;
      werden diese Daten sofort gesendet) (1 = an / 0 = aus)&lt;br /&gt;
 es = Schaltet den Synthesizer ein. (1 = an / 0 = aus)&lt;br /&gt;
 ex = Schaltet den Quarz-Oszilator ein. (1 = an / 0 = aus)&lt;br /&gt;
 eb = Vergleichbar mit BrownOutDetection -&amp;gt; Erkennt eine zu geringe Betriebsspannung und erzeugt einen Interrupt,&lt;br /&gt;
      um einen drohenden Spannungsaufall anzukündigen (1 = An / 0 = Aus)&lt;br /&gt;
 ew = Aktiviert den WakeUpTimer des Prozessors. (1 = an / 0 = aus)&lt;br /&gt;
 dc = Deaktiviert die Ausgabe des SystemClocks auf dem CLK Pin am Chip (1 = Keine ClockAusgabe / 0 = Clock ausgeben)&lt;br /&gt;
&lt;br /&gt;
=== PLL Setting ===&lt;br /&gt;
 Hex = 198 + y&lt;br /&gt;
 Bit-Syntax: 110011000 | ob1 | ob0 | lpx | ddy | ddit | bw1 | bw0&lt;br /&gt;
 ob... = ... (00= 5 oder 10MHz [standard] / 01=3.3MHz / 1x=2.5MHz oder weniger)&lt;br /&gt;
 lpx = Wählt den Low-Power-Mode für den Quarz-Oszilator aus. (0=1ms [620µA] / 1=2ms [460µA])&lt;br /&gt;
 ddy = ...&lt;br /&gt;
 ddi = Schaltet das Dithering in PLL-Schleife ab. (1=abgeschaltet / 0=eingeschaltet)&lt;br /&gt;
 bw... = Wählt die Bandbreite des PLL-Signals aus. (00=86.2kbps [-107dBc/Hz] / 01=256kbps [-102dBc/Hz]) Bei 1MHz Offset Phasenrauschen.&lt;br /&gt;
&lt;br /&gt;
=== LowBatt / µC Clock Control ===&lt;br /&gt;
 Hex = c0 &amp;amp; xx&lt;br /&gt;
 Bit-Syntax: 11000000 | d2 | d1 | d0 | v4 | v3 | v2 | v1 | v0&lt;br /&gt;
 d... = Bestimmt den Teilungsfaktor für die Clockausgabe am CLK-Pin in Abhängigkeit des Internen SystemTakts.&lt;br /&gt;
        (000=1 / 001=1.25 / 010=1.66 / 011=2 / 100=2.5 / 101=3.33 / 110=5 / 111=10)&lt;br /&gt;
 v... = Bestimmt die Minimalspannung, ab der ein Interrupt durchgeführt werden&lt;br /&gt;
 muss. (Ähnlich einer BrownOutDetection). Im Power-Managment muss das eb-Bit&lt;br /&gt;
 aktiv sein, damit dies funktioniert.&lt;br /&gt;
&lt;br /&gt;
=== Frequency-setting ===&lt;br /&gt;
Bestimmt den Offset der Sende- und Empfangsfrequenz. Dieser Offset wird auf das Basisband im Configuration Setting hinzu gerechnet.&lt;br /&gt;
 Hex = a &amp;amp; xxx&lt;br /&gt;
 Bit-Syntax: 1010 | f11 | f10 | f9 | f8 | f7 | f6 | f5 | f4 | f3 | f2 | f1 | f0&lt;br /&gt;
 f... = Bestimmt den Offsetwert der Frequenz.&lt;br /&gt;
        Als Basis gilt das eingestellte Band im Configuration-Settings-Kommando&lt;br /&gt;
&lt;br /&gt;
=== Data-Rate ===&lt;br /&gt;
 Hex = c6 &amp;amp; xx&lt;br /&gt;
 Bit-Syntax: 11000110 | cs | r6 | r5 | r4 | r3 | r2 | r1 | r0&lt;br /&gt;
 cs =  Vorteiler, Faktor 7. Hiermit kann ein Vorteiler aktiviert werden,&lt;br /&gt;
       der die errechnete Baudrate (r...) durch 7 teilt.&lt;br /&gt;
 r... = Baudratenteilerfaktor&lt;br /&gt;
&lt;br /&gt;
=== RX Control ===&lt;br /&gt;
 Hex = 94 &amp;amp; xx&lt;br /&gt;
 Bit-Syntax: 10010 | p20 | d1 | d2 | i2 | i1 | i0 | g1 | g0 | r2 | r1 | r0&lt;br /&gt;
 p20 = Bestimmt die Funktion des Pin20 (nINT / VDI) am RFM12 Chip (1 = VDI-Ausgang / 0 = Interrupt-Eingang)&lt;br /&gt;
 d... = (Valid Data Indicator). Definiert die Geschwindigkeit, mit der bestimmt wird, ob ein Signal korrekt ist, oder nicht.&lt;br /&gt;
        (00=schnell / 01=mittel / 10=langsam / 11=immer an). Je nach eingestellter Variante werden&lt;br /&gt;
        unterschiedliche Hardware- und Software-Kombinationen genuzt.&lt;br /&gt;
        Fast:  CR_Lock  OR  DQD  ... Medium:  CR_Lock  AND ( DRSSI  OR  DQD ) ... &lt;br /&gt;
        SLOW: R/S FlipFlop aus (SET)  DRSSI  OR  DQD  OR  CR_Lock  und (CLR)  DRSSI  AND  DQD  AND  CR_Lock .&lt;br /&gt;
 i... = Bestimmt die Bandbreite des Empfängers in KHz (KiloHertz).&lt;br /&gt;
        (000=Reserviert / 001=400 / 010=340 / 011=270 / 100=200 / 101=134 / 110=67 / 111=Reserviert)&lt;br /&gt;
 g... = (LNA-Gain) Verstärkungsfaktor des Rauscharmen-Eingangs-Signal-Verstärkers (LNA Low Noise Amplifier).&lt;br /&gt;
        Werte in dBm (Dezibel [Grösse: Milliwatt]) Mögliche Werte sind: 0 / -6 / -14 / -20&lt;br /&gt;
 r... = (DRSSI = Digital Received Signal Strength Indication) Minimale Empfangssignalfeldstärke.&lt;br /&gt;
        6 dBm pro Schritt: (000=-103 / 001=-97 / 010=-91 / ...)&lt;br /&gt;
&lt;br /&gt;
=== Synchron Pattern ===&lt;br /&gt;
 Hex = ce &amp;amp; xx&lt;br /&gt;
 Bit-Syntax: 11001110 | b7 | b6 | b5 | b4 | b3 | b2 | b1 | b0&lt;br /&gt;
 b... = Legt den Wert fest, der als Synchronisations-Byte für die Datenfilterung verwendet werden soll.&lt;br /&gt;
&lt;br /&gt;
=== Data Filter ===&lt;br /&gt;
 Hex = c2 &amp;amp; xx&lt;br /&gt;
 Bit-Syntax: 11000010 | al | ml | -unknow- (1) | s | -unknow- (1) | f2 | f1 | f0&lt;br /&gt;
 al = Baudratenregenerator schaltet automatisch in den langsamen Modus, &lt;br /&gt;
      sobald er einen Takt erkannt hat.&lt;br /&gt;
 ml = schneller/langsamer Modus&lt;br /&gt;
 -unknown- (1) = ??? (Standard = 1) (Auch im Datenblatt von IA4420 so beschrieben)&lt;br /&gt;
 s = (DataFilter) Typ des Datenfilters (0=DigitalFilter / 1=AnalogFilter).&lt;br /&gt;
     Bei Nutzung des Analog-Filters kann kein FIFO sowie kein ClockRecovery genuzt werden.&lt;br /&gt;
 -unknown- (1) = ??? (Standard = 1) (Auch im Datenblatt von IA4420 so beschrieben)&lt;br /&gt;
 f... = (DQD Threshold) Bestimmt den Schwellwert, ab dem ein Signal als gut empfunden wird,&lt;br /&gt;
         und der Empfänger dieses weiterverarbeiten soll.&lt;br /&gt;
         DQD (data quality detection) zählt die &amp;quot;Spikes&amp;quot; des ungefilterten Signals, und bestimmt darüber die Qualität der Daten.&lt;br /&gt;
&lt;br /&gt;
=== FIFO und RESET-Mode ===&lt;br /&gt;
 Hex = ca &amp;amp; xx&lt;br /&gt;
 Bit-Syntax: 11001010 | f3 | f2 | f1 | f0 | -unknow- (0) | al | ff | dr&lt;br /&gt;
 f... = (FIFO interrupt Level)&lt;br /&gt;
 -unknown- (0) = ??? (Standard = 0) (Auch im Datenblatt von IA4420 so beschrieben)&lt;br /&gt;
 al = (FIFO Fill Condition) Legt den Wert fest, ab dem das Füllen des FIFOs beginnt.&lt;br /&gt;
      (0=Synchron / 1=Ständig). Bei Nutzung des Synchron-Modus, werden erst dann Daten in den FIFO geschrieben,&lt;br /&gt;
      wenn eine definierte 16Bit-Datenfolge empfangen wurde (Standard ist Hex: 2dd4).&lt;br /&gt;
 ff = (FIFO Fill) Startet das Einlesen der empfangenen Daten in den FIFO-Puffer.&lt;br /&gt;
      Wenn al (FIFO Fill Condition) auf synchron steht, dann startet das Setzen dieses Bits die Synchronisation-Bit-Erkennung.&lt;br /&gt;
 dr = (Sens Reset Mode) Wenn dieses Bit auf 1 steht, wird bei einer Schwankung von 200mV auf&lt;br /&gt;
      der VCC-Leitung (Spannungsversorgung des Chips), ein System-Reset ausgelöst.&lt;br /&gt;
&lt;br /&gt;
=== Automatic Frequency Control ===&lt;br /&gt;
 Hex = c4 &amp;amp; xx&lt;br /&gt;
 Bit-Syntax: 11000100 | a1 | a0 | rl1 | rl0 | st | fi | oe | en&lt;br /&gt;
 a... = Modus der AFC-Schaltung, 0=Auto, 1=einmalig nach Einschalten, 2=Solange VDI low ist, 3=unabhängig von VDI&lt;br /&gt;
 r... = (Range Limit) Frequenzraster (00=KeineBegrenzung / 01=+15 &amp;gt; -16 / 10=+7 &amp;gt; -8 / 11=+3 &amp;gt; -4)&lt;br /&gt;
 st = Berechneten Offset-Wert übernehmen&lt;br /&gt;
 fi = Genauer Berechnungsmodus (besser aber lansgamer)&lt;br /&gt;
 oe = AFC-Offset freischalten&lt;br /&gt;
 en = AFC-Berechnung aktivieren&lt;br /&gt;
&lt;br /&gt;
=== TX Configuration Control ===&lt;br /&gt;
 Hex = 98 &amp;amp; xx&lt;br /&gt;
 Bit-Syntax: 1001100 | mp | m3 | m2 | m1 | m0 | -unknow- (0) | p2 | p1 | p0&lt;br /&gt;
 mp = (Modulation Polarity) Bestimmt die Richtung der FSK-Erzeugung (invertiert das Spektrum).&lt;br /&gt;
 m... = (fDeviation) Bestimmt den Frequenzabstand des High- und Low-Wertes bei der Ubertragung im FSK-Betrieb. Basis ist der mp-Wert.&lt;br /&gt;
 -unknown- (0) = ??? (Standard = 0) (Auch im Datenblatt von IA4420 so beschrieben)&lt;br /&gt;
 p... = Bestimmt die relative Ausgangsleistung des Senders anhand des dBm-Wertes (Dezibel [Grösse: Milliwat]) 3-dBm-Schritte.&lt;br /&gt;
        (000=0 / 001=-3 / 010=-6 / ...). Der Wert steht im Zusammenhang mit der angeschlossenen Antennen-Impedanz.&lt;br /&gt;
&lt;br /&gt;
=== Wake-Up Timer ===&lt;br /&gt;
 Bestimmt die Zeitperiode der zyklischen Einschaltung des WakeUp-Timers&lt;br /&gt;
 Hex = e &amp;amp; xxx&lt;br /&gt;
 Bit-Syntax: 111 | R4 | R3 | R2 | R1 | R0 | M7 | M6 | M5 | M4 | M3 | M2 | M1 | M0&lt;br /&gt;
 R = Exponent der Zeit&lt;br /&gt;
 M = Zeit&lt;br /&gt;
&lt;br /&gt;
=== Low Duty-Cycle ===&lt;br /&gt;
&lt;br /&gt;
Bestimmt die maximale Sendezeit pro Stunde. Dies ist wichtig, um sich an gesetzliche Frequenzzuteilungsrichtlinien zu halten, die bestimmen, wie lang jemand mit einer definierten Sendeleistung auf einer bestimmten Frequenz (mit eventuell definierter Betriebsart [Modulationstyp]) senden darf.)&lt;br /&gt;
&lt;br /&gt;
 hex = 6400 + Bits&lt;br /&gt;
 Bit-Syntax: 1100100 | r| d6 | d5 | d4 | d3 | d2 | d1 | d0 | en&lt;br /&gt;
 r =  ??????????????????&lt;br /&gt;
 d... = Einschaltdauer während der zyklischen Einschaltung&lt;br /&gt;
 en = zyklische Einschaltung aktivieren&lt;br /&gt;
&lt;br /&gt;
=== RX FIFO Read ===&lt;br /&gt;
 Hex = b000&lt;br /&gt;
 Bit-Syntax: 1011000000000000&lt;br /&gt;
&lt;br /&gt;
Dieses Kommando löst die Rückgabe eines Datenbytes (synchron mit dem 8. Bit) aus. Es ist nötig, dass das ef-Bit (RX-FIFO) im Configuration Setting gesetzt wurde, um diese Funktion nutzen zu können!&lt;br /&gt;
&lt;br /&gt;
=== TX Register Write ===&lt;br /&gt;
Dieses Kommando schreibt Daten in den TX-Puffer. Wenn der Sender aktiv ist, wird dieses sofort gesendet. el (TX-Register) muss im Configuration-Setting-Kommando aktiv sein.&lt;br /&gt;
 Hex = b8 &amp;amp; xx&lt;br /&gt;
 Bit-Syntax: 10111000 | DataByteToSend&lt;br /&gt;
 DataByteToSend = Das Datenbyte, welches gesendet werden soll.&lt;br /&gt;
&lt;br /&gt;
(Senden Funktioniert nur wenn zuvor der Status abgefragt wurde)&lt;br /&gt;
&lt;br /&gt;
=== Status Read ===&lt;br /&gt;
Dieses Kommando löst die Rückgabe des Statusregisters aus, welches nach der ersten 0 im ersten Bit synchron übertragen wird.&lt;br /&gt;
 Hex = 0000&lt;br /&gt;
 Bit-Syntax: 0000000000000000&amp;lt;000&amp;gt;&lt;br /&gt;
 Rückgabe-Syntax: x0 | x1 | x2 | x3 | x4 | x5 | x6 | x7 | x8 | x9 | x10 | x11 | x12 | x13 | x14 | x15 | x16 | x17 | x18&lt;br /&gt;
 x0 -&amp;gt; x5 = Interrupt bits&lt;br /&gt;
 x6 -&amp;gt; x15 = Status Bits&lt;br /&gt;
 x16 -&amp;gt; x18 = FIFO&lt;br /&gt;
 x0 = FFIT / RGIT (RGIT = TX-Register ist bereit neue Daten zu senden ... kann mit dem TX-Register gelöscht werden)&lt;br /&gt;
     (FFIT = Die Anzahl der Datenbits im FIFO-Puffer hat das eingestellte Limit erreicht.&lt;br /&gt;
      Kann mit einer der FIFO-Lesemethoden gelöscht werden)&lt;br /&gt;
 x1 = POR (PowerOnReset)&lt;br /&gt;
 x2 = FFOV / RGUR (RGUR = Der Datenstrom beim Senden ist abgerissen, da nicht schnell genug Daten nachgeladen wurden)&lt;br /&gt;
      (FFOV = Der RX-FIFO ist übergelaufen)&lt;br /&gt;
 x3 = WKUP&lt;br /&gt;
 x4 = EXT&lt;br /&gt;
 x5 = LBD&lt;br /&gt;
 x6 = FFBM (Der FIFO-Puffer ist leer)&lt;br /&gt;
 x7 = RSSI/ATS (ATS = )(RSSI = Die Signalstärke ist über dem eingestelltem Limit)&lt;br /&gt;
 x8 = DQD&lt;br /&gt;
 x9 = CRL&lt;br /&gt;
 x10 = ATGL&lt;br /&gt;
 x11 = OFFS_4&lt;br /&gt;
 x12 = OFFS_3&lt;br /&gt;
 x13 = OFFS_2&lt;br /&gt;
 x14 = OFFS_1&lt;br /&gt;
 x15 = OFFS_0&lt;br /&gt;
 x16 = FO&lt;br /&gt;
 x17 = FO+1&lt;br /&gt;
 x18 = FO+2&lt;br /&gt;
&lt;br /&gt;
== Bezugsquellen ==&lt;br /&gt;
* [[Elektronikversender#csd-electronics|csd-electronics]]&lt;br /&gt;
* [[Elektronikversender#IT-WNS|IT-WNS]]&lt;br /&gt;
* [[Elektronikversender#Pollin_Electronic|Pollin Electronic]]&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
* [[AVR RFM12]]&lt;br /&gt;
* [[RFM12 Protokoll Stack]]&lt;br /&gt;
* [http://www.mikrocontroller.net/topic/93801 Bezugsquellen]&lt;br /&gt;
&lt;br /&gt;
Folgende Links sind mit Vorsicht zu genießen, da die Datenblätter teilweise  fehlerbehaftet sind. Es empfiehlt sich, direkt mit dem Datenblatt des RF12 (das ist das IC auf dem Modul) zu arbeiten. Dieses ist so gut wie fehlerfrei.&lt;br /&gt;
&lt;br /&gt;
* [http://www.hoperf.com/pdf/RF12.pdf Datenblatt des ICs RF12] (PDF)&lt;br /&gt;
* [http://www.hoperf.com/pdf/RFM12.pdf Datenblatt des Moduls RFM12] (PDF)&lt;br /&gt;
* [http://www.hoperf.com/pdf/RF12_code.pdf Programming Guide] (PDF)&lt;br /&gt;
* [http://www.hoperf.com/pdf/RF12TOOLS.pdf Demo Kit User Manual] (PDF)&lt;br /&gt;
* [http://www.pollin.de/shop/downloads/D810047S.ZIP Beispielprogramm von Pollin] (ZIP)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Bauteile]]&lt;br /&gt;
[[Kategorie:Funk]]&lt;/div&gt;</summary>
		<author><name>Thymythos</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=AVR-GCC-Tutorial&amp;diff=32423</id>
		<title>AVR-GCC-Tutorial</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=AVR-GCC-Tutorial&amp;diff=32423"/>
		<updated>2008-11-09T15:57:47Z</updated>

		<summary type="html">&lt;p&gt;Thymythos: /* volatile und Pointer */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Vorwort =&lt;br /&gt;
&lt;br /&gt;
Dieses Tutorial soll den Einstieg in die Programmierung von Atmel [[AVR]]-Mikrocontrollern in der Programmiersprache [[C]] mit dem freien C-Compiler [[AVR-GCC]] erleichtern.&lt;br /&gt;
&lt;br /&gt;
Vorausgesetzt werden Grundkenntnisse der Progammiersprache C. Diese Kenntnisse kann man sich online erarbeiten, z. B. mit dem [http://www.schellong.de/c.htm C Tutorial von Helmut Schellong]. Nicht erforderlich sind Vorkenntnisse in der Programmierung von Mikrocontrollern, weder in Assembler noch in einer anderen Sprache. &lt;br /&gt;
&lt;br /&gt;
In diesem Text wird häufig auf die Standardbibliothek avr-libc verwiesen, für die es eine [http://www.nongnu.org/avr-libc/user-manual/index.html Online-Dokumentation] gibt, in der sich auch viele nützliche Informationen zum Compiler und zur Programmierung von AVR Controllern finden. Bei WinAVR gehört die avr-libc Dokumentation zum Lieferumfang und wird mitinstalliert.&lt;br /&gt;
&lt;br /&gt;
Der Compiler und die Standardbibliothek avr-libc werden stetig weiterentwickelt. Erläuterungen und Beispiele beziehen sich auf den C-Compiler avr-gcc ab Version 3.4 und die avr-libc ab Version 1.4.3. Die Unterschiede zu älteren Versionen werden im Haupttext und Anhang zwar erläutert, Anfängern sei jedoch empfohlen, die aktuellen Versionen zu nutzen (für MS-Windows: aktuelle Version des [[WinAVR]]-Pakets). &lt;br /&gt;
&lt;br /&gt;
Das ursprüngliche Tutorial stammt von Christian Schifferle, viele neue Abschnitte und aktuelle Anpassungen von Martin Thomas.&lt;br /&gt;
&lt;br /&gt;
Dieses Tutorial ist in PDF-Form erhältlich bei:&lt;br /&gt;
http://www.siwawi.arubi.uni-kl.de/avr_projects/AVR-GCC-Tutorial_-_www_mikrocontroller_net.pdf&lt;br /&gt;
(nicht immer auf aktuellem Stand)&lt;br /&gt;
&lt;br /&gt;
= Benötigte Werkzeuge =&lt;br /&gt;
&lt;br /&gt;
Um eigene Programme für AVRs mittels avr-gcc/avr-libc zu erstellen und zu testen, wird folgende Hard- und Software benötigt:&lt;br /&gt;
&lt;br /&gt;
* Platine oder Versuchsaufbau für die Aufnahme eines AVR Controllers, der vom avr-gcc Compiler unterstützt wird (alle ATmegas und die meisten AT90, siehe Dokumentation der avr-libc für unterstützte Typen). Dieses Testboard kann durchaus auch selbst gelötet oder auf einem Steckbrett aufgebaut werden. Einige Registerbeschreibungen dieses Tutorials beziehen sich auf den inzwischen veralteten AT90S2313. Der weitaus größte Teil des Textes ist aber für alle Controller der AVR-Familie gültig. Brauchbare Testplattformen sind auch das [[STK500]] und der [[AVR Butterfly]] von Atmel. Weitere Infos findet man [[AVR#Starterkits|hier]].&lt;br /&gt;
&lt;br /&gt;
* Der avr-gcc Compiler und die avr-libc. Kostenlos erhältlich für nahezu alle Plattformen und Betriebssysteme. Für MS-Windows im Paket [[WinAVR]]; für Unix/Linux siehe auch Hinweise im Artikel [[AVR-GCC]].&lt;br /&gt;
&lt;br /&gt;
* Programmiersoftware und -[[AVR In System Programmer |hardware]] z. B. PonyProg (siehe auch: [[Pony-Prog Tutorial]]) oder [[AVRDUDE]] mit [[STK200]]-Dongle oder die von Atmel verfügbare Hard- und Software ([[STK500]], Atmel AVRISP, [[AVR-Studio]]).&lt;br /&gt;
&lt;br /&gt;
* Nicht unbedingt erforderlich, aber zur Simulation und zum Debuggen unter MS-Windows recht nützlich: [[AVR-Studio]] (siehe Abschnitt [[AVR-GCC-Tutorial#Exkurs: Makefiles|Exkurs: Makefiles]]).&lt;br /&gt;
&lt;br /&gt;
= Was tun, wenn&#039;s nicht &amp;quot;klappt&amp;quot;? =&lt;br /&gt;
&lt;br /&gt;
* Herausfinden, ob es tatsächlich ein avr(-gcc) spezifisches Problem ist oder nur die eigenen C-Kenntnisse einer Auffrischung bedürfen. Allgemeine C-Fragen kann man eventuell &amp;quot;beim freundlichen Programmierer zwei Büro-, Zimmer- oder Haustüren weiter&amp;quot; loswerden. Ansonsten: [[C]]-Buch (gibt&#039;s auch &amp;quot;gratis&amp;quot; online) lesen.&lt;br /&gt;
&lt;br /&gt;
* Die [[AVR Checkliste]] durcharbeiten.&lt;br /&gt;
&lt;br /&gt;
* Die &#039;&#039;&#039;[http://www.nongnu.org/avr-libc/user-manual/index.html Dokumentation der avr-libc]&#039;&#039;&#039; lesen, vor allem (aber nicht nur) den Abschnitt Related Pages/&#039;&#039;&#039;Frequently Asked Questions&#039;&#039;&#039; = Oft gestellte Fragen (und Antworten dazu). Z.Zt leider nur in englischer Sprache verfügbar.&lt;br /&gt;
&lt;br /&gt;
* Den Artikel [[AVR-GCC]] in diesem Wiki lesen.&lt;br /&gt;
&lt;br /&gt;
* Das [http://www.mikrocontroller.net/forum/2 GCC-Forum auf  www.mikrocontroller.net] nach vergleichbaren Problemen absuchen.&lt;br /&gt;
&lt;br /&gt;
* Das avr-gcc-Forum bei [http://www.avrfreaks.net avrfreaks] nach vergleichbaren Problemen absuchen.&lt;br /&gt;
&lt;br /&gt;
* Das [http://lists.gnu.org/archive/html/avr-gcc-list/ Archiv der avr-gcc Mailing-Liste] nach vergleichbaren Problemen absuchen.&lt;br /&gt;
&lt;br /&gt;
* Nach Beispielcode suchen. Vor allem im &#039;&#039;Projects&#039;&#039;-Bereich von [http://www.avrfreaks.net AVRFREAKS] (anmelden).&lt;br /&gt;
&lt;br /&gt;
* Google oder yahoo befragen schadet nie.&lt;br /&gt;
&lt;br /&gt;
* Bei Problemen mit der Ansteuerung interner AVR-Funktionen mit C-Code: das Datenblatt des Controllers lesen (ganz und am Besten zweimal). Datenblätter sind  auf den [http://www.atmel.com Atmel Webseiten] als pdf-Dateien verfügbar. Das komplette Datenblatt (complete) und nicht die Kurzfassung (summary) verwenden.&lt;br /&gt;
&lt;br /&gt;
* Die Beispieleprogramme im [[AVR-Tutorial]] sind zwar in AVR-Assembler verfasst, Erläuterungen und Vorgehensweisen sind aber auch auf C-Programme übertragbar.&lt;br /&gt;
&lt;br /&gt;
* Einen Beitrag in eines der Foren oder eine Mail an die Mailing-Liste schreiben. Dabei möglichst viel Information geben: Controller, Compilerversion, genutzte Bibliotheken, Ausschnitte aus dem Quellcode oder besser ein [http://www.mikrocontroller.net/topic/72767#598986 Testprojekt] mit allen notwendigen Dateien, um das Problem nachzuvollziehen, sowie genaue Fehlermeldungen bzw. Beschreibung des Fehlverhaltens. Bei Ansteuerung externer Geräte die Beschaltung beschreiben oder skizzieren (z. B. mit [http://www.tech-chat.de/ Andys ASCII Circuit]). Siehe dazu auch: &#039;&#039;&#039;[http://www.lugbz.org/documents/smart-questions_de.html &amp;quot;Wie man Fragen richtig stellt&amp;quot;]&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
= Erzeugen von Maschinencode =&lt;br /&gt;
&lt;br /&gt;
Aus dem C-Quellcode erzeugt der avr-gcc Compiler (zusammen mit Hilfsprogrammen wie z.&amp;amp;nbsp;B. Präprozessor, Assembler und Linker) Maschinencode für den AVR-Controller. Üblicherweise liegt dieser Code dann im Intel Hex-Format vor (&amp;quot;Hex-Datei&amp;quot;). Die Programmiersoftware (z.&amp;amp;nbsp;B. [[AVRDUDE]], PonyProg oder AVRStudio/STK500-plugin) liest diese Datei ein und überträgt die enthaltene Information (den Maschinencode) in den Speicher des Controllers. Im Prinzip sind also &amp;quot;nur&amp;quot; der avr-gcc-Compiler (und wenige Hilfsprogramme) mit den &amp;quot;richtigen&amp;quot; Optionen aufzurufen, um aus C-Code eine &amp;quot;Hex-Datei&amp;quot; zu erzeugen. Grundsätzlich stehen dazu zwei verschiedene Ansätze zur Verfügung:&lt;br /&gt;
&lt;br /&gt;
* Die Verwendung einer integrierten Entwicklungsumgebung (IDE = &#039;&#039;&#039;I&#039;&#039;&#039;ntegrated &#039;&#039;&#039;D&#039;&#039;&#039;evelopment &#039;&#039;&#039;E&#039;&#039;&#039;nvironment), bei der alle Einstellungen z.&amp;amp;nbsp;B. in Dialogboxen durchgeführt werden können. Unter Anderem kann AVRStudio ab Version 4.12 (kostenlos auf [http://www.atmel.com/ atmel.com]) zusammen mit WinAVR als integrierte Entwicklungsumgebung für den Compiler avr-gcc genutzt werden (dazu müssen AVRStudio und WinAVR auf dem Rechner installiert sein). Weitere IDEs für den avr-gcc (ohne Anspruch auf Vollständigkeit): AtmanAvr C (relativ günstig), KamAVR (kostenlos), VMLab (ab Version 3.12 ebenfalls kostenlos). Integrierte Entwicklungsumgebungen unterscheiden sich stark in Ihrer Bedienung und stehen auch nicht für alle Plattformen zur Verfügung, auf denen der Compiler  ausführbar ist (z.&amp;amp;nbsp;B. AVRStudio nur für MS-Windows). Zur Anwendung des avr-gcc Compilers mit IDEs sei hier auf deren Dokumentation verwiesen. &lt;br /&gt;
&lt;br /&gt;
* Die Nutzung des Programms make mit passenden Makefiles. In den folgenden Abschnitten wird die Generierung von Maschinencode für einen AVR (&amp;quot;hex-Datei&amp;quot;) aus C-Quellcode (&amp;quot;c-Dateien&amp;quot;) anhand von &amp;quot;make&amp;quot; und den &amp;quot;Makefiles&amp;quot; näher erläutert. Viele der darin beschriebenen Optionen findet man auch im Konfigurationsdialog des avr-gcc-Plugins von AVRStudio (AVRStudio generiert ein makefile in einem Unterverzeichnis des Projektverzeichnisses). &lt;br /&gt;
&lt;br /&gt;
Beim Wechsel vom makefile-Ansatz nach WinAVR-Vorlage zu AVRStudio ist darauf zu achten, dass AVRStudio (Stand: AVRStudio Version 4.13) bei einem neuen Projekt die Optimierungsoption (vgl. Abschnitt [[AVR-GCC-Tutorial#Exkurs: Makefiles|Exkurs: Makefiles]], typisch: -Os) nicht einstellt und die mathematische Bibliothek der avr-libc (libm.a, Linker-Option -lm) nicht einbindet. Beides ist Standard bei Verwendung von makefiles nach WinAVR-Vorlage und sollte daher auch im Konfigurationsdialog des avr-gcc-Plugins von AVRStudio &amp;quot;manuell&amp;quot; eingestellt werden, um auch mit AVRStudio kompakten Code zu erzeugen.&lt;br /&gt;
&lt;br /&gt;
= Einführungsbeispiel =&lt;br /&gt;
&lt;br /&gt;
Zum Einstieg ein kleines Beispiel, an dem die Nutzung des Compilers und der Hilfsprogramme (der sogenannten &#039;&#039;Toolchain&#039;&#039;) demonstriert wird. Detaillierte Erläuterungen folgen in den weiteren Abschnitten dieses Tutorials.&lt;br /&gt;
&lt;br /&gt;
Das Programm soll auf einem AVR Mikrocontroller einige Ausgänge ein- und andere ausschalten. Das Beispiel ist für einen ATmega16 programmiert ([http://www.atmel.com/dyn/resources/prod_documents/doc2466.pdf Datenblatt]), kann aber sinngemäß für andere Controller der AVR-Familie modifiziert werden. &lt;br /&gt;
&lt;br /&gt;
Zunächst der Quellcode der Anwendung, der in einer Text-Datei mit dem Namen &#039;&#039;main.c&#039;&#039; abgespeichert wird.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
/* Alle Zeichen zwischen Schrägstrich-Stern &lt;br /&gt;
   und Stern-Schrägstrich sind lediglich Kommentare */&lt;br /&gt;
&lt;br /&gt;
// Zeilenkommentare sind ebenfalls möglich&lt;br /&gt;
// alle auf die beiden Schrägstriche folgenden&lt;br /&gt;
// Zeichen einer Zeile sind Kommentar&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;          // (1)&lt;br /&gt;
&lt;br /&gt;
int main (void) {            // (2)&lt;br /&gt;
&lt;br /&gt;
   DDRB  = 0xff;             // (3)&lt;br /&gt;
   PORTB = 0x03;             // (4)&lt;br /&gt;
&lt;br /&gt;
   while(1) {                // (5a)&lt;br /&gt;
     /* &amp;quot;leere&amp;quot; Schleife*/;  // (5b)&lt;br /&gt;
   }                         // (5c)&lt;br /&gt;
&lt;br /&gt;
   /* wird nie erreicht */&lt;br /&gt;
   return 0;                 // (6)&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* In der mit (1) markierten Zeile wird eine so genannte Header-Datei eingebunden. In io.h sind die Registernamen definiert, die im späteren Verlauf genutzt werden.&lt;br /&gt;
&lt;br /&gt;
* Bei (2) beginnt das eigentliche Programm. Jedes C-Programm beginnt mit den Anweisungen in der Funktion main.&lt;br /&gt;
&lt;br /&gt;
* Die Anschlüsse eines AVR (&amp;quot;Beinchen&amp;quot;) werden zu Blöcken zusammengefasst, einen solchen Block bezeichnet man als Port. Beim ATmega16 hat jeder Port 8 Anschlüsse, bei kleineren AVRs können einem Port auch weniger als 8 Anschlüsse zugeordnet sein. Da per Definition (Datenblatt) alle gesetzten Bits in einem Richtungsregister den entsprechenden Anschluss auf Ausgang schalten, werden mit DDRB=0xff alle Anschlüsse des Ports B zu Ausgängen.&lt;br /&gt;
&lt;br /&gt;
* (4) stellt die Werte der Ausgänge ein. Die den ersten beiden Bits des Ports zugeordneten Anschlüsse (PB0 und PB1) werden 1, alle anderen Anschlüsse des Ports B (PB2-PB7) zu 0. Aktivierte Ausgänge (logisch 1 oder &amp;quot;high&amp;quot;) liegen auf Betriebsspannung (VCC, meist 5 Volt), nicht aktivierte Ausgänge führen 0 Volt (GND, Bezugspotential).&lt;br /&gt;
&lt;br /&gt;
* (5) ist die so genannte Hauptschleife (main-loop). Dies ist eine Programmschleife, welche kontinuierlich wiederkehrende Befehle enthält. In diesem Beispiel ist sie leer. Der Controller durchläuft die Schleife immer wieder, ohne dass etwas passiert (außer das Strom verbraucht wird). Eine solche Schleife ist notwendig, da es auf dem Controller kein Betriebssystem gibt, das nach Beendigung des Programmes die Kontrolle übernehmen könnte. Ohne diese Schleife wäre der Zustand des Controllers nach dem Programmende undefiniert.&lt;br /&gt;
&lt;br /&gt;
* (6) wäre das Programmende. Die Zeile ist nur aus Gründen der C-Kompatibilität enthalten: int main(void) besagt, dass die Funktion einen Wert zurückgibt. Die Anweisung wird aber nicht erreicht, da das Programm die Hauptschleife nie verlässt.&lt;br /&gt;
&lt;br /&gt;
Um diesen Quellcode in ein auf dem Controller lauffähiges Programm zu übersetzen, wird hier ein Makefile genutzt. Das verwendete Makefile findet sich auf der Seite [[Beispiel Makefile]] und basiert auf der Vorlage, die in WinAVR mitgeliefert wird und wurde bereits angepasst (Controllertyp ATmega16). Man kann das Makefile bearbeiten und an andere Controller anpassen oder sich mit dem Programm MFile menügesteuert ein Makefile &amp;quot;zusammenklicken&amp;quot;. Das Makefile speichert man unter dem Namen Makefile (ohne Endung) im selben Verzeichnis, in dem auch die Datei main.c mit dem Programmcode abgelegt ist. Detailliertere Erklärungen zur Funktion von Makefiles finden sich im folgenden Abschnitt [[AVR-GCC-Tutorial#Exkurs: Makefiles|Exkurs: Makefiles]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
D:\tmp\gcc_tut\quickstart&amp;gt;dir&lt;br /&gt;
&lt;br /&gt;
 Verzeichnis von D:\tmp\gcc_tut\quickstart&lt;br /&gt;
&lt;br /&gt;
28.11.2006  22:53    &amp;lt;DIR&amp;gt;          .&lt;br /&gt;
28.11.2006  22:53    &amp;lt;DIR&amp;gt;          ..&lt;br /&gt;
28.11.2006  20:06               118 main.c&lt;br /&gt;
28.11.2006  20:03            16.810 Makefile&lt;br /&gt;
               2 Datei(en)         16.928 Bytes&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nun gibt man &#039;&#039;make all&#039;&#039; ein. Falls das mit WinAVR installierte Programmers Notepad genutzt wird, gibt es dazu einen Menüpunkt im Tools Menü. Sind alle Einstellungen korrekt, entsteht eine Datei main.hex, in der der Code für den AVR enthalten ist. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
D:\tmp\gcc_tut\quickstart&amp;gt;make all&lt;br /&gt;
&lt;br /&gt;
-------- begin --------&lt;br /&gt;
avr-gcc (GCC) 3.4.6&lt;br /&gt;
Copyright (C) 2006 Free Software Foundation, Inc.&lt;br /&gt;
This is free software; see the source for copying conditions.  There is NO&lt;br /&gt;
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Compiling C: main.c&lt;br /&gt;
avr-gcc -c -mmcu=atmega16 -I. -gdwarf-2 -DF_CPU=1000000UL -Os -funsigned-char -f&lt;br /&gt;
unsigned-bitfields -fpack-struct -fshort-enums -Wall -Wstrict-prototypes -Wundef&lt;br /&gt;
 -Wa,-adhlns=obj/main.lst  -std=gnu99 -Wundef -MD -MP -MF .dep/main.o.d main.c -&lt;br /&gt;
o obj/main.o&lt;br /&gt;
&lt;br /&gt;
Linking: main.elf&lt;br /&gt;
avr-gcc -mmcu=atmega16 -I. -gdwarf-2 -DF_CPU=1000000UL -Os -funsigned-char -funs&lt;br /&gt;
igned-bitfields -fpack-struct -fshort-enums -Wall -Wstrict-prototypes -Wundef -W&lt;br /&gt;
a,-adhlns=obj/main.o  -std=gnu99 -Wundef -MD -MP -MF .dep/main.elf.d obj/main.o&lt;br /&gt;
--output main.elf -Wl,-Map=main.map,--cref    -lm&lt;br /&gt;
&lt;br /&gt;
Creating load file for Flash: main.hex&lt;br /&gt;
avr-objcopy -O ihex -R .eeprom main.elf main.hex&lt;br /&gt;
&lt;br /&gt;
[...]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Inhalt der hex-Datei kann nun zum Controller übertragen werden. Dies kann z.&amp;amp;nbsp;B. über In-System-Programming (ISP) erfolgen, das im [[AVR-Tutorial: Equipment]] beschrieben ist. Makefiles nach der WinAVR/MFile-Vorlage sind für die Nutzung des Programms [[AVRDUDE]] vorbereitet. Wenn man den Typ und Anschluss des Programmiergerätes richtig eingestellt hat, kann mit &#039;&#039;make program&#039;&#039; die Übertragung mittels AVRDUDE gestartet werden. Jede andere Software, die hex-Dateien lesen und zu einem AVR übertragen kann (z.&amp;amp;nbsp;B. [[Pony-Prog_Tutorial|Ponyprog]], yapp, AVRStudio), kann natürlich ebenfalls genutzt werden.&lt;br /&gt;
&lt;br /&gt;
Startet man nun den Controller (Reset-Taster oder Stromzufuhr aus/an), werden vom Programm die Anschlüsse PB0 und PB1 auf 1 gesetzt. Man kann mit einem Messgerät nun an diesem Anschluss die Betriebsspannung messen oder eine LED leuchten lassen (Anode an den Pin, Vorwiderstand nicht vergessen). An den Anschlüssen PB2-PB7 misst man 0 Volt. Eine mit der Anode mit einem dieser Anschlüsse verbundene LED leuchtet nicht.&lt;br /&gt;
&lt;br /&gt;
= Exkurs: Makefiles =&lt;br /&gt;
&lt;br /&gt;
Wenn man bisher gewohnt ist, mit integrierten Entwicklungsumgebungen à la Visual-C Programme zu erstellen, wirkt das makefile-Konzept auf den ersten Blick etwas kryptisch. Nach kurzer Einarbeitung ist diese Vorgehensweise jedoch sehr praktisch. Diese Dateien (üblicher Name: &#039;Makefile&#039; ohne Dateiendung) dienen der Ablaufsteuerung des Programms make, das auf allen Unix/Linux-Systemen installiert sein sollte, und in einer Fassung fuer MS-Windows auch in [[WinAVR]] (Unterverzeichnis utils/bin) enthalten ist.&lt;br /&gt;
&lt;br /&gt;
Im Unterverzeichnis &#039;&#039;sample&#039;&#039; einer WinAVR-Installation findet man eine sehr brauchbare Vorlage, die sich einfach an das eigene Projekt anpassen lässt ([[Media:Makefile|lokale Kopie Stand Sept. 2004]]). Wahlweise kann man auch [http://www.sax.de/~joerg/mfile/ mfile] von Jörg Wunsch nutzen. mfile erzeugt ein makefile nach Einstellungen in einer grafischen Nutzeroberfläche, wird bei WinAVR mitinstalliert, ist aber als TCL/TK-Programm auf nahezu allen Plattformen lauffähig.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Die folgenden Ausführungen beziehen sich auf das WinAVR Beispiel-Makefile.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Ist im Makefile alles richtig eingestellt, genügt es, sich drei Parameter zu merken, die über die shell bzw. die Windows-Kommandozeile (cmd.exe/command.com) als Parameter an &amp;quot;make&amp;quot; übergeben werden. Das Programm make sucht sich &amp;quot;automatisch&amp;quot; das Makefile im aktuellen Arbeitsverzeichnis und führt die darin definierten Operationen für den entsprechenden Aufrufparameter durch.&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
| &#039;&#039;make all&#039;&#039;&lt;br /&gt;
| Erstellt aus den im Makefile angegebenen Quellcodes eine &#039;&#039;hex&#039;&#039;-Datei (und ggf. auch &#039;&#039;eep&#039;&#039;-Datei).&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;make program&#039;&#039;&lt;br /&gt;
| Überträgt die hex-Datei (und wahlweise auch die eep-Datei für den EEPROM) zum AVR. &lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;make clean&#039;&#039;&lt;br /&gt;
| löscht alle temporären Dateien, also auch die hex-Datei&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Diese Aufrufe können in die allermeisten Editoren in &amp;quot;Tool-Menüs&amp;quot; eingebunden werden. Dies erspart den Kontakt mit der Kommandozeile. Bei WinAVR sind die Aufrufe bereits im Tools-Menü des mitgelieferten Editors Programmers-Notepad eingefügt.&lt;br /&gt;
&lt;br /&gt;
Üblicherweise sind folgende Daten im Makefile anzupassen:&lt;br /&gt;
* Controllertyp&lt;br /&gt;
&lt;br /&gt;
* Quellcode-Dateien (c-Dateien)&lt;br /&gt;
&lt;br /&gt;
* Typ und Anschluss des Programmiergeräts&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Seltener sind folgende Einstellungen durchzuführen:&lt;br /&gt;
* Grad der Optimierung&lt;br /&gt;
&lt;br /&gt;
* Methode zur Erzeugung der Debug-Symbole (Debug-Format)&lt;br /&gt;
&lt;br /&gt;
* Assembler-Quellcode-Dateien (S-Dateien)&lt;br /&gt;
&lt;br /&gt;
Die in den folgenden Unterabschnitten gezeigten Makefile-Ausschnitte sind für ein Programm, das auf einem ATmega8 ausgeführt werden soll. Der Quellcode besteht aus den c-Dateien superprog.c (darin main()), uart.c, lcd.c und 1wire.c. Im Quellcodeverzeichnis befinden sich diese Dateien: superprog.c, uart.h, uart.c, lcd.h, lcd.c, 1wire.h, 1wire.c und das makefile (die angepasste Kopie des WinAVR-Beispiels).&lt;br /&gt;
&lt;br /&gt;
Der Controller wird mittels [[AVRDUDE]] über ein [[STK200]]-Programmierdongle an der Schnittstelle lpt1 (bzw. /dev/lp0) programmiert. Im Quellcode sind auch Daten für die &#039;&#039;section .eeprom&#039;&#039; definiert (siehe Abschnitt [[AVR-GCC-Tutorial#EEPROM|Speicherzugriffe]]), diese sollen beim Programmieren gleich mit ins EEPROM geschrieben werden. &lt;br /&gt;
&lt;br /&gt;
== Controllertyp setzen ==&lt;br /&gt;
&lt;br /&gt;
Dazu wird die &amp;quot;make-Variable&amp;quot; MCU entsprechend dem Namen des verwendeten Controllers gesetzt. Eine Liste der von avr-gcc und der avr-libc unterstützten Typen findet sich in der [http://www.nongnu.org/avr-libc/user-manual/index.html Dokumentation der avr-libc].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;code&amp;quot;&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
# Kommentare in Makefiles beginnen mit einem Doppelkreuz &lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
# ATmega8 at work&lt;br /&gt;
MCU = atmega8&lt;br /&gt;
# oder MCU = atmega16 &lt;br /&gt;
# oder MCU = at90s8535&lt;br /&gt;
# oder ...&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Quellcode-Dateien eintragen ==&lt;br /&gt;
&lt;br /&gt;
Der Name der Quellcodedatei, welche die Funktion main enthält, wird hinter TARGET eingetragen. Dies jedoch ohne die Endung &#039;&#039;.c&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;code&amp;quot;&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
TARGET = superprog&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Besteht das Projekt wie im Beispiel aus mehr als einer Quellcodedatei, sind die weiteren c-Dateien (nicht die Header-Dateien, vgl. [[Include-Files (C)]]) durch Leerzeichen getrennt bei SRC einzutragen. Die bei TARGET definierte Datei ist schon in der SRC-Liste enthalten. Diesen Eintrag nicht löschen!&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;code&amp;quot;&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
SRC = $(TARGET).c uart.c lcd.c 1wire.c &lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Alternativ kann man die Liste der Quellcodedateien auch mit dem Operator += erweitern.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;code&amp;quot;&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
SRC = $(TARGET).c uart.c 1wire.c&lt;br /&gt;
# lcd-Code fuer Controller xyz123 (auskommentiert)&lt;br /&gt;
# SRC += lcd_xyz.c&lt;br /&gt;
# lcd-Code fuer &amp;quot;Standard-Controller&amp;quot; (genutzt)&lt;br /&gt;
SRC += lcd.c&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Programmiergerät einstellen ==&lt;br /&gt;
&lt;br /&gt;
Die Vorlagen sind auf die Programmiersoftware [[AVRDUDE]] angepasst, jedoch lässt sich auch andere Programmiersoftware einbinden, sofern diese über Kommandozeile gesteuert werden kann (z.&amp;amp;nbsp;B. stk500.exe, uisp, sp12).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;code&amp;quot;&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
# Einstellung fuer STK500 an com1 (auskommentiert)&lt;br /&gt;
# AVRDUDE_PROGRAMMER = stk500&lt;br /&gt;
# com1 = serial port. Use lpt1 to connect to parallel port.&lt;br /&gt;
# AVRDUDE_PORT = com1    # programmer connected to serial device&lt;br /&gt;
&lt;br /&gt;
# Einstellung fuer STK200-Dongle an lpt1&lt;br /&gt;
AVRDUDE_PROGRAMMER = stk200&lt;br /&gt;
AVRDUDE_PORT = lpt1&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sollen Flash(=.hex) und EEPROM(=.eep) zusammen auf den Controller programmiert werden, ist das Kommentarzeichen vor AVRDUDE_WRITE_EEPROM zu löschen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;code&amp;quot;&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
# auskommentiert: EERPOM-Inhalt wird nicht mitgeschrieben&lt;br /&gt;
#AVRDUDE_WRITE_EEPROM = -U eeprom:w:$(TARGET).eep&lt;br /&gt;
&lt;br /&gt;
# nicht auskommentiert: EERPOM-Inhalt wird mitgeschrieben&lt;br /&gt;
AVRDUDE_WRITE_EEPROM = -U eeprom:w:$(TARGET).eep&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Anwendung ==&lt;br /&gt;
&lt;br /&gt;
Das erstellte Makefile und der Code müssen im gleichen Ordner sein, auch sollte der Dateiname nicht verändert werden. &lt;br /&gt;
&lt;br /&gt;
Die Eingabe von &#039;&#039;make all&#039;&#039; im Arbeitsverzeichnis mit dem Makefile und den Quellcodedateien erzeugt (unter anderem) die Dateien superprog.hex und superprog.eep. Abhängigkeiten zwischen den einzelnen c-Dateien werden dabei automatisch berücksichtigt. Die &#039;&#039;superprog.hex&#039;&#039; und &#039;&#039;superprog.eep&#039;&#039; werden mit &#039;&#039;make program&#039;&#039; zum Controller  übertragen. Mit &#039;&#039;make clean&#039;&#039; werden alle temporären Dateien gelöscht (=&amp;quot;aufgeräumt&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
== Sonstige Einstellungen ==&lt;br /&gt;
&lt;br /&gt;
=== Optimierungsgrad ===&lt;br /&gt;
&lt;br /&gt;
Der gcc-Compiler kennt verschiedene Stufen der Optimierung. Nur zu Testzwecken sollte die Optimierung ganz deaktiviert werden (&#039;&#039;OPT = 0&#039;&#039;). Die weiteren möglichen Optionen weisen den Compiler an, möglichst kompakten oder möglichst schnellen Code zu erzeugen. In den weitaus meisten Fällen ist &#039;&#039;OPT = s&#039;&#039; die empfohlene Einstellung, damit wird kompakter und oft auch der schnellste Maschinencode erzeugt. Beim Update auf eine neue Compilerversion ist zu beachten, dass diese möglicherweise intern andere Optimierungsalgorithmen verwendet und sich dadurch die Größe des Machinencodes etwas ändert, ohne dass man im Quellcode etwas geändert hat.&lt;br /&gt;
&lt;br /&gt;
Als Orientierungswerte die Größe des Maschinencodes bei verschiedenen Optionen für einen nicht näher spezifizierten relativ kleinen Testcode bei Verwendung einer nicht näher spezifizierten Compilerversion. &lt;br /&gt;
&lt;br /&gt;
* -O0 : 12&#039;217 Byte&lt;br /&gt;
&lt;br /&gt;
* -O1 : 9&#039;128 Byte&lt;br /&gt;
&lt;br /&gt;
* -O2 : 1&#039;670 Byte&lt;br /&gt;
&lt;br /&gt;
* -O3 : 3&#039;004 Byte&lt;br /&gt;
&lt;br /&gt;
* -Os : 1&#039;695 Byte&lt;br /&gt;
&lt;br /&gt;
Im diesem Testfall führt die Option -O2 mit zum kompaktesten Code, dies  allerdings hier nur mit 25 Bytes &amp;quot;Vorsprung&amp;quot;. Es kann durchaus sein, dass nur wenige Programmerweiterungen dazu führen, dass Compilieren mit -Os wieder in kompakteren Code resultiert.&lt;br /&gt;
&lt;br /&gt;
Siehe dazu auch: &lt;br /&gt;
* [http://www.nongnu.org/avr-libc/user-manual/using_tools.html#gcc_optO avr-libc manual Abschnitt Using the gnu-tools/Compiler-Optionen]&lt;br /&gt;
&lt;br /&gt;
* [http://www.nongnu.org/avr-libc/user-manual/FAQ.html#faq_optflags avr-libc Manual FAQ Nr. 16] (Stand avr-libc Version 1.4.5)&lt;br /&gt;
&lt;br /&gt;
=== Debug-Format ===&lt;br /&gt;
&lt;br /&gt;
Unterstützt werden die Formate stabs und dwarf-2. Das Format wird hinter &#039;&#039;DEBUG =&#039;&#039; eingestellt. Siehe dazu Abschnitt &#039;&#039;Eingabedateien zur Simulation&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Assembler-Dateien ===&lt;br /&gt;
&lt;br /&gt;
Die im Projekt genutzten Assembler-Dateien werden hinter ASRC durch Leerzeichen getrennt aufgelistet. Assembler-Dateien haben immer die Endung .S (großes S). Ist zum Beispiel der Assembler-Quellcode eines Software-UARTs in einer Datei softuart.S enthalten, lautet die Zeile: &#039;&#039;ASRC = softuart.S&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Taktfrequenz ===&lt;br /&gt;
&lt;br /&gt;
Neuere Versionen der WinAVR/Mfile Vorlage für Makefiles beinhalten die Definition einer Variablen F_CPU (WinAVR 2/2005). Darin wird die Taktfrequenz des Controllers in Hertz eingetragen. Die Definition steht dann im gesamten Projekt ebenfalls unter der Bezeichnung F_CPU zur Verfügung (z.&amp;amp;nbsp;B. um daraus UART-, SPI- oder ADC-Frequenzeinstellungen abzuleiten).&lt;br /&gt;
&lt;br /&gt;
Die Angabe hat rein &amp;quot;informativen&amp;quot; Charakter, die tatsächliche Taktrate wird über den externen Takt (z.&amp;amp;nbsp;B. Quarz) bzw. die Einstellung des internen R/C-Oszillators  bestimmt. Die Nutzung von F_CPU hat also nur Sinn, wenn die Angabe mit dem tatsächlichen Takt übereinstimmt.&lt;br /&gt;
&lt;br /&gt;
Innerhalb neuerer Versionen der avr-libc (ab Version 1.2) wird die Definition der Taktfrequenz (F_CPU) zur Berechnung der Wartefunktionen in delay.h genutzt. Diese funktionieren nur dann korrekt, wenn F_CPU mit der tatsächlichen Taktfrequenz übereinstimmt.&lt;br /&gt;
F_CPU muss dazu jedoch nicht unbedingt im makefile definiert werden. Es reicht aus, wird aber bei mehrfacher Anwendung unübersichtlich, vor &#039;&#039;#include &amp;lt;util/delay.h&amp;gt;&#039;&#039; (veraltet: &#039;&#039;#include &amp;lt;avr/delay.h&amp;gt;&#039;&#039;) ein &#039;&#039;#define F_CPU [hier Takt in Hz]UL&#039;&#039; einzufügen. Bei Nutzung von delay.h ist darauf zu achten, dass die Optimierung des Compilers nicht ausgeschaltet ist, sonst wird sehr viel Code erzeugt und die Wartezeit stimmt nicht mit der gewünschten Zeitspanne überein. Vgl. dazu den [http://www.nongnu.org/avr-libc/user-manual/group__util__delay.html entsprechenden Abschnitt der Dokumentation].&lt;br /&gt;
&lt;br /&gt;
== Eingabedateien zur Simulation in AVR-Studio ==&lt;br /&gt;
&lt;br /&gt;
Mit älteren AVR-Studio-Versionen kann man nur auf Grundlage so genannter &#039;&#039;coff&#039;&#039;-Dateien simulieren. Neuere Versionen von AVR-Studio (ab 4.10.356) unterstützen zudem das modernere aber noch experimentelle dwarf-2-Format, das ab WinAVR 20040722 (avr-gcc 3.4.1/Binutils inkl. Atmel add-ons) &amp;quot;direkt&amp;quot; vom Compiler erzeugt wird.&lt;br /&gt;
&lt;br /&gt;
; Vorgehensweise bei dwarf-2:&lt;br /&gt;
* Im Makefile bei DEBUG: &amp;lt;div class=&amp;quot;code&amp;quot;&amp;gt;&amp;lt;pre&amp;gt;DEBUG=dwarf-2&amp;lt;/pre&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;make all&#039;&#039; (evtl. vorher &#039;&#039;make clean&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
* Die erzeugte &#039;&#039;elf&#039;&#039;-Datei (im Beispiel oben &#039;&#039;superprog.elf&#039;&#039;) in AVR-Studio laden&lt;br /&gt;
&lt;br /&gt;
* AVR-Simulator und zu simulierenden Controller wählen, &amp;quot;Finish&amp;quot;&lt;br /&gt;
&lt;br /&gt;
* Weiteres siehe AVR-Studio Online-Hilfe&lt;br /&gt;
&lt;br /&gt;
; Vorgehensweise bei extcoff: (sollte nur noch in Ausnahmefällen genutzt werden)&lt;br /&gt;
&lt;br /&gt;
* Im Makefile bei DEBUG: &amp;lt;div class=&amp;quot;code&amp;quot;&amp;gt;&amp;lt;pre&amp;gt;DEBUG=stabs&amp;lt;/pre&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;make extcoff&#039;&#039; (evtl. vorher &#039;&#039;make clean&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
* Die erzeugte &#039;&#039;cof&#039;&#039;-Datei (im Beispiel oben &#039;&#039;superprog.cof&#039;&#039;) in AVR-Studio laden&lt;br /&gt;
&lt;br /&gt;
* AVR-Simulator und zu simulierenden Controller wählen, &amp;quot;Finish&amp;quot;&lt;br /&gt;
&lt;br /&gt;
* Weiteres siehe AVR-Studio Online-Hilfe&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Beim Simulieren scheinen oft &amp;quot;Variablen zu fehlen&amp;quot;. Ursache dafür ist, dass der Compiler diese &amp;quot;Variablen&amp;quot; direkt Registern zuweist. Dies kann vermieden werden, indem die Optimierung abgeschaltet wird (im makefile). Man simuliert dann jedoch ein vom optimierten Code stark abweichendes Programm. Das Abschalten der Optimierung wird nicht empfohlen.&lt;br /&gt;
&lt;br /&gt;
Statt des Software-Simulators kann das AVR-Studio auch genutzt werden, um mit dem ATMEL JTAGICE, einem Nachbau davon (BootICE, Evertool o.&amp;amp;nbsp;ä.) oder dem ATMEL JTAGICE MKII &amp;quot;im System&amp;quot; zu debuggen. Dazu sind keine speziellen Einstellungen im makefile erforderlich. Debugging bzw. &amp;quot;In-System-Emulation&amp;quot; mit dem JTAGICE und JTAGICE MKII sind in der AVR-Studio Online-Hilfe beschrieben.&lt;br /&gt;
&lt;br /&gt;
Die Verwendung von Makefiles bietet noch viele weitere Möglichkeiten, einige davon werden im Anhang [[AVR-GCC-Tutorial#Zus.C3.A4tzliche_Funktionen_im_Makefile|Zusätzliche Funktionen im Makefile]] erläutert.&lt;br /&gt;
&lt;br /&gt;
= Ganzzahlige (Integer) Datentypen =&lt;br /&gt;
&lt;br /&gt;
Bei der Programmierung von Mikrokontrollern ist die Definition einiger ganzzahliger Datentypen sinnvoll, an denen eindeutig die Bit-Länge abgelesen werden kann.&lt;br /&gt;
&lt;br /&gt;
Standardisierte Datentypen werden in der Header-Datei stdint.h definiert. &lt;br /&gt;
Zur Nutzung der standardisierten Typen bindet man die &amp;quot;Definitionsdatei&amp;quot; wie folgt ein:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
// ab avr-libc Version 1.2.0 möglich und empfohlen:&lt;br /&gt;
#include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
// veraltet: #include &amp;lt;inttypes.h&amp;gt;&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Einige der dort definierten Typen (avr-libc Version 1.0.4):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
typedef signed char        int8_t;&lt;br /&gt;
typedef unsigned char      uint8_t;&lt;br /&gt;
&lt;br /&gt;
typedef short              int16_t;&lt;br /&gt;
typedef unsigned short     uint16_t;&lt;br /&gt;
&lt;br /&gt;
typedef long               int32_t;&lt;br /&gt;
typedef unsigned long      uint32_t;&lt;br /&gt;
&lt;br /&gt;
typedef long long          int64_t;&lt;br /&gt;
typedef unsigned long long uint64_t;&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* int8_t steht für einen 8-Bit Integer mit einem Wertebereich -128 bis +127.&lt;br /&gt;
&lt;br /&gt;
* uint8_t steht für einen 8-Bit Integer ohne Vorzeichen (unsigned int) mit einem Wertebereich von 0 bis 255&lt;br /&gt;
&lt;br /&gt;
* int16_t steht für einen 16-Bit Integer mit einem Wertebereich -32768 bis +32767.&lt;br /&gt;
&lt;br /&gt;
* uint16_t steht für einen 16-Bit Integer ohne Vorzeichen (unsigned int) mit einem Wertebereich von 0 bis 65535.&lt;br /&gt;
&lt;br /&gt;
Die Typen ohne vorangestelltes &#039;&#039;u&#039;&#039; werden als vorzeichenbehaftete Zahlen abgespeichert. Typen mit vorgestelltem &#039;&#039;u&#039;&#039; dienen der Ablage von postiven Zahlen (inkl. 0). Siehe dazu auch: [http://www.nongnu.org/avr-libc/user-manual/index.html Dokumentation der avr-libc] Abschnitt Modules/(Standard) Integer Types.&lt;br /&gt;
&lt;br /&gt;
= Bitfelder =&lt;br /&gt;
&lt;br /&gt;
Beim Programmieren von Mikrocontrollern muss auf jedes Byte oder sogar auf&lt;br /&gt;
jedes Bit geachtet werden. Oft müssen wir in einer Variablen lediglich den&lt;br /&gt;
Zustand 0 oder 1 speichern. Wenn wir nun zur Speicherung eines einzelnen Wertes&lt;br /&gt;
den kleinsten bekannten Datentypen, nämlich &#039;&#039;&#039;unsigned char&#039;&#039;&#039;, nehmen, dann&lt;br /&gt;
verschwenden wir 7 Bits, da ein &#039;&#039;&#039;unsigned char&#039;&#039;&#039; ja 8 Bits breit ist.&lt;br /&gt;
&lt;br /&gt;
Hier bietet uns die Programmiersprache C ein mächtiges Werkzeug an, mit dessen&lt;br /&gt;
Hilfe wir 8 Bits in eine einzelne Bytevariable zusammenfassen und (fast) wie&lt;br /&gt;
8 einzelne Variablen ansprechen können. Die Rede ist von so genannten Bitfeldern. Diese werden als Strukturelemente definiert. Sehen wir uns dazu doch am besten gleich ein Beispiel an:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
struct {&lt;br /&gt;
   unsigned bStatus_1:1; // 1 Bit für bStatus_1&lt;br /&gt;
   unsigned bStatus_2:1; // 1 Bit für bStatus_2&lt;br /&gt;
   unsigned bNochNBit:1; // Und hier noch mal ein Bit&lt;br /&gt;
   unsigned b2Bits:2;    // Dieses Feld ist 2 Bits breit&lt;br /&gt;
   // All das hat in einer einzigen Byte-Variable Platz.&lt;br /&gt;
   // die 3 verbleibenden Bits bleiben ungenutzt&lt;br /&gt;
} x;&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Zugriff auf ein solches Feld erfolgt nun wie beim Strukturzugriff bekannt&lt;br /&gt;
über den Punkt- oder den Dereferenzierungs-Operator:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
x.bStatus_1 = 1;&lt;br /&gt;
x.bStatus_2 = 0;&lt;br /&gt;
x.b2Bits = 3;&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bitfelder sparen Platz im RAM, zu Lasten von Platz im Flash, verschlechtern aber unter Umständen die Les- und Wartbarkeit des Codes. Anfängern wird deshalb geraten, ein &amp;quot;ganzes&amp;quot; Byte (uint8_t) zu nutzen, auch wenn nur ein Bitwert gespeichert werden soll.&lt;br /&gt;
&lt;br /&gt;
Wenn man nur ein paar wenige Variablen vom Typ bool verwenden möchte, kann man&lt;br /&gt;
auch die Headerdatei &amp;lt;stdbool.h&amp;gt; einbinden und sich dann wie gewohnt einen Booltyp anlegen. Variablen dieses Typs brauchen dennoch 1 Byte Speicher, ermöglichen aber eine genaue Unterscheidung zwischen Zahlenvariable und boolscher Variable.&lt;br /&gt;
&lt;br /&gt;
= Grundsätzlicher Programmaufbau eines &amp;amp;micro;C-Programms =&lt;br /&gt;
&lt;br /&gt;
Wir unterscheiden zwischen 2 verschiedenen Methoden, um ein&lt;br /&gt;
Mikrocontroller-Programm zu schreiben, und zwar völlig unabhängig davon, in&lt;br /&gt;
welcher Programmiersprache das Programm geschrieben wird.&lt;br /&gt;
&lt;br /&gt;
== Sequentieller Programmablauf ==&lt;br /&gt;
&lt;br /&gt;
Bei dieser Programmiertechnik wird eine Endlosschleife programmiert, welche im&lt;br /&gt;
Wesentlichen immer den gleichen Aufbau hat:&lt;br /&gt;
&lt;br /&gt;
[[Image:Sequentielle Programme.gif]]&lt;br /&gt;
&lt;br /&gt;
== Interruptgesteuerter Programmablauf ==&lt;br /&gt;
&lt;br /&gt;
Bei dieser Methode werden beim Programmstart zuerst die gewünschten Interruptquellen aktiviert und dann in eine Endlosschleife gegangen, in welcher Dinge erledigt werden können, welche nicht zeitkritisch sind. Wenn ein Interrupt ausgelöst wird, so wird automatisch die zugeordnete Interruptfunktion ausgeführt.&lt;br /&gt;
&lt;br /&gt;
[[Image:Interrupt Programme.gif]]&lt;br /&gt;
&lt;br /&gt;
= Zugriff auf Register =&lt;br /&gt;
&lt;br /&gt;
Die AVR-Controller verfügen über eine Vielzahl von Registern. Die meisten&lt;br /&gt;
davon sind sogenannte Schreib-/Leseregister. Das heißt, das Programm kann die&lt;br /&gt;
Inhalte der Register sowohl auslesen als auch beschreiben.&lt;br /&gt;
&lt;br /&gt;
Register haben einen besonderen Stellenwert bei den AVR Controllern. Sie dienen dem Zugriff auf die Ports und die Schnittstellen des Controllers. Wir unterscheiden zwischen 8-Bit und 16-Bit Registern. Vorerst behandeln wir mal&lt;br /&gt;
die 8-Bit Register.&lt;br /&gt;
&lt;br /&gt;
Einzelne Register sind bei allen AVRs vorhanden, andere wiederum nur bei bestimmten Typen. So sind beispielsweise die Register, welche für den Zugriff auf den UART notwendig sind, selbstverständlich nur bei denjenigen Modellen vorhanden, welche über einen integrierten Hardware UART bzw. USART verfügen.&lt;br /&gt;
&lt;br /&gt;
Die Namen der Register sind in den Headerdateien zu den entsprechenden AVR-Typen definiert. Dazu muss man den Namen der controllerspezifischen Headerdatei nicht kennen. Es reicht aus, die allgemeine Headerdatei &#039;&#039;avr/io.h&#039;&#039; einzubinden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ist im Makefile der MCU-Typ z.&amp;amp;nbsp;B. mit dem Inhalt atmega8 definiert (und wird somit per -mmcu=atmega8 an den Compiler übergeben), wird beim Einlesen der io.h-Datei implizit (&amp;quot;automatisch&amp;quot;) auch die iom8.h-Datei mit den Register-Definitionen für den ATmega8 eingelesen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- Wohl besser als Anhang - spaeter... --&amp;gt;&lt;br /&gt;
Intern wird diese &amp;quot;Automatik&amp;quot; wie folgt realisiert: Der Controllertyp wird dem Compiler als Parameter übergeben (vgl. &#039;&#039;avr-gcc -c -mmcu=atmega16 [...]&#039;&#039; im Einführungsbeispiel). Wird ein Makefile nach der WinAVR/mfile-Vorlage verwendet, setzt man die Variable &#039;&#039;MCU&#039;&#039;, der Inhalt dieser Variable wird dann an passender Stelle für die Compilerparameter verwendet. Der Compiler definiert intern eine dem mmcu-Parameter zugeordnete &amp;quot;Variable&amp;quot; (genauer: ein Makro) mit dem Namen des Controllers, vorangestelltem &#039;&#039;__AVR_&#039;&#039; und angehängten Unterstrichen (z.B. wird bei &#039;&#039;-mmcu=atmega16&#039;&#039; das Makro &#039;&#039;__AVR_ATmega16__&#039;&#039; definiert). Beim Einbinden der Header-Datei &#039;&#039;avr/io.h&#039;&#039; wird geprüft, ob das jeweilige Makro definiert ist und die zum Controller passende Definitionsdatei eingelesen. Zur Veranschaulichung einige Ausschnitte aus einem Makefile:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
[...]&lt;br /&gt;
# MCU Type (&amp;quot;name&amp;quot;) setzen:&lt;br /&gt;
MCU = atmega16&lt;br /&gt;
[...]&lt;br /&gt;
&lt;br /&gt;
[...]&lt;br /&gt;
## Verwendung des Inhalts von MCU (hier atmega16) fuer die &lt;br /&gt;
## Compiler- und Assembler-Parameter&lt;br /&gt;
ALL_CFLAGS = -mmcu=$(MCU) -I. $(CFLAGS) $(GENDEPFLAGS)&lt;br /&gt;
ALL_CPPFLAGS = -mmcu=$(MCU) -I. -x c++ $(CPPFLAGS) $(GENDEPFLAGS)&lt;br /&gt;
ALL_ASFLAGS = -mmcu=$(MCU) -I. -x assembler-with-cpp $(ASFLAGS)&lt;br /&gt;
[...]&lt;br /&gt;
&lt;br /&gt;
[...]&lt;br /&gt;
## Aufruf des Compilers:&lt;br /&gt;
## mit den Parametern ($(ALL_CFLAGS) ist -mmcu=$(MCU)[...] = -mmcu=atmega16[...]&lt;br /&gt;
$(OBJDIR)/%.o : %.c&lt;br /&gt;
	@echo&lt;br /&gt;
	@echo $(MSG_COMPILING) $&amp;lt;&lt;br /&gt;
	$(CC) -c $(ALL_CFLAGS) $&amp;lt; -o $@ &lt;br /&gt;
[...]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Da --mmcu=atmega16 übergeben wurde, wird __AVR_ATmega16__ definiert und kann in avr/io.h zur Fallunterscheidung genutzt werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
// avr/io.h &lt;br /&gt;
// (bei WinAVR-Standardinstallation in C:\WinAVR\avr\include\avr)&lt;br /&gt;
[...]&lt;br /&gt;
#if defined (__AVR_AT94K__)&lt;br /&gt;
#  include &amp;lt;avr/ioat94k.h&amp;gt;&lt;br /&gt;
// [...]&lt;br /&gt;
#elif defined (__AVR_ATmega16__)&lt;br /&gt;
// da __AVR_ATmega16__ definiert ist, wird avr/iom16.h eingebunden:&lt;br /&gt;
#  include &amp;lt;avr/iom16.h&amp;gt;&lt;br /&gt;
// [...]&lt;br /&gt;
#else&lt;br /&gt;
#  if !defined(__COMPILING_AVR_LIBC__)&lt;br /&gt;
#    warning &amp;quot;device type not defined&amp;quot;&lt;br /&gt;
#  endif&lt;br /&gt;
#endif&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Schreiben in Register ==&lt;br /&gt;
&lt;br /&gt;
Zum Schreiben kann man Register einfach wie eine Variable setzen. In Quellcodes, die für ältere Versionen des avr-gcc/der avr-libc entwickelt wurden, erfolgt der Schreibzugriff über die Funktion outp(). Aktuelle Versionen des Compilers unterstützen den Zugriff nun direkt und outp() ist nicht mehr erforderlich.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
int main(void)&lt;br /&gt;
{&lt;br /&gt;
    /* Setzt das Richtungsregister des Ports A auf 0xff &lt;br /&gt;
       (alle Pins als Ausgang, vgl. Abschnitt Zugriff auf Ports): */&lt;br /&gt;
    DDRA = 0xff;    &lt;br /&gt;
&lt;br /&gt;
    /* Setzt PortA auf 0x03, Bit 0 und 1 &amp;quot;high&amp;quot;, restliche &amp;quot;low&amp;quot;: */&lt;br /&gt;
    PORTA = 0x03;   &lt;br /&gt;
    ...&lt;br /&gt;
&lt;br /&gt;
    // Setzen der Bits 0,1,2,3 und 4&lt;br /&gt;
    // Binär 00011111 = Hexadezimal 1F&lt;br /&gt;
    DDRB = 0x1F;    /* direkte Zuweisung - unübersichtlich */&lt;br /&gt;
&lt;br /&gt;
    /* Ausführliche Schreibweise: identische Funktionalität, mehr Tipparbeit&lt;br /&gt;
       aber übersichtlicher und selbsterklärend: */&lt;br /&gt;
    DDRB = (1 &amp;lt;&amp;lt; DDB0) | (1 &amp;lt;&amp;lt; DDB1) | (1 &amp;lt;&amp;lt; DDB2) | (1 &amp;lt;&amp;lt; DDB3) | (1 &amp;lt;&amp;lt; DDB4); &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die ausführliche Schreibweise sollte bevorzugt verwendet werden, da dadurch die Zuweisungen selbsterklärend sind und somit der Code leichter nachvollzogen werden kann. Atmel verwendet sie auch bei Beispielen in Datenblätten und in den allermeisten Quellcodes zu Application-Notes.&lt;br /&gt;
&lt;br /&gt;
Der gcc C-Compiler (genauer der Präprozessor) unterstützt ab Version 4.3.0 Konstanten im Binärformat, z.B. DDRB&amp;amp;nbsp;=&amp;amp;nbsp;0b00011111 (für WinAVR wurden schon ältere Versionen des gcc entsprechend angepasst). Diese Schreibweise ist jedoch nicht standardkonform und man sollte sie daher insbesondere dann nicht verwenden, wenn Code mit anderen ausgetauscht oder mit anderen Compilern bzw. älteren Versionen des gcc genutzt werden soll.  &lt;br /&gt;
&lt;br /&gt;
=== Verändern von Registerinhalten ===&lt;br /&gt;
&lt;br /&gt;
Einzelne Bits setzt und löscht man &amp;quot;Standard-C-konform&amp;quot; mittels logischer (Bit-) Operationen. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
 x |= (1 &amp;lt;&amp;lt; Bitnummer);  // Hiermit wird ein Bit in x gesetzt&lt;br /&gt;
 x &amp;amp;= ~(1 &amp;lt;&amp;lt; Bitnummer); // Hiermit wird ein Bit in x geloescht&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Es wird jeweils nur der Zustand des angegebenen Bits geändert, der vorherige Zustand der anderen Bits bleibt erhalten. &lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
#define MEINBIT 2&lt;br /&gt;
...&lt;br /&gt;
PORTA |= (1 &amp;lt;&amp;lt; MEINBIT);    /* setzt Bit 2 an PortA auf 1 */&lt;br /&gt;
PORTA &amp;amp;= ~(1 &amp;lt;&amp;lt; MEINBIT);   /* loescht Bit 2 an PortA */&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit dieser Methode lassen sich auch mehrere Bits eines Registers gleichzeitig setzen und löschen.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
DDRA &amp;amp;= ~( (1&amp;lt;&amp;lt;PA0) | (1&amp;lt;&amp;lt;PA3) );  /* PA0 und PA3 als Eingaenge */&lt;br /&gt;
PORTA |= (1&amp;lt;&amp;lt;PA0) | (1&amp;lt;&amp;lt;PA3);      /* Interne Pull-Up fuer beide einschalten */&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In Quellcodes, die für ältere Version den des avr-gcc/der avr-libc entwickelt wurden, werden einzelne Bits mittels der Funktionen sbi und cbi gesetzt bzw. gelöscht. Beide Funktionen sind nicht mehr erforderlich.&lt;br /&gt;
&lt;br /&gt;
Siehe auch:&lt;br /&gt;
* [[Bitmanipulation]]&lt;br /&gt;
* [http://www.nongnu.org/avr-libc/user-manual/index.html Dokumentation der avr-libc] Abschnitt Modules/Special Function Registers&lt;br /&gt;
&lt;br /&gt;
== Lesen aus Registern ==&lt;br /&gt;
&lt;br /&gt;
Zum Lesen kann man auf Register einfach wie auf eine Variable zugreifen. In Quellcodes, die für ältere Versionen des avr-gcc/der avr-libc entwickelt wurden, erfolgt der Lesezugriff über die Funktion inp(). Aktuelle Versionen des Compilers unterstützen den Zugriff nun direkt und inp() ist nicht mehr erforderlich.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
uint8_t foo;&lt;br /&gt;
&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
int main(void)&lt;br /&gt;
{&lt;br /&gt;
    /* kopiert den Status der Eingabepins an PortB &lt;br /&gt;
       in die Variable foo: */&lt;br /&gt;
    foo = PINB;    &lt;br /&gt;
    //...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Zustände von Bits erfolgt durch Einlesen des gesamten Registerinhalts und ausblenden der Bits deren Zustand nicht von Interesse ist. Einige Beispiele zum Prüfen ob Bits gesetzt oder gelöscht sind:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#define MEINBIT0 0 &lt;br /&gt;
#define MEINBIT2 2&lt;br /&gt;
&lt;br /&gt;
uint8_t i;&lt;br /&gt;
&lt;br /&gt;
extern test1();&lt;br /&gt;
&lt;br /&gt;
// Funkion test1 aufrufen, wenn Bit 0 in Register PINA gesetzt (1) ist&lt;br /&gt;
i = PINA;         // Inhalt in Arbeitsvariable&lt;br /&gt;
i = i &amp;amp; 0x01;     // alle Bits bis auf Bit 0 ausblenden (logisches und)&lt;br /&gt;
                  // falls das Bit gesetzt war, hat i den Inhalt 1&lt;br /&gt;
if ( i != 0 ) {   // Ergebnis ungleich 0 (wahr)? &lt;br /&gt;
  test1()         // dann muss Bit 0 in i gesetzt sein -&amp;gt; Funktion aufrufen&lt;br /&gt;
}&lt;br /&gt;
// verkürzt:&lt;br /&gt;
if ( ( PINA &amp;amp; 0x01 ) != 0 ) {&lt;br /&gt;
  test1();&lt;br /&gt;
}&lt;br /&gt;
// nochmals verkürzt:&lt;br /&gt;
if ( PINA &amp;amp; 0x01 ) {&lt;br /&gt;
  test1();&lt;br /&gt;
}&lt;br /&gt;
// mit definierter Bitnummer:&lt;br /&gt;
if ( PINA &amp;amp; ( 1 &amp;lt;&amp;lt; MEINBIT0 ) ) {&lt;br /&gt;
  test(1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Funktion aufrufen, wenn Bit 0 oder Bit 2 gesetzt ist&lt;br /&gt;
if ( PINA &amp;amp; 0x05 ) {&lt;br /&gt;
  test1();  // Vergleich &amp;lt;&amp;gt; 0 (wahr), also muss Bit 0 oder 2 gesetzt sein&lt;br /&gt;
}&lt;br /&gt;
// mit definierten Bitnummern:&lt;br /&gt;
if ( PINA &amp;amp; ( ( 1 &amp;lt;&amp;lt; MEINBIT0 ) | ( 1 &amp;lt;&amp;lt; MEINBIT2 ) ) ) {&lt;br /&gt;
  test1();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Funktion aufrufen, wenn Bit 0 und Bit 2 gesetzt sind&lt;br /&gt;
if ( ( PINA &amp;amp; 0x05 ) == 0x05 ) {  // nur wahr, wenn beide Bits gesetzt&lt;br /&gt;
  test1();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Funktion test2() aufrufen, wenn Bit 0 gelöscht (0) ist&lt;br /&gt;
i = PINA;        // einlesen in temporäre Variable&lt;br /&gt;
i = i &amp;amp; 0x01;    // maskieren von B&lt;br /&gt;
if ( i == 0 ) {  // Vergleich ist wahr, wenn Bit 0 nicht gesetzt ist&lt;br /&gt;
  test2();&lt;br /&gt;
}&lt;br /&gt;
// analog mit !-Operator (not)&lt;br /&gt;
if ( !i ) {&lt;br /&gt;
  test2();&lt;br /&gt;
}&lt;br /&gt;
// nochmals verkürzt:&lt;br /&gt;
if ( !( PINA &amp;amp; 0x01 ) ) {&lt;br /&gt;
  test2();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die AVR-Bibliothek (avr-libc) stellt auch Funktionen (Makros) zur Abfrage eines einzelnen Bits eines Registers zur Verfügung, diese sind bei anderen Compilern meist nicht verfügbar (können aber dann einfach durch Macros &amp;quot;nachgerüstet&amp;quot; werden).&lt;br /&gt;
&lt;br /&gt;
;bit_is_set (&amp;lt;Register&amp;gt;,&amp;lt;Bitnummer&amp;gt;): Die Funktion &#039;&#039;bit_is_set&#039;&#039; prüft, ob ein Bit gesetzt ist. Wenn das Bit gesetzt ist, wird ein Wert ungleich 0 zurückgegeben. Genau genommen ist es die Wertigkeit des abgefragten Bits, also 1 für Bit0, 2 für Bit1, 4 für Bit2 etc.&lt;br /&gt;
&lt;br /&gt;
;bit_is_clear (&amp;lt;Register&amp;gt;,&amp;lt;Bitnummer&amp;gt;): Die Funktion &#039;&#039;bit_is_clear&#039;&#039; prüft, ob ein Bit gelöscht ist. Wenn das Bit gelöscht ist, also auf 0 ist, wird ein Wert ungleich 0 zurückgegeben.&lt;br /&gt;
&lt;br /&gt;
Die Funktionen (eigentlich Makros) bit_is_clear bzw. bit_is_set sind nicht erforderlich, man kann und sollte C-Syntax verwenden, die universell verwendbar und portabel ist. Siehe auch [[Bitmanipulation]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Warten auf einen bestimmten Zustand ===&lt;br /&gt;
&lt;br /&gt;
Es gibt in der Bibliothek avr-libc Funktionen, die warten, bis ein bestimmter Zustand eines Bits erreicht ist. Es ist allerdings normalerweise eine eher unschöne Programmiertechnik, da in diesen Funktionen &amp;quot;blockierend&amp;quot; gewartet wird. Der Programmablauf bleibt also an dieser Stelle stehen, bis das maskierte Ereignis erfolgt ist. Setzt man den Watchdog ein, muss man darauf achten, dass dieser auch noch getriggert wird (Zurücksetzen des Watchdogtimers). &lt;br /&gt;
&lt;br /&gt;
Die Funktion &#039;&#039;&#039;loop_until_bit_is_set&#039;&#039;&#039; wartet in einer Schleife, bis das definierte Bit gesetzt ist. Wenn das Bit beim Aufruf der Funktion bereits gesetzt ist, wird die Funktion sofort wieder verlassen. Das niederwertigste Bit hat die Bitnummer 0. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
/* Warten bis Bit Nr. 2 (das dritte Bit) in Register PINA gesetzt (1) ist */&lt;br /&gt;
&lt;br /&gt;
#define WARTEPIN PINA&lt;br /&gt;
#define WARTEBIT PA2&lt;br /&gt;
&lt;br /&gt;
// mit der avr-libc Funktion:&lt;br /&gt;
loop_until_bit_is_set(WARTEPIN, WARTEBIT);&lt;br /&gt;
&lt;br /&gt;
// dito in &amp;quot;C-Standard&amp;quot;:&lt;br /&gt;
// Durchlaufe die (leere) Schleife solange das WARTEBIT in Register WARTEPIN&lt;br /&gt;
// _nicht_ ungleich 0 (also 0) ist.&lt;br /&gt;
while ( !(WARTEPIN &amp;amp; (1 &amp;lt;&amp;lt; WARTEBIT)) ) ;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die Funktion &#039;&#039;&#039;loop_until_bit_is_clear&#039;&#039;&#039; wartet in einer Schleife, bis das definierte Bit gelöscht ist. Wenn das Bit beim Aufruf der Funktion bereits gelöscht ist, wird die Funktion sofort wieder verlassen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
/* Warten bis Bit Nr. 4 (das fuenfte Bit) in Register PINB geloescht (0) ist */&lt;br /&gt;
#define WARTEPIN PINB&lt;br /&gt;
#define WARTEBIT PB4&lt;br /&gt;
&lt;br /&gt;
// avr-libc-Funktion:&lt;br /&gt;
loop_until_bit_is_clear(WARTEPIN, WARTEBIT);&lt;br /&gt;
&lt;br /&gt;
// dito in &amp;quot;C-Standard&amp;quot;:&lt;br /&gt;
// Durchlaufe die (leere) Schleife solange das WARTEBIT in Register WARTEPIN&lt;br /&gt;
// gesetzt (1) ist &lt;br /&gt;
while ( WARTEPIN &amp;amp; (1&amp;lt;&amp;lt;WARTEBIT) ) ;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Universeller und auch auf andere Plattformen besser übertragbar ist die Verwendung von C-Standardoperationen.&lt;br /&gt;
&lt;br /&gt;
Siehe auch: &lt;br /&gt;
* [http://www.nongnu.org/avr-libc/user-manual/index.html Dokumentation der avr-libc] Abschnitt Modules/Special Function Registers&lt;br /&gt;
* [[Bitmanipulation]]&lt;br /&gt;
&lt;br /&gt;
= Zugriff auf IO-Ports =&lt;br /&gt;
&lt;br /&gt;
Alle Ports der AVR-Controller werden über Register gesteuert. Dazu sind&lt;br /&gt;
jedem Port 3 Register zugeordnet:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;DDRx&#039;&#039;&#039; &lt;br /&gt;
| Datenrichtungsregister für Port&#039;&#039;&#039;x&#039;&#039;&#039;. &lt;br /&gt;
&#039;&#039;&#039;x&#039;&#039;&#039; entspricht &#039;&#039;&#039;A&#039;&#039;&#039;, &#039;&#039;&#039;B&#039;&#039;&#039;, &#039;&#039;&#039; C&#039;&#039;&#039;, &#039;&#039;&#039;D&#039;&#039;&#039; usw. (abhängig von der Anzahl der Ports des verwendeten AVR). Bit im Register gesetzt (1) für Ausgang, Bit gelöscht (0) für Eingang.&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;PINx&#039;&#039;&#039;&lt;br /&gt;
| Eingangsadresse für Port&#039;&#039;&#039;x&#039;&#039;&#039;. &lt;br /&gt;
Zustand des Ports. Die Bits in PINx entsprechen dem Zustand der als Eingang definierten Portpins. Bit 1 wenn Pin &amp;quot;high&amp;quot;, Bit 0 wenn Portpin low.&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;PORTx&#039;&#039;&#039;&lt;br /&gt;
| Datenregister für Port&#039;&#039;&#039;x&#039;&#039;&#039;. &lt;br /&gt;
Dieses Register wird verwendet, um die Ausgänge eines Ports anzusteuern. Bei Pins, die mittels DDRx auf Eingang geschaltet wurden, können über PORTx&lt;br /&gt;
die internen Pull-Up Widerstände aktiviert oder deaktiviert werden (1 = aktiv).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Jeder AVR implementiert eine unterschiedliche Menge an GPIO-Registern&lt;br /&gt;
(GPIO - General Purpose Input/Output). Die folgenden Beispiele gehen von einem AVR aus, der sowohl Port A als auch Port B besitzt. Sie müssen für andere AVRs (zum Beispiel ATmega8/48/88/168) entsprechend angepasst werden.&lt;br /&gt;
&lt;br /&gt;
== Datenrichtung bestimmen ==&lt;br /&gt;
&lt;br /&gt;
Zuerst muss die Datenrichtung der verwendeten Pins bestimmt werden. Um dies zu erreichen, wird das Datenrichtungsregister des entsprechenden Ports beschrieben.&lt;br /&gt;
&lt;br /&gt;
Für jeden Pin, der als Ausgang verwendet werden soll, muss dabei das&lt;br /&gt;
entsprechende Bit auf dem Port gesetzt werden. Soll der Pin als Eingang&lt;br /&gt;
verwendet werden, muss das entsprechende Bit gelöscht sein.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
Angenommen am Port B sollen die Pins 0 bis 4 als Ausgänge definiert werden, die noch verbleibenden Pins 5 bis 7 sollen als Eingänge fungieren. Dazu ist es daher notwendig, im für das Port B zuständigen Datenrichtungsregister DDRB folgende Bitkonfiguration einzutragen&lt;br /&gt;
&lt;br /&gt;
   +---+---+---+---+---+---+---+---+&lt;br /&gt;
   | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 1 |&lt;br /&gt;
   +---+---+---+---+---+---+---+---+&lt;br /&gt;
     7   6   5   4   3   2   1   0&lt;br /&gt;
&lt;br /&gt;
In C liest sich das dann so:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
// in io.h wird u.a. DDRB definiert:&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
// Setzen der Bits 0,1,2,3 und 4&lt;br /&gt;
// Binär 00011111 = Hexadezimal 1F&lt;br /&gt;
DDRB = 0x1F;    /* direkte Zuweisung - unübersichtlich */&lt;br /&gt;
&lt;br /&gt;
/* Ausführliche Schreibweise: identische Funktionalität, mehr Tipparbeit&lt;br /&gt;
   aber übersichtlicher und selbsterklärend: */&lt;br /&gt;
DDRB = (1 &amp;lt;&amp;lt; DDB0) | (1 &amp;lt;&amp;lt; DDB1) | (1 &amp;lt;&amp;lt; DDB2) | (1 &amp;lt;&amp;lt; DDB3) | (1 &amp;lt;&amp;lt; DDB4); &lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Pins 5 bis 7 werden (da 0) als Eingänge geschaltet. Weitere Beispiele:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
// Alle Pins des Ports B als Ausgang definieren:&lt;br /&gt;
DDRB = 0xff; &lt;br /&gt;
// Pin0 wieder auf Eingang und andere im ursprünglichen Zustand belassen:&lt;br /&gt;
DDRB &amp;amp;= ~( 1 &amp;lt;&amp;lt; DDB0 );&lt;br /&gt;
// Pin 3 und 4 auf Eingang und andere im ursprünglichen Zustand belassen:&lt;br /&gt;
DDRB &amp;amp;= ~( ( 1 &amp;lt;&amp;lt; DDB3 ) | ( 1&amp;lt;&amp;lt;DDB4) );&lt;br /&gt;
// Pin 0 und 3 wieder auf Ausgang und andere im ursprünglichen Zustand belassen:&lt;br /&gt;
DDRB |= ( 1 &amp;lt;&amp;lt; DDB0) | ( 1 &amp;lt;&amp;lt; DDB3 );&lt;br /&gt;
// Alle Pins auf Eingang:&lt;br /&gt;
DDRB = 0x00;&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Vordefinierte Bitnummern für I/O-Register ==&lt;br /&gt;
&lt;br /&gt;
Die Bitnummern (z.B. PCx, PINCx und DDCx für den Port C) sind in den io*.h-Dateien der avr-libc definiert und dienen lediglich der besseren Lesbarkeit. Man muss diese Definitionen nicht verwenden oder kann auch einfach &amp;quot;immer&amp;quot; PAx, PBx, PCx usw. nutzen, auch wenn der Zugriff auf Bits in DDRx- oder PINx-Registern erfolgt. Für den Compiler sind die Ausdrücke (1&amp;lt;&amp;lt;PC7), (1&amp;lt;&amp;lt;DDC7) und (1&amp;lt;&amp;lt;PINC7) identisch zu (1&amp;lt;&amp;lt;7) (genauer: der Präprozessor ersetzt die Ausdrücke (1&amp;lt;&amp;lt;PC7),... zu (1&amp;lt;&amp;lt;7)). Ein Ausschnitt der Definitionen für Port C eines ATmega32 aus der iom32.h-Datei zur Verdeutlichung (analog für die weiteren Ports):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
/* PORTC */&lt;br /&gt;
#define PC7     7&lt;br /&gt;
#define PC6     6&lt;br /&gt;
#define PC5     5&lt;br /&gt;
#define PC4     4&lt;br /&gt;
#define PC3     3&lt;br /&gt;
#define PC2     2&lt;br /&gt;
#define PC1     1&lt;br /&gt;
#define PC0     0&lt;br /&gt;
&lt;br /&gt;
/* DDRC */&lt;br /&gt;
#define DDC7    7&lt;br /&gt;
#define DDC6    6&lt;br /&gt;
#define DDC5    5&lt;br /&gt;
#define DDC4    4&lt;br /&gt;
#define DDC3    3&lt;br /&gt;
#define DDC2    2&lt;br /&gt;
#define DDC1    1&lt;br /&gt;
#define DDC0    0&lt;br /&gt;
&lt;br /&gt;
/* PINC */&lt;br /&gt;
#define PINC7   7&lt;br /&gt;
#define PINC6   6&lt;br /&gt;
#define PINC5   5&lt;br /&gt;
#define PINC4   4&lt;br /&gt;
#define PINC3   3&lt;br /&gt;
#define PINC2   2&lt;br /&gt;
#define PINC1   1&lt;br /&gt;
#define PINC0   0&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Digitale Signale ==&lt;br /&gt;
&lt;br /&gt;
Am einfachsten ist es, digitale Signale mit dem Mikrocontroller zu erfassen bzw. auszugeben.&lt;br /&gt;
&lt;br /&gt;
== Ausgänge ==&lt;br /&gt;
Will man als Ausgang definierte Pins (entsprechende DDRx-Bits = 1) auf Logisch 1 setzen, setzt man die  entsprechenden Bits im Portregister.&lt;br /&gt;
&lt;br /&gt;
Mit dem Befehl&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
    PORTB = 0x04; /* besser PORTB=(1&amp;lt;&amp;lt;PB2) */&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
wird also der Ausgang an Pin PB2 gesetzt (Beachte, dass die Bits immer &#039;&#039;von 0 an&#039;&#039; gezählt werden, das niederwertigste Bit ist also Bitnummer 0 und nicht etwa Bitnummer 1).&lt;br /&gt;
&lt;br /&gt;
Man beachte, dass bei der Zuweisung mittels &#039;&#039;&#039;=&#039;&#039;&#039; immer alle Pins gleichzeitig angegeben werden. Man sollte also, wenn nur bestimmte Ausgänge geschaltet werden sollen, zuerst den aktuellen Wert des Ports einlesen und das Bit des gewünschten Ports in diesen Wert einfließen lassen. Will man also nur den dritten Pin (Bit Nr. 2) an Port B auf &amp;quot;high&amp;quot; setzen und den Status der anderen Ausgänge unverändert lassen, nutze man diese Form:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
    PORTB = PORTB | 0x04; /* besser: PORTB = PORTB | ( 1&amp;lt;&amp;lt;PB2 ) */&lt;br /&gt;
    /* vereinfacht durch Nutzung des |= Operators : */&lt;br /&gt;
    PORTB |= (1&amp;lt;&amp;lt;PB2);&lt;br /&gt;
&lt;br /&gt;
    /* auch mehrere &amp;quot;gleichzeitig&amp;quot;: */&lt;br /&gt;
    PORTB |= (1&amp;lt;&amp;lt;PB4) | (1&amp;lt;&amp;lt;PB5); /* Pins PB4 und PB5 &amp;quot;high&amp;quot; */&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Ausschalten&amp;quot;, also  Ausgänge auf &amp;quot;low&amp;quot; setzen, erfolgt analog:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
    PORTB &amp;amp;= ~(1&amp;lt;&amp;lt;PB2); /* löscht Bit 2 in PORTB und setzt damit Pin PB2 auf low */ &lt;br /&gt;
    PORTB &amp;amp;= ~( (1&amp;lt;&amp;lt;PB4) | (1&amp;lt;&amp;lt;PB5) ); /* Pin PB4 und Pin PB5 &amp;quot;low&amp;quot; */&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In Quellcodes, die für ältere Version den des avr-gcc/der avr-libc entwickelt wurden, werden einzelne Bits mittels der Funktionen sbi und cbi gesetzt bzw. gelöscht. Beide Funktionen sind in aktuellen Versionen der avr-libc nicht mehr enthalten und auch nicht mehr erforderlich.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Falls der Anfangszustand von Ausgängen kritisch ist, muss die Reihenfolge beachtet werden, mit der die Datenrichtung (DDRx) eingestellt und der Ausgabewert (PORTx) gesetzt wird:&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Für Ausgangspins, die mit Anfangswert &amp;quot;high&amp;quot; initialisiert werden sollen:&lt;br /&gt;
* zuerst die Bits im PORTx-Register setzen&lt;br /&gt;
* anschließend die Datenrichtung auf Ausgang stellen&lt;br /&gt;
&lt;br /&gt;
Daraus ergibt sich die Abfolge für einen Pin, der bisher als Eingang mit abgeschaltetem Pull-Up konfiguriert ware:&lt;br /&gt;
* setze PORTx: interner Pull-Up aktiv&lt;br /&gt;
* setze DDRx: Ausgang (&amp;quot;high&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
Bei der Reihenfolge erst DDRx und dann PORTx, kann es zu einem kurzen &amp;quot;low-Puls&amp;quot; kommen, der auch externe Pull-Up-Widerstände &amp;quot;überstimmt&amp;quot;. Die (ungünstige) Abfolge: Eingang -&amp;gt; setze DDRx: Ausgang (auf &amp;quot;low&amp;quot;, da PORTx nach Reset 0) -&amp;gt; setze PORTx: Ausgang auf high. Vergleiche dazu auch das Datenblatt Abschnitt &#039;&#039;Configuring the Pin&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== Eingänge (Wie kommen Signale in den &amp;amp;micro;C) ==&lt;br /&gt;
&lt;br /&gt;
Die digitalen Eingangssignale können auf verschiedene Arten zu unserer Logik gelangen.&lt;br /&gt;
&lt;br /&gt;
=== Signalkopplung ===&lt;br /&gt;
&lt;br /&gt;
Am einfachsten ist es, wenn die Signale direkt aus einer anderen digitalen Schaltung übernommen werden können. Hat der Ausgang der entsprechenden Schaltung TTL-Pegel dann können wir sogar direkt den Ausgang der Schaltung mit einem Eingangspin von unserem Controller verbinden.&lt;br /&gt;
&lt;br /&gt;
Hat der Ausgang der anderen Schaltung keinen TTL-Pegel so müssen wir den Pegel über entsprechende Hardware (z.B. Optokoppler, [[Widerstand#Spannungsteiler|Spannungsteiler]], &amp;quot;Levelshifter&amp;quot; aka [[Pegelwandler]]) anpassen.&lt;br /&gt;
&lt;br /&gt;
Die Masse der beiden Schaltungen muss selbstverständlich miteinander verbunden werden. Der Software selber ist es natürlich letztendlich egal, wie das Signal eingespeist wird. Wir können ja ohnehin lediglich prüfen, ob an einem Pin unseres Controllers eine logische 1 (Spannung größer ca. 0,7*Vcc) oder eine logische 0 (Spannung kleiner ca. 0,2*Vcc) anliegt. Detaillierte Informationen darüber, ab welcher Spannung ein Eingang als 0 (&amp;quot;low&amp;quot;) bzw. 1 (&amp;quot;high&amp;quot;) erkannt wird, liefert die Tabelle DC Characteristics im Datenblatt des genutzten Controllers.&lt;br /&gt;
&lt;br /&gt;
Die Abfrage der Zustände der Portpins erfolgt direkt über den Registernamen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;font color=&amp;quot;#FF0000&amp;quot;&amp;gt;Dabei ist wichtig, zur Abfrage der Eingänge &#039;&#039;&#039;nicht&#039;&#039;&#039; etwa Portregister &#039;&#039;&#039;PORTx&#039;&#039;&#039; zu verwenden, &#039;&#039;&#039;sondern&#039;&#039;&#039; Eingangsregister &#039;&#039;&#039;PINx&#039;&#039;&#039;. Die Abfrage der Pinzustände über PORTx statt PINx ist ein häufiger Fehler beim AVR-&amp;quot;Erstkontakt&amp;quot;.&amp;lt;/font&amp;gt; (Ansonsten liest man nicht den Zustand der Eingänge, sondern den Status der internen Pull-Up-Widerstände.)&lt;br /&gt;
&lt;br /&gt;
Will man also die aktuellen Signalzustände von Port D abfragen und in eine Variable namens bPortD abspeichern, schreibt man folgende Befehlszeilen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
uint8_t bPortD;&lt;br /&gt;
...&lt;br /&gt;
bPortD = PIND;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit den C-Bitoperationen kann man den Status der Bits abfragen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
/* Fuehre Aktion aus, wenn Bit Nr. 1 (das &amp;quot;zweite&amp;quot; Bit) in PINC gesetzt (1) ist */&lt;br /&gt;
if ( PINC &amp;amp; (1&amp;lt;&amp;lt;PINC1) ) {&lt;br /&gt;
  /* Aktion */&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* Fuehre Aktion aus, wenn Bit Nr. 2 (das &amp;quot;dritte&amp;quot; Bit) in PINB geloescht (0) ist */&lt;br /&gt;
if ( !(PINB &amp;amp; (1&amp;lt;&amp;lt;PINB2)) ) {&lt;br /&gt;
  /* Aktion */&lt;br /&gt;
}&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Tasten und Schalter ===&lt;br /&gt;
&lt;br /&gt;
Der Anschluss mechanischer Kontakte an den Mikrocontroller gestaltet sich ebenfalls ganz einfach, wobei wir zwei unterschiedliche Methoden unterscheiden müssen (&#039;&#039;Active Low&#039;&#039; und &#039;&#039;Active High&#039;&#039;):&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Active Low&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Active High&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| [[Image:Active Low.gif]]&lt;br /&gt;
| [[Image:Active High.gif]]&lt;br /&gt;
|- &lt;br /&gt;
| Bei dieser Methode wird der Kontakt zwischen den Eingangspin des Controllers und Masse geschaltet.&lt;br /&gt;
&lt;br /&gt;
Damit bei offenem Schalter der Controller kein undefiniertes Signal bekommt wird zwischen die Versorgungsspannung und den Eingangspin ein sogenannter Pull-Up Widerstand geschaltet. Dieser dient dazu, den Pegel bei geöffnetem Schalter auf logisch 1 zu ziehen.&lt;br /&gt;
&lt;br /&gt;
Der Widerstandswert des Pull-Up Widerstands ist an sich nicht kritisch.  Wird er allerdings zu hoch gewählt, ist die Wirkung eventuell nicht gegeben. Als üblicher Wert haben sich 10 kOhm eingebürgert.&lt;br /&gt;
&lt;br /&gt;
Die AVRs haben sogar an den meisten Pins softwaremäßig zuschaltbare interne Pull-Up Widerstände, welche wir natürlich auch verwenden können.&lt;br /&gt;
&lt;br /&gt;
| Hier wird der Kontakt zwischen die Versorgungsspannung und den Eingangspin geschaltet.&lt;br /&gt;
&lt;br /&gt;
Damit bei offener Schalterstellung kein undefiniertes Signal am Controller ansteht, wird zwischen den Eingangspin und die Masse ein Pull-Down Widerstand geschaltet. Dieser dient dazu, den Pegel bei geöffneter Schalterstellung auf logisch 0 zu halten.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Pull-Up Widerstände aktivieren ====&lt;br /&gt;
&lt;br /&gt;
Die internen Pull-Up Widerstände von Vcc zu den einzelnen Portpins werden über das Register &#039;&#039;&#039; PORTx&#039;&#039;&#039; aktiviert bzw. deaktiviert, wenn ein Pin als &#039;&#039;&#039; Eingang&#039;&#039;&#039; geschaltet ist.&lt;br /&gt;
&lt;br /&gt;
Wird der Wert des entsprechenden Portpins auf 1 gesetzt, so ist der Pull-Up Widerstand aktiviert. Bei einem Wert von 0 ist der Pull-Up Widerstand nicht aktiv. Man sollte jeweils entweder den internen oder einen externen Pull-Up Widerstand verwenden, aber nicht beide zusammen.&lt;br /&gt;
&lt;br /&gt;
Im Beispiel werden alle Pins des Ports D als Eingänge geschaltet und alle Pull-Up Widerstände aktiviert. Weiterhin wird Pin PC7 als Eingang geschaltet und dessen interner Pull-Up Widerstand aktiviert, ohne die Einstellungen für die anderen Portpins (PC0-PC6) zu verändern.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
DDRD  = 0x00; /* alle Pins von Port D als Eingang */&lt;br /&gt;
PORTD = 0xff; /* interne Pull-Ups an allen Port-Pins aktivieren */&lt;br /&gt;
...&lt;br /&gt;
DDRC  &amp;amp;= ~(1&amp;lt;&amp;lt;DDC7);  /* Pin PC7 als Eingang */&lt;br /&gt;
PORTC |= (1&amp;lt;&amp;lt;PC7);    /* internen Pull-Up an PC7 aktivieren */&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== (Tasten-)Entprellung ====&lt;br /&gt;
&lt;br /&gt;
Nun haben alle mechanischen Kontakte, sei es von Schaltern, Tastern oder auch von Relais, die unangenehme Eigenschaft zu prellen. Dies bedeutet, dass beim Schließen des Kontaktes derselbe nicht direkt Kontakt herstellt, sondern mehrfach ein- und ausschaltet bis zum endgültigen Herstellen des Kontaktes.&lt;br /&gt;
&lt;br /&gt;
Soll nun mit einem schnellen Mikrocontroller gezählt werden, wie oft ein solcher Kontakt geschaltet wird, dann haben wir ein Problem, weil das Prellen als mehrfache Impulse gezählt wird. Diesem Phänomen muss beim Schreiben des Programms unbedingt Rechnung getragen werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;lt;inttypes.h&amp;gt;&lt;br /&gt;
#ifndef F_CPU&lt;br /&gt;
#warning &amp;quot;F_CPU war noch nicht definiert, wird nun mit 3686400 definiert&amp;quot;&lt;br /&gt;
#define F_CPU 3686400UL     /* Quarz mit 3.6864 Mhz  */&lt;br /&gt;
#endif&lt;br /&gt;
#include &amp;lt;util/delay.h&amp;gt;     /* bei alter avr-libc: #include &amp;lt;avr/delay.h&amp;gt; */      &lt;br /&gt;
&lt;br /&gt;
/* Einfache Funktion zum Entprellen eines Tasters */&lt;br /&gt;
inline uint8_t debounce(volatile uint8_t *port, uint8_t pin)&lt;br /&gt;
{&lt;br /&gt;
    if ( ! (*port &amp;amp; (1 &amp;lt;&amp;lt; pin)) )&lt;br /&gt;
    {&lt;br /&gt;
        /* Pin wurde auf Masse gezogen, 100ms warten   */&lt;br /&gt;
        _delay_ms(50);  // max. 262.1 ms / F_CPU in MHz&lt;br /&gt;
        _delay_ms(50); &lt;br /&gt;
        if ( *port &amp;amp; (1 &amp;lt;&amp;lt; pin) )&lt;br /&gt;
        {&lt;br /&gt;
            /* Anwender Zeit zum Loslassen des Tasters geben */&lt;br /&gt;
            _delay_ms(50);&lt;br /&gt;
            _delay_ms(50); &lt;br /&gt;
            return 1;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int main(void)&lt;br /&gt;
{&lt;br /&gt;
    DDRB &amp;amp;= ~( 1 &amp;lt;&amp;lt; PB0 );                 /* PIN PB0 auf Eingang (Taster)            */&lt;br /&gt;
    PORTB |= ( 1 &amp;lt;&amp;lt; PB0 );                 /* Pullup-Widerstand aktivieren            */&lt;br /&gt;
    ...&lt;br /&gt;
    if (debounce(&amp;amp;PINB, PB0))             /* Falls Taster an PIN PB0 gedrueckt..    */&lt;br /&gt;
        PORTD = PIND ^ ( 1 &amp;lt;&amp;lt; PD7 );  /* ..LED an Port PD7 an-&lt;br /&gt;
                                   bzw. ausschalten */&lt;br /&gt;
    ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bei diesem Beispiel ist zu beachten, dass der AVR im Falle eines Tastendrucks 200ms wartet, also brach liegt. Bei zeitkritische Anwendungen sollte man ein anderes Verfahren nutzen (z.B. Abfrage der Tastenzustände in einer Timer-Interrupt-Service-Routine).&lt;br /&gt;
&lt;br /&gt;
Zum Thema Entprellen siehe auch:&lt;br /&gt;
* Artikel [[Entprellung]]&lt;br /&gt;
&lt;br /&gt;
== Analog ==&lt;br /&gt;
&lt;br /&gt;
Die Verarbeitung von analogen Eingangswerten und die Ausgabe von Analogwerten wird in Kapitel [[AVR-GCC-Tutorial#Analoge_Ein-_und_Ausgabe|Analoge Ein- und Ausgabe]] behandelt.&lt;br /&gt;
&lt;br /&gt;
== 16-Bit Portregister (ADC, ICR1, OCR1, TCNT1, UBRR) ==&lt;br /&gt;
&lt;br /&gt;
Einige der Portregister in den AVR-Controllern sind 16 Bit breit. Im Datenblatt sind diese Register üblicherweise mit dem Suffix &amp;quot;L&amp;quot; (LSB) und &amp;quot;H&amp;quot; (MSB) versehen. Die avr-libc definiert zusätzlich die meisten dieser Variablen die Bezeichnung ohne &amp;quot;L&amp;quot; oder &amp;quot;H&amp;quot;. Auf diese kann direkt zugewiesen bzw. zugegriffen werden. Die Konvertierung von 16-bit Wort nach 2*8-bit Byte erfolgt intern.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
uint16_t foo;&lt;br /&gt;
&lt;br /&gt;
foo=ADC; /* setzt die Wort-Variable foo auf den Wert der letzten AD-Wandlung */&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Falls ben&amp;amp;ouml;tigt, kann eine 16-Bit Variable auch recht einfach manuell in ihre zwei 8-Bit Bestandteile zerlegt werden. Folgendes Beispiel demonstriert dies anhand des pseudo- 16-Bit Registers UBRR.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
#ifndef F_CPU&lt;br /&gt;
#define F_CPU 3686400&lt;br /&gt;
#endif&lt;br /&gt;
#define UART_BAUD_RATE 9600&lt;br /&gt;
&lt;br /&gt;
typedef union {&lt;br /&gt;
        uint16_t i16;&lt;br /&gt;
        struct {&lt;br /&gt;
                uint8_t i8l;&lt;br /&gt;
                uint8_t i8h;&lt;br /&gt;
        };&lt;br /&gt;
} convert16to8;&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
convert16to8 baud;&lt;br /&gt;
baud.i16 = F_CPU / (UART_BAUD_RATE * 16L) -1;&lt;br /&gt;
UBRRH = baud.i8h;&lt;br /&gt;
UBRRL = baud.i8l;&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
/*alternativ:*/&lt;br /&gt;
#include &amp;lt;inttypes.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
uint16_t wFoo16;&lt;br /&gt;
uint8_t bFooLow, bFooHigh;&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
wFoo16   = 0xAA55;                 /* zu &amp;quot;zerlegende&amp;quot; 16Bit-Integer */&lt;br /&gt;
bFooHigh = (uint8_t)(wFoo16 &amp;gt;&amp;gt; 8); /* MS-Byte */&lt;br /&gt;
bFooLow  = (uint8_t)(wFoo16);      /* LS-Byte */&lt;br /&gt;
...&lt;br /&gt;
#define us0(Data) ((unsigned char *)(&amp;amp;Data))&lt;br /&gt;
#define us1(Data) ((unsigned char *)((&amp;amp;Data)+1))&lt;br /&gt;
bFooHigh = us1(wFoo16);&lt;br /&gt;
bFoolow  = us0(wFoo16);&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bei einigen AVR-Typen (z.B. ATmega8) teilen sich UBRRH und UCSRC die gleiche Memory-Adresse. Damit der AVR trotzdem zwischen den beiden Registern unterscheiden kann, bestimmt das Bit7 (URSEL) welches Register tats&amp;amp;auml;chlich beschrieben werden soll. &#039;&#039;1000 0011&#039;&#039; (0x83) adressiert demnach UCSRC und &amp;amp;uuml;bergibt den Wert &#039;&#039;3&#039;&#039; und &#039;&#039;0000 0011&#039;&#039; (0x3) adressiert UBRRH und &amp;amp;uuml;bergibt ebenfalls den Wert &#039;&#039;3&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
Bei einigen 16-bit Registern (insbesondere die der 16-bit Timer) erfolgen Schreibzugriffe über das sogenannte &#039;&#039;temporary Register&#039;&#039;. Die Reihenfolge der Zugriffe bestimmt, wann der Wert tatsächlich ins Register geschrieben wird. Typisch wird erst das High-Byte beschrieben (xxxH) und intern im temporary Register zwischengespeichert. Nachdem das Low-Byte (xxxL) geschrieben wurde, setzt der Controller mit diesem und dem im temporary Register zwischengespeicherten Wert für das High-Byte das 16-bit Register. Dabei ist zu beachten, dass intern nur ein temporary Register verfügbar ist, welches in Interruptroutinen mglw. mit einem anderen Wert überschrieben wird, wenn dort ebenfalls 16-bit Register beschrieben werden. avr-gcc/avr-libc berücksichtigen die korrekte Reihenfolge automatisch, wenn die Register mit ihrem &amp;quot;16-bit Label&amp;quot; (ohne H bzw. L) angesprochen werden, dabei ist der Schutz des temporary Registers vor Überschreiben durch Interruptroutinen dennoch zu beachten (im Zweifel beim Schreibzugriff die Interrupts kurzzeitig global deaktivieren).&lt;br /&gt;
&lt;br /&gt;
Im Umgang mit 16-Bit Registern siehe auch:&lt;br /&gt;
* [http://www.nongnu.org/avr-libc/user-manual/index.html Dokumentation der avr-libc] Abschnitt Related Pages/Frequently Asked Questions/Nr. 8&lt;br /&gt;
* Datenblatt Abschnitt &#039;&#039;Accessing 16-bit Registers&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== IO-Register als Parameter und Variablen ==&lt;br /&gt;
&lt;br /&gt;
Um Register als Parameter für eigene Funktionen übergeben zu können, muss man sie als einen volatile uint8_t Pointer übergeben. Zum Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
uint8_t key_pressed(const volatile uint8_t *inputreg, uint8_t inputbit)&lt;br /&gt;
{&lt;br /&gt;
  static uint8_t last_state = 0;&lt;br /&gt;
 &lt;br /&gt;
  if ( last_state == ( *inputreg &amp;amp; (1&amp;lt;&amp;lt;inputbit) ) ) {&lt;br /&gt;
     return 0; /* keine Änderung */&lt;br /&gt;
  }&lt;br /&gt;
 &lt;br /&gt;
  /* Wenn doch, warten bis etwaiges Prellen vorbei ist: */&lt;br /&gt;
  _delay_ms(20);&lt;br /&gt;
&lt;br /&gt;
  /* Zustand für nächsten Aufruf merken: */&lt;br /&gt;
  last_state = ( *inputreg &amp;amp; (1&amp;lt;&amp;lt;inputbit) );&lt;br /&gt;
 &lt;br /&gt;
  /* und den entprellten Tastendruck zurückgeben: */&lt;br /&gt;
  return ( *inputreg &amp;amp; (1&amp;lt;&amp;lt;inputbit) );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* Beispiel für einen Funktionsaufruf: */&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
uint8_t i;&lt;br /&gt;
&lt;br /&gt;
//...&lt;br /&gt;
    i = key_pressed( &amp;amp;PINB, PB1 );&lt;br /&gt;
//...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein Aufruf der Funktion mit call by value würde Folgendes bewirken: Beim Funktionseintritt wird nur eine Kopie des momentanen Portzustandes angefertigt, die sich unabhängig vom tatsächlichen Zustand das Ports nicht mehr ändert, womit die Funktion wirkungslos wäre. Die Übergabe eines Zeigers wäre die Lösung, wenn der Compiler nicht optimieren würde. Denn dadurch wird im Programm nicht von der Hardware gelesen, sondern wieder nur von einem Abbild im Speicher. Das Ergebnis wäre das gleiche wie oben. Mit dem Schlüsselwort volatile sagt man nun dem Compiler, dass die entsprechende Variable entweder durch andere Softwareroutinen (Interrupts) oder durch die Hardware verändert werden kann.&lt;br /&gt;
&lt;br /&gt;
Im Übrigen können mit volatile gekennzeichnete Variablen auch als const deklariert werden, um sicherzustellen, dass sie nur noch von der Hardware änderbar sind.&lt;br /&gt;
&lt;br /&gt;
= Der UART =&lt;br /&gt;
&lt;br /&gt;
== Allgemeines zum UART ==&lt;br /&gt;
&lt;br /&gt;
Über den [[UART]] kann ein AVR leicht mit einer [[RS-232]]-Schnittstelle eines PC oder sonstiger Geräte mit &amp;quot;serieller Schnittstelle&amp;quot; verbunden werden. &lt;br /&gt;
&lt;br /&gt;
Mögliche Anwendungen des UART:&lt;br /&gt;
&lt;br /&gt;
* Debug-Schnittstelle: z.B. zur Anzeige von Zwischenergebnissen (&amp;quot;printf-debugging&amp;quot; - hier besser &amp;quot;UART-debugging&amp;quot;) auf einem PC. Auf dem Rechner reicht dazu ein [[RS-232#Terminalprogramme|Terminalprogramm]] (MS-Windows: Hyperterm oder besser Bray-Terminal, [http://www.mikrocontroller.net/forum/read-8-155472.html#new HTerm]; Unix/Linux z.B. minicom). Ein direkter Anschluss ist aufgrund unterschiedlicher Pegel nicht möglich, jedoch sind entsprechende Schnittstellen-ICs wie z.B. ein MAX232 günstig und leicht zu integrieren. Rechner ohne serielle Schnittstelle können über fertige USB-seriell-Adapter angeschlossen werden. &lt;br /&gt;
* &amp;quot;Mensch-Maschine Schnittstelle&amp;quot;: z.B. Konfiguration und Statusabfrage über eine &amp;quot;Kommandozeile&amp;quot; oder Menüs (siehe z.B. Forumsbeitrag [http://www.mikrocontroller.net/topic/52985 Auswertung RS232-Befehle]) &lt;br /&gt;
* Übertragen von gespeicherten Werten: z.B. bei einem Datenlogger&lt;br /&gt;
* Anschluss von Geräten mit serieller Schnittstelle (z.B. (Funk-)Modems, Mobiltelefone, Drucker, Sensoren, &amp;quot;intelligente&amp;quot; LC-Displays, GPS-Empfänger). &lt;br /&gt;
* &amp;quot;Feldbusse&amp;quot; auf RS485/RS422-Basis mittels entsprechenden Bustreiberbausteinen (z.B. MAX485)&lt;br /&gt;
* DMX, Midi etc.&lt;br /&gt;
* LIN-Bus (&#039;&#039;&#039;L&#039;&#039;&#039;ocal &#039;&#039;&#039;I&#039;&#039;&#039;nterconnect &#039;&#039;&#039;N&#039;&#039;&#039;etwork): Preiswerte Sensoren/Aktoren in der Automobiltechnik und darüber hinaus&lt;br /&gt;
&lt;br /&gt;
Einige AVR-Controller haben ein bis zwei vollduplexfähigen UART (&#039;&#039;&#039;U&#039;&#039;&#039;niversal &#039;&#039;&#039;A&#039;&#039;&#039;synchronous &#039;&#039;&#039;R&#039;&#039;&#039;eceiver and &#039;&#039;&#039;T&#039;&#039;&#039;ransmitter) schon eingebaut (&amp;quot;Hardware-UART&amp;quot;). &lt;br /&gt;
Übrigens: Vollduplex heißt nichts anderes, als dass der Baustein gleichzeitig senden und empfangen kann.&lt;br /&gt;
&lt;br /&gt;
Neuere AVRs (ATmega, ATtiny) verfügen über einen oder zwei U&#039;&#039;&#039;S&#039;&#039;&#039;ART(s), dieser unterscheidet sich vom UART hauptsächlich durch interne FIFO-Puffer für Ein- und Ausgabe und erweiterte Konfigurationsmöglichkeiten. Die Puffergröße ist allerdings nur 1 Byte.&lt;br /&gt;
&lt;br /&gt;
Der UART wird über vier separate Register angesprochen. USARTs der ATMEGAs verfügen über mehrere zusätzliche Konfigurationsregister. Das Datenblatt gibt darüber Auskunft. Die Folgende Tabelle gibt nur die Register für die (veralteten) UARTs wieder.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;UCR&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;U&#039;&#039;&#039;ART &#039;&#039;&#039;C&#039;&#039;&#039;ontrol &#039;&#039;&#039;R&#039;&#039;&#039;egister.&amp;lt;br /&amp;gt;&lt;br /&gt;
In diesem Register stellen wir ein, wie wir den UART verwenden möchten.&amp;lt;br /&amp;gt;&lt;br /&gt;
Das Register ist wie folgt aufgebaut:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Bit&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 7&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 6&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 5&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 4&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 2&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Name&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;RXCIE&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;TXCIE&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;UDRIE&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;RXEN&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;TXEN&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;CHR9&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;RXB8&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;TXB8&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;R/W&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | W&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Initialwert&#039;&#039;&#039;&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;
| 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;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;RXCIE&#039;&#039;&#039; (&#039;&#039;&#039;RX&#039;&#039;&#039; &#039;&#039;&#039;C&#039;&#039;&#039;omplete &#039;&#039;&#039;I&#039;&#039;&#039;nterrupt &#039;&#039;&#039;E&#039;&#039;&#039;nable)&lt;br /&gt;
:Wenn dieses Bit gesetzt ist, wird ein UART RX Complete Interrupt ausgelöst, wenn ein Zeichen vom UART empfangen wurde. Das Global Enable Interrupt Flag muss selbstverständlich auch gesetzt sein.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;TXCIE&#039;&#039;&#039; (&#039;&#039;&#039;TX&#039;&#039;&#039; &#039;&#039;&#039;C&#039;&#039;&#039;omplete &#039;&#039;&#039;I&#039;&#039;&#039;nterrupt &#039;&#039;&#039;E&#039;&#039;&#039;nable)&lt;br /&gt;
:Wenn dieses Bit gesetzt ist, wird ein UART TX Complete Interrupt ausgelöst, wenn ein Zeichen vom UART gesendet wurde. Das Global Enable Interrupt Flag muss selbstverständlich auch gesetzt sein.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;UDRIE&#039;&#039;&#039; (&#039;&#039;&#039;U&#039;&#039;&#039;ART &#039;&#039;&#039;D&#039;&#039;&#039;ata &#039;&#039;&#039;R&#039;&#039;&#039;egister &#039;&#039;&#039;E&#039;&#039;&#039;mpty &#039;&#039;&#039;I&#039;&#039;&#039;nterrupt &#039;&#039;&#039;E&#039;&#039;&#039;nable)&lt;br /&gt;
:Wenn dieses Bit gesetzt ist, wird ein UART Datenregister Leer Interrupt ausgelöst, wenn der UART wieder bereit ist um ein neues zu sendendes Zeichen zu übernehmen. Das Global Enable Interrupt Flag muss selbstverständlich auch gesetzt sein.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;RXEN&#039;&#039;&#039; (&#039;&#039;&#039;R&#039;&#039;&#039;eceiver &#039;&#039;&#039;E&#039;&#039;&#039;nable)&lt;br /&gt;
:Nur wenn dieses Bit gesetzt ist, arbeitet der Empfänger des UART überhaupt. Wenn das Bit nicht gesetzt ist, kann der entsprechende Pin des AVR als normaler I/O-Pin verwendet werden. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;TXEN&#039;&#039;&#039; (&#039;&#039;&#039;T&#039;&#039;&#039;ransmitter &#039;&#039;&#039;E&#039;&#039;&#039;nable)&lt;br /&gt;
:Nur wenn dieses Bit gesetzt ist, arbeitet der Sender des UART überhaupt. Wenn das Bit nicht gesetzt ist, kann der entsprechende Pin des AVR als normaler I/O-Pin verwendet werden.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;CHR9&#039;&#039;&#039; (9 Bit Characters)&lt;br /&gt;
:Wenn dieses Bit gesetzt ist, können 9 Bit lange Zeichen übertragen und empfangen werden. Das 9. Bit kann bei Bedarf als zusätzliches Stopbit oder als Paritätsbit verwendet werden. Man spricht dann von einem 11-Bit Zeichenrahmen:&lt;br /&gt;
:1 Startbit + 8 Datenbits + 1 Stopbit + 1 Paritätsbit = 11 Bits&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;RXB8&#039;&#039;&#039; (Receive Data Bit 8)&lt;br /&gt;
:Wenn das vorher erwähnte CHR9-Bit gesetzt ist, dann enthält dieses Bit das 9. Datenbit eines empfangenen Zeichens.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;TXB8&#039;&#039;&#039; (Transmit Data Bit 8)&lt;br /&gt;
:Wenn das vorher erwähnte CHR9-Bit gesetzt ist, dann muss in dieses Bit das 9. Bit des zu sendenden Zeichens eingeschrieben werden bevor das eigentliche Datenbyte in das Datenregister geschrieben wird.&lt;br /&gt;
&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;USR&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;U&#039;&#039;&#039;ART &#039;&#039;&#039;S&#039;&#039;&#039;tatus &#039;&#039;&#039;R&#039;&#039;&#039;egister.&amp;lt;br /&amp;gt;&lt;br /&gt;
Hier teilt uns der UART mit, was er gerade so macht.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Bit&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 7&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 6&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 5&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 4&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 2&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Name&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;RXC&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;TXC&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;UDRE&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;FE&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;OR&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;R/W&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Initialwert&#039;&#039;&#039;&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;
| 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;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;RXC&#039;&#039;&#039; (UART Receive Complete)&lt;br /&gt;
:Dieses Bit wird vom AVR gesetzt, wenn ein empfangenes Zeichen vom Empfangs-Schieberegister in das Empfangs-Datenregister transferiert wurde.&lt;br /&gt;
:Das Zeichen muss nun schnellstmöglich aus dem Datenregister ausgelesen werden. Falls dies nicht erfolgt bevor ein weiteres Zeichen komplett empfangen wurde wird eine Überlauf-Fehlersituation eintreffen. Mit dem Auslesen des Datenregisters wird das Bit automatisch gelöscht.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;TXC&#039;&#039;&#039; (UART Transmit Complete)&lt;br /&gt;
:Dieses Bit wird vom AVR gesetzt, wenn das im Sende-Schieberegister befindliche Zeichen vollständig ausgegeben wurde und kein weiteres Zeichen im Sendedatenregister ansteht. Dies bedeutet also, wenn die Kommunikation vollumfänglich abgeschlossen ist.&lt;br /&gt;
:Dieses Bit ist wichtig bei Halbduplex-Verbindungen, wenn das Programm nach dem Senden von Daten auf Empfang schalten muss. Im Vollduplexbetrieb brauchen wir dieses Bit nicht zu beachten.&lt;br /&gt;
:Das Bit wird nur dann automatisch gelöscht, wenn der entsprechende Interrupthandler aufgerufen wird, ansonsten müssen wir das Bit selber löschen.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;UDRE&#039;&#039;&#039; (&#039;&#039;&#039;U&#039;&#039;&#039;ART &#039;&#039;&#039;D&#039;&#039;&#039;ata &#039;&#039;&#039;R&#039;&#039;&#039;egister &#039;&#039;&#039;E&#039;&#039;&#039;mpty)&lt;br /&gt;
:Dieses Bit zeigt an, ob der Sendepuffer bereit ist, um ein zu sendendes Zeichen aufzunehmen. Das Bit wird vom AVR gesetzt (1), wenn der Sendepuffer leer ist. Es wird gelöscht (0), wenn ein Zeichen im Sendedatenregister vorhanden ist und noch nicht in das Sendeschieberegister übernommen wurde. Atmel empfiehlt aus Kompatibilitätsgründen mit kommenden µC, UDRE auf 0 zu setzen, wenn das UCSRA Register beschrieben wird.&lt;br /&gt;
:Das Bit wird automatisch gelöscht, wenn ein Zeichen in das Sendedatenregister geschrieben wird.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;FE&#039;&#039;&#039; (&#039;&#039;&#039;F&#039;&#039;&#039;raming &#039;&#039;&#039;E&#039;&#039;&#039;rror)&lt;br /&gt;
:Dieses Bit wird vom AVR gesetzt, wenn der UART einen Zeichenrahmenfehler detektiert, d.h. wenn das Stopbit eines empfangenen Zeichens 0 ist.&lt;br /&gt;
:Das Bit wird automatisch gelöscht, wenn das Stopbit des empfangenen Zeichens 1 ist.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;OR&#039;&#039;&#039; (&#039;&#039;&#039;O&#039;&#039;&#039;ver&#039;&#039;&#039;R&#039;&#039;&#039;un)&amp;lt;br /&amp;gt;&lt;br /&gt;
:Dieses Bit wird vom AVR gesetzt, wenn unser Programm das im Empfangsdatenregister bereit liegende Zeichen nicht abholt bevor das nachfolgende Zeichen komplett empfangen wurde.&lt;br /&gt;
:Das nachfolgende Zeichen wird verworfen.&lt;br /&gt;
:Das Bit wird automatisch gelöscht, wenn das empfangene Zeichen in das Empfangsdatenregister transferiert werden konnte.&lt;br /&gt;
&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;UDR&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;U&#039;&#039;&#039;ART &#039;&#039;&#039;D&#039;&#039;&#039;ata &#039;&#039;&#039;R&#039;&#039;&#039;egister.&amp;lt;br /&amp;gt;&lt;br /&gt;
Hier werden Daten zwischen UART und CPU übertragen. Da der UART im&lt;br /&gt;
Vollduplexbetrieb gleichzeitig empfangen und senden kann, handelt es sich&lt;br /&gt;
hier physikalisch um 2 Register, die aber über die gleiche I/O-Adresse&lt;br /&gt;
angesprochen werden. Je nachdem, ob ein Lese- oder ein Schreibzugriff auf&lt;br /&gt;
den UART erfolgt wird automatisch das richtige UDR angesprochen.&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;UBRR&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;U&#039;&#039;&#039;ART &#039;&#039;&#039;B&#039;&#039;&#039;aud &#039;&#039;&#039;R&#039;&#039;&#039;ate &#039;&#039;&#039;R&#039;&#039;&#039;egister.&amp;lt;br /&amp;gt;&lt;br /&gt;
In diesem Register müssen wir dem UART mitteilen, wie schnell wir gerne&lt;br /&gt;
kommunizieren möchten. Der Wert, der in dieses Register geschrieben&lt;br /&gt;
werden muss, errechnet sich nach folgender Formel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
\begin{matrix}&lt;br /&gt;
\mathrm{UBRR} = \frac{\mathrm{Taktfrequenz}}{\mathrm{Baudrate} \cdot 16} - 1&lt;br /&gt;
\end{matrix}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Es sind Baudraten bis zu 115200 Baud und höher möglich.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Die Hardware ==&lt;br /&gt;
&lt;br /&gt;
Der UART basiert auf normalem TTL-Pegel mit 0V (LOW) und 5V (HIGH). Die&lt;br /&gt;
Schnittstellenspezifikation für RS-232 definiert jedoch -3V ... -12V (LOW) und&lt;br /&gt;
+3 ... +12V (HIGH). Zudem muss der Signalaustausch zwischen AVR und&lt;br /&gt;
Partnergerät invertiert werden. Für die Anpassung der Pegel und das&lt;br /&gt;
Invertieren der Signale gibt es fertige Schnittstellenbausteine. Der bekannteste&lt;br /&gt;
davon ist wohl der MAX232. &lt;br /&gt;
&amp;lt;!-- &amp;quot;Hackerloesung&amp;quot; auskommentiert - nicht so gut in einem &amp;quot;Einsteiger-Tutorial&amp;quot; - mthomas&lt;br /&gt;
Allerdings kostet der auch wieder Geld und benötigt&lt;br /&gt;
zusätzlich immerhin 4 externe Elkos.&lt;br /&gt;
&lt;br /&gt;
Die in den PC eingebauten Schnittstellen vertragen ohne Klagen auch den&lt;br /&gt;
TTL-Pegel vom AVR. Allerdings müssen wir immer noch die Signale invertieren. Im&lt;br /&gt;
einfachtesn Fall verwenden wir dazu jeweils einen einfachen NPN-Transistor und 2&lt;br /&gt;
Widerstände. Näheres dazu erfahrt ihr in den folgenden Übungen.--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Streikt die Kommunikation per UART, so ist oft eine fehlerhafte Einstellung der Baudrate die Ursache. Die Konfiguration auf eine bestimmte Baudrate ist abhängig von der Taktfrequenz des Controllers. Gerade bei neu aufgebauten Schaltungen (bzw. neu gekauften Controllern) sollte man sich daher noch einmal vergewissern, dass der Controller auch tatsächlich mit der vermuteten Taktrate arbeitet und nicht z.B. den bei einigen Modellen werksseitig eingestellten internen [[Oszillator]] statt eines externen Quarzes nutzt. Die Werte der verschiedenen fuse-bits im Fehlerfall also beispielsweise mit &#039;&#039;[[AVRDUDE]]&#039;&#039; kontrollieren und falls nötig anpassen. Grundsätzlich empfiehlt sich auch immer ein Blick in die [[AVR_Checkliste]].&lt;br /&gt;
&lt;br /&gt;
== UART initialisieren ==&lt;br /&gt;
&lt;br /&gt;
Wir wollen nun Daten mit dem UART auf die serielle Schnittstelle ausgeben. Dazu müssen wir den UART zuerst mal initialisieren. Dazu setzen wir je nach gewünschter Funktionsweise die benötigten Bits im &#039;&#039;&#039;U&#039;&#039;&#039;ART &#039;&#039;&#039;C&#039;&#039;&#039;ontrol &#039;&#039;&#039;R&#039;&#039;&#039;egister.&lt;br /&gt;
&lt;br /&gt;
Da wir vorerst nur senden möchten und noch keine Interrupts auswerten wollen, gestaltet sich die Initialisierung wirklich sehr einfach, da wir lediglich das &#039;&#039;&#039;Transmitter Enable&#039;&#039;&#039; Bit setzen müssen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
    UCR |= (1&amp;lt;&amp;lt;TXEN);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Neuere AVRs mit USART haben mehrere Konfigurationsregister und erfordern eine etwas andere Konfiguration. Für einen ATmega16 z.B.:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
    UCSRB |= (1&amp;lt;&amp;lt;TXEN);                            // UART TX einschalten&lt;br /&gt;
    UCSRC |= (1&amp;lt;&amp;lt;URSEL)|(1 &amp;lt;&amp;lt; UCSZ1)|(1 &amp;lt;&amp;lt; UCSZ0); // Asynchron 8N1&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nun ist noch das Baudratenregister &#039;&#039;&#039;UBRR&#039;&#039;&#039; einzustellen. Bei neueren AVRs besteht es aus zwei Registern &#039;&#039;&#039;UBRRL&#039;&#039;&#039; und &#039;&#039;&#039;UBRRH&#039;&#039;&#039;. Der Wert dafür ergibt sich aus der angegebenen Formel durch Einsetzen der Taktfrequenz und der gewünschten Übertragungsrate. Das Berechnen der Formel wird dem [[C-Präprozessor|Präprozessor]] überlassen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
/* UART-Init beim AT90S2313 */&lt;br /&gt;
&lt;br /&gt;
#ifndef F_CPU&lt;br /&gt;
/* In neueren Version der WinAVR/Mfile Makefile-Vorlage kann&lt;br /&gt;
   F_CPU im Makefile definiert werden, eine nochmalige Definition&lt;br /&gt;
   hier wuerde zu einer Compilerwarnung fuehren. Daher &amp;quot;Schutz&amp;quot; durch&lt;br /&gt;
   #ifndef/#endif &lt;br /&gt;
&lt;br /&gt;
   Dieser &amp;quot;Schutz&amp;quot; kann zu Debugsessions führen, wenn AVRStudio &lt;br /&gt;
   verwendet wird und dort eine andere, nicht zur Hardware passende &lt;br /&gt;
   Taktrate eingestellt ist: Dann wird die folgende Definition &lt;br /&gt;
   nicht verwendet, sondern stattdessen der Defaultwert (8 MHz?) &lt;br /&gt;
   von AVRStudio - daher Ausgabe einer Warnung falls F_CPU&lt;br /&gt;
   noch nicht definiert: */&lt;br /&gt;
#warning &amp;quot;F_CPU war noch nicht definiert, wird nun nachgeholt mit 4000000&amp;quot;&lt;br /&gt;
#define F_CPU 4000000UL    // Systemtakt in Hz - Definition als unsigned long beachten &amp;gt;&amp;gt; Ohne ergeben Fehler in der Berechnung&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
#define BAUD 9600UL          // Baudrate&lt;br /&gt;
&lt;br /&gt;
// Berechnungen&lt;br /&gt;
#define UBRR_VAL ((F_CPU+BAUD*8)/(BAUD*16)-1)   // clever runden&lt;br /&gt;
#define BAUD_REAL (F_CPU/(16*(UBRR_VAL+1)))     // Reale Baudrate&lt;br /&gt;
#define BAUD_ERROR ((BAUD_REAL*1000)/BAUD) // Fehler in Promille, 1000 = kein Fehler.&lt;br /&gt;
&lt;br /&gt;
#if ((BAUD_ERROR&amp;lt;990) || (BAUD_ERROR&amp;gt;1010))&lt;br /&gt;
  #error Systematischer Fehler der Baudrate grösser 1% und damit zu hoch! &lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
int main(void)&lt;br /&gt;
{&lt;br /&gt;
    UCR |= (1&amp;lt;&amp;lt;TXEN);&lt;br /&gt;
    UBRR = UBRR_VAL;&lt;br /&gt;
    //...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&amp;lt;!-- mthomas: warum nicht UL?, wird von AVRStudio auch mit UL übergeben --&amp;gt;&lt;br /&gt;
Wieder für den Mega16 mit zwei Registern für die Baudrateneinstellung eine etwas andere Programmierung. Wichtig ist, dass UBRRH &#039;&#039;&#039;vor&#039;&#039;&#039; UBRRL geschrieben wird.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
  /* USART-Init beim ATmega16 */&lt;br /&gt;
&lt;br /&gt;
int main(void)&lt;br /&gt;
{&lt;br /&gt;
    UCSRB |= (1&amp;lt;&amp;lt;TXEN);                // UART TX einschalten&lt;br /&gt;
    UCSRC |= (1&amp;lt;&amp;lt;URSEL)|(3&amp;lt;&amp;lt;UCSZ0);    // Asynchron 8N1 &lt;br /&gt;
&lt;br /&gt;
    UBRRH = UBRR_VAL &amp;gt;&amp;gt; 8;&lt;br /&gt;
    UBRRL = UBRR_VAL &amp;amp; 0xFF;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für einige AVR (z.B. ATmega169, ATmega48/88/168, AT90CAN jedoch nicht für z.B. ATmega16/32, ATmega128, ATtiny2313) wird durch die Registerdefinitionen der avr-libc (io*.h) auch für Controller mit zwei UBRR-Registern (UBRRL/UBRRH) ein UBRR bzw. UBRR0 als &amp;quot;16-bit-Register&amp;quot; definiert und man kann auch Werte direkt per UBRR = UBRR_VAL zuweisen. Intern werden dann zwei Zuweisungen für UBRRH und UBRRL generiert. Dies ist nicht bei allen Controllern möglich, da die beiden Register nicht bei allen aufeinanderfolgende Addressen aufweisen. Die getrennte Zuweisung an UBRRH und UBRRL wie im Beispiel gezeigt ist universeller und portabler und daher vorzuziehen.&lt;br /&gt;
&lt;br /&gt;
Die Makros sind sehr praktisch, da sie sowohl automatisch den Wert für UBRR als auch den Fehler in der generierten Baudrate berechnen und im Falle einer Überschreitung (+/-1%) einen Fehler und somit Abbruch im Compilerablauf generieren. Damit können viele Probleme mit &amp;quot;UART sendet komische Zeichen&amp;quot; vermieden werden. Ausserdem kann man mühelos die Einstellung an eine neue Taktfrequenz bzw. Baudrate anpassen, ohne selber rechnen oder in Tabellen nachschlagen zu müssen.&lt;br /&gt;
&lt;br /&gt;
Siehe auch:&lt;br /&gt;
* [http://www.wormfood.net/avrbaudcalc.php WormFood&#039;s AVR Baud Rate Calculator] online.&lt;br /&gt;
&lt;br /&gt;
== Senden mit dem UART ==&lt;br /&gt;
&lt;br /&gt;
=== Senden einzelner Zeichen ===&lt;br /&gt;
&lt;br /&gt;
Um nun ein Zeichen auf die Schnittstelle auszugeben, müssen wir dasselbe&lt;br /&gt;
lediglich in das &#039;&#039;&#039;U&#039;&#039;&#039;ART &#039;&#039;&#039;D&#039;&#039;&#039;ata &#039;&#039;&#039;R&#039;&#039;&#039;egister schreiben. Vorher ist zu prüfen, ob das UART-Modul bereit ist, das zu sendende Zeichen entgegenzunehmen. Die Bezeichnungen des/der Statusregisters mit dem Bit UDRE ist abhängig vom Controllertypen (vgl. Datenblatt).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
    // bei AVR mit einem UART (&amp;quot;classic AVR&amp;quot; z.B. AT90S8515)&lt;br /&gt;
    while (!(USR &amp;amp; (1&amp;lt;&amp;lt;UDRE)))  /* warten bis Senden moeglich                   */&lt;br /&gt;
    {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    UDR = &#039;x&#039;;                  /* schreibt das Zeichen x auf die Schnittstelle */&lt;br /&gt;
&lt;br /&gt;
    /** ODER **/&lt;br /&gt;
&lt;br /&gt;
    // bei neueren AVRs steht der Status in UCSRA/UCSR0A/UCSR1A, hier z.B. fuer ATmega16:&lt;br /&gt;
    while (!(UCSRA &amp;amp; (1&amp;lt;&amp;lt;UDRE)))  /* warten bis Senden moeglich                   */&lt;br /&gt;
    {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    UDR = &#039;x&#039;;                    /* schreibt das Zeichen x auf die Schnittstelle */&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Schreiben einer Zeichenkette (String) ===&lt;br /&gt;
&lt;br /&gt;
Die Aufgabe &amp;quot;String senden&amp;quot; wird durch zwei Funktionen abgearbeitet. Die universelle/controllerunabhängige Funktion uart_puts übergibt jeweils ein Zeichen der Zeichenkette an eine Funktion uart_putc, die abhängig von der vorhandenen Hardware implementiert werden muss. In der Funktion zum Senden eines Zeichens ist darauf zu achten, dass vor dem Senden geprüft wird, ob der UART bereit ist den &amp;quot;Sendeauftrag&amp;quot; entgegenzunehmen. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
// putc fuer AVR mit einem UART (z.B. AT90S8515)&lt;br /&gt;
int uart_putc(unsigned char c)&lt;br /&gt;
{&lt;br /&gt;
    while(!(USR &amp;amp; (1 &amp;lt;&amp;lt; UDRE)))  /* warte, bis UDR bereit */&lt;br /&gt;
    {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    UDR = c;                     /* sende Zeichen */&lt;br /&gt;
    return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/** ODER **/&lt;br /&gt;
&lt;br /&gt;
// bei neueren AVRs andere Bezeichnung fuer die Statusregister, hier ATmega16:&lt;br /&gt;
int uart_putc(unsigned char c)&lt;br /&gt;
{&lt;br /&gt;
    while (!(UCSRA &amp;amp; (1&amp;lt;&amp;lt;UDRE)))  /* warten bis Senden moeglich */&lt;br /&gt;
    {&lt;br /&gt;
    }                             &lt;br /&gt;
&lt;br /&gt;
    UDR = c;                      /* sende Zeichen */&lt;br /&gt;
    return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* puts ist unabhaengig vom Controllertyp */&lt;br /&gt;
void uart_puts (char *s)&lt;br /&gt;
{&lt;br /&gt;
    while (*s)&lt;br /&gt;
    {   /* so lange *s != &#039;\0&#039; also ungleich dem &amp;quot;String-Endezeichen&amp;quot; */&lt;br /&gt;
        uart_putc(*s);&lt;br /&gt;
        s++;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die in uart_putc verwendeten Schleifen, in denen gewartet wird bis die UART-Hardware zum senden bereit ist, sind insofern etwas kritisch, da während des Sendens eines Strings nicht mehr auf andere Ereignisse reagieren werden kann. Universeller ist die Nutzung von FIFO(first-in first-out)-Puffern, in denen die zu sendenden bzw. empfangenen Zeichen/Bytes zwischengespeichert und in Interruptroutinen an die U(S)ART-Hardware weitergegeben bzw. von ihr ausgelesen werden. Dazu existieren fertige Komponenten (Bibliotheken, Libraries), die man recht einfach in eigene Entwicklungen integrieren kann. Es empfiehlt sich, diese Komponenten zu nutzen und das Rad nicht neu zu erfinden.&lt;br /&gt;
&lt;br /&gt;
=== Schreiben von Variableninhalten ===&lt;br /&gt;
&lt;br /&gt;
Sollen Inhalte von Variablen (Ganzzahlen, Fließkomma) in &amp;quot;menschenlesbarer&amp;quot; Form gesendet werden, ist vor dem Transfer eine Umwandlung in Zeichen (&amp;quot;ASCII&amp;quot;) erforderlich. Bei nur einer Ziffer ist diese Umwandlung relativ einfach: man addiert den ASCII-Wert von Null zur Ziffer und kann diesen Wert direkt senden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
// hier uart_putc (s.o.)&lt;br /&gt;
&lt;br /&gt;
// Ausgabe von 0123456789&lt;br /&gt;
char c;&lt;br /&gt;
&lt;br /&gt;
for (uint8_t i=0; i&amp;lt;=9; ++i) {&lt;br /&gt;
    c = i + &#039;0&#039;;&lt;br /&gt;
    uart_putc( c );&lt;br /&gt;
    // verkuerzt: uart_putc( i + &#039;0&#039; );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Soll mehr als eine Ziffer ausgegeben werden, bedient man sich zweckmäßigerweise vorhandener Funktionen zur Umwandlung von Zahlen in Zeichenketten/Strings. Die Funktion der avr-libc zur Umwandlung von vorzeichenbehafteten 16bit-Ganzzahlen (int16_t) in Zeichenketten heißt &#039;&#039;itoa&#039;&#039; (Integer to ASCII). Man muss der Funktion einen Speicherbereich zur Verarbeitung (buffer) mit Platz für alle Ziffern, das String-Endezeichen (&#039;\0&#039;) und evtl. das Vorzeichen bereitstellen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
// hier uart_init, uart_putc, uart_puts (s.o.)&lt;br /&gt;
&lt;br /&gt;
int main(void)&lt;br /&gt;
{&lt;br /&gt;
   char s[7];&lt;br /&gt;
   int16_t i = -12345;&lt;br /&gt;
   &lt;br /&gt;
   uart_init();&lt;br /&gt;
&lt;br /&gt;
   itoa( i, s, 10 ); // 10 fuer radix -&amp;gt; Dezimalsystem&lt;br /&gt;
   uart_puts( s );&lt;br /&gt;
&lt;br /&gt;
   // da itoa einen Zeiger auf den Beginn von s zurueckgibt verkuerzt auch:&lt;br /&gt;
   uart_puts( itoa( i, s, 10 ) );&lt;br /&gt;
&lt;br /&gt;
   while (1) {&lt;br /&gt;
      ;&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
   return 0; // never reached &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für vorzeichenlose 16bit-Ganzzahlen (uint16_t) exisitert &#039;&#039;utoa&#039;&#039;. Die Funktionen für 32bit-Ganzzahlen (int32_t und uint32_t) heißen &#039;&#039;ltoa&#039;&#039; bzw. &#039;&#039;ultoa&#039;&#039;. Da 32bit-Ganzzahlen mehr Stellen aufweisen können, ist ein entsprechend größerer Pufferspeicher vorzusehen.&lt;br /&gt;
&lt;br /&gt;
Auch Fließkommazahlen (float/double) können mit breits vorhandenen Funktionen in Zeichenfolgen umgewandelt werden, dazu existieren die Funktionen &#039;&#039;dtostre&#039;&#039; und &#039;&#039;dtostrf&#039;&#039;. dtostre nutzt Exponentialschreibweise (&amp;quot;engineering&amp;quot;-Format). (Hinweis: z.Zt. existiert im avr-gcc kein &amp;quot;echtes&amp;quot; double, intern wird immer mit &amp;quot;einfacher Genauigkeit&amp;quot;, entsprechend float, gerechnet.) &lt;br /&gt;
&lt;br /&gt;
dtostrf und dtostre benötigen die libm.a der avr-libc. Bei Nutzung von Makefiles ist der Parameter -lm in in LDFLAGS anzugeben (Standard in den WinAVR/mfile-Makefilevorlagen). Nutzt man AVRStudio als IDE für den GNU-Compiler (gcc-Plugin) ist die libm.a unter Libaries auszuwählen: Project -&amp;gt; Configurations Options -&amp;gt; Libaries -&amp;gt; libm.a mit dem Pfeil nach rechts einbinden. Siehe auch die [[FAQ#Aktivieren_der_Floating_Point_Version_von_sprintf_beim_WinAVR_mit_AVR-Studio|FAQ]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
// hier uart_init, uart_putc, uart_puts (s.o.)&lt;br /&gt;
&lt;br /&gt;
/* lt. avr-libc Dokumentation:&lt;br /&gt;
char* dtostrf(&lt;br /&gt;
  double __val,&lt;br /&gt;
  char   __width,&lt;br /&gt;
  char   __prec,&lt;br /&gt;
  char * __s&lt;br /&gt;
)  &lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
int main(void)&lt;br /&gt;
{&lt;br /&gt;
   // Pufferspeicher ausreichend groß&lt;br /&gt;
   // evtl. Vorzeichen + width + Endezeichen:&lt;br /&gt;
   char s[8]; &lt;br /&gt;
   float f = -12.345;&lt;br /&gt;
   &lt;br /&gt;
   uart_init();&lt;br /&gt;
&lt;br /&gt;
   dtostrf( f, 6, 3, s ); &lt;br /&gt;
   uart_puts( s );&lt;br /&gt;
&lt;br /&gt;
   // verkürzt: uart_puts( dtostrf( f, 7, 3, s ) );&lt;br /&gt;
&lt;br /&gt;
   while (1) {&lt;br /&gt;
      ;&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
   return 0; // never reached &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Empfangen ==&lt;br /&gt;
=== einzelne Zeichen empfangen ===&lt;br /&gt;
&lt;br /&gt;
Zum Empfang von Zeichen muss der Empfangsteil des UART bei der Initialisierung aktiviert werden, indem das RXEN-Bit im jeweiligen Konfigurationsregister (UCSRB bzw UCSR0B/UCSR1B) gesetzt wird. Im einfachsten Fall wird solange gewartet, bis ein Zeichen empfangen wurde, dieses steht dann im UART-Datenregister (UDR bzw. UDR0 und UDR1 bei AVRs mit 2 UARTS) zur Verfügung (sogen. &amp;quot;Polling-Betrieb&amp;quot;). Ein Beispiel für den ATmega16:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;inttypes.h&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/* Zusaetzlich zur Baudrateneinstellung und der weiteren Initialisierung: */&lt;br /&gt;
void Usart_EnableRX(void)&lt;br /&gt;
{&lt;br /&gt;
    UCSRB |= ( 1 &amp;lt;&amp;lt; RXEN );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* Zeichen empfangen */&lt;br /&gt;
uint8_t uart_getc(void)&lt;br /&gt;
{&lt;br /&gt;
    while (!(UCSRA &amp;amp; (1&amp;lt;&amp;lt;RXC)))   // warten bis Zeichen verfuegbar&lt;br /&gt;
        ;&lt;br /&gt;
    return UDR;                   // Zeichen aus UDR an Aufrufer zurueckgeben&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Diese Funktion blockiert den Programmablauf. Alternativ kann das RXC-Bit in einer Programmschleife abgefragt werden und dann nur bei gesetztem RXC-Bit UDR ausgelesen werden. Eleganter und in den meisten Anwendungsfällen &amp;quot;stabiler&amp;quot; ist die Vorgehensweise, die empfangenen Zeichen in einer Interrupt-Routine einzulesen und zur späteren Verarbeitung in einem Eingangsbuffer (FIFO-Buffer) zwischenzuspeichern. Dazu existieren fertige und gut getestete [[Libraries|Bibliotheken]] &amp;lt;!-- &amp;quot;echte Libraries&amp;quot; (.a) wie im Verweis beschrieben sind hier eigentlich nicht gemeint, verwirrt hier etwas, da AVR-&amp;quot;Libraries&amp;quot; meist per #defines anpassbare Source-Codes sind, vielleicht so: --&amp;gt; und Quellcodekomponenten (z.B. UART-Library von P. Fleury, procyon-avrlib und einige in der &amp;quot;Academy&amp;quot; von avrfreaks.net).&lt;br /&gt;
&lt;br /&gt;
siehe auch:&lt;br /&gt;
* [http://www.nongnu.org/avr-libc/user-manual/group__avr__stdlib.html Dokumenation der avr-libc/stdlib.h]&lt;br /&gt;
* [http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Die_Nutzung_von_printf Die Nutzung von printf]&lt;br /&gt;
* [http://homepage.hispeed.ch/peterfleury/ Peter Fleurys] UART-Bibiliothek fuer avr-gcc/avr-libc&lt;br /&gt;
&amp;lt;!-- nimmermehr: * siehe auch: Weiterführende Informationen inkl. Beispielen für die Nutzung von stdio-Funktionen (printf etc.) im [[AVR-Tutorial:_UART]]. --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
TODO: 9bit&lt;br /&gt;
&lt;br /&gt;
=== Empfang von Zeichenketten (Strings) ===&lt;br /&gt;
&lt;br /&gt;
Beim Empfang von Zeichenketten, muß man sich zunächst darüber im klaren sein, daß es ein Kriterium geben muß, an dem der µC erkennen kann, wann ein String zu Ende ist. Sehr oft wird dazu das Zeichen &#039;Return&#039; benutzt, um das Ende eines Strings zu markieren. Dies ist vom Benutzer einfach eingebbar und er ist auch daran gewöhnt, daß er eine Eingabezeile mit einem Druck auf die Return Taste abgeschlossen wird.&lt;br /&gt;
&lt;br /&gt;
Prinzipiell gibt es jedoch keine Einschränkung bezüglich dieses speziellen Zeichens. Es muß nur sichergestellt werden, daß dieses spezielle &#039;Ende eines Strings&#039; - Zeichen nicht mit einem im Text vorkommenden Zeichen verwechselt werden kann. Wenn also im zu übertragenden Text beispielsweise kein &#039;;&#039; vorkommt, dann spricht nichts dagegen, einen String mit einem &#039;;&#039; abschließen zu lassen.&lt;br /&gt;
&lt;br /&gt;
Im Folgenden wird die durchaus übliche Annahme getroffen, daß eine Stringübertragung identisch ist mit der Übertragung einer Textzeile und daher mit einem Return (&#039;\n&#039;) abgeschlossen wird.&lt;br /&gt;
&lt;br /&gt;
Das Problem der Übertragung eines Strings reduziert sich damit auf die Aufgabenstellung: Empfange und Sammle Zeichen in einem char Array, bis entweder das Array voll ist oder das &#039;String Ende Zeichen&#039; empfangen wurde. Danach wird der empfangene Text noch mit einem &#039;\0&#039; Zeichen abgeschlossen um einen Standard C-String daraus zu machen, mit dem dann weiter gearbeitet werden kann.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;C&amp;gt;&lt;br /&gt;
/* Zeichen empfangen */&lt;br /&gt;
uint8_t uart_getc(void)&lt;br /&gt;
{&lt;br /&gt;
    while (!(UCSRA &amp;amp; (1&amp;lt;&amp;lt;RXC)))   // warten bis Zeichen verfuegbar&lt;br /&gt;
        ;&lt;br /&gt;
    return UDR;                   // Zeichen aus UDR an Aufrufer zurueckgeben&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void uart_gets( char* Buffer, uint8_t MaxLen )&lt;br /&gt;
{&lt;br /&gt;
  uint8_t NextChar;&lt;br /&gt;
  uint8_t StringLen = 0;&lt;br /&gt;
&lt;br /&gt;
  NextChar = uart_getc();         // Warte auf und empfange das nächste Zeichen&lt;br /&gt;
&lt;br /&gt;
                                  // Sammle solange Zeichen, bis:&lt;br /&gt;
                                  // * entweder das String Ende Zeichen kam&lt;br /&gt;
                                  // * oder das aufnehmende Array voll ist&lt;br /&gt;
  while( NextChar != &#039;\n&#039; &amp;amp;&amp;amp; StringLen &amp;lt; MaxLen - 1 ) {&lt;br /&gt;
    *Buffer++ = NextChar;&lt;br /&gt;
    StringLen++;&lt;br /&gt;
    NextChar = uart_getc();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
                                  // Noch ein &#039;\0&#039; anhängen um einen Standard&lt;br /&gt;
                                  // C-String daraus zu machen&lt;br /&gt;
  *Buffer = &#039;\0&#039;;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/C&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Beim Aufruf ist darauf zu achten, dass das empfangende Array auch mit einer&lt;br /&gt;
vernünftigen Größe definiert wird.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;C&amp;gt;&lt;br /&gt;
  char Line[40];      // String mit maximal 39 zeichen&lt;br /&gt;
&lt;br /&gt;
  uart_gets( Line, sizeof( Line ) );&lt;br /&gt;
&amp;lt;/C&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bei der Benutzung von sizeof() ist allerdings zu beachten, dass sizeof() nicht die Anzahl der Elemente des Arrays liefert, sondern die Länge in Byte. Da ein char nur ein Byte lang ist, passt der Aufruf &#039;uart_gets(Line, sizeof( Line ) );&#039; in diesem Fall. Falls man - aus welchen Gründen auch immer - andere Datentypen benutzen möchte, sollte man zur korrekten Angabe der Array-Länge folgende Vorgehensweise bevorzugen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;C&amp;gt;&lt;br /&gt;
  int Line[40];      // Array vom Typ int&lt;br /&gt;
&lt;br /&gt;
  uart_gets( Line, sizeof( Line ) / sizeof( Line[0] ) );&lt;br /&gt;
&amp;lt;/C&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Interruptbetrieb==&lt;br /&gt;
&lt;br /&gt;
Beim ATMEGA8 muss das RXCIE Bit im Register UCSRB gesetzt werden, damit ein Interrupt ausgelöst werden kann.&lt;br /&gt;
Der Interrupt wird immer ausgelöst, wenn Daten erfolgreich empfangen wurden.&lt;br /&gt;
&lt;br /&gt;
Zusätzlich braucht man die Routine:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
ISR (USART_RXC_vect) {&lt;br /&gt;
   //irgendein Code&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
natürlich muss &amp;quot;Global Interrupt Enable&amp;quot; Aktiviert sein.&lt;br /&gt;
!! Nur getestet beim ATMEGA8 !!&lt;br /&gt;
&lt;br /&gt;
[BAUSTELLE! Aus Lerngründen eventuell als eigenen UART-Interrupt-Block hinter den grundlegenden Interrupt-Teil im Tutorial und hier eine kurze Einführung und einen Verweis darauf anbieten.]&lt;br /&gt;
&lt;br /&gt;
* Unterschied Polling-Betrieb (bisher, oben) und Interrupt-Betrieb&lt;br /&gt;
* Empfangen (Receive)&lt;br /&gt;
** Verändertes UART-Init, ISR (RXC), ggf. Fallstricke ([http://www.mikrocontroller.net/topic/84256#707214 UDR in der ISR lesen!]), Philosophie einer ISR (kurz und schmerzlos), Datenaustausch ISR zu Restprogramm (volatile)&lt;br /&gt;
** Einfachstbeispiel ([http://www.mikrocontroller.net/topic/84228#707052 Echo] (noch buggy beim Datenzugriff, siehe Lit. 2+3!)), ggf. LED zur ISR-Empfangsanzeige oder Overflow-Anzeige&lt;br /&gt;
* FIFO-Puffer, Ringpuffer&lt;br /&gt;
* Senden (Transmit)&lt;br /&gt;
** Variante &amp;quot;UART Data Register Empty&amp;quot; (UDRE) &lt;br /&gt;
** Variante &amp;quot;UART Transmit Complete&amp;quot; (TXC) &lt;br /&gt;
* Fertige UART-Bibliotheken (-&amp;gt;Fleury, -&amp;gt;Procyon)&lt;br /&gt;
* Literatur: &lt;br /&gt;
** 1/ [http://www.avrfreaks.net/index.php?name=PNphpBB2&amp;amp;file=viewtopic&amp;amp;t=48188 avrfreaks.net Tutorial] inkl. Diskussion (engl.)&lt;br /&gt;
** 2/ avr-libc FAQ: [http://www.nongnu.org/avr-libc/user-manual/FAQ.html#faq_16bitio Why do some 16-bit timer registers sometimes get trashed?]&lt;br /&gt;
** 3/ [[Interrupt]] und atomarer Datenzugriff&lt;br /&gt;
&lt;br /&gt;
==Software-UART==&lt;br /&gt;
&lt;br /&gt;
Falls die Zahl der vorhandenen Hardware-UARTs nicht ausreicht, können weitere Schnittstellen über sogennante Software-UARTs ergänzt werden. Es gibt dazu (mindestens) zwei Ansätze: &lt;br /&gt;
* Der bei AVRs üblichste Ansatz basiert auf dem Prinzip, dass ein externer Interrupt-Pin für den Empfang (&amp;quot;RX&amp;quot;) genutzt wird. Das Startbit löst den Interrupt aus, in der Interrupt-Routine (ISR) wird der externe Interrupt deaktiviert und ein Timer aktiviert. In der Interrupt-Routine des Timers wird der Zustand des Empfangs-Pins entsprechend der Baudrate abgetastet. Nach Empfang des Stop-Bits wird der externe Interrupt wieder aktiviert. Senden kann über einen beliebigen Pin (&amp;quot;TX&amp;quot;) erfolgen, der entsprechend der Baudrate und dem zu sendenden Zeichen auf 0 oder 1 gesetzt wird. Die Implementierung ist nicht ganz einfach, es existieren dazu aber fertige Bibliotheken (z.B. bei [http://www.avrfreaks.net/ avrfreaks] oder in der [http://hubbard.engr.scu.edu/embedded/avr/avrlib/ Procyon avrlib]).&lt;br /&gt;
* Ein weiterer Ansatz erfordert keinen Pin mit &amp;quot;Interrupt-Funktion&amp;quot; aber benötigt mehr Rechenzeit. Jeder Input-Pin kann als Empfangspin (RX) dienen. Über einen Timer wird der Zustand des RX-Pins mit einem vielfachen der Baudrate abgetastet (dreifach scheint üblich) und High- bzw. Lowbits anhand einer Mindestanzahl identifiziert. (Beispiel: &amp;quot;Generic Software Uart&amp;quot; Application-Note von IAR)&lt;br /&gt;
&lt;br /&gt;
Neuere AVRs (z.B. ATtiny26 oder ATmega48,88,168,169) verfügen über ein Universal Serial Interface (USI), das teilweise UART-Funktion übernehmen kann. Atmel stellt eine Application-Note bereit, in der die Nutzung des USI als UART erläutert wird (im Prinzip &amp;quot;Hardware-unterstützter Software-UART&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
==Handshaking==&lt;br /&gt;
Wenn der Sender ständig sendet, wird irgendwann der Fall eintreten, daß der Empfänger nicht bereit ist, neue Zeichen zu empfangen. In diesem Fall muß durch ein &#039;&#039;&#039;Handshake-Verfahren&#039;&#039;&#039; die Situation bereinigt werden. Handshake bedeutet nichts anderes, als daß der Empfänger dem Sender mitteilt, daß er zur Zeit keine Daten annehmen kann und der Sender die Übertragung der nächsten Zeichen solange einstellen soll, bis der Empfänger signalisiert, daß er wieder Zeichen aufnehmen kann.&lt;br /&gt;
===Hardwarehandshake (RTS/CTS)===&lt;br /&gt;
Beim Hardwarehandshake werden zusätzlich zu den beiden Daten-Übertragungsleitungen noch 2 weitere Leitungen benötigt: &#039;&#039;&#039;RTS&#039;&#039;&#039; (&#039;&#039;&#039;R&#039;&#039;&#039;equest &#039;&#039;&#039;T&#039;&#039;&#039;o &#039;&#039;&#039;S&#039;&#039;&#039;end) und &#039;&#039;&#039;CTS&#039;&#039;&#039; (&#039;&#039;&#039;C&#039;&#039;&#039;lear &#039;&#039;&#039;T&#039;&#039;&#039;o &#039;&#039;&#039;S&#039;&#039;&#039;end). Jeder der beiden Kommunikationspartner ist verpflichtet, bevor ein Zeichen gesendet wird, den Zustand der &#039;&#039;&#039;RTS&#039;&#039;&#039; Leitung zu überprüfen. Nur wenn die Gegenstelle darauf Empfangsbereitschaft signalisiert, darf das Zeichen gesendet werden. Um der Gegenstelle zu signalisieren, daß sie zur Zeit keine Zeichen schicken soll, wird die Leitung &#039;&#039;&#039;CTS&#039;&#039;&#039; benutzt.&lt;br /&gt;
&lt;br /&gt;
===Softwarehandshake (XON/XOFF)===&lt;br /&gt;
Beim Softwarehandshake sind keine speziellen Leitungen notwendig. Statt dessen werden besondere ASCII-Zeichen benutzt, die der Gegenstelle signalisieren, daß Senden einzustellen bzw. wieder aufzunehmen.&amp;lt;br /&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;XOFF&#039;&#039;&#039; Aufforderung das Senden einzustellen&lt;br /&gt;
* &#039;&#039;&#039;XON&#039;&#039;&#039;  Gegenstelle darf wieder senden&lt;br /&gt;
&lt;br /&gt;
Nachteilig bei einem Softwarehandshake ist es, dass dadurch keine direkte binäre Datenübertragung mehr möglich ist. Von den möglichen 256 Bytewerten werden ja 2 (nämlich &#039;&#039;&#039;XON&#039;&#039;&#039; und &#039;&#039;&#039;XOFF&#039;&#039;&#039;) für besondere Zwecke benutzt und fallen daher aus.&lt;br /&gt;
&lt;br /&gt;
==Fehlersuche==&lt;br /&gt;
Erstaunlich oft wird im Forum der Hilferuf laut: &amp;quot;Meine UART funktioniert nicht, was mache ich falsch&amp;quot;. In der überwiegenden Mehrzahl der Fälle stellt sich dann heraus, daß es sich um ein Hardwareproblem handelt, wobei da wiederrum der Löwenanteil auf das Konto einer nicht korrekt eingestellten Taktrate geht: Der µC benutzt nicht einen angeschlossenen Quarz, so wie er auch im Programm eingetragen ist, sondern läuft immer noch mit dem internen RC-Takt. Daraus resultiert aber auch, daß der Baudraten Konfigurationswert falsch berechnet wird.&lt;br /&gt;
&lt;br /&gt;
Eine Checkliste zum Aufspüren solcher Fehler findet sich [[AVR_Checkliste#UART.2FUSART|hier]].&lt;br /&gt;
&lt;br /&gt;
= Analoge Ein- und Ausgabe =&lt;br /&gt;
&lt;br /&gt;
Analoge Eingangswerte werden in der Regel über den AVR Analog-Digital-Converter (AD-Wandler, ADC) eingelesen, der in vielen Typen verfügbar ist (typisch 10bit Auflösung). Durch diesen werden analogen Signale (Spannungen) in digitale Zahlenwerte gewandelt. Bei AVRs, die über keinen internen AD-Wandler verfügen (z.B. ATmega162), kann durch externe Beschaltung (R/C-Netzwerk und &amp;quot;Zeitmessung&amp;quot;) die Funktion des AD-Wandlers &amp;quot;emuliert&amp;quot; werden.&lt;br /&gt;
&lt;br /&gt;
Es existieren keine AVRs mit eingebautem Digital-Analog-Konverter (DAC). Diese Funktion muss durch externe Komponenten nachgebildet werden (z.B. PWM und &amp;quot;Glättung&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Unabhängig davon besteht natürlich immer die Möglichkeit, spezielle Bausteine zur Analog-Digital- bzw. Digital-Analog-Wandlung zu nutzen und diese über eine digitale Schnittstelle (z.b. SPI oder I2C) mit einem AVR anzusteuern.&lt;br /&gt;
&lt;br /&gt;
== AC (Analog Comparator) ==&lt;br /&gt;
&lt;br /&gt;
Der Comparator vergleicht 2 Spannungen an den Pins AIN0 und AIN1 und gibt einen Status aus welche der beiden Spannungen größer ist. AIN0 Dient dabei als Referenzspannung (Sollwert) und AIN1 als Vergleichsspannung (Istwert). Als Referenzspannung kann auch alternativ eine interne Referenzspannung ausgewählt werden.&amp;lt;BR&amp;gt;&lt;br /&gt;
&amp;lt;BR&amp;gt;&lt;br /&gt;
Liegt die Vergleichsspannung (IST) unter der der Referenzspannung (SOLL) gibt der Comperator eine logische 1 aus. Ist die Vergleichsspannung hingegen größer als die Referenzspannung wird eine logische 0 ausgegeben.&amp;lt;BR&amp;gt;&lt;br /&gt;
&amp;lt;BR&amp;gt;&lt;br /&gt;
Der Comperator arbeitet völlig autark bzw. parallel zum Prozessor. Für mobile Anwendungen empfiehlt es sich ihn abzuschalten sofern er nicht benötigt wird, da er ansonsten Strom benötigt. Der Comparator kann Interruptgesteuert abgefragt werden oder im Pollingbetrieb.&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Steuer- bzw. Statusregister ist wie folgt aufgebaut:&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ACSR (0x28) - Analog Comparator Status Register&amp;lt;BR&amp;gt;&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Bit&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 7&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 6&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 5&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 4&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 2&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Name&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ACD&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ACBG&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ACO&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ACI&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ACIE&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ACIC&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ACIS1&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ACIS0&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;R/W&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Initialwert&#039;&#039;&#039;&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; | n/a&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;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
Bit 7 ACD - Analog Comparator Disable: 0 = Comparator ein, 1 = Comparator aus. Wird dieses Bit geändert kann ein Interrupt ausgelöst werden. Soll dies vermieden werden muß das Bit 3 ACIE ggf. abgeschaltet werden.&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
Bit 6 ACBG - Analog Comparator Bandgap Select: Ermöglicht das umschalten zwischen interner und externer Referenzspannung. 1 = interne (~1,3 Volt), 0 = externe Referenzspannung (an Pin AIN0)&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
Bit 5 ACO - Analog Comparator Output: Hier wird das Ergebnis des Vergleichs angezeigt. Es liegt typischerweise nach 1-2 Taktzyklen vor. &amp;lt;BR&amp;gt;&lt;br /&gt;
Ergebnis: &amp;lt;BR&amp;gt;IST &amp;lt; SOLL --&amp;gt; 1&amp;lt;BR&amp;gt;&lt;br /&gt;
IST &amp;gt; SOLL --&amp;gt; 0&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
Bit 4 ACI - Analog Comparator Interrupt Flag: Dieses Bit wird von der Hardware gesetzt wenn ein Interruptereignis das in Bit 0 und 1 definiert ist eintritt. Dieses Bit löst noch keinen Interrupt aus! Die Interruptroutine wird nur dann ausgeführt wenn das Bit 3 ACIE gesetzt ist und global Interrupts erlaubt sind (I-Bit in SREG=1). Das Bit 4 ACI wird wieder gelöscht wenn die Interruptroutine ausgeführt wurde oder wenn manuell das Bit auf 1 gesetzt wird. Das Bit kann für Abfragen genutzt werden, steuert oder konfuguriert aber nicht den Comparator.&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
Bit 3 ACIE - Analog Comparator Interrupt Enable: Ist das Bit auf 1 gesetzt wird immer ein Interrupt ausgelöst wenn das Ereignis das in Bit 1 und 0 definiert ist eintritt.&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
Bit 2 ACIC - Analog Comparator Input Capture Enable: Wird das Bit gesetzt wird der Comparatorausgang intern mit dem Counter 1 verbunden. Es könnten damit z.b. die Anzahl der Vergleiche im Counter1 gezählt werden. Um den Comparator an den Timer1 Input Capture Interrupt zu verbinden muß im Timerregister das TICIE1 Bit auf 1 gesetzt werden. Der Trigger wird immer dann ausgelöst wenn das in Bit 1 und 0 definierte Ereignis eintritt.&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
Bit 1,0 ACIS1,ACIS0 - Analog Comparator Interrupt select: Hier wird definiert welche Ereignisse einen Interrupt auslösen sollen:&amp;lt;BR&amp;gt;&lt;br /&gt;
00 = Interrupt auslösen bei jedem Flankenwechsel&amp;lt;BR&amp;gt;&lt;br /&gt;
10 = Interrupt auslösen bei fallender Flanke&amp;lt;BR&amp;gt;&lt;br /&gt;
11 = Interrupt auslösen bei steigender Flanke&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
Werden diese Bit geändert kann ein Interrupt ausgelöst werden. Soll dies vermieden werden muß das Bit 3 gelöscht werden.&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== ADC (Analog Digital Converter) ==&lt;br /&gt;
&lt;br /&gt;
Der Analog-Digital-Konverter (ADC) wandelt analoge Signale in digitale Werte um, welche vom Controller interpretiert werden können. Einige AVR-Typen haben bereits einen mehrkanaligen Analog-Digital-Konverter eingebaut. Die Genauigkeit, mit welcher ein analoges Signal aufgelöst werden kann, wird durch die Auflösung des ADC in Anzahl Bits angegeben, man hört bzw. liest jeweils von 8-Bit-ADC oder 10-Bit-ADC oder noch höher. ADCs die in AVRs enthalten sind haben zur Zeit eine maximale Auflösung von 10-Bit.&lt;br /&gt;
&lt;br /&gt;
Ein ADC mit 8 Bit Auflösung kann somit das analoge Signal mit einer Genauigkeit von 1/256 des Maximalwertes darstellen. Wenn wir nun mal annehmen, wir hätten eine Spannung zwischen 0 und 5 Volt und eine Auflösung von 3 Bit, dann könnten&lt;br /&gt;
die Werte 0V, 0.625V, 1.25, 1.875V, 2.5V, 3.125V, 3.75, 4.375, 5V&lt;br /&gt;
daherkommen, siehe dazu folgende Tabelle:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div align=&amp;quot;center&amp;quot;&amp;gt;&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;Eingangsspannung am ADC&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;Entsprechender Messwert&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0...&amp;lt;0.625V&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0.625...&amp;lt;1.25V&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1.25...&amp;lt;1.875V&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 2&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1.875...&amp;lt;2.5V&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 2.5...&amp;lt;3.125V&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 4&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3.125...&amp;lt;3.75V&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 5&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3.75...&amp;lt;4.375V&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 6&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 4.375...5V&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 7&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Angaben sind natürlich nur ungefähr. Je höher nun die Auflösung des Analog-Digital-Konverters ist, also je mehr Bits er hat, um so genauer kann der Wert erfasst werden.&lt;br /&gt;
&lt;br /&gt;
=== Der interne ADC im AVR ===&lt;br /&gt;
&lt;br /&gt;
Wenn es einmal etwas genauer sein soll, dann müssen wir auf einen AVR mit eingebautem Analog-Digital-Wandler (ADC) zurückgreifen, die über mehrere Kanäle verfügen. Kanäle heißt in diesem Zusammenhang, dass zwar bis zu zehn analoge Eingänge am AVR verfügbar sind, aber nur ein &amp;quot;echter&amp;quot; Analog-Digital-Wandler zur Verfügung steht, vor der eigentlichen Messung ist also einzustellen, welcher Kanal (&amp;quot;Pin&amp;quot;) mit dem Wandler verbunden und gemessen wird.&lt;br /&gt;
&lt;br /&gt;
Die Umwandlung innerhalb des AVR basiert auf der schrittweisen Näherung. Beim AVR müssen die Pins &#039;&#039;&#039;AGND&#039;&#039;&#039; und &#039;&#039;&#039;AVCC&#039;&#039;&#039; beschaltet werden. Für genaue Messungen sollte AVCC über ein L-C Netzwerk mit VCC verbunden werden, um Spannungsspitzen und -einbrüche vom Analog-Digital-Wandler fernzuhalten. Im Datenblatt findet sich dazu eine Schaltung, die 10uH und 100nF vorsieht.&lt;br /&gt;
&lt;br /&gt;
Das Ergebnis der Analog-Digital-Wandlung wird auf eine Referenzspannung bezogen. Aktuelle AVRs bieten drei Möglichkeiten zur Wahl dieser Spannung:&lt;br /&gt;
&lt;br /&gt;
* Eine externe Referenzspannung von maximal &#039;&#039;&#039;Vcc&#039;&#039;&#039; am Anschlusspin &#039;&#039;&#039;AREF&#039;&#039;&#039;. Die minimale (externe) Referenzspannung darf jedoch nicht beliebig niedrig sein, vgl. dazu das (aktuellste) Datenblatt des verwendeten Controllers. &lt;br /&gt;
&lt;br /&gt;
* Verfügt der AVR über eine interne Referenzspannung, kann diese genutzt werden. Alle aktuellen AVRs mit internem AD-Wandler sollten damit ausgestattet sein (vgl. Datenblatt: 2,56V oder 1,1V je nach Typ). Das Datenblatt gibt auch über die Genauigkeit dieser Spannung Auskunft.&lt;br /&gt;
&lt;br /&gt;
* Die &#039;&#039;&#039;interne&#039;&#039;&#039; Referenzspannung wird auf &#039;&#039;&#039;Vcc&#039;&#039;&#039; bezogen, eine externe Referenzspannung auf &#039;&#039;&#039;GND (Masse)&#039;&#039;&#039;. Davon unabhängig werden digitalisierte Spannungen &#039;&#039;&#039;immer&#039;&#039;&#039; auf GND bezogen. Beim ATMEGA8 z.B. ist der Pin AREF über 32kOhm mit GND verbunden, d.h. man muss diese doch extrem niedrige Eingangsimpedanz mit in die Berechnung für einen Spannungsteiler einbeziehen, bzw. kann diesen Widerstand als R2 gleich mit benutzen. Formel für Spannungsteiler: Udiv = U / ((R1 + R2) / R2)&lt;br /&gt;
&lt;br /&gt;
Bei Nutzung von Vcc oder der internen Referenz wird empfohlen, einen Kondensator zwischen dem AREF-Pin und GND anzuordnen. Die Festlegung, welche Spannungsreferenz genutzt wird, erfolgt z.B. beim ATmega16 mit den Bits REFS1/REFS0 im ADMUX-Register. Die zu messende Spannung muss im Bereich zwischen &#039;&#039;&#039;AGND&#039;&#039;&#039; und &#039;&#039;&#039;AREF&#039;&#039;&#039; (egal ob intern oder extern) liegen. &lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;&#039;ADC&#039;&#039;&#039; kann in zwei verschiedenen Betriebsarten verwendet werden:&lt;br /&gt;
&lt;br /&gt;
; Einfache Wandlung (Single Conversion) : In dieser Betriebsart wird der Wandler bei Bedarf vom Programm angestoßen für jeweils eine Messung.&lt;br /&gt;
&lt;br /&gt;
; Frei laufend (Free Running) : In dieser Betriebsart erfasst der Wandler permanent die anliegende Spannung und schreibt diese in das &#039;&#039;&#039;ADC Data Register&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==== Die Register des ADC ====&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;&#039;ADC&#039;&#039;&#039; verfügt über eigene Register. Im Folgenden die Registerbeschreibung eines  ATMega16, welcher über 8 ADC-Kanäle verfügt. Die Register unterscheiden sich jedoch nicht erheblich von denen anderer AVRs (vgl. Datenblatt).&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;ADCSRA&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;ADC&#039;&#039;&#039; &#039;&#039;&#039;C&#039;&#039;&#039;ontrol and &#039;&#039;&#039;S&#039;&#039;&#039;tatus &#039;&#039;&#039;R&#039;&#039;&#039;egister A.&amp;lt;br /&amp;gt;&lt;br /&gt;
In diesem Register stellen wir ein, wie wir den &#039;&#039;&#039;ADC&#039;&#039;&#039; verwenden möchten.&amp;lt;br /&amp;gt;&lt;br /&gt;
Das Register ist wie folgt aufgebaut:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Bit&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 7&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 6&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 5&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 4&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 2&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Name&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ADEN&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ADSC&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ADFR&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ADIF&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ADIE&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ADPS2&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ADPS1&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ADPS0&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;R/W&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Initialwert&#039;&#039;&#039;&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;
| 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;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ADEN&#039;&#039;&#039; (&#039;&#039;&#039;AD&#039;&#039;&#039;C &#039;&#039;&#039;En&#039;&#039;&#039;able)&lt;br /&gt;
:Dieses Bit muss gesetzt werden, um den &#039;&#039;&#039; ADC&#039;&#039;&#039; überhaupt zu aktivieren. Wenn das Bit nicht gesetzt ist, können die Pins wie normale I/O-Pins verwendet werden.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ADSC&#039;&#039;&#039; (&#039;&#039;&#039;AD&#039;&#039;&#039;C &#039;&#039;&#039;S&#039;&#039;&#039;tart &#039;&#039;&#039;C&#039;&#039;&#039;onversion)&lt;br /&gt;
:Mit diesem Bit wird ein Messvorgang gestartet. In der frei laufenden Betriebsart muss das Bit gesetzt werden, um die kontinuierliche Messung zu aktivieren.&lt;br /&gt;
:Wenn das Bit nach dem Setzen des &#039;&#039;&#039;ADEN&#039;&#039;&#039;-Bits zum ersten Mal gesetzt wird, führt der Controller zuerst eine zusätzliche Wandlung und erst dann die eigentliche Wandlung aus. Diese zusätzliche Wandlung wird zu Initialisierungszwecken durchgeführt.&lt;br /&gt;
:Das Bit bleibt nun so lange auf 1, bis die Umwandlung abgeschlossen ist, im Initialisierungsfall entsprechend bis die zweite Umwandlung erfolgt ist und geht danach auf 0.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ADFR&#039;&#039;&#039; (&#039;&#039;&#039;AD&#039;&#039;&#039;C &#039;&#039;&#039;F&#039;&#039;&#039;ree &#039;&#039;&#039;R&#039;&#039;&#039;un select)&lt;br /&gt;
:Mit diesem Bit wird die Betriebsart eingestellt.&lt;br /&gt;
:Ist das Bit auf 1 gesetzt arbeitet der ADC im Freerunning Modus. Dabei wird das Datenregister permanent aktualisiert. Ist das Bit hingegen auf 0 gesetzt macht der ADC nur eine Single Conversion. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ADIF&#039;&#039;&#039; (&#039;&#039;&#039;AD&#039;&#039;&#039;C &#039;&#039;&#039;I&#039;&#039;&#039;nterrupt &#039;&#039;&#039;F&#039;&#039;&#039;lag)&lt;br /&gt;
:Dieses Bit wird vom &#039;&#039;&#039; ADC&#039;&#039;&#039; gesetzt, sobald eine Umwandlung erfolgt ist und das &#039;&#039;&#039;ADC Data Register&#039;&#039;&#039; aktualisiert wurde. Das Bit wird bei lesendem Zugriff auf &#039;&#039;&#039;ADC(L,H)&#039;&#039;&#039; automatisch (d.h. durch die Hardware) gelöscht.&lt;br /&gt;
:Wenn das &#039;&#039;&#039;ADIE&#039;&#039;&#039; Bit sowie das &#039;&#039;&#039;I-Bit&#039;&#039;&#039; im AVR &#039;&#039;&#039;Statusregister&#039;&#039;&#039; gesetzt ist, wird der &#039;&#039;&#039;ADC Interrupt&#039;&#039;&#039; ausgelöst und die Interrupt-Behandlungsroutine aufgerufen.&lt;br /&gt;
:Das Bit wird automatisch gelöscht, wenn die Interrupt-Behandlungsroutine aufgerufen wird. Es kann jedoch auch gelöscht werden, indem eine logische 1 in das Register geschrieben wird.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ADIE&#039;&#039;&#039; (&#039;&#039;&#039;AD&#039;&#039;&#039;C &#039;&#039;&#039;I&#039;&#039;&#039;nterrupt &#039;&#039;&#039;E&#039;&#039;&#039;nable)&lt;br /&gt;
:Wenn dieses Bit gesetzt ist und ebenso das &#039;&#039;&#039; I-Bit&#039;&#039;&#039; im Statusregister &#039;&#039;&#039;SREG&#039;&#039;&#039;, dann wird der &#039;&#039;&#039; ADC-Interrupt&#039;&#039;&#039; aktiviert.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ADPS2...ADPS0&#039;&#039;&#039; (&#039;&#039;&#039;AD&#039;&#039;&#039;C &#039;&#039;&#039;P&#039;&#039;&#039;rescaler &#039;&#039;&#039;S&#039;&#039;&#039;elect Bits)&lt;br /&gt;
:Diese Bits bestimmen den Teilungsfaktor zwischen der Taktfrequenz und dem Eingangstakt des &#039;&#039;&#039;ADC&#039;&#039;&#039;.&lt;br /&gt;
:Der &#039;&#039;&#039;ADC&#039;&#039;&#039; benötigt einen eigenen Takt, welchen er sich selber aus der CPU-Taktfreqenz erzeugt. Der &#039;&#039;&#039;ADC&#039;&#039;&#039;-Takt sollte zwischen 50 und 200kHz sein.&lt;br /&gt;
:Der Vorteiler muss also so eingestellt werden, dass die CPU-Taktfrequenz dividiert durch den Teilungsfaktor einen Wert zwischen 50-200kHz ergibt.&lt;br /&gt;
:Bei einer CPU-Taktfrequenz von 4MHz beispielsweise rechnen wir&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;&lt;br /&gt;
\begin{matrix}&lt;br /&gt;
TF_{min}=\frac{CLK}{200\,\mathrm{kHz}}=\frac{4000000}{200000}=\mathbf{20}&lt;br /&gt;
\\&lt;br /&gt;
\\&lt;br /&gt;
TF_{max}=\frac{CLK}{50\,\mathrm{kHz}}=\frac{4000000}{50000}=\mathbf{80}&lt;br /&gt;
\end{matrix}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Somit kann hier der Teilungsfaktor 32 oder 64 verwendet werden. Im Interesse der schnelleren Wandlungszeit werden wir hier den Faktor 32 einstellen.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&lt;br /&gt;
{| style=&amp;quot;&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ADPS2&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ADPS1&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ADPS0&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;Teilungsfaktor&#039;&#039;&#039;&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;
| align=&amp;quot;center&amp;quot; | 2&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;
| align=&amp;quot;center&amp;quot; | 2&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;
| align=&amp;quot;center&amp;quot; | 4&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;
| align=&amp;quot;center&amp;quot; | 8&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;
| align=&amp;quot;center&amp;quot; | 16&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;
| align=&amp;quot;center&amp;quot; | 32&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;
| align=&amp;quot;center&amp;quot; | 64&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;
| align=&amp;quot;center&amp;quot; | 128&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;ADCL&#039;&#039;&#039;&amp;lt;br /&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;ADCH&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;ADC &#039;&#039;&#039; Data Register&amp;lt;br /&amp;gt;&lt;br /&gt;
Wenn eine Umwandlung abgeschlossen ist, befindet sich der gemessene Wert in&lt;br /&gt;
diesen beiden Registern. Von &#039;&#039;&#039;ADCH&#039;&#039;&#039; werden nur die beiden niederwertigsten Bits verwendet. Es müssen immer beide Register ausgelesen werden, und zwar immer &#039;&#039;&#039;in der Reihenfolge: ADCL, ADCH&#039;&#039;&#039;. &lt;br /&gt;
Der effektive Messwert ergibt sich dann zu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
x = ADCL;       // mit uint16_t x&lt;br /&gt;
x += (ADCH&amp;lt;&amp;lt;8); // in zwei Zeilen (LSB/MSB-Reihenfolge und&lt;br /&gt;
                // C-Operatorpriorität sichergestellt)&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
oder &lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
x = ADCW; // je nach AVR auch x = ADC (siehe avr/ioxxx.h)&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;ADMUX&amp;amp;nbsp;&amp;amp;nbsp;&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;AD&#039;&#039;&#039;C &#039;&#039;&#039;Mu&#039;&#039;&#039;ltiple&#039;&#039;&#039;x&#039;&#039;&#039;er Select Register&amp;lt;br /&amp;gt;&lt;br /&gt;
Mit diesem Register wird der zu messende Kanal ausgewählt. Beim 90S8535&lt;br /&gt;
kann jeder Pin von Port A als &#039;&#039;&#039;ADC&#039;&#039;&#039;-Eingang verwendet werden (=8 Kanäle).&amp;lt;br /&amp;gt;&lt;br /&gt;
Das Register ist wie folgt aufgebaut:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Bit&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 7&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 6&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 5&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 4&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 2&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Name&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;REFS1&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;REFS0&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ADLAR&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;MUX4&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;MUX3&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;MUX2&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;MUX1&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;MUX0&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;R/W&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Initialwert&#039;&#039;&#039;&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;
| 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;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;REFS1...REFS0&#039;&#039;&#039; (&#039;&#039;&#039;Ref&#039;&#039;&#039;erence&#039;&#039;&#039;S&#039;&#039;&#039;election Bits)&lt;br /&gt;
:Mit diesen Bits kann die Referenzspannung eingestellt werden:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&lt;br /&gt;
{| style=&amp;quot;&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;REFS1&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;REFS0&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;Referenzspanung&#039;&#039;&#039;&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; | Externes AREF&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; | AVCC als Referenz&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; | Reserviert&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; | Interne 2,56 Volt&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ADLAR&#039;&#039;&#039; (&#039;&#039;&#039;ADC &#039;&#039;&#039; &#039;&#039;&#039;L&#039;&#039;&#039;eft &#039;&#039;&#039;A&#039;&#039;&#039;djust &#039;&#039;&#039;R&#039;&#039;&#039;esult)&lt;br /&gt;
:Das ADLAR Bit verändert das Aussehen des Ergebnisses der AD-Wandlung. Bei einer logischen 1 wird das Ergebnis linksbündig ausgegeben, bei einer 0 rechtsündig. Eine Änderung in diesem Bit beeinflusst das Ergebnis sofort, ganz egal ob bereits eine Wandlung läuft.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;MUX4...MUX0&#039;&#039;&#039;&lt;br /&gt;
:Mit diesen 5 Bits wird der zu messende Kanal bestimmt. Wenn man einen einfachen 1-kanaligen ADC verwendet wird einfach die entsprechende Pinnummer des Ports in die Bits 0...2 eingeschrieben.&lt;br /&gt;
:Wenn das Register beschrieben wird, während dem eine Umwandlung läuft, so wird zuerst die aktuelle Umwandlung auf dem bisherigen Kanal beendet. Dies ist vor allem beim frei laufenden Betrieb zu berücksichtigen.&lt;br /&gt;
&lt;br /&gt;
:Eine Empfehlung ist deswegen diese, dass der frei laufende Betrieb nur bei einem einzelnen zu verwendenden Analogeingang verwendet werden sollte, wenn man sich Probleme bei der Umschalterei ersparen will.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Aktivieren des ADC ====&lt;br /&gt;
&lt;br /&gt;
Um den &#039;&#039;&#039; ADC&#039;&#039;&#039; zu aktivieren, müssen wir das &#039;&#039;&#039;ADEN&#039;&#039;&#039;-Bit im &#039;&#039;&#039;ADCSR&#039;&#039;&#039;-Register&lt;br /&gt;
setzen. Im gleichen Schritt legen wir auch gleich die Betriebsart fest. &lt;br /&gt;
&lt;br /&gt;
Ein kleines Beispiel für den &amp;quot;single conversion&amp;quot;-Mode bei einem ATmega169 und Nutzung der internen Referenzspannung (beim &#039;169 1,1V bei anderen AVRs auch 2,56V). D.h. das Eingangssignal darf diese Spannung nicht überschreiten, gegebenenfalls mit Spannungsteiler einstellen. Ergebnis der Routine ist der ADC-Wert, also 0 für 0-Volt und 1023 für V_ref-Volt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
uint16_t ReadChannel(uint8_t mux)&lt;br /&gt;
{&lt;br /&gt;
  uint8_t i;&lt;br /&gt;
  uint16_t result;&lt;br /&gt;
&lt;br /&gt;
  ADMUX = mux;                      // Kanal waehlen&lt;br /&gt;
  ADMUX |= (1&amp;lt;&amp;lt;REFS1) | (1&amp;lt;&amp;lt;REFS0); // interne Referenzspannung nutzen&lt;br /&gt;
&lt;br /&gt;
  ADCSRA = (1&amp;lt;&amp;lt;ADEN) | (1&amp;lt;&amp;lt;ADPS1) | (1&amp;lt;&amp;lt;ADPS0);    // Frequenzvorteiler &lt;br /&gt;
                               // setzen auf 8 (1) und ADC aktivieren (1)&lt;br /&gt;
&lt;br /&gt;
  /* nach Aktivieren des ADC wird ein &amp;quot;Dummy-Readout&amp;quot; empfohlen, man liest&lt;br /&gt;
     also einen Wert und verwirft diesen, um den ADC &amp;quot;warmlaufen zu lassen&amp;quot; */&lt;br /&gt;
  ADCSRA |= (1&amp;lt;&amp;lt;ADSC);              // eine ADC-Wandlung &lt;br /&gt;
  while ( ADCSRA &amp;amp; (1&amp;lt;&amp;lt;ADSC) ) {&lt;br /&gt;
     ;     // auf Abschluss der Konvertierung warten &lt;br /&gt;
  }&lt;br /&gt;
  result = ADCW;  // ADCW muss einmal gelesen werden,&lt;br /&gt;
                  // sonst wird Ergebnis der nächsten Wandlung&lt;br /&gt;
                  // nicht übernommen.&lt;br /&gt;
&lt;br /&gt;
  /* Eigentliche Messung - Mittelwert aus 4 aufeinanderfolgenden Wandlungen */&lt;br /&gt;
  result = 0; &lt;br /&gt;
  for( i=0; i&amp;lt;4; i++ )&lt;br /&gt;
  {&lt;br /&gt;
    ADCSRA |= (1&amp;lt;&amp;lt;ADSC);            // eine Wandlung &amp;quot;single conversion&amp;quot;&lt;br /&gt;
    while ( ADCSRA &amp;amp; (1&amp;lt;&amp;lt;ADSC) ) {&lt;br /&gt;
      ;   // auf Abschluss der Konvertierung warten&lt;br /&gt;
    }&lt;br /&gt;
    result += ADCW;		    // Wandlungsergebnisse aufaddieren&lt;br /&gt;
  }&lt;br /&gt;
  ADCSRA &amp;amp;= ~(1&amp;lt;&amp;lt;ADEN);             // ADC deaktivieren (2)&lt;br /&gt;
&lt;br /&gt;
  result /= 4;                     // Summe durch vier teilen = arithm. Mittelwert&lt;br /&gt;
&lt;br /&gt;
  return result;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
/* Beispielaufrufe: */&lt;br /&gt;
&lt;br /&gt;
void foo(void)&lt;br /&gt;
{&lt;br /&gt;
  uint16_t adcval;&lt;br /&gt;
&lt;br /&gt;
  adcval = ReadChannel(0); /* MUX-Bits auf 0b0000 -&amp;gt; Channel 0 */&lt;br /&gt;
  ...&lt;br /&gt;
  adcval = ReadChannel(2); /* MUX-Bits auf 0b0010 -&amp;gt; Channel 2 */&lt;br /&gt;
  ...&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im Beispiel wird bei jedem Aufruf der ADC aktiviert und nach der Wandlung wieder abgeschaltet, das spart Strom. Will man dies nicht, verschiebt man die mit (1) gekennzeichneten Zeilen in eine Funktion adc_init() o.ä. und löscht die mit (2) markierten Zeilen. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- &lt;br /&gt;
Das Löschen des ADIF-Flags sollte, &#039;&#039;&#039;entgegen&#039;&#039;&#039; der [http://www.nongnu.org/avr-libc/user-manual/FAQ.html#faq_intbits FAQ], mit&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  ADCSRA |= (1&amp;lt;&amp;lt;ADIF);&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
erfolgen. Die Methode in der FAQ eignet sich nur für Register in denen &#039;&#039;&#039;nur&#039;&#039;&#039; Interrupt-Flags stehen.&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Analog-Digital-Wandlung ohne internen ADC ===&lt;br /&gt;
&lt;br /&gt;
==== Messen eines Widerstandes ====&lt;br /&gt;
&lt;br /&gt;
Analoge Werte lassen sich ohne Analog-Digital-Wandler auch indirekt ermitteln. Im Folgenden wird die Messung des an einem Potentiometer eingestellten Widerstands anhand der Ladekurve eines Kondensators erläutert. Bei dieser Methode wird nur ein Portpin benötigt, ein Analog-Digital-Wandler oder Analog-Comparator ist nicht erforderlich. Es wird dazu ein Kondensator und der Widerstand (das Potentiometer) in Reihe zwischen Vorsorgungsspannung und Masse/GND geschaltet (sogen. RC-Netzwerk). Zusätzlich wird eine Verbindung der Leitung zwischen Kondensator und Potentiometer zu einem Portpin des Controllers hergestellt. Die folgende Abbildung verdeutlicht die erforderliche Schaltung. &lt;br /&gt;
&lt;br /&gt;
[[Image:Poti.gif]]&lt;br /&gt;
&lt;br /&gt;
Wird der Portpin des Controllers auf Ausgang konfiguriert (im Beispiel &#039;&#039;DDRD&amp;amp;nbsp;|=&amp;amp;nbsp;(1&amp;lt;&amp;lt;PD2)&#039;&#039;) und dieser Ausgang auf Logisch 1 (&amp;quot;High&amp;quot;, &#039;&#039;PORTD&amp;amp;nbsp;|=&amp;amp;nbsp;(1&amp;lt;&amp;lt;PD2)&#039;&#039;) geschaltet, liegt an beiden &amp;quot;Platten&amp;quot; des Kondensators das gleiche Potential &#039;&#039;&#039;VCC&#039;&#039;&#039; an und der Kondensator somit entladen. (Klingt komisch, mit &#039;&#039;&#039; Vcc&#039;&#039;&#039; entladen, ist aber so, da an beiden Seiten des Kondensators das gleiche Potential anliegt und somit eine Potentialdifferenz von 0V besteht =&amp;gt; Kondensator ist entladen).&lt;br /&gt;
&lt;br /&gt;
Nach einer gewissen Zeit ist der Kondensator entladen und der Portpin wird als Eingang konfiguriert (&#039;&#039;DDRD&amp;amp;nbsp;&amp;amp;=&amp;amp;nbsp;~(1&amp;lt;&amp;lt;PD2); PORTD&amp;amp;nbsp;&amp;amp;=&amp;amp;nbsp;~(1&amp;lt;&amp;lt;PD2)&#039;&#039;), wodurch dieser hochohmig wird. Der Status des Eingangspin (in PIND) ist Logisch 1 (High). Der Kondensator lädt sich jetzt über das Poti auf, dabei steigt der Spannungsabfall über dem Kondensator und derjenige über dem Poti sinkt. Fällt nun der Spannungsabfall über dem Poti unter die Thresholdspannung des Eingangspins (2/5 Vcc, also ca. 2V), wird das Eingangssignal als LOW erkannt (Bit in PIND wird 0). Die Zeitspanne zwischen der Umschaltung von Entladung auf Aufladung und dem Wechsel des Eingangssignals von High auf Low ist ein Maß für den am Potentiometer eingestellten Widerstand. Zur Zeitmessung kann einer der im Controller vorhandenen Timer genutzt werden. Der 220 Ohm Widerstand dient dem Schutz des Controllers. Es würde sonst bei Maximaleinstellung des Potentionmeters (hier 0 Ohm) ein zu hoher Strom fließen, der die Ausgangsstufe des Controllers zerstört. &lt;br /&gt;
&lt;br /&gt;
Mit einem weiteren Eingangspin und ein wenig Software können wir auch eine Kalibrierung realisieren, um den Messwert in einen vernünftigen Bereich (z.B: 0...100 % oder so) umzurechnen. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- Link 404 =&amp;gt; auskommentiert, mthomas 9.2.2008 &lt;br /&gt;
Ein Beispielprogramm findet sich auf [http://www.mypage.bluewin.ch/ch_schifferle/ Christian Schifferles Web-Seite] im Archiv &#039;&#039;ATMEL.ZIP&#039;&#039;, welches unter den Titel &#039;&#039;Tutorial &amp;quot;Programmieren mit C für Atmel Mikrocontroller&#039;&#039; heruntergeladen werden kann. --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== ADC über Komparator ====&lt;br /&gt;
&lt;br /&gt;
Es gibt einen weiteren Weg, eine analoge Spannung mit Hilfe des&lt;br /&gt;
Komparators, welcher in fast jedem AVR integriert ist, zu messen. Siehe dazu&lt;br /&gt;
auch die Application Note AVR400 von Atmel.&lt;br /&gt;
&lt;br /&gt;
Dabei wird das zu messende Signal auf den invertierenden Eingang&lt;br /&gt;
des Komparators geführt. Zusätzlich wird ein Referenzsignal an den nicht&lt;br /&gt;
invertierenden Eingang des Komparators angeschlossen. Das Referenzsignal wird&lt;br /&gt;
hier auch wieder über ein RC-Glied erzeugt, allerdings mit festen Werten für R&lt;br /&gt;
und C.&lt;br /&gt;
&lt;br /&gt;
[[Image:ADC ueber Komparator.gif]]&lt;br /&gt;
&lt;br /&gt;
Das Prinzip der Messung ist nun dem vorhergehenden recht&lt;br /&gt;
ähnlich. Durch Anlegen eines LOW-Pegels an Pin 2 wird der Kondensator zuerst&lt;br /&gt;
einmal entladen. Auch hier muss darauf geachtet werden, dass der Entladevorgang&lt;br /&gt;
genügend lang dauert.&amp;lt;br /&amp;gt;&lt;br /&gt;
Nun wird Pin 2 auf HIGH gelegt. Der Kondensator wird geladen. Wenn die Spannung&lt;br /&gt;
über dem Kondensator die am Eingangspin anliegende Spannung erreicht hat&lt;br /&gt;
schaltet der Komparator durch. Die Zeit, welche benötigt wird, um den&lt;br /&gt;
Kondensator zu laden kann nun auch wieder als Maß für die Spannung an Pin 1&lt;br /&gt;
herangezogen werden.&lt;br /&gt;
&lt;br /&gt;
Ich habe es mir gespart, diese Schaltung auch aufzubauen und&lt;br /&gt;
zwar aus mehreren Gründen:&lt;br /&gt;
&lt;br /&gt;
# 3 Pins notwendig.&lt;br /&gt;
# Genauigkeit vergleichbar mit einfacherer Lösung.&lt;br /&gt;
# War einfach zu faul.&lt;br /&gt;
&lt;br /&gt;
Der Vorteil dieser Schaltung liegt allerdings darin, dass damit&lt;br /&gt;
direkt Spannungen gemessen werden können.&lt;br /&gt;
&lt;br /&gt;
== DAC (Digital Analog Converter) ==&lt;br /&gt;
&lt;br /&gt;
Mit Hilfe eines Digital-Analog-Konverters (&#039;&#039;&#039;DAC&#039;&#039;&#039;) können wir nun auch Analogsignale ausgeben. Es gibt hier mehrere Verfahren. &amp;lt;!-- Wenn wir beim ADC die Möglichkeit haben, mit externen Komponenten zu operieren, müssen wir bei der DAC-Wandlung mit dem auskommen, was der Controller selber zu bieten hat. --mt: hmm, richtig? verstaendlich? redundant? --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== DAC über mehrere digitale Ausgänge ===&lt;br /&gt;
&lt;br /&gt;
Wenn wir an den Ausgängen des Controllers ein entsprechendes&lt;br /&gt;
Widerstandsnetzwerk aufbauen haben wir die Möglichkeit, durch die Ansteuerung&lt;br /&gt;
der Ausgänge über den Widerständen einen Addierer aufzubauen, mit dessen&lt;br /&gt;
Hilfe wir eine dem Zahlenwert proportionale Spannung erzeugen können. Das&lt;br /&gt;
Schaltbild dazu kann etwa so aussehen:&lt;br /&gt;
&lt;br /&gt;
[[Image:DAC R2R.gif]]&lt;br /&gt;
&lt;br /&gt;
Es sollten selbstverständlich möglichst genaue Widerstände verwendet&lt;br /&gt;
werden, also nicht unbedingt solche mit einer Toleranz von 10% oder mehr.&lt;br /&gt;
Weiterhin empfiehlt es sich, je nach Anwendung den Ausgangsstrom über einen&lt;br /&gt;
Operationsverstärker zu verstärken.&lt;br /&gt;
&lt;br /&gt;
=== PWM (Pulsweitenmodulation) ===&lt;br /&gt;
&lt;br /&gt;
Wir kommen nun zu einem Thema, welches in aller Munde ist, aber viele&lt;br /&gt;
Anwender verstehen nicht ganz, wie &#039;&#039;&#039;[[PWM]]&#039;&#039;&#039; eigentlich funktioniert.&lt;br /&gt;
&lt;br /&gt;
Wie wir alle wissen, ist ein Mikrocontroller ein rein digitales Bauteil.&lt;br /&gt;
Definieren wir einen Pin als Ausgang, dann können wir diesen Ausgang entweder&lt;br /&gt;
auf HIGH setzen, worauf am Ausgang die Versorgungsspannung &#039;&#039;&#039; Vcc&#039;&#039;&#039; anliegt, oder aber wir setzen den Ausgang auf LOW, wonach dann &#039;&#039;&#039; 0V&#039;&#039;&#039; am Ausgang liegt. Was passiert aber nun, wenn wir periodisch mit einer festen Frequenz zwischen HIGH und LOW umschalten? - Richtig, wir erhalten eine Rechteckspannung, wie die folgende Abbildung zeigt:&lt;br /&gt;
&lt;br /&gt;
[[Image:PWM Theorie 1.gif]]&lt;br /&gt;
&lt;br /&gt;
Diese Rechteckspannung hat nun einen arithmetischen Mittelwert, &lt;br /&gt;
der je nach Pulsbreite kleiner oder größer ist.&lt;br /&gt;
&lt;br /&gt;
[[Image:PWM Theorie 2.gif]]&lt;br /&gt;
&lt;br /&gt;
Wenn wir nun diese pulsierende Ausgangsspannung noch über ein RC-Glied filtern/&amp;quot;glätten&amp;quot;, dann haben wir schon eine entsprechende Gleichspannung erzeugt.&lt;br /&gt;
&lt;br /&gt;
Mit den AVRs können wir direkt &#039;&#039;&#039;PWM&#039;&#039;&#039;-Signale erzeugen. &lt;br /&gt;
Dazu dient der 16-Bit Zähler, welcher im sogenannten &#039;&#039;&#039;PWM&#039;&#039;&#039;-Modus betrieben werden kann.&lt;br /&gt;
&lt;br /&gt;
Hinweis:&lt;br /&gt;
:In den folgenden Überlegungen wird als Controller der 90S2313 vorausgesetzt. Die Theorie ist bei anderen AVR-Controllern vergleichbar, die Pinbelegung allerdings nicht unbedingt, weshalb ein Blick ins entsprechende Datenblatt dringend angeraten wird.&lt;br /&gt;
&lt;br /&gt;
Um den &#039;&#039;&#039;PWM&#039;&#039;&#039;-Modus zu aktivieren, müssen im Timer/Counter1 Control&lt;br /&gt;
Register A &#039;&#039;&#039;TCCR1A&#039;&#039;&#039; die Pulsweiten-Modulatorbits &#039;&#039;&#039;PWM10&#039;&#039;&#039; bzw. &#039;&#039;&#039;PWM11&#039;&#039;&#039; entsprechend nachfolgender Tabelle gesetzt werden:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;PWM11&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;PWM10&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Bedeutung&#039;&#039;&#039;&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;
| PWM-Modus des Timers ist nicht aktiv.&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;
| 8-Bit PWM.&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;
| 9-Bit PWM.&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;
| 10-Bit PWM.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Der Timer/Counter zählt nun permanent von 0 bis zur Obergrenze&lt;br /&gt;
und wieder zurück, er wird also als sogenannter Auf-/Ab Zähler betrieben. &lt;br /&gt;
Die Obergrenze hängt davon ab, ob wir mit 8, 9 oder 10-Bit PWM arbeiten wollen:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;Auflösung&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;Obergrenze&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Frequenz&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 8&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 255&lt;br /&gt;
| f&amp;lt;sub&amp;gt;TC1&amp;lt;/sub&amp;gt; / 510&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 9&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 511&lt;br /&gt;
| f&amp;lt;sub&amp;gt;TC1&amp;lt;/sub&amp;gt; / 1022&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 10&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1023&lt;br /&gt;
| f&amp;lt;sub&amp;gt;TC1&amp;lt;/sub&amp;gt; / 2046&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Zusätzlich muss mit den Bits &#039;&#039;&#039;COM1A1&#039;&#039;&#039; und &#039;&#039;&#039;COM1A0&#039;&#039;&#039; desselben&lt;br /&gt;
Registers die gewünschte Ausgabeart des Signals definiert werden:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;COM1A1&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;COM1A0&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Bedeutung&#039;&#039;&#039;&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;
| Keine Wirkung, Pin wird nicht geschaltet.&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;
| Keine Wirkung, Pin wird nicht geschaltet.&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;
| Nicht invertierende PWM.&amp;lt;br /&amp;gt;&lt;br /&gt;
Der Ausgangspin wird gelöscht beim Hochzählen und gesetzt beim&lt;br /&gt;
Herunterzählen.&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;
| Invertierende PWM.&amp;lt;br /&amp;gt;&lt;br /&gt;
Der Ausgangspin wird gelöscht beim Herunterzählen und gesetzt beim&lt;br /&gt;
Hochzählen.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Der entsprechende Befehl, um beispielsweise den Timer/Counter als&lt;br /&gt;
nicht invertierenden 10-Bit PWM zu verwenden, heißt dann:&lt;br /&gt;
&lt;br /&gt;
alte Schreibweise (PWMxx wird nicht mehr akzeptiert)&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
TCCR1A = (1&amp;lt;&amp;lt;PWM11)|(1&amp;lt;&amp;lt;PWM10)|(1&amp;lt;&amp;lt;COM1A1);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
neue Schreibweise&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
TCCR1A = (1&amp;lt;&amp;lt;WGM11)|(1&amp;lt;&amp;lt;WGM10)|(1&amp;lt;&amp;lt;COM1A1);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Damit der Timer/Counter überhaupt läuft, müssen wir im Control&lt;br /&gt;
Register B &#039;&#039;&#039;TCCR1B&#039;&#039;&#039; noch den gewünschten Takt (Vorteiler) einstellen und&lt;br /&gt;
somit auch die Frequenz des &#039;&#039;&#039;PWM&#039;&#039;&#039;-Signals bestimmen.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;CS12&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;CS11&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;CS10&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Bedeutung&#039;&#039;&#039;&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;
| Stop. Der Timer/Counter wird gestoppt.&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;
| CK&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;
| CK / 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;
| CK / 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;
| CK / 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;
| CK / 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;
| Externer Pin 1, negative 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;
| Externer Pin 1, positive Flanke&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Also um einen Takt von CK / 1024 zu generieren, verwenden wir&lt;br /&gt;
folgenden Befehl:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
TCCR1B = (1&amp;lt;&amp;lt;CS12) | (1&amp;lt;&amp;lt;CS10);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jetzt muss nur noch der Vergleichswert festgelegt werden. Diesen&lt;br /&gt;
schreiben wir in das 16-Bit Timer/Counter Output Compare Register &#039;&#039;&#039;OCR1A&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
OCR1A = xxx;&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die folgende Grafik soll den Zusammenhang zwischen dem Vergleichswert und dem generierten &#039;&#039;&#039;PWM&#039;&#039;&#039;-Signal aufzeigen.&lt;br /&gt;
&lt;br /&gt;
[[Image:PWM Theorie 3.gif]]&lt;br /&gt;
&lt;br /&gt;
[[Image:PWM Theorie 4.gif]]&lt;br /&gt;
&lt;br /&gt;
Ach ja, fast hätte ich&#039;s vergessen. Das generierte &#039;&#039;&#039;PWM&#039;&#039;&#039;-Signal&lt;br /&gt;
wird am Output Compare Pin &#039;&#039;&#039;OC1&#039;&#039;&#039; des Timers ausgegeben und leider können wir&lt;br /&gt;
deshalb auch beim AT90S2313 nur ein einzelnes &#039;&#039;&#039;PWM&#039;&#039;&#039;-Signal mit dieser Methode generieren. Andere AVR-Typen verfügen über bis zu vier PWM-Ausgänge. Zu beachten ist außerdem, das wenn der OC Pin aktiviert ist, er nichtmehr wie üblich funktioniert und z.B. nicht einfach über PINx ausgelesen werden kann.&lt;br /&gt;
&lt;br /&gt;
Ein Programm, welches an einem ATMega8 den Fast-PWM Modus verwendet, den Modus 14, könnte so aussehen&lt;br /&gt;
&amp;lt;C&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
int main()&lt;br /&gt;
{&lt;br /&gt;
  // OC1A auf Ausgang&lt;br /&gt;
  DDRB = (1 &amp;lt;&amp;lt; PB1 );&lt;br /&gt;
&lt;br /&gt;
  //&lt;br /&gt;
  // Timer 1 einstellen&lt;br /&gt;
  //  &lt;br /&gt;
  // Modus 14:&lt;br /&gt;
  //    Fast PWM, Top von ICR1&lt;br /&gt;
  //&lt;br /&gt;
  //     WGM13    WGM12   WGM11    WGM10&lt;br /&gt;
  //      1        1       1        0&lt;br /&gt;
  //&lt;br /&gt;
  //    Timer Vorteiler: 1&lt;br /&gt;
  //     CS12     CS11    CS10&lt;br /&gt;
  //       0        0       1&lt;br /&gt;
  //&lt;br /&gt;
  //  Steuerung des Ausgangsport: Set at BOTTOM, Clear at match&lt;br /&gt;
  //     COM1A1   COM1A0&lt;br /&gt;
  //       1        0&lt;br /&gt;
 &lt;br /&gt;
  TCCR1A = (1&amp;lt;&amp;lt;COM1A1) | (1&amp;lt;&amp;lt;WGM11);&lt;br /&gt;
  TCCR1B = (1&amp;lt;&amp;lt;WGM13) | (1&amp;lt;&amp;lt;WGM12) | (1&amp;lt;&amp;lt;CS10);&lt;br /&gt;
 &lt;br /&gt;
  //&lt;br /&gt;
  //  den Endwert (TOP) für den Zähler setzen&lt;br /&gt;
  //  der Zähler zählt bis zu diesem Wert&lt;br /&gt;
&lt;br /&gt;
  ICR1 = 0x6FFF;&lt;br /&gt;
 &lt;br /&gt;
  //&lt;br /&gt;
  // der Compare Wert&lt;br /&gt;
  // Wenn der Zähler diesen Wert erreicht, wird mit&lt;br /&gt;
  // obiger Konfiguration der OC1A Ausgang abgeschaltet&lt;br /&gt;
  // Sobald der Zähler wieder bei 0 startet, wird der&lt;br /&gt;
  // Ausgang wieder auf 1 gesetzt&lt;br /&gt;
  //&lt;br /&gt;
  // Durch Verändern dieses Wertes, werden die unterschiedlichen&lt;br /&gt;
  // PWM Werte eingestellt.&lt;br /&gt;
&lt;br /&gt;
  OCR1A = 0x3FFF;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  while( 1 )&lt;br /&gt;
    ;  &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/C&amp;gt;&lt;br /&gt;
&lt;br /&gt;
PWM Mode Tabelle aus dem Datenblatt des Atmega 8515:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;Mode&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;WGM13&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;WGM12&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;WGM11&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;WGM10&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;Timer/Counter Mode of Operation&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;TOP&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;Update of OCR1x at&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;TOV1 Flag set on&#039;&#039;&#039;&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;
| 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; | Normal&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0xFFFF&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | Immediate&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | MAX&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;
| 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; | PWM, Phase Correct, 8-Bit&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0x00FF&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | TOP&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | BOTTOM&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 2&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;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | PWM, Phase Correct, 9-Bit&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0x01FF&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | TOP&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | BOTTOM&lt;br /&gt;
|-&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3&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;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | PWM, Phase Correct, 10-Bit&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0x03FF&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | TOP&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | BOTTOM&lt;br /&gt;
|-&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 4&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;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | CTC&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | OCR1A&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | Immediate&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | MAX&lt;br /&gt;
|-&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 5&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;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | Fast PWM, 8-Bit&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0x00FF&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | BOTTOM&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | TOP&lt;br /&gt;
|-&lt;br /&gt;
&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 6&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;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | Fast PWM, 9-Bit&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0x01FF&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | BOTTOM&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | TOP&lt;br /&gt;
|-&lt;br /&gt;
&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 7&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;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | Fast PWM, 10-Bit&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0x03FF&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | BOTTOM&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | TOP&lt;br /&gt;
|-&lt;br /&gt;
&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 8&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;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | PWM, Phase an Frequency Correct&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | ICR1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | BOTTOM&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | BOTTOM&lt;br /&gt;
|-    &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 9&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;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | PWM, Phase an Frequency Correct&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | OCR1A&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | BOTTOM&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | BOTTOM&lt;br /&gt;
|-&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 10&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;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | PWM, Phase Correct&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | ICR1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | TOP&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | BOTTOM&lt;br /&gt;
|-&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 11&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;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | PWM, Phase an Frequency Correct&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | OCR1A&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | TOP&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | BOTTOM&lt;br /&gt;
|-&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 12&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;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | CTC&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | ICR1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | Immediate&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | MAX&lt;br /&gt;
|-&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 13&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;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | Reserved&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | -&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | -&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | -&lt;br /&gt;
|-&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 14&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;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | Fast PWM&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | ICR1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | BOTTOM&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | TOP&lt;br /&gt;
|-&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 15&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;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | Fast PWM&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | OCR1A&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | BOTTOM&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | TOP&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Für Details der PWM Möglichkeiten, muß immer das jeweilge Datenblatt des Prozessors konsultiert werden, da sich die unterschiedlichen Prozessoren in ihren Möglichkeiten doch stark unterscheiden. Auch muß man aufpassen, welches zu setzende Bit in welchem Register sind. Auch hier kann es sein, dass gleichnamige Konfigurationsbits in unterschiedlichen Konfigurationsregistern (je nach konkretem Prozessortyp) sitzen.&lt;br /&gt;
&lt;br /&gt;
= LCD-Ansteuerung =&lt;br /&gt;
&lt;br /&gt;
==Das LCD und sein Controller==&lt;br /&gt;
&lt;br /&gt;
Die meisten Text-LCDs verwenden den Controller [[HD44780|&#039;&#039;&#039;HD44780&#039;&#039;&#039;]] oder einen kompatiblen (z.B. KS0070) und haben 14 oder 16 Pins. Die Pinbelegung an der LCD-Controller-Platine ist praktisch immer gleich: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;table width=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;th width=&amp;quot;50&amp;quot; align=&amp;quot;left&amp;quot;&amp;gt;Pin #&amp;lt;/th&amp;gt;&amp;lt;th  width=&amp;quot;70&amp;quot; align=&amp;quot;left&amp;quot;&amp;gt;Bezeichnung&amp;lt;/th&amp;gt;&amp;lt;th align=&amp;quot;left&amp;quot;&amp;gt;Funktion&amp;lt;/th&amp;gt;&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;1&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Vss&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;GND&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;2&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Vcc&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;5V&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;3&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Vee&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Kontrastspannung (0V bis 5V)&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;4&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;RS&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Register Select (Befehle/Daten)&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;5&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;RW&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Read/Write&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;6&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;E&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Enable&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;7&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;DB0&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Datenbit 0&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;8&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;DB1&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Datenbit 1&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;9&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;DB2&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Datenbit 2&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;10&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;DB3&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Datenbit 3&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;11&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;DB4&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Datenbit 4&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;12&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;DB5&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Datenbit 5&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;13&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;DB6&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Datenbit 6&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;14&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;DB7&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Datenbit 7&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;15&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;A&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;LED-Beleuchtung, Anode&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;16&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;K&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;LED-Beleuchtung, Kathode&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Achtung: Unbedingt von der richtigen Seite zu zählen anfangen! Meistens ist neben Pin 1 eine kleine 1 auf der LCD-Platine, ansonsten im Datenblatt nachschauen. &lt;br /&gt;
&lt;br /&gt;
Bei LCDs mit 16-poligem Anschluss sind die beiden letzten Pins für die Hintergrundbeleuchtung reserviert. Hier unbedingt das Datenblatt zu Rate ziehen, die beiden Anschlüsse sind je nach Hersteller verdreht beschaltet. Falls kein Datenblatt vorliegt, kann man mit einem Durchgangsprüfer feststellen, welcher Anschluss mit Masse (GND) verbunden ist.&lt;br /&gt;
&lt;br /&gt;
Vss wird ganz einfach an GND angeschlossen und Vcc an 5V. Vee kann man testweise auch an GND legen. Wenn das LCD dann zu dunkel sein sollte muss man ein 10k-Potentiometer zwischen GND und 5V schalten, mit dem Schleifer an Vee: &lt;br /&gt;
&lt;br /&gt;
[[Bild:LCD_Vee.gif]]&lt;br /&gt;
&lt;br /&gt;
Es gibt zwei verschiedene Möglichkeiten zur Ansteuerung eines solchen Displays: den &#039;&#039;&#039;8-bit-&#039;&#039;&#039; und den &#039;&#039;&#039;4-bit-&#039;&#039;&#039;Modus.&lt;br /&gt;
* Für den &#039;&#039;&#039;8-bit-Modus&#039;&#039;&#039; werden (wie der Name schon sagt) alle acht Datenleitungen zur Ansteuerung verwendet, somit kann durch einen Zugriff immer ein ganzes Byte übertragen werden.&lt;br /&gt;
* Der &#039;&#039;&#039;4-bit-Modus&#039;&#039;&#039; verwendet nur die oberen vier Datenleitungen (&#039;&#039;&#039;DB4-DB7&#039;&#039;&#039;). Um ein Byte zu übertragen braucht man somit zwei Zugriffe, wobei zuerst das höherwertige &#039;&#039;&#039;&amp;quot;Nibble&amp;quot;&#039;&#039;&#039; (= 4 Bits), also Bit 4 bis Bit 7 übertragen wird und dann das niederwertige, also Bit 0 bis Bit 3. Die unteren Datenleitungen des LCDs, die beim Lesezyklus Ausgänge sind, lässt man offen (siehe Datasheets, z.B. vom KS0070).&lt;br /&gt;
&lt;br /&gt;
Der 4-bit-Modus hat den Vorteil, dass man 4 IO-Pins weniger benötigt als beim 8-bit-Modus, weshalb ich mich hier für eine Ansteuerung mit 4bit entschieden habe. &lt;br /&gt;
&lt;br /&gt;
Neben den vier Datenleitungen (DB4, DB5, DB6 und DB7) werden noch die Anschlüsse &#039;&#039;&#039;RS&#039;&#039;&#039;, &#039;&#039;&#039;RW&#039;&#039;&#039; und &#039;&#039;&#039;E&#039;&#039;&#039; (ist in manchen Unterlagen auch &#039;&#039;&#039;EN&#039;&#039;&#039;  für &#039;&#039;Enable&#039;&#039; abgekürzt) benötigt. &lt;br /&gt;
&lt;br /&gt;
* Über &#039;&#039;&#039;RS&#039;&#039;&#039; wird ausgewählt, ob man einen Befehl oder ein Datenbyte an das LCD schicken möchte. Ist RS Low, dann wird das ankommende Byte als Befehl interpretiert, ist RS high, dann wird das Byte auf dem LCD angezeigt. &lt;br /&gt;
* &#039;&#039;&#039;RW&#039;&#039;&#039; legt fest, ob geschrieben oder gelesen werden soll. High bedeutet lesen, low bedeutet schreiben. Wenn man RW auf lesen einstellt und RS auf Befehl, dann kann man das &#039;&#039;&#039;Busy-Flag&#039;&#039;&#039; an DB7 lesen, das anzeigt, ob das LCD den vorhergehenden Befehl fertig verarbeitetet hat (diese Methode u.a. in der LCD-Library von Peter Fleury verwendet). Ist RS auf Daten eingestellt, dann kann man z.B. den Inhalt des Displays lesen - was jedoch nur in den wenigsten Fällen Sinn macht. Deshalb kann man RW dauerhaft auf low lassen (= an GND anschließen), so dass man noch ein IO-Pin am Controller einspart. Der Nachteil ist, dass man dann das Busy-Flag nicht lesen kann, weswegen man nach jedem Befehl vorsichtshalber ein paar Mikrosekunden warten sollte, um dem LCD Zeit zum Ausführen des Befehls zu geben. Dummerweise schwankt die Ausführungszeit von Display zu Display und ist auch von der Betriebsspannung abhängig. Für professionellere Sachen also lieber den IO-Pin opfern und Busy abfragen.&lt;br /&gt;
* Der &#039;&#039;&#039;E&#039;&#039;&#039; Anschluss schließlich signalisiert dem LCD, dass die übrigen Datenleitungen jetzt korrekte Pegel angenommen haben und es die gewünschten Daten von den Datenleitungen bzw. Kommandos von den Datenleitungen übernehmen kann.&lt;br /&gt;
&lt;br /&gt;
== Anschluss an den Controller ==&lt;br /&gt;
&lt;br /&gt;
Jetzt da wir wissen, welche Anschlüsse das LCDs benötigt, können wir das LCD mit dem Mikrocontroller verbinden: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;table width=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;th align=&amp;quot;left&amp;quot;&amp;gt;Pin #-LCD&amp;lt;/th&amp;gt;&amp;lt;th align=&amp;quot;left&amp;quot;&amp;gt;Bezeichnung-LCD&amp;lt;/th&amp;gt;&amp;lt;th align=&amp;quot;left&amp;quot;&amp;gt;Pin-µC&amp;lt;/th&amp;gt;&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;1&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Vss&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;GND&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;2&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Vcc&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;5V&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;3&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Vee&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;GND oder Poti (siehe oben)&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;4&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;RS&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;PD4 am AVR&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;5&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;RW&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;GND&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;6&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;E&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;PD5 am AVR&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;7&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;DB0&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;offen&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;8&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;DB1&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;offen&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;9&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;DB2&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;offen&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;10&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;DB3&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;offen&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;11&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;DB4&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;PD0 am AVR&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;12&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;DB5&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;PD1 am AVR&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;13&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;DB6&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;PD2 am AVR&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&#039;&#039;&#039;14&#039;&#039;&#039;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;DB7&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;PD3 am AVR&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; &lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn man die Steuerleitungen EN und RS auf Pins an einem anderen Port legen möchte, kann man so wie in diesem [http://www.mikrocontroller.net/topic/88543#751982 Forumsbeitrag] vorgehen.&lt;br /&gt;
&lt;br /&gt;
Ok, alles ist verbunden, wenn man jetzt den Strom einschaltet sollten ein oder zwei schwarze Balken auf dem Display angezeigt werden. Doch wie bekommt man jetzt die Befehle und Daten in das Display? &lt;br /&gt;
&lt;br /&gt;
== Programmierung ==&lt;br /&gt;
Datei &#039;&#039;&#039;lcd-routines.h&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
// Ansteuerung eines HD44780 kompatiblen LCD im 4-Bit-Interfacemodus&lt;br /&gt;
// http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial&lt;br /&gt;
//&lt;br /&gt;
void lcd_data(unsigned char temp1);&lt;br /&gt;
void lcd_string(char *data);&lt;br /&gt;
void lcd_command(unsigned char temp1);&lt;br /&gt;
void lcd_enable(void);&lt;br /&gt;
void lcd_init(void);&lt;br /&gt;
void lcd_home(void);&lt;br /&gt;
void lcd_clear(void);&lt;br /&gt;
void set_cursor(uint8_t x, uint8_t y);&lt;br /&gt;
&lt;br /&gt;
// Hier die verwendete Taktfrequenz in Hz eintragen, wichtig!&lt;br /&gt;
&lt;br /&gt;
#define F_CPU 8000000&lt;br /&gt;
&lt;br /&gt;
// LCD Befehle&lt;br /&gt;
&lt;br /&gt;
#define CLEAR_DISPLAY 0x01&lt;br /&gt;
#define CURSOR_HOME   0x02&lt;br /&gt;
&lt;br /&gt;
// Pinbelegung für das LCD, an verwendete Pins anpassen&lt;br /&gt;
&lt;br /&gt;
#define LCD_PORT      PORTD&lt;br /&gt;
#define LCD_DDR       DDRD&lt;br /&gt;
#define LCD_RS        PD4&lt;br /&gt;
#define LCD_EN        PD5&lt;br /&gt;
// DB4 bis DB7 des LCD sind mit PD0 bis PD3 des AVR verbunden&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Datei &#039;&#039;&#039;lcd-routines.c&#039;&#039;&#039;:&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
// Ansteuerung eines HD44780 kompatiblen LCD im 4-Bit-Interfacemodus&lt;br /&gt;
// http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial&lt;br /&gt;
//&lt;br /&gt;
// Die Pinbelegung ist über defines in lcd-routines.h einstellbar&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;quot;lcd-routines.h&amp;quot;&lt;br /&gt;
#include &amp;lt;util/delay.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
// sendet ein Datenbyte an das LCD&lt;br /&gt;
&lt;br /&gt;
void lcd_data(unsigned char temp1)&lt;br /&gt;
{&lt;br /&gt;
   unsigned char temp2 = temp1;&lt;br /&gt;
 &lt;br /&gt;
   LCD_PORT |= (1&amp;lt;&amp;lt;LCD_RS);        // RS auf 1 setzen&lt;br /&gt;
&lt;br /&gt;
   temp1 = temp1 &amp;gt;&amp;gt; 4;&lt;br /&gt;
   temp1 = temp1 &amp;amp; 0x0F;&lt;br /&gt;
   LCD_PORT &amp;amp;= 0xF0;&lt;br /&gt;
   LCD_PORT |= temp1;               // setzen&lt;br /&gt;
   lcd_enable();&lt;br /&gt;
 &lt;br /&gt;
   temp2 = temp2 &amp;amp; 0x0F;&lt;br /&gt;
   LCD_PORT &amp;amp;= 0xF0;&lt;br /&gt;
   LCD_PORT |= temp2;               // setzen&lt;br /&gt;
   lcd_enable();&lt;br /&gt;
   &lt;br /&gt;
   _delay_us(42);&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
// sendet einen Befehl an das LCD&lt;br /&gt;
&lt;br /&gt;
void lcd_command(unsigned char temp1)&lt;br /&gt;
{&lt;br /&gt;
   unsigned char temp2 = temp1;&lt;br /&gt;
 &lt;br /&gt;
   LCD_PORT &amp;amp;= ~(1&amp;lt;&amp;lt;LCD_RS);        // RS auf 0 setzen&lt;br /&gt;
&lt;br /&gt;
   temp1 = temp1 &amp;gt;&amp;gt; 4;              // oberes Nibble holen&lt;br /&gt;
   temp1 = temp1 &amp;amp; 0x0F;            // maskieren&lt;br /&gt;
   LCD_PORT &amp;amp;= 0xF0;&lt;br /&gt;
   LCD_PORT |= temp1;               // setzen&lt;br /&gt;
   lcd_enable();&lt;br /&gt;
 &lt;br /&gt;
   temp2 = temp2 &amp;amp; 0x0F;            // unteres Nibble holen und maskieren&lt;br /&gt;
   LCD_PORT &amp;amp;= 0xF0;&lt;br /&gt;
   LCD_PORT |= temp2;               // setzen&lt;br /&gt;
   lcd_enable();&lt;br /&gt;
   &lt;br /&gt;
   _delay_us(42);&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
// erzeugt den Enable-Puls&lt;br /&gt;
void lcd_enable(void)&lt;br /&gt;
{&lt;br /&gt;
   // Bei Problemen ggf. Pause gemäß Datenblatt des LCD Controllers einfügen&lt;br /&gt;
   // http://www.mikrocontroller.net/topic/81974#685882&lt;br /&gt;
   LCD_PORT |= (1&amp;lt;&amp;lt;LCD_EN);&lt;br /&gt;
    _delay_us(1);                   // kurze Pause&lt;br /&gt;
   // Bei Problemen ggf. Pause gemäß Datenblatt des LCD Controllers verlängern&lt;br /&gt;
   // http://www.mikrocontroller.net/topic/80900&lt;br /&gt;
   LCD_PORT &amp;amp;= ~(1&amp;lt;&amp;lt;LCD_EN);&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
// Initialisierung: &lt;br /&gt;
// Muss ganz am Anfang des Programms aufgerufen werden.&lt;br /&gt;
&lt;br /&gt;
void lcd_init(void)&lt;br /&gt;
{&lt;br /&gt;
   LCD_DDR = LCD_DDR | 0x0F | (1&amp;lt;&amp;lt;LCD_RS) | (1&amp;lt;&amp;lt;LCD_EN);   // Port auf Ausgang schalten&lt;br /&gt;
&lt;br /&gt;
   // muss 3mal hintereinander gesendet werden zur Initialisierung&lt;br /&gt;
&lt;br /&gt;
   _delay_ms(15);&lt;br /&gt;
   LCD_PORT &amp;amp;= 0xF0;&lt;br /&gt;
   LCD_PORT |= 0x03;            &lt;br /&gt;
   LCD_PORT &amp;amp;= ~(1&amp;lt;&amp;lt;LCD_RS);      // RS auf 0&lt;br /&gt;
   lcd_enable();&lt;br /&gt;
&lt;br /&gt;
   _delay_ms(5);&lt;br /&gt;
   lcd_enable();&lt;br /&gt;
&lt;br /&gt;
   _delay_ms(1);&lt;br /&gt;
   lcd_enable();&lt;br /&gt;
   _delay_ms(1);&lt;br /&gt;
&lt;br /&gt;
   // 4 Bit Modus aktivieren &lt;br /&gt;
   LCD_PORT &amp;amp;= 0xF0;&lt;br /&gt;
   LCD_PORT |= 0x02;&lt;br /&gt;
   lcd_enable();&lt;br /&gt;
   _delay_ms(1);&lt;br /&gt;
&lt;br /&gt;
   // 4Bit / 2 Zeilen / 5x7&lt;br /&gt;
   lcd_command(0x28);&lt;br /&gt;
    &lt;br /&gt;
   // Display ein / Cursor aus / kein Blinken&lt;br /&gt;
   lcd_command(0x0C); &lt;br /&gt;
 &lt;br /&gt;
   // inkrement / kein Scrollen&lt;br /&gt;
   lcd_command(0x06);&lt;br /&gt;
&lt;br /&gt;
   lcd_clear();&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
// Sendet den Befehl zur Löschung des Displays&lt;br /&gt;
&lt;br /&gt;
void lcd_clear(void)&lt;br /&gt;
{&lt;br /&gt;
   lcd_command(CLEAR_DISPLAY);&lt;br /&gt;
   _delay_ms(5);&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
// Sendet den Befehl: Cursor Home&lt;br /&gt;
&lt;br /&gt;
void lcd_home(void)&lt;br /&gt;
{&lt;br /&gt;
   lcd_command(CURSOR_HOME);&lt;br /&gt;
   _delay_ms(5);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// setzt den Cursor in Zeile y (1..4) Spalte x (0..15)&lt;br /&gt;
&lt;br /&gt;
void set_cursor(uint8_t x, uint8_t y)&lt;br /&gt;
{&lt;br /&gt;
  uint8_t tmp;&lt;br /&gt;
&lt;br /&gt;
  switch (y) {&lt;br /&gt;
    case 1: tmp=0x80+0x00+x; break;    // 1. Zeile&lt;br /&gt;
    case 2: tmp=0x80+0x40+x; break;    // 2. Zeile&lt;br /&gt;
    case 3: tmp=0x80+0x10+x; break;    // 3. Zeile&lt;br /&gt;
    case 4: tmp=0x80+0x50+x; break;    // 4. Zeile&lt;br /&gt;
    default: return;                   // für den Fall einer falschen Zeile&lt;br /&gt;
  }&lt;br /&gt;
  lcd_command(tmp);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Schreibt einen String auf das LCD&lt;br /&gt;
&lt;br /&gt;
void lcd_string(char *data)&lt;br /&gt;
{&lt;br /&gt;
    while(*data) {&lt;br /&gt;
        lcd_data(*data);&lt;br /&gt;
        data++;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein Hauptprogramm, welches die Funktionen benutzt, sieht zb. so aus:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
// &lt;br /&gt;
// Anpassungen im makefile:&lt;br /&gt;
//    ATMega8 =&amp;gt; MCU=atmega8 im makefile einstellen&lt;br /&gt;
//    lcd-routines.c in SRC = ... Zeile anhängen&lt;br /&gt;
// &lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;quot;lcd-routines.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
int main(void)&lt;br /&gt;
{&lt;br /&gt;
    lcd_init();&lt;br /&gt;
&lt;br /&gt;
    lcd_data(&#039;T&#039;);&lt;br /&gt;
    lcd_data(&#039;e&#039;);&lt;br /&gt;
    lcd_data(&#039;s&#039;);&lt;br /&gt;
    lcd_data(&#039;t&#039;);&lt;br /&gt;
&lt;br /&gt;
    set_cursor(0,2);&lt;br /&gt;
&lt;br /&gt;
    lcd_string(&amp;quot;Hello World!&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    while(1)&lt;br /&gt;
    {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wichtig ist dabei, dass die Optimierung bei der Compilierung eingeschaltet ist, sonst stimmen die Zeiten der Funktionen _delay_us() und _delay_ms() nicht und der Code wird wesentlich länger (Siehe Dokumentation der libc im WinAVR).&lt;br /&gt;
&lt;br /&gt;
Ein Hauptprogramm, welches eine Variable ausgibt, sieht zb. so aus.&lt;br /&gt;
Mittels der itoa() Funktion (itoa = &amp;lt;b&amp;gt;I&amp;lt;/b&amp;gt;nteger &amp;lt;b&amp;gt;To&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;A&amp;lt;/b&amp;gt;scii ) wird von einem Zahlenwert eine textuelle Repräsentierung ermittelt (sprich: ein String erzeugt) und dieser String mit der bereits vorhandenen Funktion lcd_string ausgegeben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
// &lt;br /&gt;
// Anpassungen im makefile:&lt;br /&gt;
//    ATMega8 =&amp;gt; MCU=atmega8 im makefile einstellen&lt;br /&gt;
//    lcd-routines.c in SRC = ... Zeile anhängen &lt;br /&gt;
// &lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
#include &amp;quot;lcd-routines.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
// Beispiel&lt;br /&gt;
int variable = 42;&lt;br /&gt;
&lt;br /&gt;
int main(void)&lt;br /&gt;
{&lt;br /&gt;
    lcd_init();&lt;br /&gt;
&lt;br /&gt;
    // Ausgabe des Zeichens dessen ASCII-Code gleich dem Variablenwert ist&lt;br /&gt;
    // (Im Beispiel entspricht der ASCII-Code 42 dem Zeichen *)&lt;br /&gt;
    // http://www.code-knacker.de/ascii.htm&lt;br /&gt;
    lcd_data(variable);&lt;br /&gt;
&lt;br /&gt;
    set_cursor(0,2);&lt;br /&gt;
 &lt;br /&gt;
    // Ausgabe der Variable als Text in dezimaler Schreibweise&lt;br /&gt;
    {&lt;br /&gt;
       // ... umwandeln siehe FAQ Artikel bei www.mikrocontroller.net&lt;br /&gt;
       // WinAVR hat eine itoa()-Funktion, das erfordert obiges #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
       char Buffer[20]; // in diesem {} lokal&lt;br /&gt;
       itoa( variable, Buffer, 10 ); &lt;br /&gt;
&lt;br /&gt;
       // ... ausgeben  &lt;br /&gt;
       lcd_string( Buffer );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    while(1)&lt;br /&gt;
    {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Beim Einrichten eines Projekts muss man zu der Datei mit dem Hauptprogramm auch die Datei lcd-routines.c in das Projekt aufnehmen. Dies geschieht beim AVR Studio unter Source Files im Fenster AVR GCC oder bei WinAVR im Makefile (z.B. durch SRC += lcd-routines.c).&lt;br /&gt;
&lt;br /&gt;
= Die Timer/Counter des AVR =&lt;br /&gt;
&lt;br /&gt;
Die heutigen Mikrocontroller und insbesondere die RISC-AVRs sind für viele Steuerungsaufgaben zu schnell. Wenn wir beispielsweise eine LED oder Lampe blinken lassen wollen, können wir selbstverständlich nicht die CPU-Frequenz verwenden, da ja dann nichts mehr vom Blinken zu bemerken wäre.&lt;br /&gt;
&lt;br /&gt;
Wir brauchen also eine Möglichkeit, Vorgänge in Zeitabständen durchzuführen, die geringer als die Taktfrequenz des Controllers sind. Selbstverständlich sollte die resultierende Frequenz auch noch möglichst genau und stabil sein.&lt;br /&gt;
&lt;br /&gt;
Hier kommen die im AVR vorhandenen Timer/Counter zum Einsatz.&lt;br /&gt;
&lt;br /&gt;
Ein Timer ist ganz einfach ein bestimmtes Register im µC, das völlig ohne Zutun des Programms, also per Hardware, hochgezählt wird. Das alleine wäre noch nicht allzu nützlich, wenn nicht dieses Hardwareregister bei bestimmten Zählerständen einen Interrupt auslösen könnte. Ein solches Ereignis ist der Overflow: Da die Bitbreite des Registers beschränkt ist, kommt es natürlich auch vor, dass der Zähler so hoch zählt, dass der nächste Zählerstand mit dieser Bitbreite nicht mehr darstellbar ist und der Zähler wieder auf 0 zurückgesetzt wird. Dieses Ereignis nennt man den Overflow und es ist möglich an dieses Ereignis einen Interrupt zu koppeln.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- Alternativvorschlag mthomas &lt;br /&gt;
Jeder Timer verfügt über ein Zählerregister im Mikrocontroller, das automatisch und ohne Zutun des Programms von der Hardware weitergezählt wird. In einem einfachen Anwendungsfall stellt man den Timer auf eine Zählgeschwindigkeit (Frequenz) und kann dann anhand des Zählerstands ermitteln, wie viel Zeit vergangen ist. Das eigentlich Nützliche an Timern ist jedoch, dass man  bestimmte Zählerstände mit Interrupts verknüpfen kann, so dass der Controller beim Auftreten automatisch eine vom Anwender geschriebene Routine aufruft. Eines dieser möglichen Ereignis ist der Overflow ((Zähler-)Überlauf), der dann auftritt, wenn der Wert des Zählerregisters (Timer/Counter-Register) den maximal möglichen Wert überschreitet. Der Maximalwert wird durch die Bitbreite des Zählerregisters bestimmt (z.B. 255 bei 8-Bit Timern). Beim Überlauf/Overflow wird der Zähler durch die Hardware auf 0 zurückgesetzt und die Zählung beginnt von neuem. Wurde vorher der Overflow-Interrupt für den Timer aktiviert (im Timer Control Register) unterbricht der Controller automatisch die Ausführung des Hauptprogramms und verzweigt in die Interrupt-Routine des Anwenders.&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein anderes Anwendungsgebiet ist die Zählung von Signalen, welche über einen I/O-Pin zugeführt werden können.&lt;br /&gt;
&lt;br /&gt;
Die folgenden Ausführungen beziehen sich auf den AT90S2313. Für andere Modelltypen müsst ihr euch die allenfalls notwendigen Anpassungen aus den Datenblättern der entsprechenden Controller herauslesen.&lt;br /&gt;
&lt;br /&gt;
Wir unterscheiden grundsätzlich zwischen 8-Bit Timern, welche eine Auflösung von 256 aufweisen und 16-Bit Timern mit (logischerweise) einer Auflösung von 65536. Als Eingangstakt für die Timer/Counter kann entweder die CPU-Taktfrequenz, der Vorteiler-Ausgang oder ein an einen I/O-Pin angelegtes Signal verwendet werden. Wenn ein externes Signal verwendet wird, so darf dessen Frequenz nicht höher sein als die Hälfte des CPU-Taktes.&lt;br /&gt;
&lt;br /&gt;
== Der Vorteiler (Prescaler) ==&lt;br /&gt;
&lt;br /&gt;
Der Vorteiler dient dazu, den CPU-Takt vorerst um einen einstellbaren Faktor zu reduzieren. Die so geteilte Frequenz wird den Eingängen der Timer zugeführt.&lt;br /&gt;
&lt;br /&gt;
Wenn wir mit einem CPU-Takt von 4 MHz arbeiten und den Vorteiler auf 1024 einstellen, wird also der Timer mit einer Frequenz von 4 MHz / 1024, also mit ca. 4 kHz versorgt. Wenn also der Timer läuft, so wird das Daten- bzw. Zählregister (TCNTx) mit dieser Frequenz inkrementiert.&lt;br /&gt;
&lt;br /&gt;
== 8-Bit Timer/Counter ==&lt;br /&gt;
&lt;br /&gt;
Alle AVR-Modelle verfügen über mindestens einen, teilweise sogar zwei, 8-Bit Timer.&lt;br /&gt;
&lt;br /&gt;
Der 8-Bit Timer wird z.B bei AT90S2313 über folgende Register angesprochen (bei anderen Typen weitestgehend analog):&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;TCCR0&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;T&#039;&#039;&#039;imer/&#039;&#039;&#039;C&#039;&#039;&#039;ounter &#039;&#039;&#039;C&#039;&#039;&#039;ontrol &#039;&#039;&#039;R&#039;&#039;&#039;egister&lt;br /&gt;
Timer &#039;&#039;&#039;0&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
In diesem Register stellen wir ein, wie wir den Timer/Counter verwenden möchten.&lt;br /&gt;
&lt;br /&gt;
Das Register ist wie folgt aufgebaut:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Bit&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 7&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 6&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 5&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 4&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 2&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Name&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;CS02&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;CS01&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;CS00&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;R/W&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Initialwert&#039;&#039;&#039;&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;
| 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;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;CS02, CS01, CS00&#039;&#039;&#039; (&#039;&#039;&#039;C&#039;&#039;&#039;lock &#039;&#039;&#039;S&#039;&#039;&#039;elect Bits)&lt;br /&gt;
:Diese 3 Bits bestimmen die Quelle für den Timer/Counter:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | CS02&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | CS01&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | CS00&lt;br /&gt;
| Resultat&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;
| Stopp, Der Timer/Counter wird 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;
| CPU-Takt&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;
| CPU-Takt / 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;
| CPU-Takt / 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;
| CPU-Takt / 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;
| CPU-Takt / 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;
| Externer Pin &#039;&#039;&#039;TO&#039;&#039;&#039;, 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;
| Externer Pin &#039;&#039;&#039;TO&#039;&#039;&#039;, steigende Flanke&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/dd&amp;gt;&lt;br /&gt;
&amp;lt;/dl&amp;gt;&lt;br /&gt;
:Wenn als Quelle der externe Pin &#039;&#039;&#039;TO&#039;&#039;&#039; verwendet wird, so wird ein Flankenwechsel auch erkannt, wenn der Pin &#039;&#039;&#039;TO&#039;&#039;&#039; als Ausgang geschaltet ist.&lt;br /&gt;
&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;TCNT0&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;T&#039;&#039;&#039;imer/&#039;&#039;&#039;C&#039;&#039;&#039;ou&#039;&#039;&#039;nt&#039;&#039;&#039;er Daten Register Timer &#039;&#039;&#039;0&#039;&#039;&#039;&amp;lt;br /&amp;gt;&lt;br /&gt;
Dieses ist als 8-Bit Aufwärtszähler mit Schreib- und Lesezugriff&lt;br /&gt;
realisiert. Wenn der Zähler den Wert 255 erreicht hat beginnt er beim&lt;br /&gt;
nächsten Zyklus wieder bei 0.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Bit&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 7&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 6&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 5&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 4&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 2&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Name&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;MSB&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;LSB&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;R/W&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Initialwert&#039;&#039;&#039;&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;
| 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;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Um nun also den Timer0 in Betrieb zu setzen und ihn mit einer Frequenz von 1/1024-tel des CPU-Taktes zählen zu lassen, schreiben wir die folgende Befehlszeile:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
    TCCR0 |= (1&amp;lt;&amp;lt;CS00)|(1&amp;lt;&amp;lt;CS02);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Zähler zählt nun aufwärts bis 255, um dann wieder bei 0 zu beginnen. Der aktuelle Zählerstand steht in TCNT0. Bei jedem Überlauf von 255 auf 0 wird das Timer Overflow Flag &#039;&#039;&#039;TOV0&#039;&#039;&#039; im Timer Interrupt Flag &#039;&#039;&#039;TIFR&#039;&#039;&#039;-Register gesetzt und, falls so konfiguriert, ein entsprechender Timer-Overflow-Interrupt ausgelöst und die daran gebundene Interrupt-Routine abgearbeitet. Das TOV Flag &lt;br /&gt;
lässt sich durch das Hineinschreiben einer 1 und nicht wie erwartet einer 0 wieder zurücksetzen.&lt;br /&gt;
&lt;br /&gt;
== 16-Bit Timer/Counter ==&lt;br /&gt;
&lt;br /&gt;
Viele AVR-Modelle besitzen außer den 8-Bit Timern auch 16-Bit Timer. Die 16-Bit Timer/Counter sind etwas komplexer aufgebaut als die 8-Bit Timer/Counter, bieten dafür aber auch viel mehr Möglichkeiten, als da sind:&lt;br /&gt;
&lt;br /&gt;
* Die [[PWM]]-Betriebsart Erzeugung eines pulsweitenmodulierten Ausgangssignals. &lt;br /&gt;
* Vergleichswert-Überprüfung mit Erzeugung eines Ausgangssignals (Output Compare Match).&lt;br /&gt;
* Einfangen eines Eingangssignals mit Speicherung des aktuellen Zählerwertes (Input Capturing), mit zuschaltbarer Rauschunterdrückung (Noise Filtering).&lt;br /&gt;
&lt;br /&gt;
Folgende Register sind dem Timer/Counter 1 zugeordnet:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;TCCR1A&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;T&#039;&#039;&#039;imer/&#039;&#039;&#039;C&#039;&#039;&#039;ounter &#039;&#039;&#039;C&#039;&#039;&#039;ontrol &#039;&#039;&#039;R&#039;&#039;&#039;egister &#039;&#039;&#039;A&#039;&#039;&#039; Timer &#039;&#039;&#039;1&#039;&#039;&#039;&amp;lt;br /&amp;gt;&lt;br /&gt;
In diesem und dem folgenden Register stellen wir ein, wie wir den Timer/Counter verwenden möchten.&amp;lt;br /&amp;gt;&lt;br /&gt;
Das Register ist wie folgt aufgebaut:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Bit&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 7&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 6&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 5&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 4&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 2&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Name&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;COM1A1&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;COM1A0&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;PWM11&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;PWM10&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;R/W&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Initialwert&#039;&#039;&#039;&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;
| 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;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;COM1A1&#039;&#039;&#039;, &#039;&#039;&#039;COM1A0&#039;&#039;&#039; (&#039;&#039;&#039;Co&#039;&#039;&#039;mpare &#039;&#039;&#039;M&#039;&#039;&#039;atch Control Bits)&lt;br /&gt;
:Diese 2 Bits bestimmen die Aktion, welche am Output-Pin &#039;&#039;&#039;OC1&#039;&#039;&#039; ausgeführt werden soll, wenn der Wert des Datenregisters des Timer/Counter 1 den Wert des Vergleichsregisters erreicht, also ein so genannter Compare Match auftritt.&lt;br /&gt;
:Der Pin &#039;&#039;&#039;OC1&#039;&#039;&#039; (&#039;&#039;&#039;PB3&#039;&#039;&#039; beim 2313) muss mit dem Datenrichtungsregister als Ausgang konfiguriert werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | COM1A1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | COM1A0&lt;br /&gt;
| Resultat&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;
| Output-Pin &#039;&#039;&#039;OC1&#039;&#039;&#039; wird nicht angesteuert.&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;
| Das Signal am Pin &#039;&#039;&#039;OC1&#039;&#039;&#039; wird invertiert (Toggle).&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;
| Der Output Pin &#039;&#039;&#039;OC1&#039;&#039;&#039; wird auf 0 gesetzt.&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;
| Der Output Pin &#039;&#039;&#039;OC1&#039;&#039;&#039; wird auf 1 gesetzt.&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&lt;br /&gt;
:In der PWM-Betriebsart haben diese Bits eine andere Funktion.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | COM1A1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | COM1A0&lt;br /&gt;
| Resultat&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;
| Output-Pin &#039;&#039;&#039;OC1&#039;&#039;&#039; wird nicht angesteuert.&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;
| Output-Pin &#039;&#039;&#039;OC1&#039;&#039;&#039; wird nicht angesteuert.&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;
| Wird beim Hochzählen der Wert im Vergleichsregister erreicht, so wird der Pin &#039;&#039;&#039;OC1&#039;&#039;&#039; auf 0 gesetzt.&lt;br /&gt;
Wird beim Herunterzählen der Wert im Vergleichsregister erreicht, so wird der Pin auf 1 gesetzt.&lt;br /&gt;
&lt;br /&gt;
Man nennt dies &#039;&#039;nicht invertierende PWM&#039;&#039;.&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;
| Wird beim Hochzählen der Wert im Vergleichsregister erreicht, so wird der Pin &#039;&#039;&#039;OC1&#039;&#039;&#039; auf 1 gesetzt.&lt;br /&gt;
Wird beim Herunterzählen der Wert im Vergleichsregister erreicht, so wird der Pin auf 0 gesetzt.&lt;br /&gt;
&lt;br /&gt;
Man nennt dies &#039;&#039;invertierende PWM&#039;&#039;.&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;PWM11&#039;&#039;&#039;, &#039;&#039;&#039;PWM10&#039;&#039;&#039; (&#039;&#039;&#039;PWM&#039;&#039;&#039; Mode Select Bits)&lt;br /&gt;
:Mit diesen 2 Bits wird die PWM-Betriebsart des Timer/Counter 1 gesteuert.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | PWM11&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | PWM10&lt;br /&gt;
| Resultat&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;
| Die PWM-Betriebsart ist nicht aktiviert. Timer/Counter 1 arbeitet als normaler Timer bzw. Zähler.&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;
| 8-Bit PWM Betriebsart aktivieren.&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;
| 9-Bit PWM Betriebsart aktivieren.&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;
| 10-Bit PWM Betriebsart aktivieren.&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;TCCR1B&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;T&#039;&#039;&#039;imer/&#039;&#039;&#039;C&#039;&#039;&#039;ounter &#039;&#039;&#039;C&#039;&#039;&#039;ontrol &#039;&#039;&#039;R&#039;&#039;&#039;egister &#039;&#039;&#039;B&#039;&#039;&#039; Timer &#039;&#039;&#039;1&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Bit&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 7&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 6&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 5&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 4&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 2&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Name&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ICNC1&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ICES1&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;WGM13&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;WGM12 (CTC1)&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;CS12&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;CS11&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;CS10&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;R/W&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Initialwert&#039;&#039;&#039;&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;
| 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;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ICNC1&#039;&#039;&#039; (&#039;&#039;&#039;I&#039;&#039;&#039;nput &#039;&#039;&#039;C&#039;&#039;&#039;apture &#039;&#039;&#039;N&#039;&#039;&#039;oise &#039;&#039;&#039;C&#039;&#039;&#039;anceler (4 CKs) Timer/Counter 1&lt;br /&gt;
:oder auf Deutsch Rauschunterdrückung des Eingangssignals.&lt;br /&gt;
:Wenn dieses Bit gesetzt ist und mit dem Input Capture Signal gearbeitet wird so werden nach der Triggerung des Signals mit der entsprechenden Flanke (steigend oder fallend) am Input Capture Pin &#039;&#039;&#039;ICP&#039;&#039;&#039; jeweils 4 Messungen mit der CPU-Frequenz des Eingangssignals abgefragt. Nur dann, wenn alle 4 Messungen den gleichen Zustand aufweisen gilt das Signal als erkannt.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ICES1&#039;&#039;&#039; (&#039;&#039;&#039;I&#039;&#039;&#039;nput &#039;&#039;&#039;C&#039;&#039;&#039;apture &#039;&#039;&#039;E&#039;&#039;&#039;dge &#039;&#039;&#039;S&#039;&#039;&#039;elect Timer/Counter &#039;&#039;&#039;1&#039;&#039;&#039;)&lt;br /&gt;
:Mit diesem Bit wird bestimmt, ob die steigende (&#039;&#039;&#039;ICES1&#039;&#039;&#039;=1) oder fallende (&#039;&#039;&#039;ICES1&#039;&#039;&#039;=0) Flanke zur Auswertung des Input Capture Signals an Pin &#039;&#039;&#039;ICP&#039;&#039;&#039; heran gezogen wird.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;CTC1&#039;&#039;&#039; (&#039;&#039;&#039;C&#039;&#039;&#039;lear &#039;&#039;&#039;T&#039;&#039;&#039;imer/&#039;&#039;&#039;C&#039;&#039;&#039;ounter on Compare Match Timer/Counter &#039;&#039;&#039;1&#039;&#039;&#039;)&lt;br /&gt;
:Wenn dieses Bit gesetzt ist, so wird nach einer Übereinstimmung des Datenregisters &#039;&#039;&#039;TCNT1H&#039;&#039;&#039;/&#039;&#039;&#039;TCNT1L&#039;&#039;&#039; mit dem Vergleichswert in &#039;&#039;&#039;OCR1H&#039;&#039;&#039;/&#039;&#039;&#039;OCR1L&#039;&#039;&#039; das Datenregister &#039;&#039;&#039;TCNT1H&#039;&#039;&#039;/&#039;&#039;&#039;TCNT1L&#039;&#039;&#039; auf 0 gesetzt.&lt;br /&gt;
:Da die Übereinstimmung im Takt nach dem Vergleich behandelt wird, ergibt sich je nach eingestelltem Vorteiler ein etwas anderes Zählverhalten:&lt;br /&gt;
:Wenn der Vorteiler auf 1 gestellt, und C der voreingestellte Vergleichswert ist, dann nimmt das Datenregister, im CPU-Takt betrachtet, folgende Werte an:&lt;br /&gt;
:... | C-2 | C-1 | C | 0 | 1 |...&lt;br /&gt;
:Wenn der Vorteiler z.B. auf 8 eingestellt ist, dann nimmt das Datenregister folgende Werte an:&lt;br /&gt;
:... | C-2, C-2, C-2, C-2, C-2, C-2, C-2, C-2 | C-1, C-1, C-1, C-1, C-1, C-1, C-1, C-1 | C, 0, 0, 0, 0, 0, 0, 0 |...&lt;br /&gt;
:In der PWM-Betriebsart hat dieses Bit keine Funktion.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;CS12&#039;&#039;&#039;, &#039;&#039;&#039;CS11&#039;&#039;&#039;, &#039;&#039;&#039;CS10&#039;&#039;&#039; (&#039;&#039;&#039;C&#039;&#039;&#039;lock &#039;&#039;&#039;S&#039;&#039;&#039;elect Bits)&lt;br /&gt;
:Diese 3 Bits bestimmen die Quelle für den Timer/Counter:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | CS12&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | CS11&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | CS10&lt;br /&gt;
| Resultat&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;
| Stopp, Der Timer/Counter wird 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;
| CPU-Takt&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;
| CPU-Takt / 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;
| CPU-Takt / 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;
| CPU-Takt / 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;
| CPU-Takt / 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;
| Externer 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;
| Externer Pin T1, steigende Flanke&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&lt;br /&gt;
:Wenn als Quelle der externe Pin T1 verwendet wird, so wird ein Flankenwechsel auch erkannt, wenn der Pin T1 als Ausgang geschaltet ist.&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;TCNT1H&#039;&#039;&#039;&amp;lt;br /&amp;gt;&#039;&#039;&#039;TCNT1L&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;T&#039;&#039;&#039;imer/&#039;&#039;&#039;C&#039;&#039;&#039;ou&#039;&#039;&#039;nt&#039;&#039;&#039;er Daten Register Timer/Counter &#039;&#039;&#039;1&#039;&#039;&#039;&lt;br /&gt;
Dieses ist als 16-Bit Aufwärtszähler mit Schreib- und Lesezugriff realisiert. Wenn der Zähler den Wert 65535 erreicht hat, beginnt er beim nächsten Zyklus wieder bei 0.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Bit&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 7&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 6&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 5&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 4&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 2&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; | &amp;amp;nbsp;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Name&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;MSB&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;TCNT1H&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Name&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;LSB&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;TCNT1L&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;R/W&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Initialwert&#039;&#039;&#039;&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;
| 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;
| 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; | &amp;amp;nbsp;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
In der PWM-Betriebsart wird das Register als Auf/Ab-Zähler verwendet, d.h. der Wert steigt zuerst von 0, bis er den Überlauf von 65535 auf 0 erreicht hat. Dann zählt das Register rückwärts wiederum bis 0.&lt;br /&gt;
&lt;br /&gt;
Zum Auslesen des Registers wird von der CPU ein internes TEMP-Register verwendet. Das gleiche Register wird auch verwendet, wenn auf &#039;&#039;&#039;OCR1&#039;&#039;&#039; oder &#039;&#039;&#039;ICR1&#039;&#039;&#039; zugegriffen wird.&lt;br /&gt;
&lt;br /&gt;
Deshalb müssen vor dem Zugriff auf eines dieser Register alle Interrupts gesperrt werden, weil sonst die Möglichkeit des gleichzeitigen Zugriffs auf das Temporärregister gegeben ist, was natürlich zu fehlerhaftem Verhalten des Programms führt.. Zudem muss zuerst &#039;&#039;&#039;TCNT1L&#039;&#039;&#039; und erst danach &#039;&#039;&#039;TCNT1H&#039;&#039;&#039; ausgelesen werden.&lt;br /&gt;
&lt;br /&gt;
Wenn in das Register geschrieben werden soll, müssen ebenfalls alle Interrrupts gesperrt werden. Dann muss zuerst das &#039;&#039;&#039;TCNT1H&#039;&#039;&#039;-Register und erst danach das &#039;&#039;&#039;TCNT1L&#039;&#039;&#039;-Register geschrieben werden, also genau die umgekehrte Reihenfolge wie beim Lesen des Registers.&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;OCR1H&#039;&#039;&#039;&amp;lt;br /&amp;gt;&#039;&#039;&#039;OCR1L&#039;&#039;&#039;&lt;br /&gt;
| Timer/Counter &#039;&#039;&#039;O&#039;&#039;&#039;utput &#039;&#039;&#039;C&#039;&#039;&#039;ompare &#039;&#039;&#039;R&#039;&#039;&#039;egister Timer/Counter &#039;&#039;&#039;1&#039;&#039;&#039;&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Bit&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 7&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 6&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 5&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 4&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 2&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; | &amp;amp;nbsp;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Name&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;MSB&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;OCR1H&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Name&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;LSB&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;OCR1L&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;R/W&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Initialwert&#039;&#039;&#039;&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;
| 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;
| 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; | &amp;amp;nbsp;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Der Wert im Output Compare Register wird ständig mit dem aktuellen Wert im Datenregister TCNT1H/TCNT1L verglichen. Stimmen die beiden Werte überein, so wird ein sogenannter Output Compare Match ausgelöst. Die entsprechenden Aktionen werden über die Timer/Counter 1 Control und Status Register eingestellt.&lt;br /&gt;
&lt;br /&gt;
Zum Auslesen des Registers wird von der CPU ein internes TEMP-Register verwendet. Das gleiche Register wird auch verwendet, wenn auf &#039;&#039;&#039;TCNT1&#039;&#039;&#039; oder &#039;&#039;&#039;ICR1&#039;&#039;&#039; zugegriffen wird.&lt;br /&gt;
Deshalb müssen vor dem Zugriff auf eines dieser Register alle Interrupts gesperrt werden, weil sonst die Möglichkeit des gleichzeitigen Zugriffs auf das Temporärregister gegeben ist, was natürlich zu fehlerhaftem Verhalten des Programms führt.. Zudem muss zuerst &#039;&#039;&#039;OCR1L&#039;&#039;&#039; und erst danach &#039;&#039;&#039;OCR1H&#039;&#039;&#039; ausgelesen werden.&lt;br /&gt;
&lt;br /&gt;
Wenn in das Register geschrieben werden soll, müssen ebenfalls alle Interrupts gesperrt werden. Dann muss zuerst das &#039;&#039;&#039;OCR1H&#039;&#039;&#039;-Register und erst danach das &#039;&#039;&#039;OCR1L&#039;&#039;&#039;-Register geschrieben werden, also genau die umgekehrte Reihenfolge wie beim Lesen des Registers.&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;ICR1H&#039;&#039;&#039;&amp;lt;br /&amp;gt;&#039;&#039;&#039;ICR1L&#039;&#039;&#039;&lt;br /&gt;
| Timer/Counter &#039;&#039;&#039;I&#039;&#039;&#039;nput &#039;&#039;&#039;C&#039;&#039;&#039;apture &#039;&#039;&#039;R&#039;&#039;&#039;egister Timer/Counter &#039;&#039;&#039;1&#039;&#039;&#039;&amp;lt;br /&amp;gt;&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Bit&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 7&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 6&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 5&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 4&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 2&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; | &amp;amp;nbsp;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Name&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;MSB&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ICR1&#039;&#039;&#039;&#039;&#039;&#039;H&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Name&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;LSB&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ICR1&#039;&#039;&#039;&#039;&#039;&#039;L&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;R/W&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;amp;nbsp;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Initialwert&#039;&#039;&#039;&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;
| 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;
| 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; | &amp;amp;nbsp;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Das Input Capture Register ist ein 16-Bit Register mit Lesezugriff. Es kann nicht beschrieben werden.&lt;br /&gt;
&lt;br /&gt;
Wenn am Input Capture Pin &#039;&#039;&#039;ICP&#039;&#039;&#039; die gemäß Einstellungen im &#039;&#039;&#039;TCCR1B&#039;&#039;&#039; definierte Flanke erkannt wird, so wird der aktuelle Inhalt des Datenregisters &#039;&#039;&#039;TCNT1H&#039;&#039;&#039;/&#039;&#039;&#039;TCNT1L&#039;&#039;&#039; sofort in dieses Register kopiert und das Input Capture Flag &#039;&#039;&#039;ICF1&#039;&#039;&#039; im Timer Interrupt Flag Register &#039;&#039;&#039;TIFR&#039;&#039;&#039; gesetzt.&lt;br /&gt;
&lt;br /&gt;
Wie bereits oben erwähnt, müssen vor dem Zugriff auf dieses Register alle Interrupts gesperrt werden. Zudem müssen Low- und Highbyte des Registers in der richtigen Reihenfolge bearbeitet werden:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;0&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| Lesen:&lt;br /&gt;
| &#039;&#039;&#039;ICR1L&#039;&#039;&#039; -&amp;gt; &#039;&#039;&#039;ICR1H&#039;&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Die PWM-Betriebsart ===&lt;br /&gt;
&lt;br /&gt;
Wenn der Timer/Counter 1 in der PWM-Betriebsart betrieben wird, so bilden das Datenregister &#039;&#039;&#039;TCNT1H&#039;&#039;&#039;/&#039;&#039;&#039;TCNT1L&#039;&#039;&#039; und das Vergleichsregister &#039;&#039;&#039;OCR1H&#039;&#039;&#039;/&#039;&#039;&#039;OCR1L&#039;&#039;&#039; einen 8-, 9- oder 10-Bit, frei laufenden PWM-Modulator, welcher als PWM-Signal am &#039;&#039;&#039;OC1&#039;&#039;&#039;-Pin (&#039;&#039;&#039;PB3&#039;&#039;&#039; beim 2313) abgegriffen werden kann. Das Datenregister &#039;&#039;&#039;TCNT1H&#039;&#039;&#039;/&#039;&#039;&#039;TCNT1L&#039;&#039;&#039; wird dabei als Auf-/Ab-Zähler betrieben, welcher von 0 an aufwärts zählt bis zur Obergrenze und danach wieder zurück auf 0.&lt;br /&gt;
Die Obergrenze ergibt sich daraus, ob 8-, 9- oder 10-Bit PWM verwendet wird, und zwar gemäß folgender Tabelle:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;Auflösung&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;Obergrenze&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Frequenz&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 8&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 255&lt;br /&gt;
| f&amp;lt;sub&amp;gt;TC1&amp;lt;/sub&amp;gt; / 510&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 9&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 511&lt;br /&gt;
| f&amp;lt;sub&amp;gt;TC1&amp;lt;/sub&amp;gt; / 1022&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 10&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1023&lt;br /&gt;
| f&amp;lt;sub&amp;gt;TC1&amp;lt;/sub&amp;gt; / 2046&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Wenn nun der Zählerwert im Datenregister den in &#039;&#039;&#039;OCR1H&#039;&#039;&#039;/&#039;&#039;&#039;OCR1L&#039;&#039;&#039; gespeicherten Wert erreicht, wird der Ausgabepin &#039;&#039;&#039;OC1&#039;&#039;&#039; gesetzt bzw. gelöscht, je nach Einstellung von &#039;&#039;&#039;COM1A1&#039;&#039;&#039; und &#039;&#039;&#039;COM1A0&#039;&#039;&#039; im &#039;&#039;&#039;TCCR1A&#039;&#039;&#039;-Register.&lt;br /&gt;
&lt;br /&gt;
Ich habe versucht, die entsprechenden Signale in der folgenden Grafik zusammenzufassen&lt;br /&gt;
&lt;br /&gt;
[[Image:PWM Theorie 3.gif]] [[Image:PWM Theorie 4.gif]]&lt;br /&gt;
&lt;br /&gt;
=== Vergleichswert-Überprüfung ===&lt;br /&gt;
&lt;br /&gt;
Hier wird in ein spezielles Vergleichswertregister (&#039;&#039;&#039;OCR1H&#039;&#039;&#039;/&#039;&#039;&#039;OCR1L&#039;&#039;&#039;) ein Wert eingeschrieben, welcher ständig mit dem aktuellen Zählerwert verglichen wird.&lt;br /&gt;
Erreicht der Zähler den in diesem Register eingetragenen Wert, so kann ein Signal (0 oder 1) am Pin &#039;&#039;&#039;OC1&#039;&#039;&#039; erzeugt und/oder ein Interrupt ausgelöst werden.&lt;br /&gt;
&lt;br /&gt;
=== Einfangen eines Eingangssignals (Input Capturing) ===&lt;br /&gt;
&lt;br /&gt;
Bei dieser Betriebsart wird an den Input Capturing Pin (ICP) des Controllers eine Signalquelle angeschlossen.&lt;br /&gt;
Nun kann je nach Konfiguration entweder ein Signalwechsel von 0 nach 1 (steigende Flanke) oder von 1 nach 0 (fallende Flanke) erkannt werden und der zu diesem Zeitpunkt aktuelle Zählerstand in ein spezielles Register abgelegt werden. Gleichzeitig kann auch ein entsprechender Interrupt ausgelöst werden.&lt;br /&gt;
Wenn die Signalquelle ein starkes Rauschen beinhaltet, kann die Rauschunterdrückung eingeschaltet werden. Dann wird beim Erkennen der konfigurierten Flanke über 4 Taktzyklen das Signal überwacht und nur dann, wenn alle 4 Messungen gleich sind, wird die entsprechende Aktion ausgelöst.&lt;br /&gt;
&lt;br /&gt;
== Gemeinsame Register ==&lt;br /&gt;
&lt;br /&gt;
Verschiedene Register beinhalten Zustände und Einstellungen, welche sowohl&lt;br /&gt;
für den 8-Bit, als auch für den 16-Bit Timer/Counter in ein und demselben&lt;br /&gt;
Register zu finden sind.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;TIMSK&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;T&#039;&#039;&#039;imer/Counter &#039;&#039;&#039;I&#039;&#039;&#039;nterrupt &#039;&#039;&#039;M&#039;&#039;&#039;a&#039;&#039;&#039;sk&#039;&#039;&#039;&lt;br /&gt;
Register&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Bit&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 7&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 6&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 5&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 4&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 2&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Name&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;TOIE1&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;OCIE1A&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;TICIE&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;TOIE0&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;R/W&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Initialwert&#039;&#039;&#039;&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;
| 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;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;TOIE1&#039;&#039;&#039; (&#039;&#039;&#039;T&#039;&#039;&#039;imer/Counter &#039;&#039;&#039;O&#039;&#039;&#039;verflow &#039;&#039;&#039;I&#039;&#039;&#039;nterrupt &#039;&#039;&#039;E&#039;&#039;&#039;nable Timer/Counter &#039;&#039;&#039;1&#039;&#039;&#039;)&lt;br /&gt;
:Wenn dieses Bit gesetzt ist, wird bei einem Überlauf des Datenregisters des Timer/Counter 1 ein Timer Overflow 1 Interrupt ausgelöst. Das Global Enable Interrupt Flag muss selbstverständlich auch gesetzt sein.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;OCIE1A&#039;&#039;&#039; (&#039;&#039;&#039;O&#039;&#039;&#039;utput &#039;&#039;&#039;C&#039;&#039;&#039;ompare Match &#039;&#039;&#039;I&#039;&#039;&#039;nterrupt &#039;&#039;&#039;E&#039;&#039;&#039;nable Timer/Counter &#039;&#039;&#039;1&#039;&#039;&#039;)&lt;br /&gt;
:Beim Timer/Counter 1 kann zusätzlich zum Überlauf ein Vergleichswert definiert werden.&lt;br /&gt;
&lt;br /&gt;
:Wenn dieses Bit gesetzt ist, wird beim Erreichen des Vergleichswertes ein Compare Match Interrupt ausgelöst. Das Global Enable Interrupt Flag muss selbstverständlich auch gesetzt sein.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;TICIE&#039;&#039;&#039; (&#039;&#039;&#039;T&#039;&#039;&#039;imer/Counter &#039;&#039;&#039;I&#039;&#039;&#039;nput &#039;&#039;&#039;C&#039;&#039;&#039;apture &#039;&#039;&#039;I&#039;&#039;&#039;nterrupt &#039;&#039;&#039;E&#039;&#039;&#039;nable)&lt;br /&gt;
:Wenn dieses Bit gesetzt ist, wird ein Capture Event Interrupt ausgelöst, wenn ein entsprechendes Signalereignis am Pin PD6(ICP) auftritt. Das Global Enable Interrupt Flag muss selbstverständlich auch gesetzt sein, wenn auch ein entsprechender Interrupt ausgelöst werden soll.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;TOIE0&#039;&#039;&#039; (&#039;&#039;&#039;T&#039;&#039;&#039;imer/Counter &#039;&#039;&#039;O&#039;&#039;&#039;verflow &#039;&#039;&#039;I&#039;&#039;&#039;nterrupt &#039;&#039;&#039;E&#039;&#039;&#039;nable Timer/Counter &#039;&#039;&#039;0&#039;&#039;&#039;)&lt;br /&gt;
:Wenn dieses Bit gesetzt ist, wird bei einem Überlauf des Datenregisters des Timer/Counter 0 ein Timer Overflow 0 Interrupt ausgelöst. Das Global Enable Interrupt Flag muss selbstverständlich auch gesetzt sein.&lt;br /&gt;
&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;TIFR&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;T&#039;&#039;&#039;imer/Counter &#039;&#039;&#039;I&#039;&#039;&#039;nterrupt &#039;&#039;&#039;F&#039;&#039;&#039;lag &#039;&#039;&#039;R&#039;&#039;&#039;egister&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Bit&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 7&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 6&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 5&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 4&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 2&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Name&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;TOV1&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;OCF1A&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ICF1&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;TOV0&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;R/W&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Initialwert&#039;&#039;&#039;&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;
| 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;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;TOV1&#039;&#039;&#039; (&#039;&#039;&#039;T&#039;&#039;&#039;imer/Counter &#039;&#039;&#039;O&#039;&#039;&#039;verflow Flag Timer/Counter &#039;&#039;&#039;1&#039;&#039;&#039;)&lt;br /&gt;
:Dieses Bit wird vom Controller gesetzt, wenn beim Timer 1 ein Überlauf des Datenregisters stattfindet.&lt;br /&gt;
&lt;br /&gt;
:In der PWM-Betriebsart wird das Bit gesetzt, wenn die Zählrichtung von auf- zu abwärts und umgekehrt geändert wird (Zählerwert = 0).&lt;br /&gt;
&lt;br /&gt;
:Das Flag wird automatisch gelöscht, wenn der zugehörige Interrupt-Vektor aufgerufen wird. Es kann jedoch auch gelöscht werden, indem eine logische 1 (!) in das entsprechende Bit geschrieben wird.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;OCF1A&#039;&#039;&#039; (&#039;&#039;&#039;O&#039;&#039;&#039;utput &#039;&#039;&#039;C&#039;&#039;&#039;ompare &#039;&#039;&#039;F&#039;&#039;&#039;lag Timer/Counter &#039;&#039;&#039;1&#039;&#039;&#039;)&lt;br /&gt;
:Dieses Bit wird gesetzt, wenn der aktuelle Wert des Datenregisters von Timer/Counter 1 mit demjenigen im Vergleichsregister &#039;&#039;&#039;OCR1&#039;&#039;&#039; übereinstimmt.&lt;br /&gt;
&lt;br /&gt;
:Das Flag wird automatisch gelöscht, wenn der zugehörige Interrupt-Vektor aufgerufen wird. Es kann jedoch auch gelöscht werden, indem eine logische 1 (!) in das entsprechende Bit geschrieben wird.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ICF1&#039;&#039;&#039; (&#039;&#039;&#039;I&#039;&#039;&#039;nput &#039;&#039;&#039;C&#039;&#039;&#039;apture &#039;&#039;&#039;F&#039;&#039;&#039;lag Timer/Counter &#039;&#039;&#039;1&#039;&#039;&#039;)&lt;br /&gt;
:Dieses Bit wird gesetzt, wenn ein Capture-Ereignis aufgetreten ist, welches anzeigt, dass der Wert des Datenregisters des  Timer/Counter 1 in das Input Capture Register ICR1 übertragen wurde.&lt;br /&gt;
&lt;br /&gt;
:Das Flag wird automatisch gelöscht, wenn der zugehörige Interrupt-Vektor aufgerufen wird. Es kann jedoch auch gelöscht werden, indem eine logische 1 (!) in das entsprechende Bit geschrieben wird.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;TOV0&#039;&#039;&#039; (&#039;&#039;&#039;T&#039;&#039;&#039;imer/Counter &#039;&#039;&#039;O&#039;&#039;&#039;verflow Flag Timer/Counter &#039;&#039;&#039;0&#039;&#039;&#039;)&lt;br /&gt;
:Dieses Bit wird vom Controller gesetzt, wenn beim Timer 0 ein Überlauf des Datenregisters stattfindet.&lt;br /&gt;
&lt;br /&gt;
:Das Flag wird automatisch gelöscht, wenn der zugehörige Interrupt-Vektor aufgerufen wird. Es kann jedoch auch gelöscht werden, indem eine logische 1 (!) in das entsprechende Bit geschrieben wird.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;amp;nbsp;&lt;br /&gt;
&lt;br /&gt;
= Warteschleifen (delay.h) =&lt;br /&gt;
&lt;br /&gt;
Der Programmablauf kann verschiedene Arten von Wartefunktionen erfordern:&lt;br /&gt;
&lt;br /&gt;
* Warten im Sinn von Zeitvertrödeln&lt;br /&gt;
* Warten auf einen bestimmten Zustand an den I/O-Pins&lt;br /&gt;
* Warten auf einen bestimmten Zeitpunkt (siehe Timer)&lt;br /&gt;
* Warten auf einen bestimmten Zählerstand (siehe Counter)&lt;br /&gt;
&lt;br /&gt;
Der einfachste Fall, das Zeitvertrödeln, kann in vielen Fällen und mit großer Genauigkeit anhand der avr-libc Bibliotheksfunktionen _delay_ms() und _delay_us() erledigt werden. Die Bibliotheksfunktionen sind einfachen Zählschleifen (Warteschleifen) vorzuziehen, da leere Zählschleifen ohne besondere Vorkehrungen sonst bei eingeschalteter Optimierung vom avr-gcc-Compiler wegoptimiert werden. Weiterhin sind die Bibliotheksfunktionen bereits darauf vorbereitet, die in F_CPU definierte Taktfrequenz zu verwenden. Ausserdem sind die Funktionen der Bibliothek wirklich getestet.&lt;br /&gt;
&lt;br /&gt;
Einfach!? Schon, aber während gewartet wird, macht der µC nichts anderes mehr. Die Wartefunktion blockiert den Programmablauf. Möchte man einerseits warten, um z.B. eine LED blinken zu lassen und gleichzeitig andere Aktionen ausführen z.B. weitere LED bedienen, sollten die Timer/Counter des AVR verwendet werden.&lt;br /&gt;
&lt;br /&gt;
Die Bibliotheksfunktionen funktionieren allerdings nur dann korrekt, wenn sie mit zur Übersetzungszeit (beim Compilieren) bekannten konstanten Werten aufgerufen werden. Der Quellcode muss mit eingeschalteter Optimierung übersetzt werden, sonst wird sehr viel Maschinencode erzeugt und die Wartezeiten stimmen nicht mehr mit dem Parameter überein.&lt;br /&gt;
&lt;br /&gt;
Abhängig von der Version der Bibliothek verhalten sich die Bibliotheksfunktionen etwas unterschiedlich.&lt;br /&gt;
&lt;br /&gt;
== avr-libc Versionen kleiner 1.6 ==&lt;br /&gt;
&lt;br /&gt;
Die Wartezeit der Funktion _delay_ms() ist auf 262,14ms/F_CPU (in MHz) begrenzt, d.h. bei 20 MHz kann man nur max. 13,1ms warten. Die Wartezeit der Funktion _delay_us() ist auf 768us/F_CPU (in MHz) begrenzt, d.h. bei 20 MHz kann man nur max. 38,4us warten. Längere Wartezeiten müssen dann über einen mehrfachen Aufruf in einer Schleife gelöst werden.&lt;br /&gt;
&lt;br /&gt;
Beispiel: Blinken einer LED an PORTB Pin PB0 im ca. 1s Rhythmus&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#ifndef F_CPU&lt;br /&gt;
/* Definiere F_CPU, wenn F_CPU nicht bereits vorher definiert &lt;br /&gt;
   (z.B. durch Übergabe als Parameter zum Compiler innerhalb &lt;br /&gt;
   des Makefiles). Zusätzlich Ausgabe einer Warnung, die auf die&lt;br /&gt;
   &amp;quot;nachträgliche&amp;quot; Definition hinweist */&lt;br /&gt;
#warning &amp;quot;F_CPU war noch nicht definiert, wird nun mit 3686400 definiert&amp;quot;&lt;br /&gt;
#define F_CPU 3686400UL     /* Quarz mit 3.6864 Mhz */&lt;br /&gt;
#endif&lt;br /&gt;
#include &amp;lt;util/delay.h&amp;gt;     /* in älteren avr-libc Versionen &amp;lt;avr/delay.h&amp;gt; */ &lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
 lange, variable Verzögerungszeit, Einheit in Millisekunden&lt;br /&gt;
&lt;br /&gt;
Die maximale Zeit pro Funktionsaufruf ist begrenzt auf &lt;br /&gt;
262.14 ms / F_CPU in MHz (im Beispiel: &lt;br /&gt;
262.1 / 3.6864 = max. 71 ms) &lt;br /&gt;
&lt;br /&gt;
Daher wird die kleine Warteschleife mehrfach aufgerufen,&lt;br /&gt;
um auf eine längere Wartezeit zu kommen. Die zusätzliche &lt;br /&gt;
Prüfung der Schleifenbedingung lässt die Wartezeit geringfügig&lt;br /&gt;
ungenau werden (macht hier vielleicht 2-3ms aus).&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
void long_delay(uint16_t ms) {&lt;br /&gt;
    for(; ms&amp;gt;0; ms--) _delay_ms(1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int main( void )&lt;br /&gt;
{&lt;br /&gt;
    DDRB = ( 1 &amp;lt;&amp;lt; PB0 );        // PB0 an PORTB als Ausgang setzen&lt;br /&gt;
&lt;br /&gt;
    while( 1 ) {                // Endlosschleife&lt;br /&gt;
        PORTB ^= ( 1 &amp;lt;&amp;lt; PB0 );  // Toggle PB0 z.B. angeschlossene LED&lt;br /&gt;
        long_delay(1000);       // Eine Sekunde warten...&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== avr-libc Versionen ab 1.6 ==&lt;br /&gt;
&lt;br /&gt;
_delay_ms() kann mit einem Argument bis 6553,5 ms (= 6,5535 Sekunden) benutzt werden. Wird die früher gültige Grenze von 262,14 ms/F_CPU (in MHz) überschritten, so arbeitet _delay_ms() einfach etwas ungenauer und zählt nur noch mit einer Auflösung von 1/10 ms. Eine Verzögerung von 1000,10 ms ließe sich nicht mehr von einer von 1000,19 ms unterscheiden. Ein Verlust, der sich im Allgemeinen verschmerzen lässt. Dem Programmierer wird keine Rückmeldung gegeben, dass die Funktion ggf. gröber arbeitet, d.h. wenn es darauf ankommt, bitte den Parameter wie bisher geschickt wählen.&lt;br /&gt;
&lt;br /&gt;
Die Funktion _delay_us() wurde ebenfalls erweitert. Wenn deren maximal als genau behandelbares Argument überschritten wird, benutzt diese intern _delay_ms(). Damit gelten in diesem Fall die _delay_ms() Einschränkungen.&lt;br /&gt;
&lt;br /&gt;
Beispiel: Blinken einer LED an PORTB Pin PB0 im ca. 1s Rhythmus, avr-libc ab Version 1.6&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#ifndef F_CPU&lt;br /&gt;
/* Definiere F_CPU, wenn F_CPU nicht bereits vorher definiert &lt;br /&gt;
   (z.B. durch Übergabe als Parameter zum Compiler innerhalb &lt;br /&gt;
   des Makefiles). Zusätzlich Ausgabe einer Warnung, die auf die&lt;br /&gt;
   &amp;quot;nachträgliche&amp;quot; Definition hinweist */&lt;br /&gt;
#warning &amp;quot;F_CPU war noch nicht definiert, wird nun mit 3686400 definiert&amp;quot;&lt;br /&gt;
#define F_CPU 3686400UL     /* Quarz mit 3.6864 Mhz */&lt;br /&gt;
#endif&lt;br /&gt;
#include &amp;lt;util/delay.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
int main( void )&lt;br /&gt;
{&lt;br /&gt;
    DDRB = ( 1 &amp;lt;&amp;lt; PB0 );        // PB0 an PORTB als Ausgang setzen&lt;br /&gt;
&lt;br /&gt;
    while( 1 ) {                // Endlosschleife&lt;br /&gt;
        PORTB ^= ( 1 &amp;lt;&amp;lt; PB0 );  // Toggle PB0 z.B. angeschlossene LED&lt;br /&gt;
        _delay_ms(1000);        // Eine Sekunde +/-1/10000 Sekunde warten...&lt;br /&gt;
                                // funktioniert nicht mit Bibliotheken vor 1.6&lt;br /&gt;
&lt;br /&gt;
    }&lt;br /&gt;
    return 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Der Watchdog =&lt;br /&gt;
&lt;br /&gt;
Und hier kommt das ultimative Mittel gegen die Unvollkommenheit von uns&lt;br /&gt;
Programmierern, der Watchdog.&lt;br /&gt;
&lt;br /&gt;
So sehr wir uns auch anstrengen, es wird uns kaum je gelingen, das absolut&lt;br /&gt;
perfekte und fehlerfreie Programm zu entwickeln.&lt;br /&gt;
&lt;br /&gt;
Der Watchdog kann uns zwar auch nicht zu besseren Programmen verhelfen aber er&lt;br /&gt;
kann dafür sorgen, dass unser Programm, wenn es sich wieder mal in&#039;s Nirwana&lt;br /&gt;
verabschiedet hat, neu gestartet wird, indem ein Reset des Controllers&lt;br /&gt;
ausgelöst wird.&lt;br /&gt;
&lt;br /&gt;
Betrachten wir doch einmal folgende Codesequenz:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
    uint8_t x;&lt;br /&gt;
&lt;br /&gt;
    x = 10;&lt;br /&gt;
&lt;br /&gt;
    while (x &amp;gt;= 0)&lt;br /&gt;
    {&lt;br /&gt;
      // tu was&lt;br /&gt;
&lt;br /&gt;
      x--;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn wir die Schleife mal genau anschauen sollte uns auffallen, dass dieselbe niemals beendet wird. Warum nicht? Ganz einfach, weil eine als &#039;&#039;&#039;&#039;&#039;unsigned&#039;&#039;&#039;&#039;&#039; deklarierte Variable niemals kleiner als Null werden kann (der Compiler sollte jedoch eine ensprechende Warnung ausgeben).&lt;br /&gt;
Das Programm würde sich also hier aufhängen und auf ewig in der Schleife drehen.&lt;br /&gt;
Und hier genau kommt der Watchdog zum Zug.&lt;br /&gt;
&lt;br /&gt;
== Wie funktioniert nun der Watchdog? ==&lt;br /&gt;
&lt;br /&gt;
Der Watchdog enthält einen separaten Timer/Counter, welcher mit einem intern erzeugten Takt von 1 MHz bei 5V Vcc getaktet wird. Einige Controller haben einen eigenen Watchdog Oszillator, z.B. der Tiny2313 mit 128kHz. Nachdem der Watchdog aktiviert und der gewünschte Vorteiler eingestellt wurde, beginnt der Counter von 0 an hochzuzählen. &lt;br /&gt;
Wenn nun die je nach Vorteiler eingestellte Anzahl Zyklen erreicht wurde, löst der Watchdog einen Reset aus. Um nun also im Normalbetrieb den Reset zu verhindern, müssen wir den Watchdog regelmäßig wieder neu starten bzw. rücksetzen (Watchdog Reset). &lt;br /&gt;
Dies sollte innerhalb unserer Hauptschleife passieren.&lt;br /&gt;
&lt;br /&gt;
Um ein unbeabsichtigtes Ausschalten des Watchdogs zu verhindern, muss ein spezielles Prozedere verwendet werden, um den WD auszuschalten. Es müssen zuerst die beiden Bits WDTOE und WDE in einer einzelnen Operation (also nicht mit sbi) auf 1 gesetzt werden. &lt;br /&gt;
Dann muss innerhalb der nächsten 4 Taktzyklen das Bit WDE auf 0 gesetzt werden.&lt;br /&gt;
&lt;br /&gt;
Das Watchdog Control Register:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;WDTCR&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;W&#039;&#039;&#039;atchog &#039;&#039;&#039;T&#039;&#039;&#039;imer&amp;amp;nbsp; &#039;&#039;&#039;C&#039;&#039;&#039;ontrol &#039;&#039;&#039;R&#039;&#039;&#039;egister&lt;br /&gt;
&lt;br /&gt;
In diesem Register stellen wir ein, wie wir den Watchdog verwenden möchten.&lt;br /&gt;
&lt;br /&gt;
Das Register ist wie folgt aufgebaut:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Bit&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 7&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 6&lt;br /&gt;
| align=&amp;amp;quot;center&amp;quot; | 5&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 4&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 2&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Name&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;WDTOE&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;WDE&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;WDP2&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;WDP1&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;WDP0&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;R/W&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Initialwert&#039;&#039;&#039;&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;
| 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;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;WDTOE&#039;&#039;&#039; (&#039;&#039;&#039;W&#039;&#039;&#039;atch&#039;&#039;&#039;d&#039;&#039;&#039;og &#039;&#039;&#039;T&#039;&#039;&#039;urn &#039;&#039;&#039;O&#039;&#039;&#039;ff &#039;&#039;&#039;E&#039;&#039;&#039;nable)&lt;br /&gt;
:Dieses Bit muss gesetzt sein, wenn das Bit &#039;&#039;&#039;WDE&#039;&#039;&#039; gelöscht wird, andernfalls wird der Watchdog nicht ausgeschaltet.&lt;br /&gt;
:Wenn das Bit einmal gesetzt ist, wird es von der Hardware nach 4 Taktzyklen automatisch wieder gelöscht.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;WDE&#039;&#039;&#039; (&#039;&#039;&#039;W&#039;&#039;&#039;atch&#039;&#039;&#039;d&#039;&#039;&#039;og &#039;&#039;&#039;E&#039;&#039;&#039;nable)&lt;br /&gt;
:Wenn dieses Bit gesetzt wird, so wird der Watchdog aktiviert.&lt;br /&gt;
:Das Bit kann nur gelöscht werden, solange das Bit &#039;&#039;&#039;WDTOE&#039;&#039;&#039; auf 1 steht.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;WDP2&#039;&#039;&#039;, &#039;&#039;&#039;WDP1&#039;&#039;&#039;, &#039;&#039;&#039;WDP0&#039;&#039;&#039; (&#039;&#039;&#039;W&#039;&#039;&#039;atch&#039;&#039;&#039;d&#039;&#039;&#039;og Timer &#039;&#039;&#039;P&#039;&#039;&#039;rescaler Bits)&lt;br /&gt;
:Diese 3 Bits bestimmen die Anzahl Oszillatorzyklen für den Watchdog, also, wie lange es dauert, bis ein Reset ausgelöst wird:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | WDP2&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | WDP1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | WDP0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | Anzahl Zyklen&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | Typ. Timeoutzeit bei Vcc = 3V&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | Typ. Timeoutzeit bei Vcc = 5V&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;
| align=&amp;quot;center&amp;quot; | 16K&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 47ms&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 15ms&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;
| align=&amp;quot;center&amp;quot; | 32K&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 94ms&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 30ms&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;
| align=&amp;quot;center&amp;quot; | 64K&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0.19s&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 60ms&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;
| align=&amp;quot;center&amp;quot; | 128K&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0.38s&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0.12s&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;
| align=&amp;quot;center&amp;quot; | 256K&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0.75s&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0.24s&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;
| align=&amp;quot;center&amp;quot; | 512K&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1.5s&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0.49s&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;
| align=&amp;quot;center&amp;quot; | 1024K&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3s&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0.97s&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;
| align=&amp;quot;center&amp;quot; | 2048K&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 6s&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1.9s&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Um den Watchdog mit dem AVR-GCC Compiler zu verwenden, muss die Headerdatei &#039;&#039;wdt.h&#039;&#039; (&#039;&#039;#include &amp;lt;avr/wdt.h&amp;gt;&#039;&#039;) in die Quelldatei eingebunden werden. &lt;br /&gt;
&amp;lt;!-- mt: das stimmt wohl nicht mehr?!:&lt;br /&gt;
Dadurch wird auch der Startup-Code entsprechend angepasst, so dass der Watchdog nach einem Reset automatisch gestartet wird. &lt;br /&gt;
Das WDTCR-Register wird dabei mit dem Wert 0 beschrieben. &lt;br /&gt;
Falls ein anderer Wert gewünscht ist, so kann dies im Makfile in den Linker-Optionen eingetragen werden. &lt;br /&gt;
Dazu muss in der Zeile LDFLAGS folgende Option angefügt werden:&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; --defsym __init_wdtcr__=0x1f&amp;lt;br /&amp;gt;&lt;br /&gt;
wenn beispielsweise der Wert des Registers auf 0x1f gestellt werden soll.&amp;lt;br /&amp;gt; --&amp;gt;&lt;br /&gt;
Danach können die folgenden Funktionen verwendet werden:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;wdt_enable(uint8_t timeout)&#039;&#039;&#039;&lt;br /&gt;
:Aktiviert den Watchdog und stellt den Vorteiler auf den gewünschten Wert ein bzw. der in timeout übergebene Wert wird in das WDTCR-Register eingetragen. Einige Timeout-Werte sind als Konstanten vordefiniert&lt;br /&gt;
:Mögliche Timeoutwerte:&lt;br /&gt;
&amp;lt;div align=&amp;quot;center&amp;quot;&amp;gt;&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
! Konstante&lt;br /&gt;
! Wert&lt;br /&gt;
! TimeOut&lt;br /&gt;
|- &lt;br /&gt;
| WDTO_15MS   &lt;br /&gt;
| 0&lt;br /&gt;
| 15 ms&lt;br /&gt;
|-&lt;br /&gt;
| WDTO_30MS   &lt;br /&gt;
| 1&lt;br /&gt;
| 30 ms&lt;br /&gt;
|-&lt;br /&gt;
| WDTO_60MS   &lt;br /&gt;
| 2&lt;br /&gt;
| 60 ms&lt;br /&gt;
|-&lt;br /&gt;
| WDTO_120MS   &lt;br /&gt;
| 3&lt;br /&gt;
| 120 ms&lt;br /&gt;
|-&lt;br /&gt;
| WDTO_250MS   &lt;br /&gt;
| 4&lt;br /&gt;
| 250 ms&lt;br /&gt;
|-&lt;br /&gt;
| WDTO_500MS   &lt;br /&gt;
| 5&lt;br /&gt;
| 500 ms&lt;br /&gt;
|-&lt;br /&gt;
| WDTO_1S   &lt;br /&gt;
| 6&lt;br /&gt;
| 1 s&lt;br /&gt;
|-&lt;br /&gt;
| WDTO_2S   &lt;br /&gt;
| 7&lt;br /&gt;
| 2 s&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;wdt_disable()&#039;&#039;&#039;&lt;br /&gt;
:Mit dieser Funktion kann der Watchdog ausgeschaltet werden. Dabei wird das notwendige Prozedere, wie oben beschrieben, automatisch ausgeführt.&lt;br /&gt;
* &#039;&#039;&#039;wdt_reset()&#039;&#039;&#039;&lt;br /&gt;
:Dies ist wohl die wichtigste der Watchdog-Funktionen. Sie erzeugt einen Watchdog-Reset, welcher periodisch, und zwar vor Ablauf der Timeoutzeit, ausgeführt werden muss, damit der Watchdog nicht den AVR zurücksetzt.&lt;br /&gt;
&lt;br /&gt;
Selbstverständlich kann das &#039;&#039;&#039;WDTCR&#039;&#039;&#039;-Register auch mit den uns bereits bekannten Funktionen für den Zugriff auf Register programmiert werden.&lt;br /&gt;
&lt;br /&gt;
== Watchdog-Anwendungshinweise ==&lt;br /&gt;
&lt;br /&gt;
Ob nun der Watchdog als Schutzfunktion überhaupt verwendet werden soll, hängt stark von der Anwendung, der genutzten Peripherie und dem Umfang und der Qualitätssicherung des Codes ab. Will man sicher gehen, dass ein Programm sich nicht in einer Endlosschleife verfängt, ist der Wachdog das geeignete Mittel dies zu verhindern. Weiterhin kann bei geschickter Programmierung der Watchdog dazu genutzt werden, bestimmte Stromsparfunktionen zu implementieren. Bei einigen neueren AVRs (z.B. dem ATTiny13) kann der Watchdog auch direkt als Timer genutzt werden, der den Controller aus einem Schlafmodus aufweckt. Auch dies kann im &#039;&#039;&#039;WDTCR&#039;&#039;&#039;-Register eingestellt werden. Außerdem bietet der WD die einzige Möglichkeit einen beabsichtigten System-Reset (ein &amp;quot;richtiger Reset&amp;quot;, kein &amp;quot;jmp 0x0000&amp;quot;) ohne externe Beschaltung auszulösen, was z.B. bei der Implementierung eines Bootloaders nützlich ist. Bei bestimmten Anwendungen kann die Nutzung des WD als &amp;quot;ultimative Deadlock-Sicherung für nicht bedachte Zustände&amp;quot; natürlich immer als zusätzliche Sicherung dienen. &lt;br /&gt;
&lt;br /&gt;
Es besteht die Möglichkeit herauszufinden, ob ein Reset durch den Watchdog ausgelöst wurde (beim ATmega16 z.B. Bit WDRF in MCUCSR). Diese Information sollte auch genutzt werden, falls ein WD-Reset in der Anwendung nicht planmäßig implementiert wurde. Zum Beispiel kann man eine LED an einen freien Pin hängen, die nur bei einem Reset durch den WD aufleuchtet oder aber das &amp;quot;Ereignis WD-Reset&amp;quot; im internen EEPROM des AVR absichern, um die Information später z.B. über UART oder ein Display auszugeben (oder einfach den EEPROM-Inhalt über die ISP/JTAG-Schnittstelle auslesen).&lt;br /&gt;
&lt;br /&gt;
Siehe auch: &lt;br /&gt;
* [http://www.nongnu.org/avr-libc/user-manual/index.html Dokumentation der avr-libc] Abschnitt Modules/Watchdog timer handling&lt;br /&gt;
* [http://www.mikrocontroller.net/topic/77273#642501 Bug in ATtiny2313?]&lt;br /&gt;
&lt;br /&gt;
= Programmieren mit Interrupts =&lt;br /&gt;
&lt;br /&gt;
Nachdem wir nun alles Wissenswerte für die serielle Programmerstellung&lt;br /&gt;
gelernt haben nehmen wir jetzt ein völlig anderes Thema in Angriff, nämlich&lt;br /&gt;
die Programmierung unter Zuhilfenahme der Interrupts des AVR.&lt;br /&gt;
&lt;br /&gt;
Als erstes wollen wir uns noch einmal den allgemeinen Programmablauf bei der&lt;br /&gt;
Interrupt-Programmierung zu Gemüte führen.&lt;br /&gt;
&lt;br /&gt;
[[Image:Interrupt Programme.gif]]&lt;br /&gt;
&lt;br /&gt;
Man sieht, dass die Interruptroutine quasi parallel zum Hauptprogramm&lt;br /&gt;
abläuft. Da wir nur eine CPU haben ist es natürlich keine echte Parallelität,&lt;br /&gt;
sondern das Hauptprogramm wird beim Eintreffen eines Interrupts unterbrochen,&lt;br /&gt;
die Interruptroutine wird ausgeführt und danach erst wieder zum Hauptprogramm&lt;br /&gt;
zurückgekehrt.&lt;br /&gt;
&lt;br /&gt;
[http://www.mikrocontroller.net/forum/read-1-235092.html#new Ausführlicher Thread im Forum]&lt;br /&gt;
&lt;br /&gt;
== Anforderungen an Interrupt-Routinen ==&lt;br /&gt;
&lt;br /&gt;
Um unliebsamen Überraschungen vorzubeugen, sollten einige Grundregeln bei der Implementierung der Interruptroutinen beachtet werden. Interruptroutinen soll möglichst kurz und schnell abarbeitbar sein, daraus folgt:&lt;br /&gt;
&lt;br /&gt;
* Keine umfangreichen Berechnungen innerhalb der Interruptroutine. (*)&lt;br /&gt;
* Keine langen Programmschleifen.&lt;br /&gt;
* Obwohl es möglich ist, während der Abarbeitung einer Interruptroutine andere oder sogar den gleichen Interrupt wieder zuzulassen, wird davon ohne genaue Kenntnis der internen Abläufe dringend abgeraten.&lt;br /&gt;
&lt;br /&gt;
Interruptroutinen (ISRs) sollten also möglichst kurz sein und keine Schleifen mit vielen Durchläufen enthalten. Längere Operationen können meist in einen &amp;quot;Interrupt-Teil&amp;quot; in einer ISR und einen &amp;quot;Arbeitsteil&amp;quot; im Hauptprogramm aufgetrennt werden. Z.B. Speichern des Zustands aller Eingänge im EEPROM in bestimmten Zeitabständen: ISR-Teil: Zeitvergleich (Timer,RTC) mit Logzeit/-intervall. Bei Übereinstimmung ein globales Flag setzen (volatile bei Flag-Deklaration nicht vergessen, s.u.). Dann im Hauptprogramm prüfen, ob das Flag gesetzt ist. Wenn ja: die Daten im EEPROM ablegen und Flag löschen.&lt;br /&gt;
&lt;br /&gt;
(*)&lt;br /&gt;
Hinweis: &lt;br /&gt;
Es gibt allerdings die seltene Situation, dass man gerade eingelesene&lt;br /&gt;
ADC-Werte sofort verarbeiten muss. Besonders dann, wenn man mehrere Werte sehr&lt;br /&gt;
schnell hintereinander bekommt. Dann bleibt einem nichts anderes übrig, als die&lt;br /&gt;
Werte noch in der ISR zu verarbeiten. Kommt aber sehr selten vor und sollte&lt;br /&gt;
durch geeignete Wahl des Systemtaktes bzw. Auswahl des Controllers vermieden werden!&lt;br /&gt;
&lt;br /&gt;
== Interrupt-Quellen ==&lt;br /&gt;
&lt;br /&gt;
Die folgenden Ereignisse können einen Interrupt auf einem AVR AT90S2313 auslösen, wobei die Reihenfolge der Auflistung auch die Priorität der Interrupts aufzeigt.&lt;br /&gt;
&lt;br /&gt;
* Reset&lt;br /&gt;
* Externer Interrupt 0&lt;br /&gt;
* Externer Interrupt 1&lt;br /&gt;
* Timer/Counter 1 Capture Ereignis&lt;br /&gt;
* Timer/Counter 1 Compare Match&lt;br /&gt;
* Timer/Counter 1 Überlauf&lt;br /&gt;
* Timer/Counter 0 Überlauf&lt;br /&gt;
* UART Zeichen empfangen&lt;br /&gt;
* UART Datenregister leer&lt;br /&gt;
* UART Zeichen gesendet&lt;br /&gt;
* Analoger Komparator&lt;br /&gt;
&lt;br /&gt;
Die Anzahl der möglichen Interruptquellen variiert zwischen den verschiedenen Typen. Im Zweifel hilft ein Blick ins Datenblatt (&amp;quot;Interrupt Vectors&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
== Register ==&lt;br /&gt;
&lt;br /&gt;
Der AT90S2313 verfügt über 2 Register die mit den&lt;br /&gt;
Interrupts zusammen hängen.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;GIMSK&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;G&#039;&#039;&#039;eneral &#039;&#039;&#039;I&#039;&#039;&#039;nterrupt &#039;&#039;&#039;M&#039;&#039;&#039;ask &#039;&#039;&#039;R&#039;&#039;&#039;egister.&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Bit&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 7&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 6&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 5&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 4&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 2&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Name&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;INT1&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;INT0&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;R/W&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Initialwert&#039;&#039;&#039;&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;
| 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;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;INT1&#039;&#039;&#039; (External &#039;&#039;&#039;Int&#039;&#039;&#039;errupt Request &#039;&#039;&#039;1&#039;&#039;&#039; Enable)&lt;br /&gt;
:Wenn dieses Bit gesetzt ist, wird ein Interrupt ausgelöst, wenn am &#039;&#039;&#039;INT1&#039;&#039;&#039;-Pin eine steigende oder fallende (je nach Konfiguration im &#039;&#039;&#039;MCUCR&#039;&#039;&#039;) Flanke erkannt wird.&lt;br /&gt;
:Das Global Enable Interrupt Flag muss selbstverständlich auch gesetzt sein.&lt;br /&gt;
:Der Interrupt wird auch ausgelöst, wenn der Pin als Ausgang geschaltet ist. Auf diese Weise bietet sich die Möglichkeit, Software-Interrupts zu realisieren.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;INT0&#039;&#039;&#039; (External &#039;&#039;&#039;Int&#039;&#039;&#039;errupt Request &#039;&#039;&#039;0&#039;&#039;&#039; Enable)&lt;br /&gt;
:Wenn dieses Bit gesetzt ist, wird ein Interrupt ausgelöst, wenn am &#039;&#039;&#039;INT0&#039;&#039;&#039;-Pin eine steigende oder fallende (je nach Konfiguration im &#039;&#039;&#039;MCUCR&#039;&#039;&#039;) Flanke erkannt wird.&lt;br /&gt;
:Das Global Enable Interrupt Flag muss selbstverständlich auch gesetzt sein.&lt;br /&gt;
:Der Interrupt wird auch ausgelöst, wenn der Pin als Ausgang geschaltet ist. Auf diese Weise bietet sich die Möglichkeit, Software-Interrupts zu realisieren.&lt;br /&gt;
&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;GIFR&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;G&#039;&#039;&#039;eneral &#039;&#039;&#039;I&#039;&#039;&#039;nterrupt &#039;&#039;&#039;F&#039;&#039;&#039;lag &#039;&#039;&#039;R&#039;&#039;&#039;egister.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Bit&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 7&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 6&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 5&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 4&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 2&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Name&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;INTF1&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;INTF0&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;R/W&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Initialwert&#039;&#039;&#039;&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;
| 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;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;INTF1&#039;&#039;&#039; (External &#039;&#039;&#039;Int&#039;&#039;&#039;errupt Flag &#039;&#039;&#039;1&#039;&#039;&#039;)&lt;br /&gt;
:Dieses Bit wird gesetzt, wenn am &#039;&#039;&#039;INT1&#039;&#039;&#039;-Pin eine Interrupt-Kondition, entsprechend der Konfiguration, erkannt wird. Wenn das Global Enable Interrupt Flag gesetzt ist, wird die Interruptroutine angesprungen.&lt;br /&gt;
:Das Flag wird automatisch gelöscht, wenn die Interruptroutine beendet ist. Alternativ kann das Flag gelöscht werden, indem der Wert &#039;&#039;&#039;1(!)&#039;&#039;&#039; eingeschrieben wird.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;INTF0&#039;&#039;&#039; (External &#039;&#039;&#039;Int&#039;&#039;&#039;errupt Flag &#039;&#039;&#039;0&#039;&#039;&#039;)&lt;br /&gt;
:Dieses Bit wird gesetzt, wenn am &#039;&#039;&#039;INT0&#039;&#039;&#039;-Pin eine Interrupt-Kondition, entsprechend der Konfiguration, erkannt wird. Wenn das Global Enable Interrupt Flag gesetzt ist, wird die Interruptroutine angesprungen.&lt;br /&gt;
:Das Flag wird automatisch gelöscht, wenn die Interruptroutine beendet ist. Alternativ kann das Flag gelöscht werden, indem der Wert &#039;&#039;&#039;1(!)&#039;&#039;&#039; eingeschrieben wird.&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;MCUCR&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;MCU&#039;&#039;&#039; &#039;&#039;&#039;C&#039;&#039;&#039;ontrol &#039;&#039;&#039;R&#039;&#039;&#039;egister.&lt;br /&gt;
&lt;br /&gt;
Das MCU Control Register enthält Kontrollbits für allgemeine&lt;br /&gt;
MCU-Funktionen.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Bit&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 7&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 6&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 5&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 4&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 3&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 2&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Name&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;SE&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;SM&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ISC11&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ISC10&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ISC01&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ISC00&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;R/W&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Initialwert&#039;&#039;&#039;&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;
| 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;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;SE&#039;&#039;&#039; (&#039;&#039;&#039;S&#039;&#039;&#039;leep &#039;&#039;&#039;E&#039;&#039;&#039;nable)&lt;br /&gt;
:Dieses Bit muss gesetzt sein, um den Controller mit dem &#039;&#039;&#039;SLEEP&#039;&#039;&#039;-Befehl in den Schlafzustand versetzen zu können.&lt;br /&gt;
:Um den Schlafmodus nicht irrtümlich einzuschalten, wird empfohlen, das Bit erst unmittelbar vor Ausführung des &#039;&#039;&#039;SLEEP&#039;&#039;&#039;-Befehls zu setzen.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;SM&#039;&#039;&#039; (&#039;&#039;&#039;S&#039;&#039;&#039;leep &#039;&#039;&#039;M&#039;&#039;&#039;ode)&lt;br /&gt;
:Dieses Bit bestimmt der Schlafmodus.&lt;br /&gt;
:Ist das Bit gelöscht, so wird der &#039;&#039;&#039;Idle&#039;&#039;&#039;-Modus ausgeführt. Ist das Bit gesetzt, so wird der &#039;&#039;&#039;Power-Down&#039;&#039;&#039;-Modus ausgeführt. (für andere AVR Controller siehe Abschnitt &amp;quot;Sleep-Mode&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ISC11&#039;&#039;&#039;, &#039;&#039;&#039;ISC10&#039;&#039;&#039; (&#039;&#039;&#039;I&#039;&#039;&#039;nterrupt &#039;&#039;&#039;S&#039;&#039;&#039;ense &#039;&#039;&#039;C&#039;&#039;&#039;ontrol &#039;&#039;&#039;1&#039;&#039;&#039; Bits)&lt;br /&gt;
:Diese beiden Bits bestimmen, ob die steigende oder die fallende Flanke für die Interrupterkennung am &#039;&#039;&#039;INT1&#039;&#039;&#039;-Pin ausgewertet wird.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ISC11&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ISC10&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Bedeutung&#039;&#039;&#039;&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;
| Low Level an &#039;&#039;&#039;INT1&#039;&#039;&#039; erzeugt einen Interrupt.&lt;br /&gt;
&lt;br /&gt;
In der Beschreibung heißt es, der Interrupt wird getriggert, solange der Pin auf 0 bleibt, also eigentlich unbrauchbar.&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;
| Reserviert&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;
| Die fallende Flanke an &#039;&#039;&#039;INT1&#039;&#039;&#039; erzeugt einen Interrupt.&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;
| Die steigende Flanke an &#039;&#039;&#039;INT1&#039;&#039;&#039; erzeugt einen Interrupt.&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;ISC01&#039;&#039;&#039;, &#039;&#039;&#039;ISC00&#039;&#039;&#039; (&#039;&#039;&#039;I&#039;&#039;&#039;nterrupt &#039;&#039;&#039;S&#039;&#039;&#039;ense &#039;&#039;&#039;C&#039;&#039;&#039;ontrol &#039;&#039;&#039;0&#039;&#039;&#039; Bits)&lt;br /&gt;
:Diese beiden Bits bestimmen, ob die steigende oder die fallende Flanke für die Interrupterkennung am &#039;&#039;&#039;INT0&#039;&#039;&#039;-Pin ausgewertet wird.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ISC01&#039;&#039;&#039;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &#039;&#039;&#039;ISC00&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Bedeutung&#039;&#039;&#039;&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;
| Low Level an &#039;&#039;&#039;INT0&#039;&#039;&#039; erzeugt einen Interrupt.&lt;br /&gt;
&lt;br /&gt;
In der Beschreibung heißt es, der Interrupt wird getriggert, solange der Pin auf 0 bleibt, also eigentlich unbrauchbar.&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;
| Reserviert&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;
| Die fallende Flanke an &#039;&#039;&#039;INT0&#039;&#039;&#039; erzeugt einen Interrupt.&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;
| Die steigende Flanke an &#039;&#039;&#039;INT0&#039;&#039;&#039; erzeugt einen Interrupt.&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Allgemeines über die Interrupt-Abarbeitung ==&lt;br /&gt;
&lt;br /&gt;
Wenn ein Interrupt eintrifft, wird automatisch das &#039;&#039;&#039;Global Interrupt Enable&#039;&#039;&#039; Bit im Status Register &#039;&#039;&#039;SREG&#039;&#039;&#039; gelöscht und alle weiteren Interrupts unterbunden. Obwohl es möglich ist, zu diesem Zeitpunkt bereits wieder das GIE-bit zu setzen, rate ich dringend davon ab. Dieses wird nämlich automatisch gesetzt, wenn die Interruptroutine beendet wird. Wenn in der Zwischenzeit weitere Interrupts eintreffen, werden die zugehörigen Interrupt-Bits gesetzt und die Interrupts bei Beendigung der laufenden Interrupt-Routine in der Reihenfolge ihrer Priorität ausgeführt. Dies kann&lt;br /&gt;
eigentlich nur dann zu Problemen führen, wenn ein hoch priorisierter Interrupt ständig und in kurzer Folge auftritt. Dieser sperrt dann möglicherweise alle anderen Interrupts mit niedrigerer Priorität. Dies ist einer der Gründe, weshalb die Interrupt-Routinen sehr kurz gehalten werden sollen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- === Das Status-Register ===&lt;br /&gt;
&lt;br /&gt;
Es gilt auch zu beachten, dass das Status-Register während der Abarbeitung einer Interruptroutine nicht automatisch gesichert wird. Falls notwendig, muss dies vom Programmierer selber vorgesehen werden. --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Interrupts mit dem AVR GCC Compiler (WinAVR) ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- Selbstverständlich können alle interruptspezifischen Registerzugriffe wie gewohnt über I/O-Adressierung vorgenommen werden. Etwas einfacher geht es jedoch, wenn wir die vom Compiler zur Verfügung gestellten Mittel einsetzen.--&amp;gt;&lt;br /&gt;
Funktionen zur Interrupt-Verarbeitung werden in den Includedateien &#039;&#039;interrupt.h&#039;&#039;  der avr-libc zur Verfügung gestellt (bei älterem Quellcode zusätzlich &#039;&#039;signal.h&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
// fuer sei(), cli() und ISR():&lt;br /&gt;
#include &amp;lt;avr/interrupt.h&amp;gt;&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Makro &#039;&#039;&#039;sei()&#039;&#039;&#039; schaltet die Interrupts ein. Eigentlich wird nichts anderes gemacht, als das &#039;&#039;&#039;Global Interrupt Enable&#039;&#039;&#039; Bit im Status Register gesetzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
    sei();&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Makro &#039;&#039;&#039;cli()&#039;&#039;&#039; schaltet die Interrupts aus, oder anders gesagt, das &#039;&#039;&#039;Global Interrupt Enable&#039;&#039;&#039; Bit im Status Register wird gelöscht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
    cli();&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Oft steht man vor der Aufgabe, dass eine Codesequenz nicht unterbrochen werden darf. Es liegt dann nahe, zu Beginn dieser Sequenz ein cli() und am Ende ein sei() einzufügen. Dies ist jedoch ungünstig, wenn die Interrupts vor Aufruf der Sequenz deaktiviert waren und danach auch weiterhin deaktiviert bleiben sollen. Ein sei() würde ungeachtet des vorherigen  Zustands die Interrups aktivieren, was zu unerwünschten Seiteneffekten führen kann. Die aus dem folgenden Beispiel ersichtliche Vorgehensweise ist in solchen Fällen vorzuziehen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/interrupt.h&amp;gt;&lt;br /&gt;
#include &amp;lt;inttypes.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
void NichtUnterbrechenBitte(void)&lt;br /&gt;
{&lt;br /&gt;
   uint8_t tmp_sreg;  // temporaerer Speicher fuer das Statusregister&lt;br /&gt;
&lt;br /&gt;
   tmp_sreg = SREG;   // Statusregister (also auch das I-Flag darin) sichern&lt;br /&gt;
   cli();             // Interrupts global deaktivieren&lt;br /&gt;
&lt;br /&gt;
   /* hier &amp;quot;unterbrechnungsfreier&amp;quot; Code */&lt;br /&gt;
&lt;br /&gt;
   /* Beispiel Anfang&lt;br /&gt;
     JTAG-Interface eines ATmega16 per Software deaktivieren &lt;br /&gt;
     und damit die JTAG-Pins an PORTC für &amp;quot;general I/O&amp;quot; nutzbar machen&lt;br /&gt;
     ohne die JTAG-Fuse-Bit zu aendern. Dazu ist eine &amp;quot;timed sequence&amp;quot;&lt;br /&gt;
     einzuhalten (vgl Datenblatt ATmega16, Stand 10/04, S. 229): &lt;br /&gt;
     Das JTD-Bit muss zweimal innerhalb von 4 Taktzyklen geschrieben &lt;br /&gt;
     werden. Ein Interrupt zwischen den beiden Schreibzugriffen wuerde &lt;br /&gt;
     die erforderliche Sequenz &amp;quot;brechen&amp;quot;, das JTAG-Interface bliebe&lt;br /&gt;
     weiterhin aktiv und die IO-Pins weiterhin für JTAG reserviert. */&lt;br /&gt;
&lt;br /&gt;
   MCUCSR |= (1&amp;lt;&amp;lt;JTD);&lt;br /&gt;
   MCUCSR |= (1&amp;lt;&amp;lt;JTD); // 2 mal in Folge ,vgl. Datenblatt fuer mehr Information&lt;br /&gt;
&lt;br /&gt;
   /* Beispiel Ende */&lt;br /&gt;
  &lt;br /&gt;
   SREG = tmp_sreg;     // Status-Register wieder herstellen &lt;br /&gt;
                      // somit auch das I-Flag auf gesicherten Zustand setzen&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void NichtSoGut(void)&lt;br /&gt;
{&lt;br /&gt;
   cli();&lt;br /&gt;
   &lt;br /&gt;
   /* hier &amp;quot;unterbrechnungsfreier&amp;quot; Code */&lt;br /&gt;
   &lt;br /&gt;
   sei();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
int main(void)&lt;br /&gt;
{&lt;br /&gt;
   //...&lt;br /&gt;
&lt;br /&gt;
   cli();  &lt;br /&gt;
   // Interrupts global deaktiviert &lt;br /&gt;
&lt;br /&gt;
   NichtUnterbrechenBitte();&lt;br /&gt;
   // auch nach Aufruf der Funktion deaktiviert&lt;br /&gt;
&lt;br /&gt;
   sei();&lt;br /&gt;
   // Interrupts global aktiviert &lt;br /&gt;
&lt;br /&gt;
   NichtUnterbrechenBitte();&lt;br /&gt;
   // weiterhin aktiviert&lt;br /&gt;
   //...&lt;br /&gt;
&lt;br /&gt;
   /* Verdeutlichung der unguenstigen Vorgehensweise mit cli/sei: */&lt;br /&gt;
   cli();  &lt;br /&gt;
   // Interrupts jetzt global deaktiviert &lt;br /&gt;
&lt;br /&gt;
   NichtSoGut();&lt;br /&gt;
   // nach Aufruf der Funktion sind Interrupts global aktiviert &lt;br /&gt;
   // dies ist mglw. ungewollt!&lt;br /&gt;
   //...&lt;br /&gt;
   &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- mt: besser so nicht(?), lieber &amp;quot;datenblattkonform&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;font face=&amp;quot;Courier New&amp;quot;&amp;gt;&#039;&#039;&#039;timer_enable_int (unsigned char ints);&amp;lt;br /&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;/font&amp;gt;Schaltet Timerbezogene Interrupts ein bzw. aus.&amp;lt;br /&amp;gt;&lt;br /&gt;
Wenn als Argument &#039;&#039;&#039;ints&#039;&#039;&#039; der Wert 0 übergeben wird so werden alle&lt;br /&gt;
Timerinterrupts ausgeschaltet, ansonsten muss in &#039;&#039;&#039;ints&#039;&#039;&#039; angegeben werden,&lt;br /&gt;
welche Interrupts zu aktivieren sind. Dabei müssen einfach die entsprechend zu&lt;br /&gt;
setzenden Bits definiert werden.&amp;lt;br /&amp;gt;&lt;br /&gt;
Beispiel: &#039;&#039;&#039;&amp;lt;font face=&amp;quot;Courier New&amp;quot;&amp;gt;timer_enable_int (1 &amp;lt;&amp;lt; TOIE1));&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;/font&amp;gt;&#039;&#039;&#039;Achtung: Wenn ein Timerinterrupt eingeschaltet wird während ein&lt;br /&gt;
anderer Timerinterrupt bereits läuft, dann müssen beide Bits angegeben werden&lt;br /&gt;
sonst wird der andere Timerinterrupt versehentlich ausgeschaltet.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;font face=&amp;quot;Courier New&amp;quot;&amp;gt;&#039;&#039;&#039;enable_external_int (unsigned char ints);&amp;lt;br /&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;/font&amp;gt;Schaltet die externen Interrupts ein bzw. aus.&amp;lt;br /&amp;gt;&lt;br /&gt;
Wenn als Argument &#039;&#039;&#039;ints&#039;&#039;&#039; der Wert 0 übergeben wird so werden alle externen&lt;br /&gt;
Interrrups ausgeschaltet, ansonsten muss in &#039;&#039;&#039;ints&#039;&#039;&#039; angegeben werden, welche&lt;br /&gt;
Interrupts zu aktivieren sind. Dabei müssen einfach die entsprechend zu&lt;br /&gt;
setzenden Bits definiert werden.&amp;lt;br /&amp;gt;&lt;br /&gt;
Beispiel: &#039;&#039;&#039;&amp;lt;font face=&amp;quot;Courier New&amp;quot;&amp;gt;enable_external_int ((1&amp;lt;&lt;br /&gt;
&amp;lt;/font&amp;gt;&#039;&#039;&#039;Schaltet die externen Interrupts 0 und 1 ein.&lt;br /&gt;
&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nachdem nun die Interrupts aktiviert sind, braucht es selbstverständlich noch den auszuführenden Code, der ablaufen soll, wenn ein Interrupt eintrifft. Dazu existiert die Definition (ein Makro) &#039;&#039;&#039;ISR&#039;&#039;&#039;. SIGNAL sollte nicht mehr genutzt werden, zur Portierung von SIGNAL nach ISR siehe Abschnitt (TODO: verlinken) im Anhang.&lt;br /&gt;
&amp;lt;!--Dazu gibt es zwei Definitionen: &#039;&#039;&#039;SIGNAL&#039;&#039;&#039; und &#039;&#039;&#039;INTERRUPT&#039;&#039;&#039;, welche allerdings AVR-GCC spezifisch sind und bei anderen Compilern womöglich anders heissen können.--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== ISR ===&lt;br /&gt;
&lt;br /&gt;
(&#039;&#039;ISR()&#039;&#039; ersetzt bei neueren Versionen der avr-libc &#039;&#039;SIGNAL()&#039;&#039;. vgl. [[AVR-GCC-Tutorial#Anhang|Anhang]])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/signal.h&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
SIGNAL (siglabel)&lt;br /&gt;
{&lt;br /&gt;
    /* Interrupt Code */&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/interrupt.h&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
ISR(Vectorname) /* vormals: SIGNAL(siglabel) dabei Vectorname != siglabel ! */&lt;br /&gt;
{&lt;br /&gt;
    /* Interrupt Code */&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;ISR&#039;&#039; wird eine Funktion für die Bearbeitung eines Interrupts eingeleitet. Als Argument muss dabei die Benennung des entsprechenden Interruptvektors angegeben werden. Diese sind in den jeweiligen Includedateien IOxxxx.h zu finden. Die Bezeichnung entspricht dem Namen aus dem Datenblatt, bei dem die Leerzeichen durch Unterstriche ersetzt sind und ein &#039;&#039;_vect&#039;&#039; angehängt ist.&lt;br /&gt;
&lt;br /&gt;
Als Beispiel ein Ausschnitt aus der Datei für den ATmega8 (bei WinAVR Standardinstallation in C:\WinAVR\avr\include\avr\iom8.h) in der neben den aktuellen Namen für &#039;&#039;ISR&#039;&#039; (*_vect) noch die Bezeichnungen für das inzwischen nicht mehr aktuelle &#039;&#039;SIGNAL&#039;&#039; (SIG_*) enthalten sind.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
/* $Id: iom8.h,v 1.13 2005/10/30 22:11:23 joerg_wunsch Exp $ */&lt;br /&gt;
&lt;br /&gt;
/* avr/iom8.h - definitions for ATmega8 */&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
/* Interrupt vectors */&lt;br /&gt;
&lt;br /&gt;
/* External Interrupt Request 0 */&lt;br /&gt;
#define INT0_vect                       _VECTOR(1)&lt;br /&gt;
#define SIG_INTERRUPT0                  _VECTOR(1)&lt;br /&gt;
&lt;br /&gt;
/* External Interrupt Request 1 */&lt;br /&gt;
#define INT1_vect                       _VECTOR(2)&lt;br /&gt;
#define SIG_INTERRUPT1                  _VECTOR(2)&lt;br /&gt;
&lt;br /&gt;
/* Timer/Counter2 Compare Match */&lt;br /&gt;
#define TIMER2_COMP_vect                _VECTOR(3)&lt;br /&gt;
#define SIG_OUTPUT_COMPARE2             _VECTOR(3)&lt;br /&gt;
&lt;br /&gt;
/* Timer/Counter2 Overflow */&lt;br /&gt;
#define TIMER2_OVF_vect                 _VECTOR(4)&lt;br /&gt;
#define SIG_OVERFLOW2                   _VECTOR(4)&lt;br /&gt;
&lt;br /&gt;
/* Timer/Counter1 Capture Event */&lt;br /&gt;
#define TIMER1_CAPT_vect                _VECTOR(5)&lt;br /&gt;
#define SIG_INPUT_CAPTURE1              _VECTOR(5)&lt;br /&gt;
&lt;br /&gt;
/* Timer/Counter1 Compare Match A */&lt;br /&gt;
#define TIMER1_COMPA_vect               _VECTOR(6)&lt;br /&gt;
#define SIG_OUTPUT_COMPARE1A            _VECTOR(6)&lt;br /&gt;
&lt;br /&gt;
/* Timer/Counter1 Compare Match B */&lt;br /&gt;
#define TIMER1_COMPB_vect               _VECTOR(7)&lt;br /&gt;
#define SIG_OUTPUT_COMPARE1B            _VECTOR(7)&lt;br /&gt;
&lt;br /&gt;
//...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--Vor Nutzung von SIGNAL muss ebenfalls die Header-Datei signal.h eingebunden werden.--&amp;gt; &lt;br /&gt;
Mögliche Funktionsrümpfe für Interruptfunktionen sind zum Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/interrupt.h&amp;gt;&lt;br /&gt;
/* veraltet: #include &amp;lt;avr/signal.h&amp;gt; */&lt;br /&gt;
&lt;br /&gt;
ISR(INT0_vect)       /* veraltet: SIGNAL(SIG_INTERRUPT0) */&lt;br /&gt;
{&lt;br /&gt;
    /* Interrupt Code */&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
ISR(TIMER0_OVF_vect) /* veraltet: SIGNAL(SIG_OVERFLOW0) */&lt;br /&gt;
{&lt;br /&gt;
    /* Interrupt Code */&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
ISR(USART_RXC_vect) /* veraltet: SIGNAL(SIG_UART_RECV) */&lt;br /&gt;
{&lt;br /&gt;
    /* Interrupt Code */&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// und so weiter und so fort...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Auf die korrekte Schreibweise der Vektorbezeichnung ist zu achten. Der gcc-Compiler prüft erst ab Version 4.x, ob ein Signal/Interrupt der angegebenen Bezeichnung tatsächlich in der Includedatei definiert ist und gibt andernfalls eine Warnung aus. Bei WinAVR (ab 2/2005) wurde die Überprüfung auch in den mitgelieferten Compiler der Version 3.x integriert. Aus dem gcc-Quellcode Version 3.x selbst erstellte Compiler enthalten die Prüfung nicht (vgl. [[AVR-GCC]]). &lt;br /&gt;
&lt;br /&gt;
Während der Ausführung der Funktion sind alle weiteren Interrupts automatisch gesperrt. Beim Verlassen der Funktion werden die Interrupts wieder zugelassen.&lt;br /&gt;
&lt;br /&gt;
Sollte während der Abarbeitung der Interruptroutine ein weiterer Interrupt (gleiche oder andere Interruptquelle) auftreten, so wird das entsprechende Bit im zugeordneten Interrupt Flag Register gesetzt und die entsprechende Interruptroutine automatisch nach dem Beenden der aktuellen Funktion aufgerufen.&lt;br /&gt;
&lt;br /&gt;
Ein Problem ergibt sich eigentlich nur dann, wenn während der Abarbeitung der aktuellen Interruptroutine mehrere gleichartige Interrupts auftreten. Die entsprechende Interruptroutine wird im Nachhinein zwar aufgerufen jedoch wissen wir nicht, ob nun der entsprechende Interrupt einmal, zweimal oder gar noch öfter aufgetreten ist. Deshalb soll hier noch einmal betont werden, dass Interruptroutinen so schnell wie nur irgend möglich wieder verlassen werden sollten.&lt;br /&gt;
&lt;br /&gt;
=== Unterbrechbare Interruptroutinen ===&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Faustregel&amp;quot;: im Zweifel &#039;&#039;&#039;ISR&#039;&#039;&#039;. Die nachfolgend beschriebene Methode nur dann verwenden, wenn man sich über die unterschiedliche Funktionsweise im Klaren ist.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/interrupt.h&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
INTERRUPT (signame)&lt;br /&gt;
{&lt;br /&gt;
    /* Interrupt Code */&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/interrupt.h&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
void XXX_vect(void) __attribute__((interrupt));&lt;br /&gt;
void XXX_vect(void) {&lt;br /&gt;
  //...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hierbei steht XXX für den oben beschriebenen Namen des Vektors (also z.B. &#039;&#039;void TIMER0_OVF_vect(void)...&#039;&#039;). Der Unterschied im Vergleich zu ISR ist, dass hier beim Aufrufen der Funktion das &#039;&#039;&#039;Global Enable Interrupt&#039;&#039;&#039; Bit automatisch wieder gesetzt und somit weitere Interrupts zugelassen werden. Dies kann zu nicht unerheblichen Problemen von im einfachsten Fall einem Stack overflow bis zu sonstigen unerwarteten Effekten führen und sollte wirklich &#039;&#039;&#039;nur dann&#039;&#039;&#039; angewendet werden, wenn man sich absolut sicher ist, das Ganze auch im Griff zu haben.  &amp;lt;!--Vor Nutzung von INTERRUPT muss die Header-Datei interrupt.h eingebunden werden.--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
siehe auch: Hinweise in [[AVR-GCC]]&lt;br /&gt;
&lt;br /&gt;
siehe dazu: http://www.nongnu.org/avr-libc/user-manual/group__avr__interrupts.html&lt;br /&gt;
&lt;br /&gt;
== Datenaustausch mit Interrupt-Routinen ==&lt;br /&gt;
&lt;br /&gt;
Variablen die sowohl in Interrupt-Routinen (ISR = Interrupt Service Routine(s)), als auch vom übrigen Programmcode geschrieben oder gelesen werden, müssen mit einem &#039;&#039;&#039;volatile&#039;&#039;&#039; deklariert werden. Damit wird dem Compiler mitgeteilt, dass der Inhalt der Variablen vor jedem Lesezugriff aus dem Speicher gelesen und nach jedem Schreibzugriff in den Speicher geschrieben wird. Ansonsten könnte der Compiler den Code so optimieren, dass der Wert der Variablen nur &lt;br /&gt;
in Prozessorregistern zwischengespeichert wird, die nichts von der Änderung woanders mitbekommen.&lt;br /&gt;
&lt;br /&gt;
Zur Veranschaulichung ein Codefragment für eine Tastenentprellung mit Erkennung einer &amp;quot;lange gedrückten&amp;quot; Taste.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/interrupt.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
// Schwellwerte&lt;br /&gt;
// Entprellung: &lt;br /&gt;
#define CNTDEBOUNCE 10&lt;br /&gt;
// &amp;quot;lange gedrueckt:&amp;quot;&lt;br /&gt;
#define CNTREPEAT 200&lt;br /&gt;
&lt;br /&gt;
// hier z.B. Taste an Pin2 PortA &amp;quot;active low&amp;quot; = 0 wenn gedrueckt&lt;br /&gt;
#define KEY_PIN  PINA&lt;br /&gt;
#define KEY_PINNO PA2&lt;br /&gt;
&lt;br /&gt;
// beachte: volatile! &lt;br /&gt;
volatile uint8_t gKeyCounter;&lt;br /&gt;
&lt;br /&gt;
// Timer-Compare Interrupt ISR, wird z.B. alle 10ms ausgefuehrt&lt;br /&gt;
ISR(TIMER1_COMPA_vect)&lt;br /&gt;
{&lt;br /&gt;
   // hier wird gKeyCounter veraendert. Die übrigen&lt;br /&gt;
   // Programmteile müssen diese Aenderung &amp;quot;sehen&amp;quot;:&lt;br /&gt;
   // volatile -&amp;gt; aktuellen Wert immer in den Speicher schreiben&lt;br /&gt;
   if ( !(KEY_PIN &amp;amp; (1&amp;lt;&amp;lt;KEY_PINNO)) ) {&lt;br /&gt;
      if (gKeyCounter &amp;lt; CNTREPEAT) gKeyCounter++;&lt;br /&gt;
   }&lt;br /&gt;
   else {&lt;br /&gt;
      gKeyCounter = 0;&lt;br /&gt;
   }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
int main(void)&lt;br /&gt;
{&lt;br /&gt;
//...&lt;br /&gt;
    /* hier: Initialisierung der Ports und des Timer-Interrupts */&lt;br /&gt;
//... &lt;br /&gt;
   // hier wird auf gKeyCounter zugegriffen. Dazu muss der in der&lt;br /&gt;
   // ISR geschriebene Wert bekannt sein:&lt;br /&gt;
   // volatile -&amp;gt; aktuellen Wert immer aus dem Speicher lesen&lt;br /&gt;
   if ( gKeyCounter &amp;gt; CNTDEBOUNCE ) { // Taste mind. 10*10 ms &amp;quot;prellfrei&amp;quot;&lt;br /&gt;
       if (gKeyCounter == CNTREPEAT) {&lt;br /&gt;
          /* hier: Code fuer &amp;quot;Taste lange gedrueckt&amp;quot; */&lt;br /&gt;
       }&lt;br /&gt;
       else {&lt;br /&gt;
          /* hier: Code fuer &amp;quot;Taste kurz gedrueckt&amp;quot; */&lt;br /&gt;
       }&lt;br /&gt;
   }&lt;br /&gt;
//...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== volatile und Pointer ===&lt;br /&gt;
&lt;br /&gt;
Bei &#039;&#039;&#039;volatile&#039;&#039;&#039; in Verbindung mit Pointern ist zu beachten, ob der Pointer selbst oder die Variable auf die der Pointer zeigt &#039;&#039;&#039;volatile&#039;&#039;&#039; ist.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
volatile uint8_t *a;   // das Ziel von a ist volatile&lt;br /&gt;
&lt;br /&gt;
uint8_t *volatile a;   // a selbst ist volatile&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Variablen größer 1 Byte ===&lt;br /&gt;
&lt;br /&gt;
Bei Variablen größer ein Byte, auf die in Interrupt-Routinen und im Hauptprogramm zugegriffen wird, muss darauf geachtet werden, dass die Zugriffe auf die einzelnen Bytes außerhalb der ISR nicht durch einen Interrupt unterbrochen werden. (Allgemeinplatz: AVRs sind 8-bit Controller). Zur Veranschaulichung ein Codefragment:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
volatile uint16_t gMyCounter16bit;&lt;br /&gt;
//...&lt;br /&gt;
ISR(...)&lt;br /&gt;
{&lt;br /&gt;
//...&lt;br /&gt;
   gMyCounter16Bit++;&lt;br /&gt;
//...&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int main(void)&lt;br /&gt;
{&lt;br /&gt;
   uint16_t tmpCnt;&lt;br /&gt;
//...&lt;br /&gt;
   // nicht gut: Mglw. hier ein Fehler, wenn ein Byte von MyCounter &lt;br /&gt;
   // schon in tmpCnt kopiert ist aber vor dem Kopieren des zweiten Bytes &lt;br /&gt;
   // ein Interrupt auftritt, der den Inhalt von MyCounter verändert.&lt;br /&gt;
   tmpCnt = gMyCounter16bit; &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
   // besser: Änderungen &amp;quot;außerhalb&amp;quot; verhindern -&amp;gt; alle &amp;quot;Teilbytes&amp;quot;&lt;br /&gt;
   // bleiben konsistent&lt;br /&gt;
   cli();  // Interupts deaktivieren&lt;br /&gt;
   tmpCnt = gMyCounter16Bit;&lt;br /&gt;
   sei();  // wieder aktivieren&lt;br /&gt;
&lt;br /&gt;
   // oder: vorheriger Status des globalen Interrupt-Flags bleibt erhalten&lt;br /&gt;
   uint8_t sreg_tmp;&lt;br /&gt;
   sreg_tmp = SREG;    /* Sichern */&lt;br /&gt;
   cli()&lt;br /&gt;
   tmpCnt = gMyCounter16Bit;&lt;br /&gt;
   SREG = sreg_tmp;    /* Wiederherstellen */&lt;br /&gt;
&lt;br /&gt;
   // oder: mehrfach lesen, bis man konsistente Daten hat&lt;br /&gt;
   uint16_t count1 = gMyCounter16Bit;&lt;br /&gt;
   uint16_t count2 = gMyCounter16Bit;&lt;br /&gt;
   while (count1 != count2) {&lt;br /&gt;
       count1 = count2;&lt;br /&gt;
       count2 = gMyCounter16Bit;&lt;br /&gt;
   }&lt;br /&gt;
   tmpCnt = count1;&lt;br /&gt;
//...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Interrupt-Routinen und Registerzugriffe ==&lt;br /&gt;
&lt;br /&gt;
Falls Register sowohl im Hauptprogramm als auch in Interrupt-Routinen verändert werden, ist darauf zu achten, dass diese Zugriffe sich nicht überlappen. Nur wenige Anweisungen lassen sich in sogenannte &amp;quot;atomare&amp;quot; Zugriffe übersetzen, die nicht von Interrupt-Routinen unterbrochen werden können. &lt;br /&gt;
&lt;br /&gt;
Zur Veranschaulichung eine Anweisung, bei der ein Bit und im Anschluss drei Bits in einem Register gesetzt werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
int main(void)&lt;br /&gt;
{&lt;br /&gt;
//...&lt;br /&gt;
	PORTA |= (1&amp;lt;&amp;lt;PA0);&lt;br /&gt;
	&lt;br /&gt;
	PORTA |= (1&amp;lt;&amp;lt;PA2)|(1&amp;lt;&amp;lt;PA3)|(1&amp;lt;&amp;lt;PA4);&lt;br /&gt;
//...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Compiler übersetzt diese Anweisungen für einen ATmega128 bei Optimierungsstufe &amp;quot;S&amp;quot; nach:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;code&amp;quot;&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
        PORTA |= (1&amp;lt;&amp;lt;PA0);&lt;br /&gt;
  d2:	d8 9a       	sbi	0x1b, 0	; 27 (a)&lt;br /&gt;
	&lt;br /&gt;
        PORTA |= (1&amp;lt;&amp;lt;PA2)|(1&amp;lt;&amp;lt;PA3)|(1&amp;lt;&amp;lt;PA4);&lt;br /&gt;
  d4:	8b b3       	in	r24, 0x1b	; 27 (b)&lt;br /&gt;
  d6:	8c 61       	ori	r24, 0x1C	; 28 (c)&lt;br /&gt;
  d8:	8b bb       	out	0x1b, r24	; 27 (d)&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Setzen des einzelnen Bits wird bei eingeschalteter Optimierung für Register im unteren Speicherbereich in eine einzige Assembler-Anweisung (sbi) übersetzt und ist nicht anfällig für Unterbrechnungen durch Interrupts. Die Anweisung zum Setzen von drei Bits wird jedoch in drei abhängige Assembler-Anweisungen übersetzt und bietet damit zwei &amp;quot;Angriffspunkte&amp;quot; für Unterbrechnungen. Eine Interrupt-Routine könnte nach dem Laden des Ausgangszustands in den Zwischenspeicher (hier Register 24) den Wert des Registers ändern, z.B. ein Bit löschen. Damit würde der Zwischenspeicher nicht mehr mit dem tatsächlichen Zustand übereinstimmen aber dennoch nach der Bitoperation (hier ori) in das Register zurückgeschrieben. &lt;br /&gt;
&lt;br /&gt;
Beispiel: PORTA sei anfangs 0b00000000. Die erste Anweisung (a) setzt Bit 0, PORTA ist danach 0b00000001. Nun wird im ersten Teil der zweiten Anweisung der Portzustand in ein Register eingelesen (b). Unmittelbar darauf (vor (c)) &amp;quot;feuert&amp;quot; ein Interrupt, in dessen Interrupt-Routine Bit 0 von PORTA gelöscht wird. Nach Verlassen der Interrupt-Routine hat PORTA den Wert 0b00000000. In den beiden noch folgenden Anweisungen des Hauptprogramms wird nun der zwischengespeicherte &amp;quot;alte&amp;quot; Zustand 0b00000001 mit 0b00011100 logisch-oder-verknüft (c) und das Ergebnis 0b00011101 in PortA geschrieben (d). Obwohl zwischenzeitlich Bit 0 gelöscht wurde, ist es nach (d) wieder gesetzt. &lt;br /&gt;
&lt;br /&gt;
Lösungsmöglichkeiten:&lt;br /&gt;
* Register ohne besondere Vorkehrungen nicht in Interruptroutinen &#039;&#039;und&#039;&#039; im Hauptprogramm verändern.&lt;br /&gt;
* Interrupts vor Veränderungen in Registern, die auch in ISRs verändert werden, deaktivieren (&amp;quot;cli&amp;quot;).&lt;br /&gt;
* Bits einzeln löschen oder setzen. sbi und cbi können nicht unterbrochen werden. Vorsicht: nur Register im unteren Speicherbereich sind mittels sbi/cbi ansprechbar. Der Compiler kann nur für diese sbi/cbi-Anweisungen generieren. Für Register außerhalb dieses Adressbereichs (&amp;quot;Memory-Mapped&amp;quot;-Register) werden auch zur Manipulation einzelner Bits abhängige Anweisungen erzeugt (lds,...,sts).&lt;br /&gt;
&lt;br /&gt;
* siehe auch: [http://www.nongnu.org/avr-libc/user-manual/index.html Dokumentation der avr-libc] Frequently asked Questions/Fragen Nr. 1 und 8. (Stand: avr-libc Vers. 1.0.4)&lt;br /&gt;
&lt;br /&gt;
== Was macht das Hauptprogramm? ==&lt;br /&gt;
&lt;br /&gt;
Im einfachsten (Ausnahme-)Fall gar nichts mehr. Es ist also durchaus denkbar, ein Programm zu schreiben, welches in der main-Funktion lediglich noch die Interrupts aktiviert und dann in einer Endlosschleife verharrt. Sämtliche Funktionen werden dann in den ISRs abgearbeitet. Diese Vorgehensweise ist jedoch bei den meisten Anwendungen schlecht: man verschenkt eine Verarbeitungsebene und hat außerdem möglicherweise Probleme durch Interruptroutinen, die zu viel Verarbeitungszeit benötigen.&lt;br /&gt;
&lt;br /&gt;
Normalerweise wird man in den Interruptroutinen nur die bei Auftreten des jeweiligen Interruptereignisses unbedingt notwendigen Operationen ausführen lassen. Alle weniger kritischen Aufgaben werden dann im Hauptprogramm abgearbeitet.&lt;br /&gt;
&lt;br /&gt;
* siehe auch: [http://www.nongnu.org/avr-libc/user-manual/index.html Dokumentation der avr-libc] Abschnitt Modules/Interrupts and Signals&lt;br /&gt;
&lt;br /&gt;
= Sleep-Modes =&lt;br /&gt;
&lt;br /&gt;
AVR Controller verfügen über eine Reihe von sogenannten &#039;&#039;Sleep-Modes&#039;&#039; (&amp;quot;Schlaf-Modi&amp;quot;). Diese ermöglichen es, Teile des Controllers abzuschalten. Zum Einen kann damit besonders bei Batteriebetrieb Strom gespart werden, zum Anderen können Komponenten des Controllers deaktiviert werden, die die Genauigkeit des Analog-Digital-Wandlers bzw. des Analog-Comparators negativ beeinflussen. Der Controller wird durch Interrupts aus dem Schlaf geweckt. Welche Interrupts den jeweiligen Schlafmodus beenden, ist einer Tabelle im Datenblatt des jeweiligen Controllers zu entnehmen.&lt;br /&gt;
Die Funktionen (eigentlich Makros) der avr-libc stehen nach Einbinden der header-Datei &#039;&#039;sleep.h&#039;&#039; zur Verfügung.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;set_sleep_mode(uint8_t mode)&#039;&#039;&#039;&lt;br /&gt;
:Setzt den Schlafmodus, der bei Aufruf von sleep() aktiviert wird. In sleep.h sind einige Konstanten definiert (z.B. SLEEP_MODE_PWR_DOWN). Die definierten Modi werden jedoch nicht alle von sämtlichten AVR-Controllern unterstützt.&lt;br /&gt;
* &#039;&#039;&#039;sleep_enable()&#039;&#039;&#039;&lt;br /&gt;
:aktiviert den gesetzten Schlafmodus, versetzt den Controller aber noch nicht in den Schlafmodus&lt;br /&gt;
* &#039;&#039;&#039;sleep_cpu()&#039;&#039;&#039;&lt;br /&gt;
: Versetzt den Controller in den Schlafmodus (sleep_cpu wird im Prinzip durch die Assembler-Anweisung &#039;&#039;sleep&#039;&#039; ersetzt)&lt;br /&gt;
* &#039;&#039;&#039;sleep_disable()&#039;&#039;&#039;&lt;br /&gt;
:deaktiviert den gesetzten Schlafmodus&lt;br /&gt;
* &#039;&#039;&#039;sleep_mode()&#039;&#039;&#039;&lt;br /&gt;
:Versetzt den Controller in den mit set_sleep_mode gewählten Schlafmodus. Das Makro entspricht sleep_enable()+sleep_cpu()+sleep_disable(), beinhaltet also nicht die Aktivierung von Interrupts (besser nicht benutzen).&lt;br /&gt;
&lt;br /&gt;
Bei Anwendung von sleep_cpu() müssen Interrupts also bereits freigeben sein (sei()), da der Controller sonst nicht mehr &amp;quot;aufwachen&amp;quot; kann. sleep_mode() ist nicht geeignet für die Verwendung in ISR Interrupt-Service-Routinen, da bei deren Abarbeitung Interrupts global deaktiviert sind und somit auch die möglichen &amp;quot;Aufwachinterrupts&amp;quot;. Abhilfe: stattdessen sleep_enable(), sei(), sleep_cpu(), sleep_disable() und evtl. cli() verwenden (vgl. Dokumentation der avr-libc).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/sleep.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
int main(void)&lt;br /&gt;
{&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
   while (1) {&lt;br /&gt;
...&lt;br /&gt;
      set_sleep_mode(SLEEP_MODE_PWR_DOWN);&lt;br /&gt;
      sleep_mode();&lt;br /&gt;
   &lt;br /&gt;
      // Code hier wird erst nach Auftreten eines entsprechenden&lt;br /&gt;
      // &amp;quot;Aufwach-Interrupts&amp;quot; verarbeitet&lt;br /&gt;
...&lt;br /&gt;
   }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In älteren Versionenen der avr-libc wurden nicht alle AVR-Controller durch die sleep-Funktionen richtig angesteuert. Mit avr-libc 1.2.0 wurde die Anzahl der unterstützten Typen jedoch deutlich erweitert. Bei nicht-unterstützten Typen erreicht man die gewünschte Funktionalität durch direkte &amp;quot;[[Bitmanipulation]]&amp;quot; der entsprechenden Register (vgl. Datenblatt) und Aufruf des Sleep-Befehls via Inline-Assembler oder sleep_cpu():&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
   // Sleep-Mode &amp;quot;Power-Save&amp;quot; beim ATmega169 &amp;quot;manuell&amp;quot; aktivieren&lt;br /&gt;
   SMCR = (3&amp;lt;&amp;lt;SM0) | (1&amp;lt;&amp;lt;SE);&lt;br /&gt;
   asm volatile (&amp;quot;sleep&amp;quot;::); // alternativ sleep_cpu() aus sleep.h&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* siehe auch: [http://www.nongnu.org/avr-libc/user-manual/index.html Dokumentation der avr-libc] Abschnitt Modules/Power Management and Sleep-Modes&lt;br /&gt;
* [http://www.mikrocontroller.net/topic/96369#832712 Forenbeitrag] zur &amp;quot;Nichtverwendung&amp;quot; von sleep_mode in ISRs.&lt;br /&gt;
&lt;br /&gt;
= Speicherzugriffe =&lt;br /&gt;
&lt;br /&gt;
Atmel AVR-Controller verfügen typisch über drei Speicher:&lt;br /&gt;
&lt;br /&gt;
* [[RAM]]: Im RAM (genauer statisches RAM/SRAM) wird vom gcc-Compiler Platz für Variablen reserviert. Auch der Stack befindet sich im RAM. Dieser Speicher ist &amp;quot;flüchtig&amp;quot;, d.h. der Inhalt der Variablen geht beim Ausschalten oder einem Zusammenbruch der Spannungsversorgung verloren.&lt;br /&gt;
&lt;br /&gt;
* Programmspeicher: Ausgeführt als FLASH-Speicher, seitenweise wiederbeschreibbar. Darin ist das Anwendungsprogramm abgelegt.&lt;br /&gt;
&lt;br /&gt;
* [[EEPROM]]: Nichtflüchtiger Speicher, d.h. der einmal geschriebene Inhalt bleibt auch ohne Stromversorgung erhalten. Byte-weise schreib/lesbar. Im EEPROM werden typischerweise gerätespezifische Werte wie z.B. Kalibrierungswerte von Sensoren abgelegt.&lt;br /&gt;
&lt;br /&gt;
Einige AVRs besitzen keinen RAM-Speicher, lediglich die Register können als &amp;quot;Arbeitsvariablen&amp;quot;&lt;br /&gt;
genutzt werden. Da die Anwendung des avr-gcc auf solch &amp;quot;kleinen&amp;quot; Controllern ohnehin selten sinnvoll ist und auch nur bei einigen RAM-losen Typen nach [http://lightner.net/avr/ATtinyAvrGcc.html &amp;quot;Bastelarbeiten&amp;quot;] möglich ist, werden diese Controller hier nicht weiter berücksichtigt. Auch EEPROM-Speicher ist nicht auf allen Typen verfügbar. Generell sollten die nachfolgenden Erläuterungen auf alle ATmega-Controller und die größeren AT90-Typen übertragbar sein. Für die Typen ATtiny2313, ATtiny26 und viele weitere der &amp;quot;ATtiny-Reihe&amp;quot; gelten die Ausführungen ebenfalls.&lt;br /&gt;
&lt;br /&gt;
== RAM ==&lt;br /&gt;
&lt;br /&gt;
Die Verwaltung des RAM-Speichers erfolgt durch den Compiler, im Regelfall ist beim Zugriff auf Variablen im RAM nichts Besonderes zu beachten. Die Erläuterungen in jedem brauchbaren C-Buch gelten auch für den vom avr-gcc-Compiler erzeugten Code.&lt;br /&gt;
&lt;br /&gt;
Um Speicher dynamisch (während der Laufzeit) zu reservieren, kann &#039;&#039;&#039;malloc()&#039;&#039;&#039; verwendet werden. malloc(size) &amp;quot;allozieren&amp;quot; (~reserviert) einen gewissen Speicherblock mit &#039;&#039;&#039;size&#039;&#039;&#039; Bytes. Ist kein Platz für den neuen Block, wird NULL (0) zurückgegeben.&lt;br /&gt;
&lt;br /&gt;
Wird der angelegte Block zu klein (groß), kann die Größe mit realloc() verändert werden. Den allozierten Speicherbereich kann man mit free() wieder freigeben. Wenn das Freigeben eines Blocks vergessen wird spricht man von einem &amp;quot;Speicherleck&amp;quot; (memory leak).&lt;br /&gt;
&lt;br /&gt;
malloc() legt Speicherblöcke im &#039;&#039;&#039;Heap&#039;&#039;&#039; an, belegt man zuviel Platz, dann wächst der Heap zu weit nach oben und überschreibt den Stack, und der Controller kommt in Teufels Küche. Das kann leider nicht nur passieren wenn man insgesamt zu viel Speicher anfordert, sondern auch wenn man Blöcke unterschiedlicher Größe in ungünstiger Reihenfolge alloziert/freigibt (siehe Artikel [[Heap-Fragmentierung]]). Aus diesem Grund sollte man malloc() auf Mikrocontrollern sehr sparsam (am besten gar nicht) verwenden.&lt;br /&gt;
&lt;br /&gt;
Beispiel zur Verwendung von malloc():&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
void foo(void) {&lt;br /&gt;
  // neuen speicherbereich anlegen,&lt;br /&gt;
  // platz für 10 uint16&lt;br /&gt;
  uint16_t* pBuffer = malloc(10 * sizeof(uint16_t));&lt;br /&gt;
&lt;br /&gt;
  // darauf zugreifen, als wärs ein gewohnter Buffer&lt;br /&gt;
  pBuffer[2] = 5;&lt;br /&gt;
&lt;br /&gt;
  // Speicher (unbedingt!) wieder freigeben&lt;br /&gt;
  free(pBuffer);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn (wie in obigem Beispiel) dynamischer Speicher nur für die Dauer einer Funktion benötigt und am Ende wieder freigegeben wird, bietet es sich an, statt malloc() &#039;&#039;&#039;alloca()&#039;&#039;&#039; zu verwenden. Der Unterschied zu malloc() ist, dass der Speicher auf dem Stack reserviert wird, und beim Verlassen der Funktion automatisch wieder freigegeben wird. Es kann somit kein Speicherleck und keine Fragmentierung entstehen.&lt;br /&gt;
&lt;br /&gt;
siehe auch:&lt;br /&gt;
* http://www.nongnu.org/avr-libc/user-manual/malloc.html&lt;br /&gt;
&lt;br /&gt;
== Programmspeicher (Flash) ==&lt;br /&gt;
&lt;br /&gt;
Ein Zugriff auf Konstanten im Programmspeicher ist mittels avr-gcc nicht &amp;quot;transparent&amp;quot; möglich. D.h. es sind besondere Zugriffsfunktionen erforderlich, um Daten aus diesem Speicher zu lesen. Grundsätzlich basieren alle Zugriffsfunktionen auf der Assembler-Anweisung lpm (load program memory, bei AVR Controllern mit mehr als 64kB Flash auch elpm). Die Standard-Laufzeitbibliothek des avr-gcc (die avr-libc) stellt diese Funktionen nach Einbinden der Header-Datei pgmspace.h zur Verfügung. Mit diesen Funktionen können einzelne Bytes, Datenworte (16bit) und Datenblöcke gelesen werden. &lt;br /&gt;
&lt;br /&gt;
Deklarationen von Variablen im Flash-Speicher werden durch das &amp;quot;Attribut&amp;quot; PROGMEM ergänzt. Lokale Variablen (eigentlich Konstanten) innerhalb von Funktionen können ebenfalls im Programmspeicher abgelegt werden. Dazu ist bei der Definition jedoch ein &#039;&#039;static&#039;&#039; voranzustellen, da solche &amp;quot;Variablen&amp;quot; nicht auf dem Stack bzw. (bei Optimierung) in Registern verwaltet werden können. Der Compiler &amp;quot;wirft&amp;quot; eine Warnung falls static fehlt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/pgmspace.h&amp;gt;&lt;br /&gt;
#include &amp;lt;inttypes.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
/* Byte */&lt;br /&gt;
const uint8_t pgmFooByte PROGMEM = 123;&lt;br /&gt;
&lt;br /&gt;
/* Wort */&lt;br /&gt;
const uint16_t pgmFooWort PROGMEM = 12345;&lt;br /&gt;
&lt;br /&gt;
/* Byte-Feld */&lt;br /&gt;
const uint8_t pgmFooByteArray1[] PROGMEM = { 18, 3 ,70 };&lt;br /&gt;
const uint8_t pgmFooByteArray2[] PROGMEM = { 30, 7 ,79 };&lt;br /&gt;
&lt;br /&gt;
/* Zeiger */&lt;br /&gt;
const uint8_t *pgmPointerToArray1 PROGMEM = pgmFooByteArray1;&lt;br /&gt;
const uint8_t *pgmPointerArray[] PROGMEM = { pgmFooByteArray1, pgmFooByteArray2 };&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
void foo(void)&lt;br /&gt;
{&lt;br /&gt;
  static /*const*/ uint8_t pgmTestByteLocal PROGMEM = 0x55;&lt;br /&gt;
  static /*const*/ char pgmTestStringLocal[] PROGMEM = &amp;quot;im Flash&amp;quot;;&lt;br /&gt;
  // so nicht (static fehlt): char pgmTestStringLocalFalsch [] PROGMEM = &amp;quot;so nicht&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 // ...&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Byte lesen ===&lt;br /&gt;
&lt;br /&gt;
Mit der Funktion pgm_read_byte aus pgmspace.h erfolgt der Zugriff auf die Daten. Parameter der Funktion ist die Adresse des Bytes im Flash-Speicher.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
const uint8_t pgmFooByte PROGMEM = 123;&lt;br /&gt;
const uint8_t pgmFooByteArray1[] PROGMEM = { 18, 3 ,70 };&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    // Wert der Ram-Variablen myByte auf den Wert von pgmFooByte setzen:&lt;br /&gt;
    uint8_t myByte;&lt;br /&gt;
&lt;br /&gt;
    myByte = pgm_read_byte(&amp;amp;pgmFooByte);&lt;br /&gt;
    // myByte hat nun den Wert 123&lt;br /&gt;
&lt;br /&gt;
    //...&lt;br /&gt;
&lt;br /&gt;
    // Schleife ueber ein Array aus Byte-Werten im Flash&lt;br /&gt;
    uint8_t i;&lt;br /&gt;
&lt;br /&gt;
    for (i=0;i&amp;lt;3;i++) {&lt;br /&gt;
        myByte = pgm_read_byte(&amp;amp;pgmFooByteArray1[i]);&lt;br /&gt;
        // mach&#039; was mit myByte....&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Wort lesen ===&lt;br /&gt;
&lt;br /&gt;
Für &amp;quot;einfache&amp;quot; 16-bit breite Variablen erfolgt der Zugriff analog zum Byte-Beispiel, jedoch mit der Funktion pgm_read_word.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
const uint16_t pgmFooWort PROGMEM = 12345;&lt;br /&gt;
&lt;br /&gt;
    uint16_t myWord;&lt;br /&gt;
&lt;br /&gt;
    myWord = pgm_read_word(&amp;amp;pgmFooWort);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zeiger auf Werte im Flash sind ebenfalls 16 Bits &amp;quot;groß&amp;quot; (Stand avr-gcc 3.4.x). Damit ist der mögliche Speicherbereich für &amp;quot;Flash-Konstanten&amp;quot; auf 64kB begrenzt.  &amp;lt;!-- Einige avr-libc/pgmspace-Funktionen ermöglichen den Lesezugriff auf den gesamten Flash-Speicher) (intern via Assembler Anweisung ELPM). Die Initialisierungswerde des Speicherinhalts jenseits der 64kB-Marke müssen dann jedoch auf anderem Weg angelegt werden (nicht PROGMEM, evtl. eigene Section und Linker-Optionen - TODO) /// alt - und nicht ganz korrekt: (Die avr-libc pgmspace-Funktionen unterstützen nur die unteren 64kB Flash bei Controllern mit mehr als 64kB.)--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
    uint8_t *ptrToArray;&lt;br /&gt;
&lt;br /&gt;
    ptrToArray = (uint8_t*)(pgm_read_word(&amp;amp;pgmPointerToArray1));&lt;br /&gt;
    // ptrToArray enthält nun die Startadresse des Byte-Arrays pgmFooByteArray1&lt;br /&gt;
    // Allerdings würde ein direkter Zugriff mit diesem Pointer (z.B. temp=*ptrToArray)&lt;br /&gt;
    // &#039;&#039;&#039;nicht&#039;&#039;&#039; den Inhalt von pgmFooByteArray1[0] liefern, sondern von einer Speicherstelle&lt;br /&gt;
    // im &#039;&#039;&#039;RAM&#039;&#039;&#039;, die die gleiche Adresse hat wie pgmFooByteArray1[0]&lt;br /&gt;
    // Daher muss nun die Funktion pgm_read_byte() benutzt werden, die die in ptrToArray&lt;br /&gt;
    // enthaltene Adresse benutzt und auf das Flash zugreift.&lt;br /&gt;
&lt;br /&gt;
    for (i=0;i&amp;lt;3;i++) {&lt;br /&gt;
        myByte = pgm_read_byte(ptrToArray+i);&lt;br /&gt;
        // mach&#039; was mit myByte... (18, 3, 70)&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    ptrToArray = (uint8_t*)(pgm_read_word(&amp;amp;pgmPointerArray[1]));&lt;br /&gt;
    &lt;br /&gt;
    // ptrToArray enthält nun die Adresse des ersten Elements des Byte-Arrays pgmFooByteArray2&lt;br /&gt;
    // da im zweiten Element des Pointer-Arrays pgmPointerArray die Adresse&lt;br /&gt;
    // von pgmFooByteArray2 abgelegt ist&lt;br /&gt;
&lt;br /&gt;
    for (i=0;i&amp;lt;3;i++) {&lt;br /&gt;
        myByte = pgm_read_byte(ptrToArray+i);&lt;br /&gt;
        // mach&#039; was mit myByte... (30, 7, 79)&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Floats und Structs lesen ===&lt;br /&gt;
&lt;br /&gt;
Um komplexe Datentypen (structs), nicht-integer Datentypen (floats) aus dem Flash auszulesen, sind Hilfsfunktionen erforderlich. Einige Beispiele:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
/* Beispiel float aus Flash */&lt;br /&gt;
&lt;br /&gt;
float pgmFloatArray[3] PROGMEM = {1.1, 2.2, 3.3};&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
/* liest float von Flash-Addresse addr und gibt diese als return-value zurueck */&lt;br /&gt;
inline float pgm_read_float(const float *addr)&lt;br /&gt;
{	&lt;br /&gt;
	union&lt;br /&gt;
	{&lt;br /&gt;
		uint16_t i[2];	// 2 16-bit-Worte&lt;br /&gt;
		float f;&lt;br /&gt;
	} u;&lt;br /&gt;
	&lt;br /&gt;
	u.i[0]=pgm_read_word((PGM_P)addr);&lt;br /&gt;
	u.i[1]=pgm_read_word((PGM_P)addr+2);&lt;br /&gt;
	&lt;br /&gt;
	return u.f;&lt;br /&gt;
} &lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
void egal(void)&lt;br /&gt;
{&lt;br /&gt;
   int i;&lt;br /&gt;
   float f;&lt;br /&gt;
&lt;br /&gt;
   for (i=0;i&amp;lt;3;i++) {&lt;br /&gt;
      f = pgm_read_float(&amp;amp;pgmFloatArray[i]); // entspr. &amp;quot;f = pgmFloatArray[i];&amp;quot;&lt;br /&gt;
      // mach&#039; was mit f &lt;br /&gt;
   }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
TODO: Beispiele fuer structs und pointer aus flash auf struct im flash (menues, state-machines etc.)&lt;br /&gt;
&lt;br /&gt;
=== Array aus Zeichenketten im Flash-Speicher ===&lt;br /&gt;
&lt;br /&gt;
Felder aus Zeichenketten im Flash-Speicher werden in zwei Schritten angelegt: Zuerst die einzelnen Elemente des Arrays und im Anschluss ein Array, in dem die Addressen der Zeichenketten abgelegt werden. Zum Auslesen wird zuerst die Adresse des i-ten Elements aus dem Array im Flash-Speicher gelesen, die im Anschluss dazu genutzt wird, auf das Element (die Zeichenkette) selbst zuzugreifen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/pgmspace.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
const char str1[] PROGMEM = &amp;quot;first_A&amp;quot;;&lt;br /&gt;
const char str2[] PROGMEM = &amp;quot;second_A&amp;quot;;&lt;br /&gt;
const char str3[] PROGMEM = &amp;quot;third_A&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
const char *strarray1[] PROGMEM = {&lt;br /&gt;
	str1,&lt;br /&gt;
	str2,&lt;br /&gt;
	str3&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
int main(void)&lt;br /&gt;
{&lt;br /&gt;
	int i, j, l;&lt;br /&gt;
	const char *pstrflash;&lt;br /&gt;
	char work[20], work2[20];&lt;br /&gt;
	// fuer Simulation: per volatile Optimierung verhindern, &lt;br /&gt;
	//                  da c nicht genutzt&lt;br /&gt;
	volatile char c;&lt;br /&gt;
	&lt;br /&gt;
	for ( i = 0; i &amp;lt; (sizeof(strarray1)/sizeof(strarray1[0]) ); i++ ) {&lt;br /&gt;
&lt;br /&gt;
		// setze Pointer auf die Addresse des i-ten Elements des&lt;br /&gt;
		// &amp;quot;Flash-Arrays&amp;quot; (str1, str2, ...)&lt;br /&gt;
		pstrflash = (const char*)( pgm_read_word( &amp;amp;(strarray1[i]) ) );&lt;br /&gt;
		&lt;br /&gt;
		// kopiere den Inhalt der Zeichenkette von der&lt;br /&gt;
		// in pstrflash abgelegten Adresse in das work-Array&lt;br /&gt;
		// analog zu strcpy( work, strarray1[i]) wenn alles im RAM&lt;br /&gt;
		strcpy_P( work, pstrflash );&lt;br /&gt;
		// verkuerzt:&lt;br /&gt;
		strcpy_P( work2, (const char*)( pgm_read_word( &amp;amp;(strarray1[i]) ) ) );&lt;br /&gt;
		&lt;br /&gt;
&lt;br /&gt;
		// Zeichen-fuer-Zeichen&lt;br /&gt;
		l = strlen_P( pstrflash );&lt;br /&gt;
		for ( j=0; j &amp;lt; l; j++ ) {&lt;br /&gt;
			// analog zu c=strarray[i][j] wenn alles im RAM&lt;br /&gt;
			c = (char)( pgm_read_byte( pstrflash++ ) );&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	while (1) { ; }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Siehe dazu auch die avr-libc FAQ: &amp;quot;How do I put an array of strings completely in ROM?&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=== Vereinfachung für Zeichenketten (Strings) im Flash ===&lt;br /&gt;
&lt;br /&gt;
Zeichenketten können innerhalb des Quellcodes als &amp;quot;Flash-Konstanten&amp;quot; ausgewiesen werden. Dazu dient das Makro PSTR aus pgmspace.h. Dies erspart die getrennte Deklaration mit PROGMEM-Attribut.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/pgmspace.h&amp;gt;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#define MAXLEN 30&lt;br /&gt;
&lt;br /&gt;
char StringImFlash[] PROGMEM = &amp;quot;Erwin Lindemann&amp;quot;; // im &amp;quot;Flash&amp;quot;&lt;br /&gt;
char StringImRam[MAXLEN];&lt;br /&gt;
&lt;br /&gt;
//...&lt;br /&gt;
    strcpy(StringImRam, &amp;quot;Mueller-Luedenscheidt&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (!strncmp_P(StringImRam, StringImFlash, 5)) { &lt;br /&gt;
        // mach&#039; was, wenn die ersten 5 Zeichen identisch - hier nicht&lt;br /&gt;
    }&lt;br /&gt;
    else {&lt;br /&gt;
        // der Code hier wuerde ausgefuehrt &lt;br /&gt;
    } &lt;br /&gt;
&lt;br /&gt;
    if (!strncmp_P(StringImRam, PSTR(&amp;quot;Mueller-Schmitt&amp;quot;), 5)) {&lt;br /&gt;
        // der Code hier wuerde ausgefuehrt, die ersten 5 Zeichen stimmen ueberein&lt;br /&gt;
    }&lt;br /&gt;
    else {&lt;br /&gt;
        // wuerde bei nicht-Uebereinstimmung ausgefuehrt&lt;br /&gt;
    }&lt;br /&gt;
//...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Aber Vorsicht: Ersetzt man zum Beispiel&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
const char textImFlashOK[] PROGMEM = &amp;quot;mit[]&amp;quot;; &lt;br /&gt;
// = Daten im &amp;quot;Flash&amp;quot;, textImFlashOK* zeigt auf Flashadresse&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
durch&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
const char* textImFlashProblem PROGMEM = &amp;quot;mit*&amp;quot;;&lt;br /&gt;
// Konflikt: Daten im BSS (lies: RAM), textImFlashFAIL* zeigt auf Flashadresse&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
dann kann es zu Problemen mit AVR-GCC kommen. Zu erkennen daran, dass der Initialisierungsstring von &amp;quot;textImFlashProblem&amp;quot; zu den Konstanten ans Ende des Programmcodes gelegt wird (BSS), von dem aus er zur Benutzung eigentlich ins RAM kopiert werden sollte (und wird). Da der lesende Code (mittels pgm_read*) trotzdem an einer Stelle vorne im Flash sucht, wird Unsinn gelesen. Dies scheint ein weiters Problem des AVR-GCC (gesehen bei avr-gcc 3.4.1 und 3.4.2) bei der Anpassung an die Harvard-Architektur zu sein (konstanter Pointer auf variable Daten?!). Abhilfe (&amp;quot;Workaround&amp;quot;): Initialisierung bei Zeichenketten mit [] oder gleich im Code PSTR(&amp;quot;...&amp;quot;) nutzen.&lt;br /&gt;
&lt;br /&gt;
Übergibt man Zeichenketten (genauer: die Adresse des ersten Zeichens), die im Flash abglegt sind an eine Funktion, muss diese entsprechend programmiert sein. Die Funktion selbst hat keine Möglichkeit zu unterscheiden, ob es sich um eine Adresse im Flash oder im RAM handelt. Die avr-libc und viele andere avr-gcc-Bibliotheken halten sich an die Konvention, dass Namen von Funktionen die Flash-Adressen erwarten mit dem Suffix _p (oder _P) versehen sind.&lt;br /&gt;
&lt;br /&gt;
Eine Funktion, die einen im Flash abgelegten String z.B. an eine UART ausgibt, würde dann so aussehen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
void uart_puts_p(const char *text)&lt;br /&gt;
{&lt;br /&gt;
    char Zeichen;&lt;br /&gt;
&lt;br /&gt;
    while (Zeichen = pgm_read_byte(text))&lt;br /&gt;
    {   /* so lange, wie mittels pgm_read_byte ein Zeichen vom Flash gelesen&lt;br /&gt;
           werden konnte, welches nicht das &amp;quot;String-Endezeichen&amp;quot; darstellt */&lt;br /&gt;
&lt;br /&gt;
        /* Das gelesene Zeichen über die normalen Kanäle verschicken */&lt;br /&gt;
        uart_putc(Zeichen);&lt;br /&gt;
        text++;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Von einigen Bibliotheken werden Makros definiert, die &amp;quot;automatisch&amp;quot; ein PSTR bei Verwendung einer Funktion einfügen. Ein Blick in den Header-File der Bibliothek zeigt, ob dies der Fall ist. Ein Beispiel aus P. Fleurys lcd-Library:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
// Ausschnitt aus dem Header-File lcd.h der &amp;quot;Fleury-LCD-Lib.&amp;quot;&lt;br /&gt;
//...&lt;br /&gt;
extern void lcd_puts_p(const char *progmem_s);&lt;br /&gt;
#define lcd_puts_P(__s) lcd_puts_p(PSTR(__s))&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
// in einer Anwendung (wieauchimmmer.c)&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/pgmspace.h&amp;gt;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
#include &amp;quot;lcd.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
char StringImFlash[] PROGMEM = &amp;quot;Erwin Lindemann&amp;quot;; // im &amp;quot;Flash&amp;quot;&lt;br /&gt;
&lt;br /&gt;
//...&lt;br /&gt;
    lcd_puts_p(StringImFlash); &lt;br /&gt;
    lcd_puts_P(&amp;quot;Dr. Kloebner&amp;quot;); &lt;br /&gt;
    // daraus wird wg. #define lcd_put_P...:  lcd_puts_p( PSTR(&amp;quot;Dr. Kloebner&amp;quot;) );&lt;br /&gt;
//...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Flash in der Anwendung schreiben ===&lt;br /&gt;
&lt;br /&gt;
Bei AVRs mit &amp;quot;self-programming&amp;quot;-Option (auch bekannt als Bootloader-Support) können Teile des Flash-Speichers auch vom Anwendungsprogramm selbst beschrieben werden. Dies ist nur möglich, wenn die Schreibfunktionen in einem besonderen Speicherbereich (boot-section) des Programmspeichers/Flash abgelegt sind. Bei wenigen &amp;quot;kleinen&amp;quot; AVRs gibt es keine gesonderte Boot-Section, bei diesen kann der Flashspeicher von jeder Stelle des Programms geschrieben werden. Für Details sei hier auf das jeweilige Controller-Datenblatt und die Erläuterungen zum Modul boot.h der avr-libc verwiesen. Es existieren auch Application-Notes dazu bei atmel.com, die auf avr-gcc-Code übertragbar sind.&lt;br /&gt;
&lt;br /&gt;
=== Warum so kompliziert? ===&lt;br /&gt;
&lt;br /&gt;
Zu dem Thema, warum die Verabeitung von Werten aus dem Flash-Speicher so &amp;quot;kompliziert&amp;quot; ist, sei hier nur kurz erläutert: Die Harvard-Architektur des AVR weist getrennte Adressräume für Programm(Flash)- und Datenspeicher(RAM) auf. Der C-Standard und der gcc-Compiler sehen keine unterschiedlichen Adressräume vor. &lt;br /&gt;
Hat man zum Beispiel eine Funktion string_an_uart(const char* s) und übergibt an diese Funktion die Adresse einer Zeichenkette (einen Pointer, z.B. 0x01fe), &amp;quot;weiß&amp;quot; die Funktion nicht, ob die Adresse auf den Flash-Speicher oder den/das RAM zeigt. Allein aus dem Pointer-Wert (der Zahl) kann nicht geschlossen werden, ob ein &amp;quot;einfaches&amp;quot; zeichen_an_uart(s[i]) oder zeichen_an_uart(pgm_read_byte(&amp;amp;s[i]) genutzt werden muss, um das i-te Zeichen auszugeben.&lt;br /&gt;
&lt;br /&gt;
Einige AVR-Compiler &amp;quot;tricksen&amp;quot; etwas, in dem sie für einen Pointer nicht nur die Adresse anlegen, sondern zusätzlich zu jedem Pointer den Ablageort (Flash oder RAM) intern sichern. Bei Aufruf einer Funktion wird dann bei Pointer-Parametern neben der Adresse auch der Speicherbereich, auf den der Pointer zeigt, übergeben. Dies hat jedoch nicht nur Vorteile; Erläuterungen warum dies so ist, führen an dieser Stelle zu weit.&lt;br /&gt;
&lt;br /&gt;
* siehe auch: [http://www.nongnu.org/avr-libc/user-manual/index.html Dokumentation der avr-libc] Abschnitte Modules/Program Space String Utilities und Abschnitt Modules/Bootloader Support Utilities&lt;br /&gt;
&lt;br /&gt;
== EEPROM ==&lt;br /&gt;
&lt;br /&gt;
Man beachte, dass der EEPROM-Speicher nur eine begrenzte Anzahl von Schreibzugriffen zulässt. Beschreibt man eine EEPROM-Zelle öfter als die im Datenblatt zugesicherte Anzahl (typisch 100.000), wird die Funktion der Zelle nicht mehr garantiert. &lt;br /&gt;
Dies gilt für jede einzelne Zelle. Bei geschickter Programmierung (z.B. Ring-Puffer), bei der die zu beschreibenden Zellen regelmäßig gewechselt werden, kann man eine deutlich höhere Anzahl an Schreibzugriffen, bezogen auf den Gesamtspeicher, erreichen.&lt;br /&gt;
&lt;br /&gt;
Schreib- und Lesezugriffe auf den EEPROM-Speicher erfolgen über die im Modul eeprom.h definierten Funktionen. Mit diesen Funktionen können einzelne Bytes, Datenworte (16bit) und Datenblöcke geschrieben und gelesen werden. &lt;br /&gt;
&lt;br /&gt;
Bei Nutzung des EEPROMs ist zu beachten, dass vor dem Zugriff auf diesen Speicher abgefragt wird, ob der Controller die vorherige EEPROM-Operation abgeschlossen hat. Die avr-libc-Funktionen beinhalten diese Prüfung, man muss sie nicht selbst implementieren. Man sollte auch verhindern, dass der Zugriff durch die Abarbeitung einer Interrupt-Routine unterbrochen wird, da bestimme Befehlsabfolgen vorgegeben sind, die innerhalb weniger Taktzyklen aufeinanderfolgen müssen (&amp;quot;timed sequence&amp;quot;). Auch dies muss bei Nutzung der Funktionen aus der avr-libc/eeprom.h-Datei nicht selbst implementiert werden. Innerhalb der Funktionen werden Interrupts vor der &amp;quot;EEPROM-Sequenz&amp;quot; global deaktiviert und im Anschluss, falls vorher auch schon eingeschaltet, wieder aktiviert.&lt;br /&gt;
&lt;br /&gt;
Bei der Deklaration einer Variable im EEPROM, ist das Attribut für die Section &amp;quot;.eeprom&amp;quot; zu ergänzen. Siehe dazu folgendes Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/eeprom.h&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/interrupt.h&amp;gt;&lt;br /&gt;
#include &amp;lt;inttypes.h&amp;gt; // wird in aktuellen Versionen der avr-lib mit xx.h eingebunden&lt;br /&gt;
&lt;br /&gt;
// EEMEM wird bei aktuellen Versionen der avr-lib in eeprom.h definiert&lt;br /&gt;
// hier: definiere falls noch nicht bekannt (&amp;quot;alte&amp;quot; avr-libc)&lt;br /&gt;
#ifndef EEMEM&lt;br /&gt;
// alle Textstellen EEMEM im Quellcode durch __attribute__ ... ersetzen&lt;br /&gt;
#define EEMEM  __attribute__ ((section (&amp;quot;.eeprom&amp;quot;)))&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
/* Byte */&lt;br /&gt;
uint8_t eeFooByte EEMEM = 123;&lt;br /&gt;
&lt;br /&gt;
/* Wort */&lt;br /&gt;
uint16_t eeFooWord EEMEM = 12345;&lt;br /&gt;
&lt;br /&gt;
/* float */&lt;br /&gt;
float eeFooFloat EEMEM;&lt;br /&gt;
&lt;br /&gt;
/* Byte-Feld */&lt;br /&gt;
uint8_t eeFooByteArray1[] EEMEM = { 18, 3 ,70 };&lt;br /&gt;
uint8_t eeFooByteArray2[] EEMEM = { 30, 7 ,79 };&lt;br /&gt;
&lt;br /&gt;
/* 16-bit unsigned short feld */&lt;br /&gt;
uint16_t eeFooWordArray1[4] EEMEM;&lt;br /&gt;
//...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Bytes lesen/schreiben ===&lt;br /&gt;
&lt;br /&gt;
Die avr-libc Funktion zum Lesen eines Bytes heißt eeprom_read_byte. Parameter ist die Adresse des Bytes im EEPROM. Geschrieben wird über die Funktion eeprom_write_byte mit den Parametern Adresse und Inhalt. Anwendungsbeispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
    uint8_t myByte;&lt;br /&gt;
&lt;br /&gt;
    myByte = eeprom_read_byte(&amp;amp;eeFooByte); // lesen&lt;br /&gt;
    // myByte hat nun den Wert 123&lt;br /&gt;
//...&lt;br /&gt;
    myByte = 99;&lt;br /&gt;
    eeprom_write_byte(&amp;amp;eeFooByte, myByte); // schreiben&lt;br /&gt;
    // der Wert 99 wird im EEPROM an die Adresse der&lt;br /&gt;
    // &#039;Variablen&#039; eeFooByte geschrieben&lt;br /&gt;
//...&lt;br /&gt;
    myByte = eeprom_read_byte(&amp;amp;eeFooByteArray1[1]); &lt;br /&gt;
    // myByte hat nun den Wert 3&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
    // Beispiel zur &amp;quot;Sicherung&amp;quot; gegen leeres EEPROM nach &amp;quot;Chip Erase&amp;quot;&lt;br /&gt;
    // (z.B. wenn die .eep-Datei nach Programmierung einer neuen Version&lt;br /&gt;
    // des Programms nicht in den EEPROM uebertragen wurde und EESAVE&lt;br /&gt;
    // deaktiviert ist (unprogrammed/1)&lt;br /&gt;
    // &lt;br /&gt;
    // Vorsicht: wenn EESAVE &amp;quot;programmed&amp;quot; ist, hilft diese Sicherung nicht&lt;br /&gt;
    // weiter, da die Speicheraddressen in einem neuen/erweiterten Programm&lt;br /&gt;
    // moeglicherweise verschoben wurden. An der Stelle &amp;amp;eeFooByte steht&lt;br /&gt;
    // dann u.U. der Wert einer anderen Variable aus einer &amp;quot;alten&amp;quot; Version.&lt;br /&gt;
&lt;br /&gt;
    #define EEPROM_DEF 0xFF&lt;br /&gt;
    uint8_t fooByteDefault = 222;&lt;br /&gt;
    if ( ( myByte = eeprom_read_byte(&amp;amp;eeFooByte) ) == EEPROM_DEF ) {&lt;br /&gt;
        myByte = fooByteDefault;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Wort lesen/schreiben ===&lt;br /&gt;
&lt;br /&gt;
Schreiben und Lesen von Datenworten erfolgt analog zur Vorgehensweise bei Bytes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
    uint16_t myWord;&lt;br /&gt;
&lt;br /&gt;
    myWord = eeprom_read_word(&amp;amp;eeFooWord); // lesen&lt;br /&gt;
    // myWord hat nun den Wert 12345&lt;br /&gt;
//...&lt;br /&gt;
    myWord = 2222;&lt;br /&gt;
    eeprom_write_word(&amp;amp;eeFooWord, myWord); // schreiben&lt;br /&gt;
//...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Block lesen/schreiben ===&lt;br /&gt;
&lt;br /&gt;
Lesen und Schreiben von Datenblöcken erfolgt über die Funktionen &#039;&#039;eeprom_read_block()&#039;&#039; bzw. &#039;&#039;eeprom_write_block()&#039;&#039;. Die Funktionen erwarten drei Parameter: die Adresse der Quell- bzw. Zieldaten im RAM, die EEPROM-Addresse und die Länge des Datenblocks in Bytes (size_t).&lt;br /&gt;
&lt;br /&gt;
TODO: &#039;&#039;&#039;Vorsicht!&#039;&#039;&#039; die folgenden Beispiele sind noch nicht geprüft, erstmal nur als Hinweis auf &amp;quot;das Prinzip&amp;quot;. Evtl. fehlen &amp;quot;casts&amp;quot; und möglicherweise noch mehr.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
    uint8_t  myByteBuffer[3];&lt;br /&gt;
    uint16_t myWordBuffer[4];&lt;br /&gt;
&lt;br /&gt;
    /* Datenblock aus EEPROM LESEN  */&lt;br /&gt;
&lt;br /&gt;
    /* liest 3 Bytes ab der von eeFooByteArray1 definierten EEPROM-Adresse&lt;br /&gt;
       in das RAM-Array myByteBuffer */&lt;br /&gt;
    eeprom_read_block(myByteBuffer,eeFooByteArray1,3);&lt;br /&gt;
&lt;br /&gt;
    /* dito etwas anschaulicher aber &amp;quot;unnütze Tipparbeit&amp;quot;: */&lt;br /&gt;
    eeprom_read_block(&amp;amp;myByteBuffer[0],&amp;amp;eeFooByteArray[0],3);&lt;br /&gt;
&lt;br /&gt;
    /* dito mit etwas Absicherung betr. der Länge */&lt;br /&gt;
    eeprom_read_block(myByteBuffer,eeFooByteArray1,sizeof(myByteBuffer));&lt;br /&gt;
&lt;br /&gt;
    /* und nun mit &amp;quot;16bit&amp;quot; */&lt;br /&gt;
    eeprom_read_block(myWordBuffer,eeFooWordArray1,sizeof(myWordBuffer));&lt;br /&gt;
&lt;br /&gt;
    /* Datenlock in EEPROM SCHREIBEN */&lt;br /&gt;
    eeprom_write_block(eeFooByteArray1,myByteBuffer,sizeof(myByteBuffer));&lt;br /&gt;
    eeprom_write_block(eeFooWordArray1,myWordBuffer,sizeof(myWordBuffer));&lt;br /&gt;
//...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Nicht-Integer&amp;quot;-Datentypen wie z.B. Fließkommazahlen lassen sich recht praktisch über eine &#039;&#039;union&#039;&#039; in &amp;quot;Byte-Arrays&amp;quot; konvertieren und wieder &amp;quot;zurückwandeln&amp;quot;. Dies erweist sich hier (aber nicht nur hier) als nützlich.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
   float myFloat = 12.34;&lt;br /&gt;
&lt;br /&gt;
   union {&lt;br /&gt;
      float r;&lt;br /&gt;
      uint8_t i[sizeof(float)];&lt;br /&gt;
   } u;&lt;br /&gt;
&lt;br /&gt;
   u.r = myFloat;&lt;br /&gt;
   &lt;br /&gt;
   /* float in EEPROM */&lt;br /&gt;
   eeprom_write_block(&amp;amp;eeFooFloat,&amp;amp;(u.i),sizeof(float));&lt;br /&gt;
&lt;br /&gt;
   /* float aus EEPROM */&lt;br /&gt;
   eeprom_read_block(&amp;amp;(u.i),&amp;amp;eeFooFloat,sizeof(float));&lt;br /&gt;
   /* u.r wieder 12.34 */&lt;br /&gt;
//...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Auch zusammengesetzte Typen lassen sich mit den Block-Routinen verarbeiten.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
typedef struct {&lt;br /&gt;
    uint8_t   label[8];&lt;br /&gt;
    uint8_t   rom_code[8];&lt;br /&gt;
} tMyStruct;&lt;br /&gt;
&lt;br /&gt;
#define MAXSENSORS 3&lt;br /&gt;
tMyStruct eeMyStruct[MAXSENSORS] EEMEM;&lt;br /&gt;
&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
void egal(void)&lt;br /&gt;
{&lt;br /&gt;
   tMyStruct work;&lt;br /&gt;
   &lt;br /&gt;
   strcpy(work.label,&amp;quot;Flur&amp;quot;);&lt;br /&gt;
   GetRomCode(work.rom_code);     // Dummy zur Veranschaulichung - setzt rom-code&lt;br /&gt;
&lt;br /&gt;
   /* Sichern von &amp;quot;work&amp;quot; im EEPROM */&lt;br /&gt;
   eeprom_write_block(&amp;amp;eeMyStruct[0],&amp;amp;work,sizeof(tMyStruct)); // f. Index 0&lt;br /&gt;
   strcpy(work.label,&amp;quot;Bad&amp;quot;);&lt;br /&gt;
   GetRomCode(work.rom_code);&lt;br /&gt;
   eeprom_write_block(&amp;amp;eeMyStruct[1],&amp;amp;work,sizeof(tMyStruct)); // f. Index 1&lt;br /&gt;
//...&lt;br /&gt;
   /* Lesen der Daten EEPROM Index 0 in &amp;quot;work&amp;quot; */&lt;br /&gt;
   eeprom_read_block(&amp;amp;work,&amp;amp;eeMyStruct[0],sizeof(tMyStruct));&lt;br /&gt;
   // work.label hat nun den Inhalt &amp;quot;Flur&amp;quot;&lt;br /&gt;
//...&lt;br /&gt;
}&lt;br /&gt;
//...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== EEPROM-Speicherabbild in .eep-Datei ===&lt;br /&gt;
&lt;br /&gt;
Mit den zum Compiler gehörenden Werkzeugen kann der aus den Variablendeklaration abgeleiteten EEPROM-Inhalt in eine Datei geschrieben werden (übliche Dateiendung: .eep, Daten im Intel Hex-Format). Damit können recht elegant Standardwerte für den EEPROM-Inhalt im Quellcode definiert werden. Makefiles nach WinAVR/MFile-Vorlage enthalten bereits die notwendigen Einstellungen (siehe dazu die Erläuterungen im Abschnitt Exkurs: Makefiles). Der Inhalt der eep-Datei muss ebenfalls zum Mikrocontroller übertragen werden (Write EEPROM), wenn die Initialisierungswerte aus der Deklaration vom Programm erwartet werden. Ansonsten enthält der EEPROM-Speicher nach der Übertragung des Programmers mittels ISP abhängig von der Einstellung der EESAVE-Fuse (vgl. Datenblatt Abschnitt Fuse Bits) die vorherigen Daten (EESAVE programmed = 0), deren Position möglicherweise nicht mehr mit der Belegung im aktuellen Programm übereinstimmt oder den Standardwert nach &amp;quot;Chip Erase&amp;quot;: 0xFF (EESAVE unprogrammed = 1). Als Sicherung kann man im Programm nochmals die Standardwerte vorhalten, beim Lesen auf 0xFF prüfen und gegebenfalls einen Standardwert nutzen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--Eine besondere Funktion des avr-gcc ist, dass mit entsprechenden Optionen im Makefile aus den Initialisierungswerten der Variablen im Quellcode eine Datei erzeugt werden kann, die man auf den Controller programmieren kann (.eep-Datei). Damit können sehr elegant Standardwerte für den EEPROM-Inhalt im Quellcode definiert werden. Die Vorgehensweise wird aus dem WinAVR-Beispielmakefile ersichtlich. Siehe dazu die Erläuterungen im Abschnitt Exkurs: Makefiles.--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== EEPROM-Variable auf feste Adressen legen ===&lt;br /&gt;
&lt;br /&gt;
Gleich zu Beginn möchte ich darauf hinweisen, dass dieses Verfahren nur ein Workaround ist, mit dem man das Problem der anscheinend &amp;quot;zufälligen&amp;quot; Verteilung&lt;br /&gt;
der EEPROM-Variablen durch den Compiler etwas in den Griff bekommen kann.&lt;br /&gt;
&lt;br /&gt;
Hilfreich kann dies vor allem dann sein, wenn man z.B. über einen Kommandointerpreter (o.ä. Funktionen) direkt bestimmte EEPROM-Adressen manipulieren möchte. Auch wenn man über einen JTAG-Adapter (mk I oder mkII) den Programmablauf manipulieren möchte, indem man die EEPROM-Werte direkt ändert, kann diese Technik hilfreich sein.&lt;br /&gt;
&lt;br /&gt;
Im folgenden nun zwei Sourcelistings mit einem Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
/////////////////////////////////////////////////&lt;br /&gt;
// Datei &amp;quot;eeprom.h&amp;quot; eines eigenen Projektes&lt;br /&gt;
/////////////////////////////////////////////////&lt;br /&gt;
&lt;br /&gt;
#inlcude &amp;lt;avr/eeprom.h&amp;gt;     // Die EEPROM-Definitionen/Macros der avr-libc einbinden&lt;br /&gt;
&lt;br /&gt;
#define   EESIZE   512      // Maximale Größe des EEPROMS&lt;br /&gt;
&lt;br /&gt;
#define   EE_DUMMY   0x000  // Dummyelement (Adresse 0 sollte nicht genutzt werden)&lt;br /&gt;
#define   EE_VALUE1  0x001  // Eine Bytevariable  &lt;br /&gt;
#define   EE_WORD1L  0x002  // Eine Wordvariable (Lowbyte)&lt;br /&gt;
#define   EE_WORD1H  0x003  // Eine Wordvariable (Highbyte)&lt;br /&gt;
#define   EE_VALUE2  0x004  // Eine weitere Bytevariable&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit den Macros &#039;&#039;&#039;#define EE_VALUE1&#039;&#039;&#039; legt man den Namen und die Adresse der&lt;br /&gt;
&#039;Variablen&#039; fest.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;font color=$FF0000&amp;gt;WICHTIG:&amp;lt;/font&amp;gt;Die Adressen sollten fortlaufend, zumindest aber aufsteigend sortiert sein! Ansonsten besteht die Gefahr, daß man sehr schnell ein Durcheinander im EEPROM Speicher veranstaltet.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;font color=$FF0000&amp;gt;WICHTIG:&amp;lt;/font&amp;gt;Für den Compiler sind das lediglich Speicher-Adressen, über die auf das EEPROM zugegriffen wird. Der Compiler sieht nichts davon als eine echte Variable an und stößt sich daher auch nicht daran, wenn 2 Makros mit der gleichen Speicheradresse, bzw. überlappenden Speicherbereichen definiert werden. Es liegt einzig und alleine in der Hand des Programmierers, hier keinen Fehler zu machen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
/////////////////////////////////////////////////&lt;br /&gt;
// Datei &amp;quot;eeprom.c&amp;quot; eines eigenen Projektes&lt;br /&gt;
/////////////////////////////////////////////////&lt;br /&gt;
&lt;br /&gt;
#include &amp;quot;eeprom.h&amp;quot;          // Eigene EEPROM-Headerdatei einbinden&lt;br /&gt;
&lt;br /&gt;
uint8_t ee_mem[EESIZE] EEMEM =&lt;br /&gt;
{&lt;br /&gt;
   [EE_DUMMY]   = 0x00,&lt;br /&gt;
   [EE_VALUE1]  = 0x05,&lt;br /&gt;
   [EE_WORD1L]  = 0x01,   &lt;br /&gt;
   [EE_WORD1H]  = 0x00,&lt;br /&gt;
   [EE_VALUE2]  = 0xFF&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Durch die Verwendung eines Array, welches das gesammte EEPROM umfasst, bleibt&lt;br /&gt;
dem Compiler nicht anderes übrig, als das Array so zu platzieren, dass Element 0&lt;br /&gt;
des Arrays der Adresse 0 des EEPROMs entspricht. (&#039;&#039;Ich hoffe nur, dass die Compilerbauer daran nichts ändern!&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
Wie man in dem obigen Codelisting auch sehen kann, hat das Verfahren einen kleinen Haken. Variablen die größer sind als 1 Byte, müssen etwas umständlicher&lt;br /&gt;
definiert werden. Benötigt man keine Initialisierung durch das Programm (was der Normalfall sein dürfte), dann kann man das auch so machen:&lt;br /&gt;
&lt;br /&gt;
Möchte man im EEPROM hintereinander beispielsweise Variablen, mit den Namen &#039;&#039;&#039;Wert&#039;&#039;&#039;, &#039;&#039;&#039;Anzahl&#039;&#039;&#039;, &#039;&#039;&#039;Name&#039;&#039;&#039; und &#039;&#039;&#039;Wertigkeit&#039;&#039;&#039; definieren, wobei Wert und Wertigkeit 1 Byte belegen sollen, Anzahl als 1 Wort (also 2 Bytes) und Name mit 10 Bytes reserviert werden soll, so geht auch folgendes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#define EE_DUMMY      0x000&lt;br /&gt;
#define EE_WERT       ( 0x000 + sizeof( uint8_t ) )&lt;br /&gt;
#define EE_ANZAHL     ( EE_WERT + sizeof( uint8_t ) )&lt;br /&gt;
#define EE_NAME       ( EE_ANZAHL + sizeof( uint16_t ) )&lt;br /&gt;
#define EE_WERTIGKEIT ( EE_NAME + 10 * sizeof( uint8_t ) )&lt;br /&gt;
#define EE_LAST       ( EE_WERTIGKEIT + sizeof( uint8_t ) )&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jedes Makro definiert also seine Startadresse durch die Startadresse der unmittelbar vorhergehende &#039;Variablen&#039; plus der Anzahl der Bytes die von der vorhergehenden &#039;Variablen&#039; verbraucht werden. Dadurch ist man zumindest etwas auf der sicheren Seite, dass keine 2 &#039;Variablen&#039; im EEPROM überlappend definiert werden. Möchte man eine weitere &#039;Variable&#039; hinzufügen, so wird deren&lt;br /&gt;
Name, einfach anstelle der EE_LAST eingesetzt und eine neue Zeile für EE_LAST eingefügt, in der dann die Größe der &#039;Variablen&#039; festgelegt wird. Zb.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#define EE_DUMMY      0x000&lt;br /&gt;
#define EE_WERT       ( 0x000 + sizeof( uint8_t ) )&lt;br /&gt;
#define EE_ANZAHL     ( EE_WERT + sizeof( uint8_t ) )&lt;br /&gt;
#define EE_NAME       ( EE_ANZAHL + sizeof( uint16_t ) )&lt;br /&gt;
#define EE_WERTIGKEIT ( EE_NAME + 10 * sizeof( uint8_t ) )&lt;br /&gt;
#define EE_PROZENT    ( EE_WERTIGKEIT + sizeof( uint8_t ) )&lt;br /&gt;
#define EE_LAST       ( EE_WERTIGKEIT + sizeof( double ) )&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
EE_PROZENT legt die Startadresse für eine neue &#039;Variable&#039; des Datentyps double fest.&lt;br /&gt;
&lt;br /&gt;
Der Zugriff auf die EEPROM Werte kann dann z.B.so erfolgen:&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
uint8_t   temp1;&lt;br /&gt;
uint16_t  temp2;&lt;br /&gt;
&lt;br /&gt;
temp1 = eeprom_read_byte(EE_VALUE1);&lt;br /&gt;
temp2 = eeprom_read_word(EE_WORD1L);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ob die in der avr-libc vorhandenen Funktionen dafür verwendet werden können, weiß ich nicht. Aber in einigen Fällen muss man sich sowieso eigene Funktionen&lt;br /&gt;
bauen, welche die spezifischen Anforderungen (Interrupt - Atom Problem, etc.)&lt;br /&gt;
erfüllen.&lt;br /&gt;
&lt;br /&gt;
Die oben beschriebene Möglichkeit ist nur eine Möglichkeit, wie man dies realisieren kann. Sie bietet einem eine relativ einfache Art die EEPROM-Werte&lt;br /&gt;
auf beliebige Adressen zu legen oder Adressen zu ändern. Die Andere Möglichkeit besteht darin, die EEPROM-Werte wie folgt zu belegen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
/////////////////////////////////////////////////&lt;br /&gt;
// Datei &amp;quot;eeprom.c&amp;quot; eines eigenen Projektes&lt;br /&gt;
/////////////////////////////////////////////////&lt;br /&gt;
&lt;br /&gt;
#include &amp;quot;eeprom.h&amp;quot;          // Eigene EEPROM-Headerdatei einbinden&lt;br /&gt;
&lt;br /&gt;
uint8_t ee_mem[EESIZE] EEMEM =&lt;br /&gt;
{&lt;br /&gt;
  0x00,                     //  ee_dummy&lt;br /&gt;
  0x05,                     //  ee_value1&lt;br /&gt;
  0x01,                     //  ee_word1L&lt;br /&gt;
  0x00,                     // (ee_word1H)&lt;br /&gt;
  0xFF                      //  ee_value2&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hierbei kann man Variablen, die größer sind als 1 Byte einfacher definieren und&lt;br /&gt;
man muss nur die Highbyte- oder Lowbyte-Adresse in der &amp;quot;eeprom.h&amp;quot; definieren.&lt;br /&gt;
Allerdings muss man hier höllisch aufpassen, dass man nicht um eine oder mehrere&lt;br /&gt;
Positionen verrutscht!&lt;br /&gt;
&lt;br /&gt;
Welche der beiden Möglichkeiten man einsetzt, hängt vor allem davon ab, wieviele&lt;br /&gt;
Byte, Word und sonstige Variablen man benutzt. Gewöhnen sollte man sich an beide Varianten können ;)&lt;br /&gt;
&lt;br /&gt;
Kleine Schlussbemerkung:&lt;br /&gt;
&lt;br /&gt;
* Der avr-gcc unterstützt die Variante 1 und die Variante 2&lt;br /&gt;
* Der icc-avr Compiler unterstützt nur die Variante 2!&lt;br /&gt;
&lt;br /&gt;
=== Bekannte Probleme bei den EEPROM-Funktionen ===&lt;br /&gt;
&lt;br /&gt;
Vorsicht: Bei alten Versionen der avr-libc wurden nicht alle AVR Controller  untersützt. Z.B. bei der avr-libc Version 1.2.3 insbesondere bei AVRs &amp;quot;der neuen Generation&amp;quot; (ATmega48/88/168/169) funktionieren die Funktionen nicht korrekt (Ursache: unterschiedliche Speicheradressen der EEPROM-Register). In neueren Versionen (z.B. avr-libc 1.4.3 aus WinAVR 20050125) wurde die Zahl der unterstüzten Controller deutlich erweitert und eine Methode zur leichten Anpassung an zukünftige Controller eingeführt.&lt;br /&gt;
&lt;br /&gt;
In jedem Datenblatt zu AVR-Controllern mit EEPROM sind kurze Beispielecodes für den Schreib- und Lesezugriff enthalten. Will oder kann man nicht auf die neue Version aktualisieren, kann der dort gezeigte Code auch mit dem avr-gcc (ohne avr-libc/eeprom.h) genutzt werden (&amp;quot;copy/paste&amp;quot;, gegebenfalls Schutz vor Unterbrechnung/Interrupt ergänzen &#039;&#039;uint8_t sreg; sreg=SREG; cli(); [EEPROM-Code] ; SREG=sreg; return;&#039;&#039;, siehe Abschnitt Interrupts). Im Zweifel hilft ein Blick in den vom Compiler erzeugten Assembler-Code (lst/lss-Dateien).&lt;br /&gt;
&lt;br /&gt;
* siehe auch: [http://www.nongnu.org/avr-libc/user-manual/index.html Dokumentation der avr-libc] Abschnitt Modules/EEPROM handling&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== EEPROM Register ===&lt;br /&gt;
Um das EEPROM anzusteuern sind drei Register von Bedeutung.&amp;lt;BR&amp;gt;&lt;br /&gt;
&amp;lt;LI&amp;gt; EEAR Hier werden die Adressen eingetragen zum Schreiben oder Lesen. Dieses Register unterteilt sich nochmal in EEARH und EEARL da in einem 8 Bit Register keine 512 Adressen adressiert werden können&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
&amp;lt;LI&amp;gt; EEDR Hier werden die Daten eingetragen die geschrieben werden sollen bzw. es enthält die gelesenen Daten&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
&amp;lt;LI&amp;gt; EECR Ist das Kontrollregister für das EEPROM&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das EECR steuert den Zugriff auf das EEPROM und ist wie folgt aufgebaut:&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;TABLE BORDER=1&amp;gt;&lt;br /&gt;
&amp;lt;TR&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;Bit&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;&amp;amp;nbsp;&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;7&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;6&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;5&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;4&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;3&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;2&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;1&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;0&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;/TD&amp;gt;&lt;br /&gt;
&amp;lt;/TR&amp;gt;&lt;br /&gt;
&amp;lt;TR&amp;gt; &lt;br /&gt;
  &amp;lt;TD&amp;gt;Name&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;&amp;amp;nbsp;&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;-&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;-&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;-&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;-&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;EERIE&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;EEMWE&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;EEWE&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;EERE&amp;lt;/TD&amp;gt;&lt;br /&gt;
&amp;lt;/TR&amp;gt;&lt;br /&gt;
&amp;lt;TR&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;Read/Write&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;R&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;R&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;R&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;R&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;R/W&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;R/W&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;R/W&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;R/W&amp;lt;/TD&amp;gt;&lt;br /&gt;
&amp;lt;/TR&amp;gt;&lt;br /&gt;
&amp;lt;TR&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;Init Value&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;0&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;0&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;0&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;0&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;0&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;0&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;0&amp;lt;/TD&amp;gt;&lt;br /&gt;
  &amp;lt;TD&amp;gt;0&amp;lt;/TD&amp;gt;&lt;br /&gt;
&amp;lt;/TR&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/TABLE&amp;gt;&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;U&amp;gt;Bedeutung der Bits:&amp;lt;/U&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
Bit 4-7 nicht belegt.&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;U&amp;gt;Bit 3 (EERIE) - EEPROM Ready Interrupt Enable:&amp;lt;/U&amp;gt; Wenn das Bit gesetzt ist und globale Interrupts erlaubt sind in Register SREG (Bit 7) wird ein Interrupt ausgelöst nach Beendigung des Schreibzyklus (EEPROM Ready Interrupt). Ist einer der beiden Bits 0 wird kein Interrupt ausgelöst.&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;U&amp;gt;Bit 2(EEMWE) - EEPROM Master Write Enable:&amp;lt;/U&amp;gt; Dieses Bit bestimmt, daß wenn EEWE = 1 gesetzt wird (innerhalb von 4 Taktzyklen), das EEPROM beschrieben wird mit den Daten in EEDR bei Adresse EEAR. Wenn EEMWE =0 ist und EEWE = 1 gesetzt wird hat das keine Auswirkungen. Der Schreibvorgang wird dann nicht ausgelöst.&lt;br /&gt;
Nach 4 Taktzyklen wird das Bit EEMWE automatisch wieder auf 0 gesetzt. Dieses Bit löst den Schreibvorgang nicht aus, es dient sozusagen als Sicherungsbit für EEWE.&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;U&amp;gt;Bit 1 (EEWE) - EEPROM Write Enable:&amp;lt;/U&amp;gt; Dieses Bit löst den Schreibvorgang aus wenn es auf 1 gesetzt wird, sofern vorher EEMWE gesetzt wurde und seitdem nicht mehr als 4 Taktzyklen vergangen sind. Wenn der Schreibvorgang abgeschlossen ist wird dieses Bit automatisch wieder auf 0 gesetzt und sofern EERIE gesetzt ist ein Interrupt ausgelöst. &amp;lt;BR&amp;gt;&lt;br /&gt;
Ein Schreibvorgang sieht typischerweise wie folgt aus:&amp;lt;BR&amp;gt;&lt;br /&gt;
1. EEPROM Bereitschaft abwarten (EEWE=0) &lt;br /&gt;
2. Adresse übergeben an EEAR&amp;lt;BR&amp;gt;&lt;br /&gt;
3. Daten übergeben an EEDR&amp;lt;BR&amp;gt;&lt;br /&gt;
4. Schreibvorgang auslösen in EECR mit Bit EEMWE=1 und EEWE=1 &amp;lt;BR&amp;gt;&lt;br /&gt;
5. (Optinal) Warten bis Schreibvorgang abgeschlossen ist.&amp;lt;BR&amp;gt;&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
&amp;lt;U&amp;gt;Bit 0 EERE – EEPROM Read Enable:&amp;lt;/U&amp;gt; Wird dieses Bit auf 1 gesetzt wird das EEPROM an der Adresse in EEAR ausgelesen und die Daten in EEDR gespeichert. Das EEPROM kann nicht ausgelesen werden wenn bereits eine Schreiboperation gestartet wurde. Es ist daher zu empfehlen die Bereitschaft vorher zu prüfen. Das EEPROM ist lesebereit wenn das Bit EEWE=0 ist. ISt der LEsevorgang abgeschlossen wird das Bit wieder auf 0 gesetzt und das EEPROM ist für neue Lese/Schreibbefehle wieder bereit.&amp;lt;BR&amp;gt;&lt;br /&gt;
Ein typischer Lesevorgang kann wie folgt aufgebaut sein:&amp;lt;BR&amp;gt;&lt;br /&gt;
1. Bereitschaft zum lesen prüfen (EEWE=0)&amp;lt;BR&amp;gt;&lt;br /&gt;
2. Adresse übergeben an EEAR&amp;lt;BR&amp;gt;&lt;br /&gt;
3. Lesezyklus auslösen mit EERE = 1&amp;lt;BR&amp;gt;&lt;br /&gt;
4. Warten bis Lesevorgang abgeschlossen EERE = 0&amp;lt;BR&amp;gt;&lt;br /&gt;
5. Daten abholen aus EEDR&amp;lt;BR&amp;gt;&lt;br /&gt;
&amp;lt;BR&amp;gt;&amp;lt;BR&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Die Nutzung von printf =&lt;br /&gt;
&lt;br /&gt;
Um komfortabel Ausgaben auf ein Display oder die serielle Schnittstelle zu tätigen, bietet sich printf/sprintf an. &lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// ...&lt;br /&gt;
// nicht dargestellt: Implementierung von uart_puts (vgl. Abschnitt UART)&lt;br /&gt;
// ...&lt;br /&gt;
&lt;br /&gt;
uint16_t counter;&lt;br /&gt;
&lt;br /&gt;
void uart_puti( uint16_t value )&lt;br /&gt;
{&lt;br /&gt;
    uint8_t s[20];&lt;br /&gt;
&lt;br /&gt;
    sprintf( s, &amp;quot;Zählerstand: %d&amp;quot;, value );&lt;br /&gt;
    uart_puts( s );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int main()&lt;br /&gt;
{&lt;br /&gt;
  counter = 5;&lt;br /&gt;
&lt;br /&gt;
  uart_puti( counter );&lt;br /&gt;
  uart_puti( 42 );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Eine weitere elegante Möglichkeit besteht darin, die Ausgabe stdout auf eigene Ausgabefunktionen umzuleiten. Dazu wird dem Ausgabemechanismus eine neue Ausgabefunktion bekannt gemacht, deren Aufgabe es ist, ein einzelnes Zeichen auszugeben (wie auch immer die Ausgabe stattfindet). Alle anderen, höheren, Funktionen greifen letztendlich auf diese eine Ausgabefunktion zurück, die die Ausgabe eines einzelnen Zeichens vornimmt. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
void uart_init(void);&lt;br /&gt;
int uart_putchar(char c, FILE *stream);&lt;br /&gt;
&lt;br /&gt;
static FILE mystdout = FDEV_SETUP_STREAM( uart_putchar, NULL, _FDEV_SETUP_WRITE );&lt;br /&gt;
&lt;br /&gt;
void uart_init(void)&lt;br /&gt;
{&lt;br /&gt;
    /* hier µC spezifischen Code zur Initialisierung */&lt;br /&gt;
    /* des UART einfügen... s.o. im AVR-GCC-Tutorial */&lt;br /&gt;
&lt;br /&gt;
    // Beispiel: &lt;br /&gt;
    //&lt;br /&gt;
    // myAVR Board 1.5 mit externem Quarz Q1 3,6864 MHz&lt;br /&gt;
    // 9600 Baud 8N1&lt;br /&gt;
&lt;br /&gt;
#ifndef F_CPU&lt;br /&gt;
#define F_CPU 3686400&lt;br /&gt;
#endif&lt;br /&gt;
#define UART_BAUD_RATE 9600&lt;br /&gt;
&lt;br /&gt;
// Hilfsmakro zur UBRR-Berechnung (&amp;quot;Formel&amp;quot; laut Datenblatt)&lt;br /&gt;
#define UART_UBRR_CALC(BAUD_,FREQ_) ((FREQ_)/((BAUD_)*16L)-1)&lt;br /&gt;
&lt;br /&gt;
    UCSRB |= (1&amp;lt;&amp;lt;TXEN) | (1&amp;lt;&amp;lt;RXEN);    // UART TX und RX einschalten&lt;br /&gt;
    UCSRC |= (1&amp;lt;&amp;lt;URSEL)|(3&amp;lt;&amp;lt;UCSZ0);    // Asynchron 8N1 &lt;br /&gt;
 &lt;br /&gt;
    UBRRH = (uint8_t)( UART_UBRR_CALC( UART_BAUD_RATE, F_CPU ) &amp;gt;&amp;gt; 8 );&lt;br /&gt;
    UBRRL = (uint8_t)UART_UBRR_CALC( UART_BAUD_RATE, F_CPU );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int uart_putchar( char c, FILE *stream )&lt;br /&gt;
{&lt;br /&gt;
    if( c == &#039;\n&#039; )&lt;br /&gt;
        uart_putchar( &#039;\r&#039;, stream );&lt;br /&gt;
&lt;br /&gt;
    loop_until_bit_is_set( UCSRA, UDRE );&lt;br /&gt;
    UDR = c;&lt;br /&gt;
    return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int main(void)&lt;br /&gt;
{&lt;br /&gt;
    uart_init();&lt;br /&gt;
    stdout = &amp;amp;mystdout;&lt;br /&gt;
    printf( &amp;quot;Hello, world!\n&amp;quot; );&lt;br /&gt;
    return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Quelle: avr-libc-user-manual-1.4.3.pdf, S.74&lt;br /&gt;
//         + Ergänzungen&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Sollen Fließkommazahlen ausgegeben werden, muss im Makefile eine andere (größere) Version der [[FAQ#Aktivieren_der_Floating_Point_Version_von_sprintf_beim_WinAVR_mit_AVR-Studio|printflib]] eingebunden werden.&lt;br /&gt;
&lt;br /&gt;
Der Nachteil aller printf-Varianten: Sie sind recht speicherintensiv.&lt;br /&gt;
&lt;br /&gt;
= Assembler und Inline-Assembler =&lt;br /&gt;
&lt;br /&gt;
Gelegentlich erweist es sich als nützlich, C- und Assembler-Code in einer Anwendung zu nutzen. Typischerweise wird das Hauptprogramm in C verfasst und wenige, extrem zeitkritische oder hardwarenahe Operationen in Assembler.&lt;br /&gt;
&lt;br /&gt;
Die &amp;quot;gnu-Toolchain&amp;quot; bietet dazu zwei Möglichkeiten:&lt;br /&gt;
&lt;br /&gt;
* Inline-Assembler: Die Assembleranweisungen werden direkt in den C-Code integriert. Eine Quellcode-Datei enthält somit C- und Assembleranweisungen&lt;br /&gt;
* Assembler-Dateien: Der Assemblercode befindet sich in eigenen Quellcodedateien. Diese werden vom gnu-Assembler (avr-as) zu Object-Dateien assembliert (&amp;quot;compiliert&amp;quot;) und mit den aus dem C-Code erstellten Object-Dateien zusammengebunden (gelinkt).&lt;br /&gt;
&lt;br /&gt;
== Inline-Assembler ==&lt;br /&gt;
&lt;br /&gt;
Inline-Assembler bietet sich an, wenn nur wenig Assembleranweisungen benötigt werden. Typische Anwendung sind kurze Codesequenzen für zeitkritische Operationen in Interrupt-Routinen oder sehr präzise Warteschleifen (z.B. 1-Wire). Inline-Assembler wird mit &#039;&#039;&#039;asm volatile&#039;&#039;&#039; eingeleitet, die Assembler-Anweisungen werden in einer Zeichenkette zusammengefasst, die als &amp;quot;Parameter&amp;quot; übergeben wird. Durch Doppelpunkte getrennt werden die Ein- und Ausgaben sowie die &amp;quot;Clobber-Liste&amp;quot; angegeben.&lt;br /&gt;
&lt;br /&gt;
Ein einfaches Beispiel für Inline-Assembler ist das Einfügen einer NOP-Anweisung (NOP steht für No Operation). Dieser Assembler-Befehl benötigt genau einen Taktzyklus, ansonsten &amp;quot;tut sich nichts&amp;quot;. Sinnvolle Anwendungen für NOP sind genaue Delay(=Warte)-Funktionen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
    ...&lt;br /&gt;
   /* Verzögern der weiteren Programmausführung um&lt;br /&gt;
      genau 3 Taktzyklen */&lt;br /&gt;
    asm volatile (&amp;quot;nop&amp;quot;);&lt;br /&gt;
    asm volatile (&amp;quot;nop&amp;quot;);&lt;br /&gt;
    asm volatile (&amp;quot;nop&amp;quot;);&lt;br /&gt;
    ...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Weiterhin kann mit einem NOP verhindert werden, dass leere Schleifen, die als Warteschleifen gedacht sind, wegoptimiert werden. Der Compiler erkennt ansonsten die vermeintlich nutzlose Schleife und erzeugt dafür keinen Code im ausführbaren Programm.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
    ...&lt;br /&gt;
    uint16_t i;&lt;br /&gt;
&lt;br /&gt;
    /* leere Schleife - wird bei eingeschalteter Compiler-Optimierung   wegoptimiert */&lt;br /&gt;
    for (i = 0; i &amp;lt; 1000; i++)&lt;br /&gt;
      ;&lt;br /&gt;
&lt;br /&gt;
    ...&lt;br /&gt;
&lt;br /&gt;
    /* Schleife erzwingen (keine Optimierung): &amp;quot;NOP-Methode&amp;quot; */&lt;br /&gt;
    for (i = 0; i &amp;lt; 1000; i++)&lt;br /&gt;
      asm volatile(&amp;quot;NOP&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    ...&lt;br /&gt;
&lt;br /&gt;
    /* alternative Methode (keine Optimierung): */&lt;br /&gt;
    volatile uint16_t j;&lt;br /&gt;
    for (j = 0; j &amp;lt; 1000; j++)&lt;br /&gt;
      ;&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein weiterer nützlicher &amp;quot;Assembler-Einzeiler&amp;quot; ist der Aufruf von sleep (&#039;&#039;asm volatile (&amp;quot;sleep&amp;quot;);&#039;&#039;), da hierzu in älteren Versionen der avr-libc keine eigene Funktion existiert (in neueren Versionen &#039;&#039;sleep_cpu()&#039;&#039; aus sleep.h).&lt;br /&gt;
&lt;br /&gt;
Als Beispiel für mehrzeiligen Inline-Assembler eine präzise Delay-Funktion. Die Funktion erhält ein 16-bit Wort als Parameter, prüft den Parameter auf 0 und beendet die Funktion in diesem Fall oder durchläuft die folgende Schleife sooft wie im Wert des Parameters angegeben. Inline-Assembler hat hier den Vorteil, dass die Laufzeit unabhängig von der Optimierungsstufe (Parameter -O, vgl. makefile) und der Compiler-Version ist.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
static inline void delayloop16 (uint16_t count)&lt;br /&gt;
{&lt;br /&gt;
    asm volatile (&amp;quot;cp  %A0, __zero_reg__ \n\t&amp;quot;&lt;br /&gt;
                  &amp;quot;cpc %B0, __zero_reg__ \n\t&amp;quot;&lt;br /&gt;
                  &amp;quot;breq 2f               \n\t&amp;quot;&lt;br /&gt;
                  &amp;quot;1:                    \n\t&amp;quot;&lt;br /&gt;
                  &amp;quot;sbiw %0,1             \n\t&amp;quot;&lt;br /&gt;
                  &amp;quot;brne 1b               \n\t&amp;quot;&lt;br /&gt;
                  &amp;quot;2:                    &amp;quot;  &lt;br /&gt;
                  : &amp;quot;=w&amp;quot; (count)&lt;br /&gt;
	          : &amp;quot;0&amp;quot;  (count)&lt;br /&gt;
    );                            &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Jede Anweisung wird mit &#039;&#039;&#039;\n\t&#039;&#039;&#039; abgeschlossen. Der Zeilenumbruch teilt dem Assembler mit, dass ein neuer Befehl beginnt.&lt;br /&gt;
* Als Sprung-Marken (Labels) werden Ziffern verwendet. Diese speziellen Labels sind mehrfach im Code verwendbar. Gesprungen wird jeweils zurück (b) oder vorwärts (f) zum nächsten ausffindbaren Label.&lt;br /&gt;
&lt;br /&gt;
Das Resultat zeigt ein Blick in die Assembler-Datei, die der Compiler mit der option &amp;lt;tt&amp;gt;-save-temps&amp;lt;/tt&amp;gt; nicht löscht:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;avrasm&amp;gt;&lt;br /&gt;
	cp  r24, __zero_reg__ 	 ;  count&lt;br /&gt;
	cpc r25, __zero_reg__ 	 ;  count&lt;br /&gt;
	breq 2f               &lt;br /&gt;
	1:                    &lt;br /&gt;
	sbiw r24,1             	 ;  count&lt;br /&gt;
	brne 1b               &lt;br /&gt;
	2:&lt;br /&gt;
&amp;lt;/avrasm&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Detaillierte Ausführungen zum Thema Inline-Assembler finden sich in der Dokumentation der avr-libc im Abschnitt [http://www.nongnu.org/avr-libc/user-manual/inline_asm.html Related Pages/Inline Asm]. &lt;br /&gt;
&lt;br /&gt;
Siehe auch: &lt;br /&gt;
* [http://www.atmel.com/dyn/resources/prod_documents/doc0856.pdf AVR Assembler-Anweisungsliste]&lt;br /&gt;
* [http://www.roboternetz.de/wissen/index.php/Inline-Assembler_in_avr-gcc Deutsche Einführung in Inline-Assembler]&lt;br /&gt;
&lt;br /&gt;
== Assembler-Dateien ==&lt;br /&gt;
&lt;br /&gt;
Assembler-Dateien erhalten die Endung .S (&#039;&#039;grosses&#039;&#039; S) und werden im makefile nach WinAVR/mfile-Vorlage hinter &#039;&#039;ASRC=&#039;&#039; durch Leerzeichen getrennt aufgelistet.&lt;br /&gt;
&lt;br /&gt;
Wenn man mit dem AVR Studio arbeitet, kann alternativ auch das standardmäßig erstellte Makefile bearbeitet und folgende Zeilen eingefügt werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;code&amp;quot;&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
## Objects that must be built in order to link&lt;br /&gt;
OBJECTS = (alte Dateien...) useful.o&lt;br /&gt;
&lt;br /&gt;
## Compile&lt;br /&gt;
## Hier folgt eine Liste der gelinkten Dateien, darunter einfügen:&lt;br /&gt;
useful.o: ../useful.S&lt;br /&gt;
	$(CC) $(INCLUDES) $(ASMFLAGS) -c  $&amp;lt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
Das war es schon. Allerdings gilt es zu beachten, dass das makefile über &amp;quot;Project -&amp;gt; Configuration options&amp;quot; selbst einzubinden ist, sonst wird es natürlich wieder überschrieben.&lt;br /&gt;
&lt;br /&gt;
Im Beispiel eine Funktion &#039;&#039;superFunc&#039;&#039;, die alle Pins des Ports D auf &amp;quot;Ausgang&amp;quot; schaltet, eine Funktion &#039;&#039;ultraFunc&#039;&#039;, die die Ausgänge entsprechend des übergebenen Parameters schaltet, eine Funktion &#039;&#039;gigaFunc&#039;&#039;, die den Status von Port A zurückgibt und eine Funktion &#039;&#039;addFunc&#039;&#039;, die zwei Bytes zu einem 16-bit-Wort addiert. Die Zuweisungen im C-Code (PORTx = ...) verhindern, dass der Compiler die Aufrufe wegoptimiert und dienen nur zur Veranschaulichung der Parameterübergaben.&lt;br /&gt;
&lt;br /&gt;
Zuerst der Assembler-Code. Der Dateiname sei useful.S:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;avrasm&amp;gt;&lt;br /&gt;
#include &amp;quot;avr/io.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
//; Arbeitsregister (ohne &amp;quot;r&amp;quot;) &lt;br /&gt;
workreg  = 16&lt;br /&gt;
workreg2 = 17&lt;br /&gt;
&lt;br /&gt;
//; Konstante:&lt;br /&gt;
ALLOUT = 0xff&lt;br /&gt;
&lt;br /&gt;
//; ** Setze alle Pins von PortD auf Ausgang **&lt;br /&gt;
//; keine Parameter, keine Rückgabe&lt;br /&gt;
.global superFunc&lt;br /&gt;
.func superFunc&lt;br /&gt;
superFunc:&lt;br /&gt;
   push workreg&lt;br /&gt;
   ldi workreg, ALLOUT&lt;br /&gt;
   out  _SFR_IO_ADDR(DDRD), workreg  // beachte: _SFR_IO_ADDR()&lt;br /&gt;
   pop workreg&lt;br /&gt;
   ret&lt;br /&gt;
.endfunc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
//; ** Setze PORTD auf übergebenen Wert **&lt;br /&gt;
//; Parameter in r24 (LSB immer bei &amp;quot;graden&amp;quot; Nummern)&lt;br /&gt;
.global ultraFunc&lt;br /&gt;
.func ultraFunc&lt;br /&gt;
ultraFunc:&lt;br /&gt;
   out  _SFR_IO_ADDR(PORTD), 24&lt;br /&gt;
   ret&lt;br /&gt;
.endfunc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
//; ** Zustand von PINA zurückgeben **&lt;br /&gt;
//; Rückgabewerte in r24:r25 (LSB:MSB), hier nur LSB genutzt&lt;br /&gt;
.global gigaFunc&lt;br /&gt;
.func gigaFunc&lt;br /&gt;
gigaFunc:&lt;br /&gt;
   in 24, _SFR_IO_ADDR(PINA)&lt;br /&gt;
   ret&lt;br /&gt;
.endfunc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
//; ** Zwei Bytes addieren und 16-bit-Wort zurückgeben **&lt;br /&gt;
//; Parameter in r24 (Summand1) und r22 (Summand2) -&lt;br /&gt;
//;  Parameter sind Word-&amp;quot;aligned&amp;quot; d.h. LSB immer auf &amp;quot;graden&amp;quot;&lt;br /&gt;
//;  Registernummern. Bei 8-Bit und 16-Bit Paramtern somit &lt;br /&gt;
//;  beginnend bei r24 dann r22 dann r20 etc.&lt;br /&gt;
//; Rückgabewert in r24:r25&lt;br /&gt;
.global addFunc&lt;br /&gt;
.func addFunc&lt;br /&gt;
addFunc:&lt;br /&gt;
   push workreg&lt;br /&gt;
   push workreg2&lt;br /&gt;
   clr workreg2&lt;br /&gt;
   mov workreg, 22&lt;br /&gt;
   add workreg, 24&lt;br /&gt;
   adc workreg2, 1    // r1 - assumed to be always zero ...&lt;br /&gt;
   movw r24, workreg&lt;br /&gt;
   pop workreg2&lt;br /&gt;
   pop workreg&lt;br /&gt;
   ret&lt;br /&gt;
.endfunc&lt;br /&gt;
&lt;br /&gt;
//; oh je - sorry - Mein AVR-Assembler ist eingerostet, hoffe das stimmt so...&lt;br /&gt;
&lt;br /&gt;
.end&lt;br /&gt;
&amp;lt;/avrasm&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im Makefile ist der Name der Assembler-Quellcodedatei einzutragen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;code&amp;quot;&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
ASRC = useful.S&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Aufruf erfolgt dann im C-Code so:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
extern void superFunc(void);&lt;br /&gt;
extern void ultraFunc(uint8_t setVal);&lt;br /&gt;
extern uint8_t gigaFunc(void);&lt;br /&gt;
extern uint16_t addFunc(uint8_t w1, uint8_t w2);&lt;br /&gt;
&lt;br /&gt;
int main(void)&lt;br /&gt;
{&lt;br /&gt;
[...]&lt;br /&gt;
  superFunc();&lt;br /&gt;
  &lt;br /&gt;
  ultraFunc(0x55);&lt;br /&gt;
  &lt;br /&gt;
  PORTD = gigaFunc();&lt;br /&gt;
&lt;br /&gt;
  PORTA = (addFunc(0xF0, 0x11) &amp;amp; 0xff);&lt;br /&gt;
  PORTB = (addFunc(0xF0, 0x11) &amp;gt;&amp;gt; 8);&lt;br /&gt;
[...]&lt;br /&gt;
} &lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Ergebnis wird wieder in der lss-Datei ersichtlich:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;code&amp;quot;&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
[...]&lt;br /&gt;
   superFunc();&lt;br /&gt;
 148:	0e 94 f6 00 	call	0x1ec&lt;br /&gt;
  &lt;br /&gt;
  ultraFunc(0x55);&lt;br /&gt;
 14c:	85 e5       	ldi	r24, 0x55	; 85&lt;br /&gt;
 14e:	0e 94 fb 00 	call	0x1f6&lt;br /&gt;
  &lt;br /&gt;
  PORTD = gigaFunc();&lt;br /&gt;
 152:	0e 94 fd 00 	call	0x1fa&lt;br /&gt;
 156:	82 bb       	out	0x12, r24	; 18&lt;br /&gt;
  &lt;br /&gt;
  PORTA = (addFunc(0xF0, 0x11) &amp;amp; 0xff);&lt;br /&gt;
 158:	61 e1       	ldi	r22, 0x11	; 17&lt;br /&gt;
 15a:	80 ef       	ldi	r24, 0xF0	; 240&lt;br /&gt;
 15c:	0e 94 ff 00 	call	0x1fe&lt;br /&gt;
 160:	8b bb       	out	0x1b, r24	; 27&lt;br /&gt;
  PORTB = (addFunc(0xF0, 0x11) &amp;gt;&amp;gt; 8);&lt;br /&gt;
 162:	61 e1       	ldi	r22, 0x11	; 17&lt;br /&gt;
 164:	80 ef       	ldi	r24, 0xF0	; 240&lt;br /&gt;
 166:	0e 94 fc 00 	call	0x1f8&lt;br /&gt;
 16a:	89 2f       	mov	r24, r25&lt;br /&gt;
 16c:	99 27       	eor	r25, r25&lt;br /&gt;
 16e:	88 bb       	out	0x18, r24	; 24&lt;br /&gt;
&lt;br /&gt;
[...]&lt;br /&gt;
000001ec &amp;lt;superFunc&amp;gt;:&lt;br /&gt;
// setze alle Pins von PortD auf Ausgang&lt;br /&gt;
.global superFunc&lt;br /&gt;
.func superFunc&lt;br /&gt;
superFunc:&lt;br /&gt;
   push workreg&lt;br /&gt;
 1ec:	0f 93       	push	r16&lt;br /&gt;
   ldi workreg, ALLOUT&lt;br /&gt;
 1ee:	0f ef       	ldi	r16, 0xFF	; 255&lt;br /&gt;
   out  _SFR_IO_ADDR(DDRD), workreg&lt;br /&gt;
 1f0:	01 bb       	out	0x11, r16	; 17&lt;br /&gt;
   pop workreg&lt;br /&gt;
 1f2:	0f 91       	pop	r16&lt;br /&gt;
   ret&lt;br /&gt;
 1f4:	08 95       	ret&lt;br /&gt;
&lt;br /&gt;
000001f6 &amp;lt;ultraFunc&amp;gt;:&lt;br /&gt;
.endfunc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// setze PORTD auf übergebenen Wert&lt;br /&gt;
.global ultraFunc&lt;br /&gt;
.func ultraFunc&lt;br /&gt;
ultraFunc:&lt;br /&gt;
   out  _SFR_IO_ADDR(PORTD), 24&lt;br /&gt;
 1f6:	82 bb       	out	0x12, r24	; 18&lt;br /&gt;
   ret&lt;br /&gt;
 1f8:	08 95       	ret&lt;br /&gt;
&lt;br /&gt;
000001fa &amp;lt;gigaFunc&amp;gt;:&lt;br /&gt;
.endfunc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// Zustand von PINA zurückgeben&lt;br /&gt;
.global gigaFunc&lt;br /&gt;
.func gigaFunc&lt;br /&gt;
gigaFunc:&lt;br /&gt;
   in 24, _SFR_IO_ADDR(PINA)&lt;br /&gt;
 1fa:	89 b3       	in	r24, 0x19	; 25&lt;br /&gt;
   ret&lt;br /&gt;
 1fc:	08 95       	ret&lt;br /&gt;
&lt;br /&gt;
000001fe &amp;lt;addFunc&amp;gt;:&lt;br /&gt;
.endfunc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// zwei Bytes addieren und 16-bit-Wort zurückgeben&lt;br /&gt;
.global addFunc&lt;br /&gt;
.func addFunc&lt;br /&gt;
addFunc:&lt;br /&gt;
   push workreg&lt;br /&gt;
 1fe:	0f 93       	push	r16&lt;br /&gt;
   push workreg2&lt;br /&gt;
 200:	1f 93       	push	r17&lt;br /&gt;
   clr workreg2&lt;br /&gt;
 202:	11 27       	eor	r17, r17&lt;br /&gt;
   mov workreg, 22&lt;br /&gt;
 204:	06 2f       	mov	r16, r22&lt;br /&gt;
   add workreg, 24&lt;br /&gt;
 206:	08 0f       	add	r16, r24&lt;br /&gt;
   adc workreg2, 1    // r1 - assumed to be always zero ...&lt;br /&gt;
 208:	11 1d       	adc	r17, r1&lt;br /&gt;
   movw r24, workreg&lt;br /&gt;
 20a:	c8 01       	movw	r24, r16&lt;br /&gt;
   pop workreg2&lt;br /&gt;
 20c:	1f 91       	pop	r17&lt;br /&gt;
   pop workreg&lt;br /&gt;
 20e:	0f 91       	pop	r16&lt;br /&gt;
   ret&lt;br /&gt;
 210:	08 95       	ret&lt;br /&gt;
&lt;br /&gt;
[...]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Zuweisung von Registern zu Parameternummer und die Register für die Rückgabewerte sind in den &amp;quot;Register Usage Guidelines&amp;quot; der avr-libc-Dokumentation erläutert.&lt;br /&gt;
&lt;br /&gt;
Siehe auch:&lt;br /&gt;
* [http://www.nongnu.org/avr-libc/user-manual/assembler.html avr-libc-Dokumentation: Related Pages/avr-libc and assembler programs]&lt;br /&gt;
* [http://www.nongnu.org/avr-libc/user-manual/FAQ.html#faq_reg_usage avr-libc-Dokumentation: Related Pages/FAQ/&amp;quot;What registers are used by the C compiler?&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
== Globale Variablen für Datenaustausch ==&lt;br /&gt;
&lt;br /&gt;
Oftmals kommt man um globale Variablen nicht herum, z.B. um den Datenaustausch zwischen Hauptprogramm und Interrupt-Routinen zu realisieren. &lt;br /&gt;
Hierzu muss man im Assembler wissen, wo genau die Variable vom C-Compiler abgespeichert wird.&lt;br /&gt;
&lt;br /&gt;
Hierzu muss die Variable, hier &amp;quot;zaehler&amp;quot; genannt, zuerst im C-Code als Global definiert werden, z.B. so:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
volatile uint8_t zaehler;&lt;br /&gt;
&lt;br /&gt;
int16_t main (void)&lt;br /&gt;
{&lt;br /&gt;
    // irgendein Code, in dem zaehler benutzt werden kann&lt;br /&gt;
    &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im foldenden Assembler-Beispiel wird der Externe Interrupt0  verwendet, um den Zähler hochzuzählen. Es fehlen die Initialisierungen des Interrupts und die Interrupt-Freigabe, so richtig sinnvoll ist der Code auch nicht, aber er zeigt (hoffentlich) wie es geht.&lt;br /&gt;
&lt;br /&gt;
Im Umgang mit Interrupt-Vektoren gilt beim GCC-Assembler das Gleiche, wie bei C: Man muss die exakte Schreibweise beachten, ansonsten wird nicht der Interrupt-Vektor angelegt, sondern eine neue Funktion - und man wundert sich, dass nichts funktionert (vgl. das AVR-GCC-Handbuch).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;avrasm&amp;gt;&lt;br /&gt;
#include &amp;quot;avr/io.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
temp = 16&lt;br /&gt;
&lt;br /&gt;
.extern zaehler&lt;br /&gt;
&lt;br /&gt;
.global INT0_vect&lt;br /&gt;
INT0_vect:&lt;br /&gt;
&lt;br /&gt;
     push temp                      //; wichtig: Benutzte Register und das&lt;br /&gt;
     in temp,_SFR_IO_ADDR(SREG)     //; Status-Register (SREG) sichern!&lt;br /&gt;
     push temp&lt;br /&gt;
&lt;br /&gt;
     lds temp,zaehler               //; Wert aus dem Speicher lesen&lt;br /&gt;
     inc temp                       //; bearbeiten&lt;br /&gt;
     sts zaehler,temp               //; und wieder zurückschreiben&lt;br /&gt;
&lt;br /&gt;
     pop temp                       //; die benutzten Register wiederherstellen&lt;br /&gt;
     out _SFR_IO_ADDR(SREG),temp&lt;br /&gt;
     pop temp&lt;br /&gt;
     reti&lt;br /&gt;
&lt;br /&gt;
.end&lt;br /&gt;
&amp;lt;/avrasm&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Globale Variablen im Assemblerfile anlegen ===&lt;br /&gt;
&lt;br /&gt;
Alternativ können Variablen aber auch im Assemblerfile angelegt werden. Dadurch kann auf eine .c-Datei verzichtet werden. Für das obige Beispiel könnte der Quelltext dann die Dateien zaehl_asm.S und zaehl_asm.h abgelegt werden, so dass nur noch zaehl_asm.S mit kompiliert werden müsste.&lt;br /&gt;
&lt;br /&gt;
Anstatt im Assemblerfile über das Schlüsselwort &#039;&#039;.extern &#039;&#039; auf eine vorhandene Variable zu verweisen, wird dazu mit dem Schlüsselwort &#039;&#039;.comm&#039;&#039; die benötigte Anzahl von Bytes für eine Variable reserviert.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;zaehl_asm.S&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;avrasm&amp;gt;&lt;br /&gt;
#include &amp;quot;avr/io.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
temp = 16&lt;br /&gt;
&lt;br /&gt;
//; 1 Byte im RAM für den Zähler reservieren&lt;br /&gt;
.comm zaehler, 1&lt;br /&gt;
&lt;br /&gt;
.global INT0_vect&lt;br /&gt;
INT0_vect:&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/avrasm&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In der Headerdatei wird dann auf die Variable nur noch verwiesen (Schlüsselwort &#039;&#039;extern&#039;&#039;):&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;zaehl_asm.h&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#ifndef ZAEHL_ASM_H&lt;br /&gt;
#define ZAEHL_ASM_H&lt;br /&gt;
&lt;br /&gt;
extern volatile uint8_t zaehler;&lt;br /&gt;
&lt;br /&gt;
#endif&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im Gegensatz zu globalen Variablen in C werden so angelegte Variablen nicht automatisch mit dem Wert 0 initialisiert. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Variablen größer als 1 Byte ===&lt;br /&gt;
&lt;br /&gt;
Variablen, die größer als &#039;&#039;&#039;ein&#039;&#039;&#039; Byte sind, können in Assembler auf ähnliche Art angesprochen werden. Hierzu müssen nur genug Bytes angefordert werden, um die Variable aufzunehmen. Soll z.B. für den Zähler eine Variable vom Typ &#039;&#039;unsigned long&#039;&#039;, also &#039;&#039;uint32_t&#039;&#039; verwendet werden, so müssen 4 Bytes reserviert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;avrasm&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
// 4 Byte im RAM für den Zähler reservieren&lt;br /&gt;
.comm zaehler, 4&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/avrasm&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die dazugehörige Deklaration im Headerfile wäre dann:&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
extern volatile uint32_t zaehler;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bei Variablen, die größer als ein Byte sind, werden die Werte beginnend mit dem niederwertigsten Byte im RAM abgelegt. Das folgende Codeschnippsel zeigt, wie unter Assembler auf die einzelnen Bytes zugegriffen werden kann. Dazu wird im Interrupt nun ein 32-Bit Zähler erhöht:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;avrasm&amp;gt;&lt;br /&gt;
#include &amp;quot;avr/io.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
temp = 16&lt;br /&gt;
&lt;br /&gt;
// 4 Byte im RAM für den Zähler reservieren&lt;br /&gt;
.comm zaehler, 4&lt;br /&gt;
&lt;br /&gt;
.global INT0_vect&lt;br /&gt;
INT0_vect:&lt;br /&gt;
&lt;br /&gt;
     push temp                      // wichtig: Benutzte Register und das&lt;br /&gt;
     in temp,_SFR_IO_ADDR(SREG)     // Status-Register (SREG) sichern !&lt;br /&gt;
     push temp&lt;br /&gt;
&lt;br /&gt;
     // 32-Bit-Zähler incrementieren&lt;br /&gt;
     lds temp, (zaehler + 0)        // 0. Byte (niederwertigstes Byte)&lt;br /&gt;
     inc temp&lt;br /&gt;
     sts (zaehler + 0), temp&lt;br /&gt;
     brne RAUS&lt;br /&gt;
	&lt;br /&gt;
     lds temp, (zaehler + 1)        // 1. Byte&lt;br /&gt;
     inc temp&lt;br /&gt;
     sts (zaehler + 1), temp&lt;br /&gt;
     brne RAUS&lt;br /&gt;
&lt;br /&gt;
     lds temp, (zaehler + 2)        // 2. Byte&lt;br /&gt;
     inc temp&lt;br /&gt;
     sts (zaehler + 2), temp&lt;br /&gt;
     brne RAUS&lt;br /&gt;
&lt;br /&gt;
     lds temp, (zaehler + 3)        // 3. Byte (höchstwertigstes Byte)&lt;br /&gt;
     inc temp&lt;br /&gt;
     sts (zaehler + 3), temp&lt;br /&gt;
     brne RAUS&lt;br /&gt;
	&lt;br /&gt;
RAUS:&lt;br /&gt;
     pop temp                       // die benutzten Register wiederherstellen&lt;br /&gt;
     out _SFR_IO_ADDR(SREG),temp&lt;br /&gt;
     pop temp&lt;br /&gt;
     reti&lt;br /&gt;
&lt;br /&gt;
.end&lt;br /&gt;
&amp;lt;/avrasm&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;TODO:&#039;&#039;&#039; 16-Bit / 32-Bit Variablen, Zugriff auf Arrays (Strings)&lt;br /&gt;
&lt;br /&gt;
= Anhang =&lt;br /&gt;
&lt;br /&gt;
== Besonderheiten bei der Anpassung bestehenden Quellcodes ==&lt;br /&gt;
&lt;br /&gt;
Einige Funktionen, die in frühren Versionen der avr-libc vorhanden waren, werden inzwischen als veraltet angesehen. Sie sind nicht mehr vorhanden oder als &#039;&#039;deprecated&#039;&#039; (missbilligt) ausgewiesen und Definitionen in &amp;lt;compat/deprecated.h&amp;gt; verschoben. Es empfiehlt sich, vorhandenen Code zu portieren und die alten Funktionen nicht mehr zu nutzen, auch wenn diese noch zur Verfügung stehen.&lt;br /&gt;
&lt;br /&gt;
=== Veraltete Funktionen zur Deklaration von Interrupt-Routinen ===&lt;br /&gt;
&lt;br /&gt;
Die Funktionen (eigentlich Makros) &#039;&#039;SIGNAL&#039;&#039; und &#039;&#039;INTERRUPT&#039;&#039; zur Deklaration von Interruptroutinen sollten nicht mehr genutzt werden. &lt;br /&gt;
&lt;br /&gt;
In aktuellen Versionen der avr-libc (z.B. avr-libc 1.4.3 aus WinAVR 20060125) werden Interruptroutinen, die &#039;&#039;&#039;nicht&#039;&#039;&#039; durch andere Interrupts &#039;&#039;&#039;unterbrechbar&#039;&#039;&#039; sind, mit ISR deklariert (siehe Abschnitt im Hauptteil). Auch die Benennung wurden vereinheitlicht und an die üblichen Bezeichnungen in den AVR Datenblättern angepasst. In der Dokumentation der avr-libc sind alte und neue Bezeichnungen in der Tabelle gegenübergestellt. Die erforderlichen Schritte zur Portierung:&lt;br /&gt;
&lt;br /&gt;
* #include von avr/signal.h entfernen&lt;br /&gt;
* SIGNAL duch ISR ersetzen&lt;br /&gt;
* Name des Interrupt-Vektors anpassen (SIG_* durch entsprechendes *_vect)&lt;br /&gt;
&lt;br /&gt;
Als Beispiel für die Anpassung zuerst ein &amp;quot;alter&amp;quot; Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/interrupt.h&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/signal.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
/* Timer2 Output Compare bei einem ATmega8 */&lt;br /&gt;
SIGNAL(SIG_OUTPUT_COMPARE2)&lt;br /&gt;
{&lt;br /&gt;
   ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im Datenblatt wird der Vektor mit TIMER2 COMP bezeichnet. Die Bezeichnung in der avr-libc entspricht dem Namen im Datenblatt, Leerzeichen werden durch Unterstriche (_) ersetzt und ein _vect angehängt. &lt;br /&gt;
&lt;br /&gt;
Der neue Code sieht dann so aus:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/interrupt.h&amp;gt; &lt;br /&gt;
/* signal.h entfällt */&lt;br /&gt;
&lt;br /&gt;
ISR(TIMER2_COMP_vect)&lt;br /&gt;
{&lt;br /&gt;
   ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bei Unklarheiten bezüglich der neuen Vektorlabels hilft (noch) ein Blick in die Headerdatei des entsprechenden Controllers. Für das vorherige Beispiel also der Blick in die Datei iom8.h für den ATmega8, dort findet man die veraltete Bezeichnung unterhalb der aktuellen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
/* $Id: iom8.h,v 1.13 2005/10/30 22:11:23 joerg_wunsch Exp $ */&lt;br /&gt;
/* avr/iom8.h - definitions for ATmega8 */&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
/* Timer/Counter2 Compare Match */&lt;br /&gt;
#define TIMER2_COMP_vect		_VECTOR(3)&lt;br /&gt;
#define SIG_OUTPUT_COMPARE2		_VECTOR(3)&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- Nachfolgendes mit avr-libc 1.4.5 (in WinAVR 1/2007 behoben - noch eine Weile auskommentiert lassen und dann löschen.&lt;br /&gt;
Konnte in alten Versionen signal.h ohne interrupt.h eingebunden werden, erhält man bei Verwendung der avr-libc Version 1.4.3 (WinAVR 2/2005) beim Compilieren eine Fehlermeldung, da mit signal.h nicht die erforderlichen Definitionen eingebunden werden. Der Lösungsvorschlag in signal.h auch interrupt.h einzubinden, wurde von den avr-libc-Enwicklern akzeptiert und das Problem ist  im Quellcode (CVS) bereits behoben. Es ist aber noch keine avr-libc-&amp;quot;Release&amp;quot; bzw. noch kein WinAVR mit dieser avr-libc-Korrektur verfügbar (Stand 5.2.2006). Will oder kann man den Quellcode nicht aktualisieren, gibt es folgende Alternativen:&lt;br /&gt;
* in Quellcodedateien, in denen nur avr/signal.h eingebunden wird, interrupt.h einbinden (&#039;&#039;#include &amp;amp;lt;avr/interrupt.h&amp;amp;gt;&#039;&#039;). signal.h weiterhin einbinden, falls Kompatibiltät mit alten Versionen gewünscht ist.&lt;br /&gt;
* in der Datei signal.h (bein WinAVR in c:/WinAVR/avr/include/avr/signal.h) ein (&#039;&#039;#include &amp;amp;lt;avr/interrupt.h&amp;amp;gt;&#039;&#039;) ergänzen --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für &#039;&#039;&#039;unterbrechbare&#039;&#039;&#039; Interruptroutinen, die mittels &#039;&#039;INTERRUPT&#039;&#039; deklariert sind, gibt es keinen direkten Ersatz in Form eines Makros. Solche Routinen sind laut Dokumentation der avr-libc in folgender Form zu deklarieren:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
void XXX_vect(void) __attribute__((interrupt));&lt;br /&gt;
void XXX_vect(void) {&lt;br /&gt;
  ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
/* ** alt ** */&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/interrupt.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
INTERRUPT(SIG_OVERFLOW0)&lt;br /&gt;
{&lt;br /&gt;
   ...&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* ** neu: ** */&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
void TIMER0_OVF_vect(void) __attribute__((interrupt));&lt;br /&gt;
void TIMER0_OVF_vect(void) &lt;br /&gt;
{&lt;br /&gt;
   ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Will oder kann man den Code nicht portieren, ist zur weiteren Verwendung von &#039;&#039;INTERRUPT&#039;&#039; die Header-Datei &#039;&#039;compat/deprecated.h&#039;&#039; einzubinden. Man sollte bei dieser Gelegenheit jedoch nochmals überprüfen, ob die Funktionalität von &#039;&#039;INTERRUPT&#039;&#039; tatsächlich gewollt ist. In vielen Fällen wurde &#039;&#039;INTERRUPT&#039;&#039; dort genutzt, wo eigentlich &#039;&#039;SIGNAL&#039;&#039; (nunmehr &#039;&#039;ISR&#039;&#039;) hätte genutzt werden sollen.&lt;br /&gt;
&lt;br /&gt;
=== Veraltete Funktionen zum Portzugriff ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;inp&#039;&#039; und &#039;&#039;outp&#039;&#039; zum Einlesen bzw. Schreiben von Registern sind nicht mehr erforderlich, der Compiler unterstützt dies ohne diesen Umweg.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
unsigned char i, j;&lt;br /&gt;
&lt;br /&gt;
// alt:&lt;br /&gt;
  i = inp(PINA);&lt;br /&gt;
  j = 0xff;&lt;br /&gt;
  outp(PORTB, j);&lt;br /&gt;
&lt;br /&gt;
// neu (nicht mehr wirklich neu...):&lt;br /&gt;
  i = PINA&lt;br /&gt;
  j = 0xff;&lt;br /&gt;
  PORTB = j;&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Will oder kann man den Code nicht portieren, ist zur weiteren Verwendung von inp und outp die Header-Datei &#039;&#039;&#039;compat/deprecated.h&#039;&#039;&#039; einzubinden.&lt;br /&gt;
&lt;br /&gt;
=== Veraltete Funktionen zum Zugriff auf Bits in Registern ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;cbi&#039;&#039; und &#039;&#039;sbi&#039;&#039; zum Löschen und Setzen von Bits sind nicht mehr erforderlich, der Compiler unterstützt dies ohne diesen Umweg. Die Bezeichnung ist ohnehin irreführend da die Funktionen nur für Register mit Adressen im unteren Speicherbereich tatsächlich in die Assembleranweisungen cbi und sbi übersetzt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
// alt:&lt;br /&gt;
  sbi(PORTB, PB2);&lt;br /&gt;
  cbi(PORTC, PC1);&lt;br /&gt;
&lt;br /&gt;
// neu (auch nicht mehr wirklich neu...):&lt;br /&gt;
  PORTB |=  (1&amp;lt;&amp;lt;PB2);&lt;br /&gt;
  PORTC &amp;amp;= ~(1&amp;lt;&amp;lt;PC1);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Will oder kann man den Code nicht portieren, ist zur weiteren Verwendung von sbi und cbi die Header-Datei &#039;&#039;&#039;compat/deprecated.h&#039;&#039;&#039; einzubinden. Wer unbedingt will, kann sich natürlich eigene Makros mit aussagekräftigeren Namen definieren. Zum Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#define SET_BIT(PORT, BITNUM)    ((PORT) |=  (1&amp;lt;&amp;lt;(BITNUM)))&lt;br /&gt;
#define CLEAR_BIT(PORT, BITNUM)  ((PORT) &amp;amp;= ~(1&amp;lt;&amp;lt;(BITNUM)))&lt;br /&gt;
#define TOGGLE_BIT(PORT, BITNUM) ((PORT) ^=  (1&amp;lt;&amp;lt;(BITNUM)))&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Selbstdefinierte (nicht-standardisierte) ganzzahlige Datentypen ===&lt;br /&gt;
&lt;br /&gt;
Bei den im Folgenden genannten Typdefinitionen ist zu beachten, dass die Bezeichnungen für &amp;quot;Worte&amp;quot; teilweise je nach Prozessorplattform unterschiedlich verwendet werden. Die angegebenen Definitionen beziehen sich auf die im Zusammenhang mit AVR/8-bit-Controllern üblichen &amp;quot;Bit-Breiten&amp;quot; (In Erläuterungen zum ARM7TDMI z.B. werden oft 32-bit Integer mit &amp;quot;Wort&amp;quot; ohne weitere Ergänzung bezeichnet). Es empfiehlt sich, bei der Überarbeitung von altem Code die im Abschnitt &#039;&#039;standardisierten ganzzahligen Datentypen&#039;&#039; beschriebenen Datentypen zu nutzen (stdint.h) und damit &amp;quot;Missverständnissen&amp;quot; vorzubeugen, die z.B. bei der Portierung von C-Code zwischen verschiedenen Plattformen auftreten können.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
typedef unsigned char      BYTE;       // besser: uint8_t  aus &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
typedef unsigned short     WORD;       // besser: uint16_t aus &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
typedef unsigned long      DWORD;      // besser: uint32_t aus &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
typedef unsigned long long QWORD;      // besser: uint64_t aus &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; BYTE : Der Datentyp BYTE definiert eine Variable mit 8 Bit Breite zur Darstellung von ganzen Zahlen im Bereich zwischen 0 ... 255. &lt;br /&gt;
&lt;br /&gt;
; WORD : Der Datentyp WORD definiert eine Variable mit 16 Bit Breite zur Darstellung von ganzen Zahlen im Bereich zwischen 0 ... 65535. &lt;br /&gt;
&lt;br /&gt;
; DWORD : Der Datentyp DWORD (gesprochen: Double-Word) definiert eine Variable mit 32 Bit Breite zur Darstellung von ganzen Zahlen im Bereich zwischen 0 ... 4294967295.&lt;br /&gt;
&lt;br /&gt;
; QWORD : Der Datentyp QWORD (gesprochen: Quad-Word) definiert eine Variable mit 64 Bit Breite zur Darstellung von ganzen Zahlen im Bereich zwischen 0 ... 18446744073709551615.&lt;br /&gt;
&lt;br /&gt;
== Zusätzliche Funktionen im Makefile ==&lt;br /&gt;
&lt;br /&gt;
=== Bibliotheken (Libraries/.a-Dateien) hinzufügen ===&lt;br /&gt;
&lt;br /&gt;
Um Funktionen aus Bibliotheken (&amp;quot;echte&amp;quot; Libraries, *.a-Dateien) zu nutzen, sind dem Linker die Namen der Bibliotheken als Parameter zu übergeben. Dazu ist die Option -l (kleines L) vorgesehen, an die der Name der Library angehängt wird. &lt;br /&gt;
&lt;br /&gt;
Dabei ist zu beachten, dass der Name der Library und der Dateiname der Library nicht identisch sind. Der hinter -l angegebene Name entspricht dem Dateinamen der Library ohne die Zeichenfolge &#039;&#039;lib&#039;&#039; am Anfang des Dateinamens und ohne die Endung &#039;&#039;.a&#039;&#039;. Sollen z.B. Funktionen aus einer Library mit dem Dateinamen &#039;&#039;libefsl.a&#039;&#039; eingebunden (gelinkt) werden, lautet der entsprechende Parameter -lefsl (vergl. auch -lm zum Anbinden von libm.a). &lt;br /&gt;
&lt;br /&gt;
In Makefiles wird traditonell eine make-Variable LDLIBS genutzt, in die &amp;quot;l-Parameter&amp;quot; abgelegt werden. Die WinAVR-makefile-Vorlage enthält diese Variable zwar nicht, dies stellt jedoch keine Einschränkung dar, da alle in der make-Variable LDFLAGS abgelegten Parameter an den Linker weitergereicht werden. &lt;br /&gt;
&lt;br /&gt;
Beispiele:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;code&amp;quot;&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
# Einbinden von Funktionen aus einer Library efsl (Dateiname libefsl.a)&lt;br /&gt;
LDFLAGS += -lefsl&lt;br /&gt;
# Einbinden von Funktionen aus einer Library xyz (Dateiname libxyz.a)&lt;br /&gt;
LDFLAGS += -lxyz&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Liegen die Library-Dateien nicht im Standard Library-Suchpfad, sind die Pfade mittels Parameter &#039;&#039;-L&#039;&#039; ebenfalls anzugeben. (Der vordefinierte Suchpfad kann mittels &#039;&#039;avr-gcc --print-search-dirs&#039;&#039; angezeigt werden.)&lt;br /&gt;
&lt;br /&gt;
Als Beispiel ein Projekt (&amp;quot;superapp2&amp;quot;), in dem der Quellcode von zwei Libraries (efsl und xyz) und der Quellcode der eigentlichen Anwendung in verschiedenen Verzeichnissen mit der folgenden &amp;quot;Baumstruktur&amp;quot; abgelegt sind:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;code&amp;quot;&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
superapp2&lt;br /&gt;
|&lt;br /&gt;
+----- efslsource (darin libefsl.a)&lt;br /&gt;
|&lt;br /&gt;
+----- xyzsource (darin libxyz.a)&lt;br /&gt;
|&lt;br /&gt;
+----- firmware (darin Anwendungs-Quellcode und Makefile)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Daraus folgt, dass im Makefile die Verzeichnis efslsource und xyzsource in den Library-Suchpfad aufzunehmen sind:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;code&amp;quot;&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
LDFLAGS += -L../efslsource/ -L../xyzsource/&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Fuse-Bits ===&lt;br /&gt;
&lt;br /&gt;
Zur Berechnung der Fuse-Bits bietet sich neben dem Studium des Datenblattes auch der [http://palmavr.sourceforge.net/cgi-bin/fc.cgi AVR Fuse Calculator] an. Gewarnt werden muss vor der Benutzung von PonyProg, weil dort durch die negierte Darstellung gern Fehler gemacht werden.&lt;br /&gt;
&lt;br /&gt;
Soll die Programmierung von Fuse- und Lockbits automatisiert werden, kann man dies ebenfalls durch Einträge im Makefile vornehmen, die beim Aufruf von &amp;quot;make program&amp;quot; an die genutzte Programmiersoftware übergeben werden. In der makefile-Vorlage von WinAVR (und mfile) gibt es dafuer jedoch keine &amp;quot;Ausfüllhilfe&amp;quot; (Stand 9/2006). Die folgenden Ausführungen gelten für die Programmiersoftware [[AVRDUDE]] (Standard in der WinAVR-Vorlage), können jedoch sinngemäß auf andere Programmiersoftware übertragen werden, die die Angabe der Fuse- und Lockbits-Einstellungen per Kommandozeilenparameter unterstützt (z.B. stk500.exe). Im einfachsten Fall ergänzt man im Makefile einige Variablen, deren Werte natürlich vom verwendeten Controller und den gewünschten Einstellungen abhängen (vgl. Datenblatt Fuse-/Lockbits):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#---------------- Programming Options (avrdude) ----------------&lt;br /&gt;
&lt;br /&gt;
#...&lt;br /&gt;
#Beispiel! f. ATmega16 - nicht einfach uebernehmen! Zahlenwerte anhand&lt;br /&gt;
#--------- des Datenblatts nachvollziehen und gegebenenfalls aendern.&lt;br /&gt;
#&lt;br /&gt;
AVRDUDE_WRITE_LFUSE = -U lfuse:w:0xff:m&lt;br /&gt;
AVRDUDE_WRITE_HFUSE = -U hfuse:w:0xd8:m&lt;br /&gt;
AVRDUDE_WRITE_LOCK  = -U lock:w:0x2f:m&lt;br /&gt;
#...&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Damit diese Variablen auch genutzt werden, ist der Aufruf von avrdude im Makefile entsprechend zu ergänzen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
# Program the device.  &lt;br /&gt;
program: $(TARGET).hex $(TARGET).eep&lt;br /&gt;
# ohne Fuse-/Lock-Einstellungen (nach WinAVR Vorlage Stand 4/2006)&lt;br /&gt;
#	$(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH) \&lt;br /&gt;
#        $(AVRDUDE_WRITE_EEPROM)&lt;br /&gt;
# mit Fuse-/Lock-Einstellungen&lt;br /&gt;
        $(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_LFUSE) \&lt;br /&gt;
        $(AVRDUDE_WRITE_HFUSE) $(AVRDUDE_WRITE_FLASH) \&lt;br /&gt;
        $(AVRDUDE_WRITE_EEPROM) $(AVRDUDE_WRITE_LOCK)&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Eine weiter Möglichkeit besteht darin, die Fuse- und Lockbit-Einstellungen vom Preprozessor/Compiler generieren zu lassen. Die Fuse-Bits werden dann bei Verwendung von AVRDUDE in eigene Hex-Files geschrieben. Hierzu kann man z.B. folgendes Konstrukt verwenden:&lt;br /&gt;
&lt;br /&gt;
In eine der C-Sourcen wird eine Variable je Fuse-Byte vom Typ &#039;&#039;unsigned char&#039;&#039; deklariert und in eine extra Section gepackt. Dies kann entweder in einem vorhandenen File passieren oder in ein neues (z.B. fuses.c) geschrieben werden. Das File muss im Makefile aber auf jeden Fall mit kompiliert und gelinkt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
// tiny 2313 fuses low byte&lt;br /&gt;
#define CKDIV8  7&lt;br /&gt;
#define CKOUT   6&lt;br /&gt;
#define SUT1    5&lt;br /&gt;
#define SUT0    4&lt;br /&gt;
#define CKSEL3  3&lt;br /&gt;
#define CKSEL2  2&lt;br /&gt;
#define CKSEL1  1&lt;br /&gt;
#define CKSEL0  0&lt;br /&gt;
&lt;br /&gt;
// tiny2313 fuses high byte&lt;br /&gt;
#define DWEN       7&lt;br /&gt;
#define EESAVE     6&lt;br /&gt;
#define SPIEN      5&lt;br /&gt;
#define WDTON      4&lt;br /&gt;
#define BODLEVEL2  3&lt;br /&gt;
#define BODLEVEL1  2&lt;br /&gt;
#define BODLEVEL0  1&lt;br /&gt;
#define RSTDISBL   0&lt;br /&gt;
&lt;br /&gt;
// tiny2313 fuses extended byte&lt;br /&gt;
#define SELFPRGEN  0&lt;br /&gt;
&lt;br /&gt;
#define LFUSE         __attribute__ ((section (&amp;quot;lfuses&amp;quot;)))&lt;br /&gt;
#define HFUSE         __attribute__ ((section (&amp;quot;hfuses&amp;quot;)))&lt;br /&gt;
#define EFUSE         __attribute__ ((section (&amp;quot;efuses&amp;quot;)))&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// select ext crystal 3-8Mhz&lt;br /&gt;
unsigned char lfuse LFUSE =&lt;br /&gt;
    ( (1&amp;lt;&amp;lt;CKDIV8) | (1&amp;lt;&amp;lt;CKOUT) | (1&amp;lt;&amp;lt;CKSEL3) | (1&amp;lt;&amp;lt;CKSEL2) | &lt;br /&gt;
      (0&amp;lt;&amp;lt;CKSEL1) | (1&amp;lt;&amp;lt;CKSEL0) | (0&amp;lt;&amp;lt;SUT1) | (1&amp;lt;&amp;lt;SUT0) );&lt;br /&gt;
unsigned char hfuse HFUSE =&lt;br /&gt;
    ( (1&amp;lt;&amp;lt;DWEN) | (1&amp;lt;&amp;lt;EESAVE) | (0&amp;lt;&amp;lt;SPIEN) | (1&amp;lt;&amp;lt;WDTON) | &lt;br /&gt;
      (1&amp;lt;&amp;lt;BODLEVEL2) | (1&amp;lt;&amp;lt;BODLEVEL1) | (0&amp;lt;&amp;lt;BODLEVEL0) | (1&amp;lt;&amp;lt;RSTDISBL) );&lt;br /&gt;
unsigned char efuse EFUSE =&lt;br /&gt;
    ((0&amp;lt;&amp;lt;SELFPRGEN));&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ACHTUNG: Die Bitpositionen wurden nicht vollständig getestet!&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Eine &amp;quot;1&amp;quot; bedeutet hier, dass das Fuse-Bit &#039;&#039;nicht&#039;&#039; programmiert wird - die Funktion also i.A. nicht aktiviert ist. Eine &amp;quot;0&amp;quot; hingegen aktiviert die meisten Funktionen. Dies ist wie im Datenblatt (1 = unprogrammed, 0 = programmed).&lt;br /&gt;
&lt;br /&gt;
Das Makefile muss nun noch um folgende Targets erweitert werden (mit Tabulator einrücken - nicht mit Leerzeichen):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;code&amp;quot;&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
lfuses: build&lt;br /&gt;
        -$(OBJCOPY) -j lfuses --change-section-address lfuses=0 \&lt;br /&gt;
          -O ihex $(TARGET).elf $(TARGET)-lfuse.hex&lt;br /&gt;
        @if [ -f $(TARGET)-lfuse.hex ]; then \&lt;br /&gt;
         $(AVRDUDE) $(AVRDUDE_FLAGS) -U lfuse:w:$(TARGET)-lfuse.hex; \&lt;br /&gt;
        fi;&lt;br /&gt;
&lt;br /&gt;
hfuses: build&lt;br /&gt;
        -$(OBJCOPY) -j hfuses --change-section-address hfuses=0 \&lt;br /&gt;
          -O ihex $(TARGET).elf $(TARGET)-hfuse.hex&lt;br /&gt;
        @if [ -f $(TARGET)-hfuse.hex ]; then \&lt;br /&gt;
         $(AVRDUDE) $(AVRDUDE_FLAGS) -U hfuse:w:$(TARGET)-hfuse.hex; \&lt;br /&gt;
        fi;&lt;br /&gt;
&lt;br /&gt;
efuses: build&lt;br /&gt;
        -$(OBJCOPY) -j efuses --change-section-address efuses=0 \&lt;br /&gt;
         -O ihex $(TARGET).elf $(TARGET)-efuse.hex&lt;br /&gt;
        @if [ -f $(TARGET)-efuse.hex ]; then \&lt;br /&gt;
         $(AVRDUDE) $(AVRDUDE_FLAGS) -U efuse:w:$(TARGET)-efuse.hex;&lt;br /&gt;
        fi;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Target &amp;quot;clean&amp;quot; muss noch um die Zeilen&lt;br /&gt;
&amp;lt;div class=&amp;quot;code&amp;quot;&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
        $(REMOVE) $(TARGET)-lfuse.hex&lt;br /&gt;
        $(REMOVE) $(TARGET)-hfuse.hex&lt;br /&gt;
        $(REMOVE) $(TARGET)-efuse.hex&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
erweitert werden, wenn auch die Fuse-Dateien gelöscht werden sollen.&lt;br /&gt;
&lt;br /&gt;
Um nun die Fusebits des angeschlossenen Controllers zu programmieren muss lediglichein &amp;quot;make lfuses&amp;quot;, &amp;quot;make hfuses&amp;quot; oder &amp;quot;make efuses&amp;quot; gestartet werden.&lt;br /&gt;
Bei den Fuse-Bits ist besondere Vorsicht geboten, da diese das Programmieren des Controllers unmöglich machen können. Also erst programmieren, wenn man einen HV-Programmierer hat oder ein paar Reserve-AVRs zur Hand ;-)&lt;br /&gt;
&lt;br /&gt;
Um weiterhin den &amp;quot;normalen&amp;quot; Flash beschreiben zu können, ist es wichtig, für das Target &amp;quot;*.hex&amp;quot; im Makefile nicht nur &amp;quot;-R .eeprom&amp;quot; als Parameter zu übergeben sondern zusätzlich noch &amp;quot;-R lfuses -R efuses -R hfuses&amp;quot;. Sonst bekommt AVRDUDE Probleme diese Sections in den Flash (wo sie ja nicht hingehören) zu schreiben.&lt;br /&gt;
&lt;br /&gt;
Siehe auch: [[AVR_Fuses#Vergleich_der_Fuses_bei_verschiedenen_Programmen|Vergleich der Fuses bei verschiedenen Programmen]]&lt;br /&gt;
&lt;br /&gt;
== Externe Referenzspannung des internen Analog-Digital-Wandlers ==&lt;br /&gt;
&lt;br /&gt;
Die minimale (externe) Referenzspannung des ADC darf nicht beliebig niedrig sein, vgl. dazu das (aktuellste) Datenblatt des verwendeten Controllers. z.B. beim ATMEGA8 darf sie laut Datenblatt (S.245, Tabelle 103, Zeile &amp;quot;VREF&amp;quot;) 2,0V nicht unterschreiten. HINWEIS: diese Information findet sich erst in der letzten Revision (Rev. 2486O-10/04) des Datenblatts.&lt;br /&gt;
&lt;br /&gt;
Meiner &amp;lt;!-- Wer? - es gibt inzwischen x Leute die mehr oder weniger viel in diesem Artikel geschrieben haben --&amp;gt; eigenen Erfahrung nach kann man aber (auf eigene Gefahr und natürlich nicht für Seriengeräte) durchaus noch ein klein wenig weiter heruntergehen, bei dem von mir unter die Lupe genommenen ATMEGA8L (also die Low-Voltage-Variante) funktioniert der ADC bei 5V Betriebsspannung mit bis zu VREF=1,15V hinunter korrekt, ab 1,1V und darunter digitalisiert er jedoch nur noch Blödsinn). Ich würde sicherheitshalber nicht unter 1,5V gehen und bei niedrigeren Betriebsspannungen mag sich die Untergrenze für VREF am Pin AREF ggf. nach oben&#039;&#039;&#039;(!)&#039;&#039;&#039; verschieben.&lt;br /&gt;
&lt;br /&gt;
In der letzten Revision des Datenblatts ist außerdem korrigiert, dass ADC4 und ADC5 sehr wohl 10 Bit Genauigkeit bieten (und nicht bloß 8 Bit, wie in älteren Revisionen irrtümlich angegeben.)&lt;br /&gt;
&lt;br /&gt;
= TODO =&lt;br /&gt;
* Aktualisierung Register- und Bitbeschreibungen an aktuelle AVR&lt;br /&gt;
* stdio.h, malloc() &lt;br /&gt;
* Code-Optimierungen (&amp;quot;tricks&amp;quot;), siehe auch Application Note [http://www.atmel.com/dyn/resources/prod_documents/doc1497.pdf AVR035: Efficient C Coding for AVR]&lt;br /&gt;
* &amp;quot;naked&amp;quot;-Funktionen&lt;br /&gt;
* SPI siehe [http://www.uni-koblenz.de/~physik/informatik/MCU/SPI.pdf SPI Bus mit Atmel AVR]&lt;br /&gt;
* I²C / TWI Bus [http://www.roboternetz.de/wissen/index.php/TWI]&lt;br /&gt;
* Bootloader (bez. auf boot.h)&lt;br /&gt;
* CAN-Bus&lt;br /&gt;
* Einsatz von einfachen Betriebssystemen auf dem AVR&lt;br /&gt;
* Übersicht zu den C bzw. GCC-predefined Makros (__DATE__, __TIME__,...)&lt;br /&gt;
[[Category:AVR]]&lt;br /&gt;
* ADC ; &lt;br /&gt;
* Timer&lt;br /&gt;
* USB ; Steuerung mit USB&lt;br /&gt;
* Multiplexen Siebensegment&lt;/div&gt;</summary>
		<author><name>Thymythos</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=RFM12_Protokoll_Stack&amp;diff=32407</id>
		<title>RFM12 Protokoll Stack</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=RFM12_Protokoll_Stack&amp;diff=32407"/>
		<updated>2008-11-08T10:39:25Z</updated>

		<summary type="html">&lt;p&gt;Thymythos: /* Typ 0: Management */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Bild:RFM12 Stack.svg|right]]&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel beschreibt einen [http://de.wikipedia.org/wiki/ISO/OSI ISO/OSI] Protokoll [http://de.wikipedia.org/wiki/Protokollstack Stack] für den [[RFM12]] Funkchip.&amp;lt;br/&amp;gt;&lt;br /&gt;
Einige Hardwarebeispiele finden sich in [[AVR RFM12]].&amp;lt;br/&amp;gt;&lt;br /&gt;
Fehler und Anregungen können gerne auf der [[Diskussion:RFM12_Protokoll_Stack|Diskussionsseite]] besprochen werden.&lt;br /&gt;
&lt;br /&gt;
Eine Referenz-Implementierung für den [[AVR]] wird bereitgestellt:&lt;br /&gt;
{| style=&amp;quot;border:1px dashed green&amp;quot;&lt;br /&gt;
|&#039;&#039;svn://mikrocontroller.net/rfm12/trunk/RFM12_Stack&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
;Implementierungskriterien&lt;br /&gt;
* Wo möglich werden [http://de.wikipedia.org/wiki/R%C3%BCckruffunktion Callback]-Funktionen anstatt [http://de.wikipedia.org/wiki/First_In_%E2%80%93_First_Out FIFOs] verwendet um RAM zu sparen.&lt;br /&gt;
* Interruptgesteuerter Ablauf des Stacks&lt;br /&gt;
* Funktionen sollten nicht blockieren&lt;br /&gt;
&lt;br /&gt;
== Layer 1: Physical ==&lt;br /&gt;
&lt;br /&gt;
[[Bild:RFM12 PHY StateMachine.svg|thumb|320px|Layer1 State Diagram]]&lt;br /&gt;
&lt;br /&gt;
Der Physical-Layer kümmert sich um die direkte Ansteuerung des RFM12. Alle Funktionen des Chips werden als Software-API bereitgestellt.&lt;br /&gt;
&lt;br /&gt;
Folgende Eigenschaften sind bereits vom RFM12 vorgegeben:&lt;br /&gt;
&lt;br /&gt;
* [http://de.wikipedia.org/wiki/ISM-Band 70cm Band (433MHz)]&lt;br /&gt;
* [http://de.wikipedia.org/wiki/Frequenzumtastung FSK]-Modulation&lt;br /&gt;
* Sync-Erkennung auf &#039;&#039;0x2D 0xD4&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Definiert werden muss jedoch noch:&lt;br /&gt;
&lt;br /&gt;
* Baudrate&lt;br /&gt;
* Zuordnung von Frequenzen zu [[#Kanalzuordnung|Kanälen]]&lt;br /&gt;
* Bandbreite der Kanäle&lt;br /&gt;
* Management der Sendeleistung/Empfangsempfindlichkeit&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;API&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
void RFM12_PHY_modeTX(void);&lt;br /&gt;
&lt;br /&gt;
void RFM12_PHY_modeRX(void);&lt;br /&gt;
&lt;br /&gt;
bool RFM12_PHY_busy(void);&lt;br /&gt;
&lt;br /&gt;
void RFM12_setBaudrate(uint32_t baud);&lt;br /&gt;
&lt;br /&gt;
void RFM12_setCenterFrequency(uint16_t freq);&lt;br /&gt;
&lt;br /&gt;
void RFM12_setDataFilter(bool autoLock, bool fastMode, bool analog, uint8_t dqdThres);&lt;br /&gt;
&lt;br /&gt;
void RFM12_setReceiverBandwidth(RFM12_VDI_t vdi, RFM12_RxBW_t bandwidth, RFM12_GAIN_t gain, RFM12_RSSI_t drssi);&lt;br /&gt;
&lt;br /&gt;
void RFM12_setPowerManagement(bool enRX, bool enBB, bool startTX, bool enSynth, bool enOSC, bool enBat, bool enWkT, bool clkOff);&lt;br /&gt;
&lt;br /&gt;
void RFM12_setTransmitPower(RFM12_Power_t power, RFM12_TxDev_t deviation);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Layer 2: Data Link ==&lt;br /&gt;
&lt;br /&gt;
=== Media Access Control (MAC) ===&lt;br /&gt;
&lt;br /&gt;
Der MAC-Layer ist sehr einfach gehalten und regelt den Zugriff auf das Medium. Hier soll ein [http://de.wikipedia.org/wiki/CSMA-CA CSMA/CA] Verfahren eingesetzt werden.&lt;br /&gt;
&lt;br /&gt;
# Im Grundzustand befindet sich der RFM12 im Empfangsmodus und wartet auf eine SYNC-Sequenz.&lt;br /&gt;
# Kommt eine Sendeanforderung, wird so lange gewartet bis das Medium frei ist, dann darf nach Ablauf einer (pseudo) zufälligen Zeitspanne gesendet werden.&lt;br /&gt;
# Wurde gerade ein Paket empfangen, darf sofort ein ACK gesendet werden.&lt;br /&gt;
&lt;br /&gt;
Der Frameaufbau ist teilweise vom RFM12 vorgegeben (SYNC-Erkennung). Der Start-Of-Frame (SOF) dient der Synchronisation. Als End-Of-Frame (EOF) wird ebenfalls die Sequenz &#039;&#039;0xAA&#039;&#039; verwendet. Diese darf im Datenteil nicht vorkommen!&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|+ MAC Frameaufbau&lt;br /&gt;
|-&lt;br /&gt;
!&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; | SOF&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; | Sync&lt;br /&gt;
! &#039;&#039;n Byte Daten&#039;&#039;&lt;br /&gt;
! EOF&lt;br /&gt;
|----&lt;br /&gt;
! Bits&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; | 16 || colspan=&amp;quot;2&amp;quot; | 16 || 0 - 512    || 8&lt;br /&gt;
|----&lt;br /&gt;
! Wert&lt;br /&gt;
| 0xAA || 0xAA     || 0x2D || 0xD4     || &#039;&#039;Daten&#039;&#039;  || 0xAA&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;API&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
void RFM12_MAC_setChannel(uint8_t channel);&lt;br /&gt;
&lt;br /&gt;
bool RFM12_MAC_isReceiving(void);&lt;br /&gt;
&lt;br /&gt;
bool RFM12_MAC_mediaBusy(void);&lt;br /&gt;
&lt;br /&gt;
void RFM12_MAC_startCtrlTransmission(void);&lt;br /&gt;
&lt;br /&gt;
void RFM12_MAC_endCtrlTransmission(void);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Logical Link Control (LLC) ===&lt;br /&gt;
&lt;br /&gt;
Der LLC-Layer kümmert sich um die Sicherung der zu übertragenden Daten.&lt;br /&gt;
Außerdem können Geräte direkt mit ihrer Adresse (8-Bit) angesprochen werden.&lt;br /&gt;
&lt;br /&gt;
;[http://de.wikipedia.org/wiki/Vorw%C3%A4rtsfehlerkorrektur FEC]&lt;br /&gt;
:Alle Bytes werden auf eine [[#Hamming-Tabelle|16-Bit Hamming-Sequenz]] erweitert, wodurch die Datenrate halbiert wird.&lt;br /&gt;
:Dies erlaubt es einzelne Bitfehler zu korrigieren.&lt;br /&gt;
:Bei zu vielen Fehlern können diese jedoch nicht erkannt werden.&lt;br /&gt;
:Im Hamming-Code kommt die Sequenz &#039;&#039;0xAA&#039;&#039; nicht vor (siehe MAC-Layer).&lt;br /&gt;
&lt;br /&gt;
;[http://de.wikipedia.org/wiki/Cyclic_Redundancy_Check CRC]&lt;br /&gt;
:Der gesamte Frame wird nochmals durch eine Checksumme gesichert. (CRC-8: &#039;&#039;x&amp;lt;sup&amp;gt;8&amp;lt;/sup&amp;gt; + x&amp;lt;sup&amp;gt;5&amp;lt;/sup&amp;gt; + x&amp;lt;sup&amp;gt;4&amp;lt;/sup&amp;gt; + 1&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Es werden mehrere Frame-Typen zur Verfügung gestellt:&lt;br /&gt;
&lt;br /&gt;
* Broadcast an alle Geräte (immer ohne ACK)&lt;br /&gt;
* Nachricht an ein bestimmtes Gerät (mit oder ohne ACK)&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|+ LLC Frameaufbau&lt;br /&gt;
|-&lt;br /&gt;
!&lt;br /&gt;
! Empfänger&lt;br /&gt;
! Sender&lt;br /&gt;
! need ACK&lt;br /&gt;
! is ACK&lt;br /&gt;
!&lt;br /&gt;
!&lt;br /&gt;
! TypeID&lt;br /&gt;
! &#039;&#039;n Byte Daten&#039;&#039;&lt;br /&gt;
! CRC-8&lt;br /&gt;
|----&lt;br /&gt;
! Bits&lt;br /&gt;
| 8      || 8      || 1 || 1 || 1 || 1 || 4 || 0-480 || 8&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039; API &#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
void RFM12_LLC_registerType(RFM12_ProtocolID_t typeID, RFM12_L3_Protocol_t proto);&lt;br /&gt;
&lt;br /&gt;
uint8_t RFM12_LLC_sendFrame(RFM12_ProtocolID_t proto, uint8_t receiver, bool requireACK);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Layer 3: Network ==&lt;br /&gt;
&lt;br /&gt;
Für den Network-Layer werden nur einige Beispiele angeführt. Ab hier können beliebige eigene Protokolle eingesetzt werden. Das verwendete Protokoll wird durch die &#039;&#039;TypeID&#039;&#039; im LLC-Layer angegeben. Die Layer-3-Protokolle sollten nach Möglichkeit nur über die LLC-API mit dem Rest des Stacks kommunizieren.&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;TypeID&#039;&#039;s sind wie folgt definiert:&lt;br /&gt;
&lt;br /&gt;
=== Typ 0: Management ===&lt;br /&gt;
&lt;br /&gt;
Management Protokoll: Beacons etc.&lt;br /&gt;
&lt;br /&gt;
* Sollte ähnliche Funktionen bieten wie das Service Discovery Protocol (SDP) bei Bluetooth&lt;br /&gt;
&lt;br /&gt;
=== Typ 1: Bytestream ===&lt;br /&gt;
&lt;br /&gt;
Die Einteilung in Pakete wird aufgehoben. Daten kommen 1:1 in der Reihenfolge an, wie sie gesendet wurden.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;API&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
void RFM12_Serial_setPeer(uint8_t peer);&lt;br /&gt;
&lt;br /&gt;
bool RFM12_Serial_txAvailable(void);&lt;br /&gt;
&lt;br /&gt;
void RFM12_Serial_txData(uint8_t data);&lt;br /&gt;
&lt;br /&gt;
bool RFM12_Serial_rxAvailable(void);&lt;br /&gt;
&lt;br /&gt;
uint8_t RFM12_Serial_rxData(void);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Typ 3: IPv4 ===&lt;br /&gt;
&lt;br /&gt;
z.B. [http://www.sics.se/~adam/uip/index.php/Main_Page uIP TCP/IP Stack] von Adam Dunkels &amp;lt;adam@dunkels.com&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Anhänge ==&lt;br /&gt;
&lt;br /&gt;
=== Sequenzdiagramme ===&lt;br /&gt;
&lt;br /&gt;
Empfang:&lt;br /&gt;
[[Bild:RFM12 RX Sequence.svg|center|800px|RX Sequenz]]&lt;br /&gt;
&lt;br /&gt;
Senden:&lt;br /&gt;
[[Bild:RFM12 TX Sequence.svg|center|800px|TX Sequenz]]&lt;br /&gt;
&lt;br /&gt;
=== Frames ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Beachte:&#039;&#039;&#039; Durch die Hamming-Codierung sind alle Bytes innerhalb des MAC-Layer doppelt so lang wie angegeben!&lt;br /&gt;
{|&lt;br /&gt;
! bgcolor=&amp;quot;#9fffa8&amp;quot; | MAC || bgcolor=&amp;quot;#a9f3f2&amp;quot; | LLC || bgcolor=&amp;quot;#d28787&amp;quot; | L3&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; align=&amp;quot;center&amp;quot; style=&amp;quot;text-align:center&amp;quot;&lt;br /&gt;
|+ Frameaufbau&lt;br /&gt;
|-&lt;br /&gt;
!&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; bgcolor=&amp;quot;#9fffa8&amp;quot; | SOF&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; bgcolor=&amp;quot;#9fffa8&amp;quot; | Sync&lt;br /&gt;
! bgcolor=&amp;quot;#a9f3f2&amp;quot; | Empfänger&lt;br /&gt;
! bgcolor=&amp;quot;#a9f3f2&amp;quot; | Sender&lt;br /&gt;
! bgcolor=&amp;quot;#a9f3f2&amp;quot; | need ACK | is ACK | | | TypeID&lt;br /&gt;
! bgcolor=&amp;quot;#d28787&amp;quot; | &#039;&#039;n Byte Daten&#039;&#039;&lt;br /&gt;
! bgcolor=&amp;quot;#a9f3f2&amp;quot; | CRC-8&lt;br /&gt;
! bgcolor=&amp;quot;#9fffa8&amp;quot; | EOF&lt;br /&gt;
|----&lt;br /&gt;
! Bits&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; bgcolor=&amp;quot;#9fffa8&amp;quot; | 16 || colspan=&amp;quot;2&amp;quot; bgcolor=&amp;quot;#9fffa8&amp;quot; | 16&lt;br /&gt;
| bgcolor=&amp;quot;#a9f3f2&amp;quot; | 8 || bgcolor=&amp;quot;#a9f3f2&amp;quot; | 8 || bgcolor=&amp;quot;#a9f3f2&amp;quot; | &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; 1 &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; | &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; 1 &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; |1|1| &amp;amp;nbsp;&amp;amp;nbsp; 4 &amp;amp;nbsp;&amp;amp;nbsp;&lt;br /&gt;
| bgcolor=&amp;quot;#d28787&amp;quot; | 0-480&lt;br /&gt;
| bgcolor=&amp;quot;#a9f3f2&amp;quot; | 8&lt;br /&gt;
| bgcolor=&amp;quot;#9fffa8&amp;quot; | 8&lt;br /&gt;
|----&lt;br /&gt;
! Wert&lt;br /&gt;
| bgcolor=&amp;quot;#9fffa8&amp;quot; | 0xAA || bgcolor=&amp;quot;#9fffa8&amp;quot; | 0xAA || bgcolor=&amp;quot;#9fffa8&amp;quot; | 0x2D || bgcolor=&amp;quot;#9fffa8&amp;quot; | 0xD4&lt;br /&gt;
| bgcolor=&amp;quot;#a9f3f2&amp;quot; | || bgcolor=&amp;quot;#a9f3f2&amp;quot; | || bgcolor=&amp;quot;#a9f3f2&amp;quot; | &lt;br /&gt;
| bgcolor=&amp;quot;#d28787&amp;quot; | &lt;br /&gt;
| bgcolor=&amp;quot;#a9f3f2&amp;quot; |&lt;br /&gt;
| bgcolor=&amp;quot;#9fffa8&amp;quot; | 0xAA&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Kanalzuordnung ===&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|+ 433MHz Band&lt;br /&gt;
|-&lt;br /&gt;
! Kanal&lt;br /&gt;
| 0 || 1 || 2 || 3 || 4 || 5 || 6 || 7 || 8 || 9 || 10 || 11 || 12 || 13 || 14 || 15&lt;br /&gt;
|-&lt;br /&gt;
! Mittenfrequenz&lt;br /&gt;
|  431.0 || 431.5 || 432.0 || 432.5 || 433.0 || 433.5 || 434.0 || 434.5 || 435.0 || 435.5 || 436.0 || 436.5 || 437.0 || 437.5 || 438.0 || 438.5&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Hamming-Tabelle ===&lt;br /&gt;
&lt;br /&gt;
==== Encodieren ====&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;3&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|&lt;br /&gt;
! colspan=&amp;quot;4&amp;quot; | Algorithmus&lt;br /&gt;
! colspan=&amp;quot;4&amp;quot; | Beispiel&lt;br /&gt;
|-&lt;br /&gt;
| 1:&lt;br /&gt;
| width=&amp;quot;80&amp;quot; |&lt;br /&gt;
| width=&amp;quot;160&amp;quot; colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 8-Bit Wert&lt;br /&gt;
| width=&amp;quot;160&amp;quot; colspan=&amp;quot;2&amp;quot; |&lt;br /&gt;
| width=&amp;quot;160&amp;quot; colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 10010110&lt;br /&gt;
| width=&amp;quot;80&amp;quot; |&lt;br /&gt;
|-&lt;br /&gt;
| 2: || || align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 4-7 ||  align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 0-3 || colspan=&amp;quot;2&amp;quot; | ||  align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 1001 || align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 0110 || &lt;br /&gt;
|-&lt;br /&gt;
| 3:&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | HammingE[(4-7)]&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | HammingE[(0-3)]&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 0xC7&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 0x38&lt;br /&gt;
|-&lt;br /&gt;
| 4:&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | high&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | low&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 11000111&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 00111000&lt;br /&gt;
|-&lt;br /&gt;
| 5:&lt;br /&gt;
| colspan=&amp;quot;4&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 16-Bit Codewort&lt;br /&gt;
| colspan=&amp;quot;4&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 11000111 00111000&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;3&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|+ HammingE&lt;br /&gt;
|-&lt;br /&gt;
!  0 || 1 || 2  || 3 || 4 || 5 || 6 || 7 || 8 || 9 || A || B || C || D || E || F&lt;br /&gt;
|-&lt;br /&gt;
|bgcolor=&amp;quot;#ff0000&amp;quot;|0x15||bgcolor=&amp;quot;#ff1111&amp;quot;|0x02||bgcolor=&amp;quot;#ff2222&amp;quot;|0x49||bgcolor=&amp;quot;#ff3333&amp;quot;|0x5E||bgcolor=&amp;quot;#ff4444&amp;quot;|0x64||bgcolor=&amp;quot;#ff5555&amp;quot;|0x73||bgcolor=&amp;quot;#ff6666&amp;quot;|0x38||bgcolor=&amp;quot;#ff7777&amp;quot;|0x2F||bgcolor=&amp;quot;#ff8888&amp;quot;|0xD0||bgcolor=&amp;quot;#ff9999&amp;quot;|0xC7||bgcolor=&amp;quot;#ffaaaa&amp;quot;|0x8C||bgcolor=&amp;quot;#ffbbbb&amp;quot;|0x9B||bgcolor=&amp;quot;#ffcccc&amp;quot;|0xA1||bgcolor=&amp;quot;#ffdddd&amp;quot;|0xB6||bgcolor=&amp;quot;#ffeeee&amp;quot;|0xFD||bgcolor=&amp;quot;#ffffff&amp;quot;|0xEA&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Die Einträge in der Tabelle sind so gewählt, dass der Code den maximalen [http://de.wikipedia.org/wiki/Hamming-Abstand#Hamming-Abstand_eines_Codes Hamming-Abstand] von 4 Bit hat.&lt;br /&gt;
&lt;br /&gt;
==== Dekodieren ====&lt;br /&gt;
&lt;br /&gt;
In der Tabelle &#039;&#039;HammingD&#039;&#039; stehen nur 4-Bit breite Werte. Um einen 8-Bit Wert zu erhalten müssen also 2 Einträge aus der Tabelle ausgewählt werden.&lt;br /&gt;
&lt;br /&gt;
Wird nun ein 16-Bit Wert empfangen, bestimmt das High-Byte den ersten Eintrag, das Low-Byte den zweiten.&lt;br /&gt;
&lt;br /&gt;
Es können bis zu zwei gekippte Bits im High- und im Low-Byte korrigiert werden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;3&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|&lt;br /&gt;
! colspan=&amp;quot;4&amp;quot; | Algorithmus || colspan=&amp;quot;4&amp;quot; | Beispiel (mit Bitfehlern)&lt;br /&gt;
|-&lt;br /&gt;
| 1:&lt;br /&gt;
| colspan=&amp;quot;4&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 16-Bit Codewort&lt;br /&gt;
| colspan=&amp;quot;4&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 110&#039;&#039;&#039;1&#039;&#039;&#039;0111 001&#039;&#039;&#039;0&#039;&#039;&#039;100&#039;&#039;&#039;1&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 2:&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | high&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | low&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 110&#039;&#039;&#039;1&#039;&#039;&#039;0111&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 001&#039;&#039;&#039;0&#039;&#039;&#039;100&#039;&#039;&#039;1&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 3:&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | HammingD[high]&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | HammingD[low]&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 0x09&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 0x06&lt;br /&gt;
|-&lt;br /&gt;
| 4: || || align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 4-7&lt;br /&gt;
| align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 0-3 || &lt;br /&gt;
| || align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 1001&lt;br /&gt;
| align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 0110 || &lt;br /&gt;
|-&lt;br /&gt;
| 5:&lt;br /&gt;
| width=&amp;quot;80&amp;quot; |&lt;br /&gt;
| width=&amp;quot;160&amp;quot; colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 8-Bit Wert&lt;br /&gt;
| width=&amp;quot;80&amp;quot; | || width=&amp;quot;80&amp;quot; |&lt;br /&gt;
| width=&amp;quot;160&amp;quot; colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 10010110&lt;br /&gt;
| width=&amp;quot;80&amp;quot; |&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;3&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|+ HammingD&lt;br /&gt;
|-&lt;br /&gt;
!  || 0 || 1 || 2  || 3 || 4 || 5 || 6 || 7 || 8 || 9 || A || B || C || D || E || F&lt;br /&gt;
|-&lt;br /&gt;
! 0&lt;br /&gt;
|bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ffaaAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07&lt;br /&gt;
|-&lt;br /&gt;
! 1&lt;br /&gt;
|bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03&lt;br /&gt;
|-&lt;br /&gt;
! 2&lt;br /&gt;
|bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07&lt;br /&gt;
|-&lt;br /&gt;
! 3&lt;br /&gt;
|bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07&lt;br /&gt;
|-&lt;br /&gt;
! 4&lt;br /&gt;
|bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03&lt;br /&gt;
|-&lt;br /&gt;
! 5&lt;br /&gt;
|bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03&lt;br /&gt;
|-&lt;br /&gt;
! 6&lt;br /&gt;
|bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07&lt;br /&gt;
|-&lt;br /&gt;
! 7&lt;br /&gt;
|bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07&lt;br /&gt;
|-&lt;br /&gt;
! 8&lt;br /&gt;
|bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ff1111&amp;quot;|0x01||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B&lt;br /&gt;
|-&lt;br /&gt;
! 9&lt;br /&gt;
|bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff0000&amp;quot;|0x00||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B&lt;br /&gt;
|-&lt;br /&gt;
! A&lt;br /&gt;
|bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ff7777&amp;quot;|0x07&lt;br /&gt;
|-&lt;br /&gt;
! B&lt;br /&gt;
|bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ff6666&amp;quot;|0x06||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F&lt;br /&gt;
|-&lt;br /&gt;
! C&lt;br /&gt;
|bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ff2222&amp;quot;|0x02||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09&lt;br /&gt;
|-&lt;br /&gt;
! D&lt;br /&gt;
|bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B||bgcolor=&amp;quot;#ffAAAA&amp;quot;|0x0A||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ff3333&amp;quot;|0x03||bgcolor=&amp;quot;#ffBBBB&amp;quot;|0x0B&lt;br /&gt;
|-&lt;br /&gt;
! E&lt;br /&gt;
|bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ff4444&amp;quot;|0x04||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ff9999&amp;quot;|0x09||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F&lt;br /&gt;
|-&lt;br /&gt;
! F&lt;br /&gt;
|bgcolor=&amp;quot;#ff8888&amp;quot;|0x08||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ff5555&amp;quot;|0x05||bgcolor=&amp;quot;#ffCCCC&amp;quot;|0x0C||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffDDDD&amp;quot;|0x0D||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E||bgcolor=&amp;quot;#ffFFFF&amp;quot;|0x0F||bgcolor=&amp;quot;#ffEEEE&amp;quot;|0x0E&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Funk]]&lt;br /&gt;
[[Kategorie:Wettbewerb]]&lt;/div&gt;</summary>
		<author><name>Thymythos</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=Diskussion:RFM12_Protokoll_Stack&amp;diff=32399</id>
		<title>Diskussion:RFM12 Protokoll Stack</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=Diskussion:RFM12_Protokoll_Stack&amp;diff=32399"/>
		<updated>2008-11-07T18:37:45Z</updated>

		<summary type="html">&lt;p&gt;Thymythos: /* Beispiel */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Fehler ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;F:&#039;&#039;&#039; &#039;&#039;(17.09.2008)&#039;&#039; Im IE haben die Hamming-Tabellen alle einen schwarzen Hintergrund und schwarze Schrift (Im Firefox ist die Darstellung i.o.)&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;A:&#039;&#039;&#039; Ich hab die Kurzschreibweise für Farben verwendet (#f12 statt #ff1122), ist aber eigentlich leider nur in CSS erlaubt... (Aber es scheint eine gute Methode zu sein um Inhalte vor IE nutzern zu verstecken *g*)&lt;br /&gt;
&lt;br /&gt;
== Anregungen ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;F:&#039;&#039;&#039; &#039;&#039;(31.08.2008)&#039;&#039; Ist der Code bereits benutzbar? Falls ja fände ein Beispielprogramm sehr hilfreich.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;A:&#039;&#039;&#039; Im LLC fehlt noch ein bisschen was, aber PHY und MAC sind benutzbar.&lt;br /&gt;
&lt;br /&gt;
== Fragen ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;F:&#039;&#039;&#039; &#039;&#039;(04.09.2008)&#039;&#039; Warum gibt es auf LLC-Ebene keine Paketlängeninformation? (Jörg Wunsch)&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;A:&#039;&#039;&#039; Overhead. Durch das Paketendezeichen ist die Länge definiert. Zugegeben, in manchen Applikationen erscheint es sinnvoll vor dem Empfang des Paketes die Länge zu wissen, aber IP hat z.B. dafür ein eigenes Feld.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;F:&#039;&#039;&#039; &#039;&#039;(07.10.2008)&#039;&#039; Benutzung?&lt;br /&gt;
Der Stack auf Layer 3 sieht ja so eigentlich ganz einfach zu verwenden aus. Aber wie genau benutze ich den jetzt?&lt;br /&gt;
Die einfachste Methode wäre ja beim Layer 3 ein init und sofort Daten draufschieben. Aber ich sehe im Quellcode keine Verbindung zu beispielsweise RFM12_PHY_init(). Also um welche Funktionen muss ich mich wirklich kümmern, um auf Layer 3 Bytes hin und her zu schicken?&lt;br /&gt;
Und ist das bischen was am 31.08.2008 fehlte inzwischen drinne?&lt;br /&gt;
&lt;br /&gt;
[[Benutzer:Malte|Malte]] 19:15, 7. Okt. 2008 (CEST)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;A:&#039;&#039;&#039; So in etwa hab ich mir das API gedacht:&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;quot;rfm12_phy.h&amp;quot;&lt;br /&gt;
#include &amp;quot;rfm12_mac.h&amp;quot;&lt;br /&gt;
#include &amp;quot;rfm12_llc.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
#define MY_RECEIVER  2&lt;br /&gt;
#define MY_PROTOCOL  13&lt;br /&gt;
#define BUF_SIZE     16&lt;br /&gt;
&lt;br /&gt;
uint8_t *buffer = &amp;quot;Hello world&amp;quot;;&lt;br /&gt;
uint8_t pos;&lt;br /&gt;
&lt;br /&gt;
void myrx(uint8_t data) {&lt;br /&gt;
    // TODO: handle rx data&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int16_t mytx(void) {&lt;br /&gt;
    if(pos &amp;lt; sizeof(buffer))&lt;br /&gt;
        return txBuf[pos++];&lt;br /&gt;
    return RFM12_L3_EOD;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void myack(bool ack) {&lt;br /&gt;
    printf(&amp;quot;Sending &amp;quot;);&lt;br /&gt;
    if(ack) printf(&amp;quot;OK\n&amp;quot;);&lt;br /&gt;
    else    printf(&amp;quot;failed\n&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void main() {&lt;br /&gt;
    RFM12_L3_Protocol_t proto = {myrx, mytx, myack};&lt;br /&gt;
&lt;br /&gt;
    RFM12_PHY_init();&lt;br /&gt;
    RFM12_MAC_init();&lt;br /&gt;
    RFM12_MAC_setChannel(1);&lt;br /&gt;
    RFM12_LLC_registerType(MY_PROTOCOL, proto);&lt;br /&gt;
&lt;br /&gt;
    while(1) {&lt;br /&gt;
         while(RFM12_MAC_mediaBusy());&lt;br /&gt;
         pos = 0;&lt;br /&gt;
         RFM12_LLC_sendFrame(MY_PROTOCOL, MY_RECEIVER, false);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;/div&gt;</summary>
		<author><name>Thymythos</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=AVR_RFM12&amp;diff=32398</id>
		<title>AVR RFM12</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=AVR_RFM12&amp;diff=32398"/>
		<updated>2008-11-07T17:12:56Z</updated>

		<summary type="html">&lt;p&gt;Thymythos: /* USBprogRFM12 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Schaltungen und Software für AVR und das Funkmodul [[RFM12]].&lt;br /&gt;
&lt;br /&gt;
== SVN ==&lt;br /&gt;
&lt;br /&gt;
svn://mikrocontroller.net/rfm12&lt;br /&gt;
&lt;br /&gt;
Wegen Zugangsdaten bitte bei [http://www.mikrocontroller.net/user/show/andreas Andreas Schwarz] melden.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Software ==&lt;br /&gt;
&lt;br /&gt;
=== Treiber ===&lt;br /&gt;
&lt;br /&gt;
[http://www.mikrocontroller.net/attachment/22473/rfm12_pc.zip Firmware v1.0.0] von Benedikt K.&lt;br /&gt;
&lt;br /&gt;
[http://www.mikrocontroller.net/attachment/23542/RMxx_Driver.tar.bz2 Firmware v2.0.1] von Jürgen Eckert&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot;&lt;br /&gt;
|+ Funktionalität&lt;br /&gt;
|-&lt;br /&gt;
!  || Beschreibung || Software&lt;br /&gt;
|-&lt;br /&gt;
!1. Stufe:&lt;br /&gt;
| Die Daten von der seriellen Schnittstelle werden über die Funkstrecke auf die serielle Schnittstelle der anderen Seite übertragen. (Wir freuen uns über jedes Byte das ankommt)&lt;br /&gt;
| [http://www.mikrocontroller.net/topic/67273#564945 Claude Schwarz], [http://www.mikrocontroller.net/topic/71682#584915 Benedikt K.] oder [http://www.mikrocontroller.net/attachment/36742/RFM12_V3.zip Manuel Stahl]&lt;br /&gt;
|-&lt;br /&gt;
! 2. Stufe:&lt;br /&gt;
| Es findet eine Fehlererkennung (z.B. mit CRC-Summen) statt. Fehlerhafte Daten werden erneut angefordert. Dadurch gehen auf der Funkstrecke keine Daten verloren und es werden keine Daten verfälscht.&lt;br /&gt;
| [http://www.mikrocontroller.net/topic/71682#585851 Benedikt K.]&lt;br /&gt;
|-&lt;br /&gt;
! 3. Stufe:&lt;br /&gt;
| Die Datenübertragung wird individualisiert. Dadurch können zwei Funkstrecken, die im gleichen Empfangsbereich liegen nebeneinander arbeiten, ohne sich zu beeinträchtigen.&lt;br /&gt;
| [[RFM12_Protokoll_Stack]]&lt;br /&gt;
|-&lt;br /&gt;
! 4. Stufe: &lt;br /&gt;
| Die Datenübertragung wird verschlüsselt und damit abhörsicher.&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
!5. Stufe:&lt;br /&gt;
| Neben den Daten der seriellen Schnittstelle werden auch Änderungen der Statusleitungen übertragen. Damit erhält man eine &amp;quot;RS232-Verlängerung&amp;quot; über eine Funkstrecke, die fehlerfrei arbeitet und zu einer Drahtverbindung weitestgehend kompatibel ist.&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== RS232 &amp;lt;-&amp;gt; RFM12 ===&lt;br /&gt;
&lt;br /&gt;
TODO&lt;br /&gt;
&lt;br /&gt;
=== USB &amp;lt;-&amp;gt; RFM12 ===&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;&#039;[http://www.obdev.at/products/avrusb/index.html avrusb]&#039;&#039;&#039; lässt sich ein USB-Slave in Software emulieren.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;[http://www.recursion.jp/avrcdc/ AVR-CDC]&#039;&#039;&#039; läuft mit Anpassung der USB-Pins. &#039;&#039;(Zumindest unter Windows an einem USB2.0-Port)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Adapter für &#039;&#039;&#039;[http://www.embedded-projects.net/?page_id=135 USBprog]:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Funktionierender Code liegt im oben genannten SVN&lt;br /&gt;
* Implementiert die USB-CDC-Klasse (kein Treiber nötig)&lt;br /&gt;
* Sicherung der Übertragung durch Hamming-Code&lt;br /&gt;
* Work in progress... (Manuel Stahl)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Hardware ==&lt;br /&gt;
&lt;br /&gt;
=== Basismodul V1.0 ===&lt;br /&gt;
&lt;br /&gt;
==== Prozessor ====&lt;br /&gt;
&lt;br /&gt;
ATmega8 TQFP32 (kompatibel ATmega48, ATmega88, ATmega168)&lt;br /&gt;
&lt;br /&gt;
==== Schnittstellen ====&lt;br /&gt;
&lt;br /&gt;
* RS232&lt;br /&gt;
* I²C:&lt;br /&gt;
* USB&lt;br /&gt;
* GPIO&lt;br /&gt;
&lt;br /&gt;
==== Platine ====&lt;br /&gt;
&lt;br /&gt;
[[Bild:AVR RFM12 Schematic.png|200px|ATmega48 + USB]]&lt;br /&gt;
[[Bild:AVR RFM12 Board TOP.png|220px|2-lagig top]]&lt;br /&gt;
[[Bild:AVR RFM12 Board BOTTOM.png|240px|2-lagig bottom]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Bauteile:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Größe: SMD 0603&lt;br /&gt;
&lt;br /&gt;
* R1, R2: 68R (nur USB)&lt;br /&gt;
* R3, R4: 10k&lt;br /&gt;
* R5: 1k5 (nur USB)&lt;br /&gt;
* C1, C2: 22pF&lt;br /&gt;
* C3 - C9: 100nF&lt;br /&gt;
* Q1: 12Mhz (nur USB)&lt;br /&gt;
* D1, D2: beliebig, Minimelf&lt;br /&gt;
* IC3: MAX3221CUE&lt;br /&gt;
&lt;br /&gt;
==== Bugs / Erweiterungen ====&lt;br /&gt;
&lt;br /&gt;
* Der 1,5k Widerstand muss direkt an den VCC-Pin angelötet werden (Pad ist nicht verbunden)&lt;br /&gt;
* Beim Fertigen wurde das Polygon, welches das VCC-Signal durch die eine Ecke des ATmega48 leitet, unterbrochen. Hier hilft nur eine Drahtbrücke.&lt;br /&gt;
* Unter den RFM12 und unter das Quarz am Besten Isolierband kleben!&lt;br /&gt;
* Beim Programmieren sollte der SEL des RFM12 (J1 der zweite Pin vom RS232 aus) auf VCC gelegt werden&lt;br /&gt;
&lt;br /&gt;
==== Fertigung ====&lt;br /&gt;
&lt;br /&gt;
Kosten:&lt;br /&gt;
&lt;br /&gt;
* MiniUSB SMD: &#039;&#039;&#039;1,25€&#039;&#039;&#039;&lt;br /&gt;
* HF-Buchse MMCX: &#039;&#039;&#039;4,25€&#039;&#039;&#039;&lt;br /&gt;
* ATmega48: &#039;&#039;&#039;2,85€&#039;&#039;&#039;&lt;br /&gt;
* MAX3221CUE: &#039;&#039;&#039;1,10€&#039;&#039;&#039;&lt;br /&gt;
* Quarz 12Mhz 30ppm: &#039;&#039;&#039;1,19€&#039;&#039;&#039;&lt;br /&gt;
* Kleinkram: &#039;&#039;&#039;&amp;lt; 1,10€&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* habe ein verbindliches Angebot für 24 Stück von http://mme-pcb.de/: &#039;&#039;&#039;4,00€ pro Platine&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[http://www.mikrocontroller.net/attachment/24012/RFM12.brd Board]:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Board bottom bestuecken.png|200px|bottom]]&lt;br /&gt;
[[Bild:AVR RFM12 Board top bestuecken.png|200px|top]]&lt;br /&gt;
&lt;br /&gt;
=== USBprogRFM12 ===&lt;br /&gt;
&lt;br /&gt;
Da der USBprog genau das SPI-Interface des ATmega32 zur Verfügung stellt, eignet er sich perfekt als USB-RFM12-Adapter.&lt;br /&gt;
&lt;br /&gt;
[[Bild:USBprogRFM12_schematic.png|200px|USBprogRFM12]] [[Bild:USBprogRFM12_board.png|200px|USBprogRFM12]]&lt;br /&gt;
&lt;br /&gt;
[[Bild:USBprogRFM12.jpg|400px|USBprogRFM12]]&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
* [http://www.mikrocontroller.net/topic/65984 Allgemeine Diskussion]&lt;br /&gt;
* [http://www.mikrocontroller.net/topic/71682  bidirektionale RS232 Funkbrücke mit RFM12]&lt;br /&gt;
* [http://www.das-labor.org/wiki/Datenfunk_mit_dem_AVR Datenfunk mit dem AVR] bei das-labor.org&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Projekte]]&lt;br /&gt;
[[Kategorie:AVR]]&lt;br /&gt;
[[Kategorie:Funk]]&lt;/div&gt;</summary>
		<author><name>Thymythos</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=Datei:USBprogRFM12.jpg&amp;diff=32397</id>
		<title>Datei:USBprogRFM12.jpg</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=Datei:USBprogRFM12.jpg&amp;diff=32397"/>
		<updated>2008-11-07T17:12:15Z</updated>

		<summary type="html">&lt;p&gt;Thymythos: USBprog mit RFM12&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;USBprog mit RFM12&lt;/div&gt;</summary>
		<author><name>Thymythos</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=AVR&amp;diff=32396</id>
		<title>AVR</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=AVR&amp;diff=32396"/>
		<updated>2008-11-07T16:56:34Z</updated>

		<summary type="html">&lt;p&gt;Thymythos: /* Software */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Die AVR-[[Mikrocontroller]] von [http://www.atmel.com Atmel] sind besonders in Deutschland sehr beliebt, da sie meist in DIL-Gehäusen verfügbar sind, per [[ISP | In-System-Programming]] programmiert werden können, und eine Vielzahl von kostenlosen Programmen zur Softwareentwicklung (Assembler, Compiler) existiert. Diese Eigenschaften machen den AVR zum perfekten Mikrocontroller für Anfänger.&lt;br /&gt;
&lt;br /&gt;
Über die Bedeutung des Namens &amp;quot;AVR&amp;quot; gibt es verschiedene Ansichten; manche meinen er sei eine Abkürzung für &#039;&#039;&#039;A&#039;&#039;&#039;dvanced &#039;&#039;&#039;V&#039;&#039;&#039;irtual [[RISC]], andere vermuten dass der Name aus den Anfangsbuchstaben der Namen der Entwickler (&#039;&#039;&#039;A&#039;&#039;&#039;lf Egin Bogen und &#039;&#039;&#039;V&#039;&#039;&#039;egard Wollan) zusammengesetzt wurde. Laut Atmel ist der Name bedeutungslos.&lt;br /&gt;
&lt;br /&gt;
==Architektur==&lt;br /&gt;
&lt;br /&gt;
Die Architektur ist eine 8-Bit-[[Harvard-Architektur]], das heißt es gibt getrennte Speicher für Programmcode ([[Speicher#Flash-ROM |Flash-ROM]]) und Daten ([[Speicher#RAM |RAM]]). Bei der Programmierung hat das den Nachteil, dass sich Konstanten aus dem ROM nicht mit dem gleichen Code laden lassen wie Daten aus dem RAM. Abgesehen davon ist der Aufbau des Controllers recht übersichtlich und birgt wenige Fallstricke.&lt;br /&gt;
&lt;br /&gt;
* 32 größtenteils gleichwertige Register&lt;br /&gt;
* 3 Pointerregister&lt;br /&gt;
* ca. 110 Befehle, die meist 1-2 Taktzyklen dauern&lt;br /&gt;
* Taktfrequenz bis 20 MHz&lt;br /&gt;
* Betriebsspannung von 1,8-5,5 V&lt;br /&gt;
* Speicher&lt;br /&gt;
**1-256 kB [[Speicher#Flash-ROM | Flash-ROM]]&lt;br /&gt;
**0-4 kB [[Speicher#EEPROM | EEPROM]]&lt;br /&gt;
**0-8 kB [[speicher#RAM | RAM]]&lt;br /&gt;
* Peripherie: [[AD-Wandler]], [[Timer]], [[SPI]], [[I²C]] (TWI), [[UART]], [[Speicher#Mit_XMEM-Interface | externer SRAM]]&lt;br /&gt;
* [[JTAG]] bei den größeren ATmegas&lt;br /&gt;
&lt;br /&gt;
== Software ==&lt;br /&gt;
&lt;br /&gt;
* [[AVR-Studio]]: Kostenlose Enwicklungsumgebung mit Simulator&lt;br /&gt;
* [http://sourceforge.net/projects/kontrollerlab/ KontrollerLab]: Kostenlose Entwicklungsumgebung für KDE&lt;br /&gt;
* [[AVR Eclipse]]: Plugin-basierte kostenlose Entwicklungsumgebung (Win, Linux, Mac)&lt;br /&gt;
* [[AVR-GCC]]: Kostenloser C-Compiler&lt;br /&gt;
* [http://www.mcselec.com/bascom-avr.htm Bascom AVR], [http://www.fastavr.com/ FastAVR]: beliebte Basic-Compiler&lt;br /&gt;
* [http://www.e-lab.de AVRCo Pascal Compiler]&lt;br /&gt;
* [http://amforth.sourceforge.net/ amforth]:  interaktives ANS Forth für AVR unter GNU Lizenz (Open Source)&lt;br /&gt;
&lt;br /&gt;
== Boards &amp;amp; Starterkits ==&lt;br /&gt;
&lt;br /&gt;
* [http://shop.mikrocontroller.net/?category_id=10 diverse im Mikrocontroller.net-Shop]&lt;br /&gt;
* [[STK200]]&lt;br /&gt;
* [[STK500]]&lt;br /&gt;
* [[STK600]]&lt;br /&gt;
* [[AVR Butterfly]]&lt;br /&gt;
* AVR-ISP / AVR-ISP mkII&lt;br /&gt;
* AVR-Dragon &lt;br /&gt;
* AVR JTAG-ICE&lt;br /&gt;
* [http://www.robotikhardware.de RN-Control]&lt;br /&gt;
* [http://www.conrad.de C-Control PRO]&lt;br /&gt;
* [http://www.myavr.de myAVR Board]&lt;br /&gt;
* [http://www.rowalt.de AVR Lehrbuch und -bausatz]&lt;br /&gt;
* [http://www.pollin.de preiswerte Starterkits sowie Lösungen für RFID-125kHz und EtherNet]&lt;br /&gt;
* [http://www.lochraster.org/rumpus Rumpus von lochraster.org, ist ein günstiges und gut dokumentiertes Starterkit mit Atmega 168]&lt;br /&gt;
&lt;br /&gt;
== Projekte ==&lt;br /&gt;
* [[PWM_foxlight]] - LED Lampe mit PWM&lt;br /&gt;
* [[Digitaler Funktionsgenerator]]&lt;br /&gt;
* [[Midi Rekorder mit MMC/SD-Karte]]&lt;br /&gt;
* [[Schrittmotor-Controller (Stepper)]]&lt;br /&gt;
* [[Pulsuhrempfänger mit AVR Butterfly]]&lt;br /&gt;
* [[DCF77-Funkwecker mit AVR]]&lt;br /&gt;
* [[Fahrradcomputer]]&lt;br /&gt;
* [[Einfacher und billiger Webserver mit AtMega32]]&lt;br /&gt;
* [[AVR RFM12]]&lt;br /&gt;
&lt;br /&gt;
== Tutorials ==&lt;br /&gt;
* [[AVR-Tutorial]]&lt;br /&gt;
* [[AVR-GCC-Tutorial]]&lt;br /&gt;
* http://www.avr-asm-tutorial.net&lt;br /&gt;
&lt;br /&gt;
== Tipps &amp;amp; Hinweise ==&lt;br /&gt;
* [[AVR Typen]] - Die verschiedenen Typen (AT90S, ATmega, ATTiny)&lt;br /&gt;
* [[AVR Checkliste]] - Liste mit Hinweisen zur Lösung üblicher Probleme&lt;br /&gt;
* [[AVR Fuses|Fuse-Bits]] - Das Setzen der Fuse-Bits ist ein berüchtigter Fallstrick bei den AVRs; vor dem Rumspielen damit unbedingt diese Hinweise lesen!&lt;br /&gt;
* [[AVR In System Programmer]] - Programmierhardware&lt;br /&gt;
* [[Pony-Prog Tutorial]] - Hinweise zur Programmiersoftware PonyProg&lt;br /&gt;
* [[AVRDUDE]] - Programmiersoftware für die Kommandozeile&lt;br /&gt;
* [[AVR-GCC-Codeoptimierung]] - Wie man mehr aus dem Controller rausholen kann, ohne ein Assembler-Guru sein zu muessen.&lt;br /&gt;
* [[AVR Softwarepool]] - Verschiedene Softwaremodule und Codeschnippsel aus der Codesammlung&lt;br /&gt;
&lt;br /&gt;
Weitere Verweise (Links) auf externe Informationen und Projekte finden sich in der &#039;&#039;&#039;[[Linksammlung#AVR|Linksammlung]]&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
[[Category:Mikrocontroller]][[Category:AVR]]&lt;br /&gt;
__NOTOC__&lt;/div&gt;</summary>
		<author><name>Thymythos</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=Benutzer:Thymythos&amp;diff=32352</id>
		<title>Benutzer:Thymythos</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=Benutzer:Thymythos&amp;diff=32352"/>
		<updated>2008-11-06T18:41:59Z</updated>

		<summary type="html">&lt;p&gt;Thymythos: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{|&lt;br /&gt;
|Name: || Manuel Stahl&lt;br /&gt;
|-&lt;br /&gt;
|Mail: || mythos_at_tru42.org&lt;br /&gt;
|-&lt;br /&gt;
|Jabber: || mythos_at_tru42.org&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Projekte im Wiki ===&lt;br /&gt;
&lt;br /&gt;
* [[AVR RFM12]]&lt;br /&gt;
* [[RFM12 Protokoll Stack]]&lt;/div&gt;</summary>
		<author><name>Thymythos</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=Diskussion:AVR-GCC-Tutorial&amp;diff=32351</id>
		<title>Diskussion:AVR-GCC-Tutorial</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=Diskussion:AVR-GCC-Tutorial&amp;diff=32351"/>
		<updated>2008-11-06T18:40:26Z</updated>

		<summary type="html">&lt;p&gt;Thymythos: /* Tutorial nach Wikibooks portieren */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Benutzerfreundlichkeit erhöhen ==&lt;br /&gt;
&lt;br /&gt;
Das Tutorial ist momentan ein prima Nachschlagewerk für erfahrene Benutzer, leider hat seine Qualität als Tutorial etwas nachgelassen. Auch ich habe mit ihm meinen Einstieg in dei Welt der µC gefunden, aber ich glaube ich würde dies nicht mehr schaffen. Werde in den nächsten Wochen das Tutorial ein wenig verbessern, an den Mega16 anpassen und erweitern. &lt;br /&gt;
Zusätzlich werde ich ein Tutorial für Digital-Elektronik schreiben.&lt;br /&gt;
&lt;br /&gt;
[[Benutzer:FeeJai|FeeJai]] 20:26, 27. Nov 2006 (CET)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Dazu&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
* &amp;quot;...momentan ein prima Nachschlagewerk für erfahrene Benutzer...&amp;quot;: Sorry, aber &amp;quot;erfahrene Benutzer&amp;quot; finden dem Tutorial wenig bis garnichts neues. Die Dokumentation der avr-libc ist eher ein gutes Nachschlagewerk. Das Tutorial nicht, vieles wird nicht detailliert erläutert und einiges nicht mal angesprochen. Was genau macht das Tutorial zu einem Nachschlagewerk?&lt;br /&gt;
* &amp;quot;Qualität als Tutorial etwas nachgelassen&amp;quot;: Da ich wohl die meisten Erweiterungen und Aktualisierungen geschrieben habe, seit der Artikel ins Wiki aufgenommen wurde, nehme ich das mal zum Anlass zu fragen, was mit &amp;quot;Qualität nachlassen&amp;quot; gemeint ist. Hier &amp;quot;Qualität nachlassen&amp;quot; ohne ein wenig Begründung hinzuschreiben ist mir zu platt. Wenn richtig erinnert, habe zumindest ich nichts aus einen &amp;quot;qualitativ&amp;quot; hochwertigeren alten Zustand gelöscht (bis auf Links zu Quellcode, die nicht mehr gültig waren und nur neuen Text dazu geschrieben bzw. veraltete Informationen aktualisiert.&lt;br /&gt;
* &amp;quot;...nicht mehr schaffen...&amp;quot;: Warum nicht? Was war vorher einfacher &amp;quot;zu schaffen&amp;quot;? Nur weil der Makefile-Exkurs etwas ausgeufert ist? Falls das der einzige Grund war: habe nun versucht, es etwas aufzuspalten. Etwas konkreter dürfte das &amp;quot;nicht mehr schaffen&amp;quot; schon sein. Bisher habe ich diese Meinung genau einmal gelesen (hier), aber vielleicht auch woanders nicht wahrgenommen. Wenn die Verbesserung darin bestand, die Erläuterungen zum Makefiles in den Anhang zu verschieben und dann im Text zu schreiben: &amp;quot;Sollte man noch nie mit Makefiles gearbeitet haben ist es nun an der Zeit sich den Exkurs: makefiles im Anhang A durchzulesen.&amp;quot; ist das bestenfalls unglücklich. Der Großteil der Anfänger, die das Tutorial zum Einstieg lesen, wird vorher kaum ein makefile selbst editiert haben. Viele von den, die C mit Borland, MS oder welcher IDE auch immer gelernt haben, werden nicht mal wissen, was ein makefile ist - da hilft auch der Hinweis auf MFile erstmal wenig. Den ganzen Abschnitt nach ganz unten zu verschieben (und dabei Links und Gliederung zu zerschießen) und dann unmittelbar an der ursprünglichen Stelle den wahrscheinlich typischen Anfänger (die eigentliche Zielgruppe) dahin zu verweisen, war für mich keine nachvollziehbare Verbesserung der &amp;quot;Benutzerfreundlichkeit&amp;quot;.&lt;br /&gt;
* &amp;quot;...in den nächsten Wochen...&amp;quot;: Dann aber zumindest den Artikel nach jeder Änderung so hinterlassen, dass die Gliederungsebenen und internen Verlinkungen noch passen - nicht so wie zum Stand 20061128_1900.&lt;br /&gt;
* &amp;quot;...an den Mega16...&amp;quot;: die Aktualisierung der Tabellen mit Registerbeschreibungen ist eine gute Idee. Aber wenn man sich schon die Mühe macht, dann wäre eine Anpassung an aktuelle AVR (ATmega644, ATmega48/88/168,...) sinnvoller, da die Registernamen bei den neueren von Herstellerseite noch etwas einheitlicher sind und sich wahrscheinlich in Zukunft auch selten jemand die Mühe macht die Beschreibungen zu überarbeiten. ATmega16 ist auch schon etwas betagt. Aber nicht aufhalten lassen, für ATmega16 ist auf jeden Fall schon besser als für abgekündigte AT90S.&lt;br /&gt;
* In der neuen Makefile-Seite (Stand 20061128_1900) blind die Vorlage zusammen mit dem Eintrag für CPPSRC (&amp;quot;CPPSRC = main.cpp&amp;quot;) reinzukopieren und dann in der &amp;quot;Einführung&amp;quot; darauf zu verweisen, hatte die Benutzerfreundlichkeit eher umkehren. &lt;br /&gt;
* Die Ergänzung um eine Schritt-für-Schritt Einführung ist ein gute Idee. War aber meiner Meinung zu knapp, z.B. Begriffe, die ein Microcontroller-Anfänger eher nicht kennt, Erklärungen nicht ganz richtig (aber das sind meine Ergänzungen/Änderungen wahrscheinlich auch nicht alle). Die inkompatible Binärschreibweise (0b00..) war nicht gut (braucht gepatchten gcc - nicht alle nutzen WinAVR). Syntaxfehler (fehlendes ;).&lt;br /&gt;
&lt;br /&gt;
Also: behutsamer Erweitern, mindestens einmal prüfen - im Zweifel den Compiler anwerfen und testen (makefile, Syntaxfehler), größere Änderungen auf dieser Seite zur Diskussion stellen. Gliederung und Verlinkung beachten. &lt;br /&gt;
&lt;br /&gt;
Nun denn, habe ein wenig an dem Tutorial herumgebastelt, einiges übernommen, einiges ergänzt aber an einigen Stellen Änderungen auch rückgängig gemacht. Das soll aber kein Anlass sein, nun keine Änderungen oder Erweiterungen mehr einzubringen. Das Wiki &amp;quot;lebt&amp;quot; davon, dass viele Leute das beitragen, was sie für richtig halten und das Ganze sich auf Dauer durch Ergänzungen und Änderungen stetig verbessert.&lt;br /&gt;
&lt;br /&gt;
Martin Thomas&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Hallo! Mich freut es, dass sich jemand für meine Änderungen interessiert und diese auch verbessert. Inzwischen wurden ja noch ein paar kleine Änderungen vorgenommen. Was ich besonders wichtig finde, ist dass der Benutzer ein schnelles Erfolgserlebnis hat und damit nicht mehr so leicht frustriert aufgibt. Deswegen habe ich den Exkurs Makefiles in den Anhang verschoben. Ich fand dass er ansonsten zu abschreckend ist und potentielle Anfänger geradezu erschlägt. Bei meinem Start habe ich ihn übersprungen und das compilieren schlug natürlich fehl. Allerdings hatte ich die LCD samples von U. Radig auf meinem PC und habe sein Makefile beutzt. Daher das sample für Anfänger.&lt;br /&gt;
==&amp;gt; Ich wäre dafür den sehr ausführlichen &amp;quot;Exkurs&amp;quot; in den Anhang zu verschieben, Anfänger mit einem bereitgestellten Beispiel beginnen zu lassen und das Makefile-Konzept anhand praktischer Beispiele nach und nach zu erklären. So sind auch die meisten sehr erfolgreichen Computerbücher (z.B. von Michael Kofler) aufgebaut.&lt;br /&gt;
Die Sache mit dem Nachschlagewerk für erfahrene Benutzer, hätte ich vielleicht anderst formulieren sollen. Zutreffender ist: Amateure, jedenfalls nutze ich es gerne als Nachschlagewerk.&lt;br /&gt;
Das mit Qualität als Tutorial nachgelassen war so von mir nicht richtig. Ich finde es in seiner bestehenden Anordnung und Detailliertheit gerade am Anfang zu umfangreich. Man kann selbst mit Vorkentnissen nicht alles verstehen, geschweige denn behalten.&lt;br /&gt;
Den M16 habe ich genommen denn er besitzt nahezu alle in AVRs vorkommenden Funktionen, ist erschwinglich, beliebt, wird mit ziemlicher Sicherheit demnächst nicht abgekündigt und vorallem kenne ich mich gut mit ihm aus.&lt;br /&gt;
Die Sache mit der Gliederung tut mir sehr leid, ich werde mich bemühen, dass etwas derartiges nicht mehr vorkommt. Leider habe ich mit derart großen Texten in wikis auch noch nie gearbeitet.&lt;br /&gt;
Grüße,&lt;br /&gt;
&lt;br /&gt;
[[Benutzer:FeeJai|FeeJai]] 21:38, 29. Nov 2006 (CET)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Dann bietet es sich doch an, die einzelnen Abschnitte im Tutorial mehr nach Erfahrungslevel (Einsteiger, Kenner, Könner ;-) zu gliedern und auch zu kennzeichnen. &lt;br /&gt;
&lt;br /&gt;
[[Benutzer:Stefan|Stefan]] 00:24, 30. Nov 2006 (CET)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prinzipiell nichts dagegen. Möchte noch Antowrt von mt abwarten. So ähnlich habe ich es ja auch vor. Da ich glaube dass es oben etwas unverständlich war was ich gerne machen würde, möchte ich es hier nochmals erläutern:&lt;br /&gt;
*Konzept: Mir ist das Tutorial bisher zu theoretisch. Ich möchte den Leser nach dem Einführungsbeispiel anhand praktischer Beispiele, die Zeile für Zeile erklärt werden und langsam anspruchsvoller werden die Welt der µC näher bringen. So etwas nennt man schrittweise Hinführung.&lt;br /&gt;
*Mit den Makefiles würde ich es gerne ähnlich handhaben: Da man sie immer zum compilieren benötigt, am Anfang ein funktionierendes Makefile bereitstellen, dieses muss der Leser noch nicht verstehen! Wenn die Projekte dann anspruchsvoller werden das Makefile entsprechend erweitern und somit erklären. Eine zusammenfassende alles abdeckende Erklärung ist im Anhang gut aufgehoben, überfordert aber IMHO Anfänger.&lt;br /&gt;
*Der Konjunktiv: sehr höflich, wenn man absoluten Anfängern etwas beibringen will aber eher Kontraproduktiv. Beispiel Programmers Notepad. Jemand der noch nie mit µC gearbeitet hat freut sich über eine klare(!) Anweisung, wie zu Verfahren ist und die auch funktioniert. Die Loslösung von den klares Strukturen wenn man bspw. PonyProg nicht verweden will kommt mit dem zunehmenden Verständnis wie von selbst.&lt;br /&gt;
Grüße,&lt;br /&gt;
&lt;br /&gt;
[[Benutzer:FeeJai|FeeJai]] 16:19, 30. Nov 2006 (CET)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Dazu - und zu den jüngsten Änderungen&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Vielleicht habe ich mich nicht klar ausgedrückt: wenn man &amp;quot;irgendwann&amp;quot; mal vorhat des Tutorial &amp;quot;Anfängerfreundlicher&amp;quot; zu machen, fängt man nicht damit an vorhandene Erklärungen durch die Gegend zu schieben und fehlerhafte/unvollständige Informationen einzubauen. Meine Meinung abwarten war wohl eher als Witz gemeint. Ich habe den Exkurs &amp;quot;Makefiles&amp;quot; aus dem Anhang teilweise wieder hochgezogen - und das mit Absicht. Jetzt wird er wieder runtergeschoben - soll das irgendwie zur Belustigung beitragen? Mich motiviert sowas nicht - aber auch gar nicht. Wie wäre es damit, in den Unterabschnitten ein paar weiter Erläuterungen zur &amp;quot;Hinführung&amp;quot; zu ergänzen und als neuer Mitarbeiter an dem Wiki die Sache mal langsam angehen zu lassen? Wie wäre es mit den angekündigten Anpassungen der Registerbeschreibungen an ATMega16 - die stehen in weiten Teilen soweit ich das gesehen habe noch aus.&lt;br /&gt;
&lt;br /&gt;
Ausser den nützlichen Anpassungen der Registerbeschreibungen an einer Tabelle wurde bisher nur hin- und hergeschoben ohne entsprechende Umsicht, ein &amp;quot;Anfängerbeispiel&amp;quot; mit Syntaxfehler eingetragen, eine ohne Änderung nicht brauchbare Makefilevorlage reinkopiert, im Beispiel speziellen Compilererweiterungen genutzt, die es nicht fuer jeden avr-gcc gibt und Erklärungen zum Beispiel gegeben, die mehr als knapp sind - teilweise sogar falsch (z.B. ist eine header-Datei keine Bibliothek/Library wie geschrieben stand). Wenn das &amp;quot;Hinführung&amp;quot; sein sollte, dann nur weiter so, keine Ahnung wen das wo hinführen soll. Ich finde so etwas &amp;quot;kontraproduktiv&amp;quot;. Ich habe versucht, das etwas auszubügeln, da ich froh bin, wenn jemand etwas zu dem Tutorial beiträgt und die Idee eine kleinen Intros gut finde (ob das nun mit meinen Änderungen besser ist als vorher, muss jemand anderes beurteilen). &lt;br /&gt;
&lt;br /&gt;
Hier zu erklären was man &amp;quot;schrittweise Hinführung&amp;quot; nennt und was &amp;quot;der Anfänger&amp;quot; will oder was &amp;quot;Kontrakproduktiv&amp;quot; ist, ist grosspurig. Erstmal zeigen, dass man selbst kann, bevor man hier belehrend über das urteilt, was andere gemacht haben. (Bisher war der gezeigte Einsteig in die Mitarbeit am Text alles andere als Überzeugend - aber auch das ist natürlich nur eine (meine) Einzelmeinung).&lt;br /&gt;
&lt;br /&gt;
Zum speziellen: Ponyprog ist der Anfang vielen Übels, ich weiss nicht wie viele Fusebits wegen Pronyprog falsch eingestellt wurden (ja, ich habe auch seinerzeit mit PonyProg angefangen, ja ich habe auch einen ATmega16 damit zerfust und war erstmal aufgeschmissen denn zu der Zeit kannte ich das Forum noch nicht und auch keinen der helfen konnte). AVRdude ist im Beispiel-Makefile vorgekaut (aber ja - man will auf Makefiles ja erst im Laufe des Tutorials &amp;quot;Schritt fuer Schritt&amp;quot; eingehen). Nicht jeder, der sich mit avr und gcc beschäftigt nutzt MS-Windows und hat somit auch nicht Programmers-Notepad (Zeit für den Exkurs Programmers-Notepad mit Wine auf Linux...). Etwas mehr über den Tellerrand darf man schon schauen, vor allem wenn man sich anmaßt den Blick für die Bedürfnisse von Anfängern zu haben.&lt;br /&gt;
&lt;br /&gt;
Soweit&lt;br /&gt;
mt&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Mir gefallen die jüngsten Änderungen nicht. Viele Schreibfehler jucken in den Augen und drängen mich zum Verbessern. Beim Verbessern sehe ich immer mehr ungenaue Formulierungen (&#039;&#039;serieller Programmablauf&#039;&#039;) und Voraussetzungen (&#039;&#039;Hello_World.hex.zip&#039;&#039;) und irgendwann bin ich so genervt, dass ich meine Korrektur verwerfe und das Bearbeiten abbreche. Abgesehen davon, dass ich bestimmte strukturelle Änderungen schlecht finde (Verschiebung der Erklärung des interruptgesteuerten Programmablaufs). Die richtige Lösung wäre gewesen, eine alternative Version vorzubereiten und darüber abstimmen zu lassen, statt die bestehende Version so grundlegend zu ändern. Bis es rum ist, lese ich in der [http://www.mikrocontroller.net/wikisoftware/index.php?title=AVR-GCC-Tutorial&amp;amp;oldid=18451 älteren Version].&lt;br /&gt;
&lt;br /&gt;
[[Benutzer:Stefan|Stefan]] 17:16, 1. Dez 2006 (CET)&lt;br /&gt;
&lt;br /&gt;
Hallo Allerseits!&lt;br /&gt;
&lt;br /&gt;
Habe den ersten Beitrag offensichtlich nicht so negativ verstanden wie er gemeint war. Deswegen habe ich den Exkurs nun wieder nach oben geholt, ich dachte zuerst mt willst ihn nur solange oben haben bis im Text besser darauf eingegangen wird. Die Sache mit den Schreibfehlern stimmt natürlich, es war viel in kurzer Zeit was ich geändert habe. Ich würde mich daher auch freuen, wenn jemand hilft, diese zu korrigieren. Sollten mir selbst welche auffallen, werde ich sie selbstverständlich auch beheben. Dass du das Bearbeiten abbrichst finde ich aber wirklic schade.&lt;br /&gt;
&lt;br /&gt;
Die ungenauen Formulierungen rühren leider auch von Unwissenheit meinerseits, die Formulierung serieller Programmablauf, die als Beispiel genannt wird, stammt aber so nicht von mir. Was Stefan an der Hello_World.zip nicht gut findet, kann ich so leider nicht nachvollziehen. Das Projekt habe ich, um für den Endanwender Tipparbeit einzusparen, als zip-Datei Online gestellt. In ihr befindet sich auch ein Makefile und das compilierte Projekt als .hex. &lt;br /&gt;
&lt;br /&gt;
Der Artikel &amp;quot;I/O Grundlagen&amp;quot; in der Hinführung bedarf tatsächlich einer Überarbeitung. Ich werde mir mal durchlesen, wie Andreas das in seinem Tut erledigt hat. Das &amp;quot;Hello World&amp;quot; gefällt mir persönlich gut, wenn es aber in dieser Form nicht erwünscht ist werde ich es auch schlucken, falls die Hinführung gelöscht wird.&lt;br /&gt;
&lt;br /&gt;
Die Probleme mit Ponyprog sind wahr, leider war es als ich damals anfing das einzige Programm welches auf meinem Rechner gut funktionierte - deswegen benutze ich es hauptsächlich. Weitere Vorteile sind IMHO: Benutzerfreundlich durch einfache Bedienbarkeit und dass die meisten Nutzer es bereits kennen, da es oft von PC Zeitschriften genutzt wird. Grüße,&lt;br /&gt;
&lt;br /&gt;
[[Benutzer:FeeJai|FeeJai]] 17:57, 1. Dez 2006 (CET)&lt;br /&gt;
&lt;br /&gt;
PS: Ich finde die Einführung mit deinen Änderungen wesentlich besser. Allerdings habe ich nochmal kleine Details verändert - wenn es dir nicht gefällt hau es einfach raus. Die neuen Beispiele sind alle getestet, auch ich lerne aus Fehlern. Die Sache mit dem 0b war mir so nicht bekannt und ist wahrlich wenig erfreulich.&lt;br /&gt;
&lt;br /&gt;
===Bitte fügt für einen Satz und ein paar Links keine neuen Abschnitte ein (aktuell: TWI)===&lt;br /&gt;
&lt;br /&gt;
Der Artikel ist ein Tutorial, das heißt dem Leser sollen die verschiedenen Aspekte der Programmierung mit AVR-GCC &#039;&#039;erklärt&#039;&#039; werden; ein Abschnitt über TWI mit drei großen Überschriften aber nur einem allgemeinen Satz und ein paar Links passt da nicht gut dazu. Wenn sich jemand die Mühe machen würde das Thema etwas ausführlicher und mit Beispielcode zu erklären wäre das natürlich &#039;&#039;&#039;sehr&#039;&#039;&#039; willkommen.&lt;br /&gt;
[[Benutzer:Andreas|andreas]] 15:15, 2. Dez 2007 (CET)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Tutorial nach Wikibooks portieren ===&lt;br /&gt;
&lt;br /&gt;
Was haltet ihr davon das Tutorial nach Wikibooks zu portieren? Die Seite wird immer größer und unübersichtlicher. Die Einteilung in mehrere Seiten, sowie die Möglichkeit weiterführende Hinweise für fortgeschrittene Nutzer in eine Aufklappbox zu schreiben würden dem Tutorial sicher gut tun.&lt;br /&gt;
[[Benutzer:Thymythos|Manuel Stahl]] 17:31, 14. Okt. 2008 (CEST)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ich kann mir nicht recht vorstellen, wie das aussehen würde. Mein Vorschlag probiere es aus und stelle das Ergebnis zur Anschauung und Diskussion vor. Das Bessere ist des Guten  Tod. Du kannst dafür die Version auf der [[Spielwiese avr-gcc Tutorial]] benutzen. Ich würde nach Möglichkeit die Umwandlung etc. mit Skripten o.ä. automatisieren, damit künftige Änderungen im jetzigen Text (siehe die grosse ToDo-Liste) rasch und automatisch ins Wikibook übertragen werden können. [[Benutzer:Stefan|Stefan]] 12:57, 15. Okt. 2008 (CEST)&lt;br /&gt;
&lt;br /&gt;
Hier mal ein erster Versuch: http://de.wikibooks.org/wiki/C-Programmierung_mit_AVR-GCC --[[Benutzer:Thymythos|Thymythos]] 19:40, 6. Nov. 2008 (CET)&lt;br /&gt;
&lt;br /&gt;
== Veraltete Register ==&lt;br /&gt;
&lt;br /&gt;
Hi. Leider sind in dem Tutorial viele Register und Einstellungen auf inzwischen veraltete und viele verschiedene AVRs bezogen. Ich wäre dafür alles auf den ATMega16 anzupassen, da dieser alle Funktionen hat und trotzdem bezahlbar ist. Habe heute mit dem ADC angefangen und so viel Arbeit ist es nicht. Werde, falls es erwünscht ist nach und nach alles an den Mega16 anpassen.&lt;br /&gt;
&lt;br /&gt;
[[Benutzer:FeeJai|FeeJai]] 18:13, 26. Nov 2006 (CET)&lt;br /&gt;
&lt;br /&gt;
==Frage zum Codebsp.==&lt;br /&gt;
&lt;br /&gt;
Warum hier im Codebsp. die Frequenz gesetzt wenn man im Einfache Wandlung (Single Conversion)-modus ist?&lt;br /&gt;
&lt;br /&gt;
  ADCSRA = (1&amp;lt;&amp;lt;ADEN) | (1&amp;lt;&amp;lt;ADPS1) | (1&amp;lt;&amp;lt;ADPS0);    // Frequenzvorteile setzen auf 8 (1)&lt;br /&gt;
&lt;br /&gt;
Weil man immer den Vorteiler entsprechend der Quarzfrequenz setzen mu�? um den ADC nicht mit einem zu hohen Takt zu versorgen. --[[Benutzer:Matthias|Matthias]] 19:58, 21. Sep 2004 (CEST)&lt;br /&gt;
&lt;br /&gt;
Ich benutze folgenden code der funktioniert. Es wird kein vorteiler gesetzt!!&lt;br /&gt;
&lt;br /&gt;
    sbi(ADCSR,ADEN);   //ADC An&lt;br /&gt;
    sbi(ADMUX,MUX0);	//kanal wählen&lt;br /&gt;
    for (;;) {                           /* loop forever */&lt;br /&gt;
           	sbi(ADCSR,ADSC);				//wandlung starten&lt;br /&gt;
    	    	while(bit_is_set(ADCSR,ADSC)); 	//warten bis wandlung fertig&lt;br /&gt;
    		num = ADCW;&lt;br /&gt;
&lt;br /&gt;
--- schnipp ---&lt;br /&gt;
&lt;br /&gt;
Der Vorteiler hat nichts mit &amp;quot;funktionieren&amp;quot; oder &amp;quot;nicht funktionieren&amp;quot; zu tun. Man sollte sich eher Gedanken um die Genauigkeit und einzuhaltende Maximalfrequenzen bei der Wandlung machen. Der Abschnitt &amp;quot;ADC/Prescaling and Conversion Time&amp;quot; im Datenblatt gibt eigentlich erschoepfend Auskunft darueber. Das &amp;quot;sbi&amp;quot; in dem Beispielcode oben in einem Diskussionsbeitrag zum gcc-tutorial noch auftaucht ist mir schleierhaft, da kann ich mir die Aktualisierung auch sparen. Falls das im Artikel gezeigte Beispiel nachweislich falsch sein sollte: bitte aendern.&lt;br /&gt;
MfG M. Thomas&lt;br /&gt;
&lt;br /&gt;
Butterfly schoen und gut, aber diese beiden Hinweise in letzter Zeit mit der Preisangabe &amp;quot;30Eur&amp;quot;... Ist das irgendwo ein Lager &amp;quot;zu voll&amp;quot; und wird hier versucht &amp;quot;etwas Werbung&amp;quot; zu machen? Der Preis ist &amp;quot;normal&amp;quot; aber wenn man sich umschaut und/oder sich mit ein paar Leuten für eine Sammelbestellung zusammentut gibt es die Teile deutlich guenstiger.&lt;br /&gt;
&lt;br /&gt;
==Links korrigiert==&lt;br /&gt;
Einige der Links im Kapitel 11.1.1 (Messen eines Widerstandes) funktionieren nicht. Dies wären:&lt;br /&gt;
* http://www.mypage.bluewin.ch/ch_schifferle/AtmelC/Uebungen/Allgemein/UartPrintF.c&lt;br /&gt;
* http://www.mypage.bluewin.ch/ch_schifferle/AtmelC/Uebungen/Allgemein/UartPrintF.h&lt;br /&gt;
* http://www.mypage.bluewin.ch/ch_schifferle/AtmelC/Uebungen/Poti/makefile&lt;br /&gt;
&lt;br /&gt;
--[[Benutzer:Oxygene|Oxygene]] 12:05, 12. Nov 2004 (CET)&lt;br /&gt;
&lt;br /&gt;
==Tabellen==&lt;br /&gt;
Habe die Tabellen übersichtlicher gemacht, überflüssige Tabellen durch gewöhnliche Einrückungen ersetzt und recht viele Kommafehler bei Konditionalsätzen berichtigt (so um die 762 *g*). Inhaltlich ist alles gleich geblieben.&lt;br /&gt;
--[[Benutzer:Oxygene|Oxygene]] 15:01, 12. Nov 2004 (CET)&lt;br /&gt;
&lt;br /&gt;
==Inhaltliches==&lt;br /&gt;
&lt;br /&gt;
Danke fuer die Korrekturen, einige der Fehler sind sicher &amp;quot;auf meinem Mist gewachsen&amp;quot;. Die Links zu &amp;quot;Messen eines Widerstands&amp;quot; sollten ganz raus, entweder ein aktualisiertes Beispiel direkt im Text oder in einem anderen Wiki-Artikel oder ersatzlos streichen. Schlussendlich ist es ein avr-gcc Tutorial die Beispiele sollten avr-gcc-Spezifisches erläutern und den manchmal etwas &amp;quot;trockenen&amp;quot; Text auflockern. Wie man einzelne Komponenten des AVR ansteuert hat nur in seltenen Fällen mit der Impementierungssprache zu tun. Hier vor allem dann, wenn die avr-libc entsprechende &amp;quot;APIs&amp;quot; zur Verfügung stellt. Alles Andere gehört eigentlich in ein &amp;quot;sprachunabhängiges&amp;quot; AVR-Tutorial. Das avr-gcc Tutorial &amp;quot;schleppt&amp;quot; mein Meinung in dieser Hinsicht noch einige Altlasten mit. [[Benutzer:mthomas]]&lt;br /&gt;
&lt;br /&gt;
Also ich habe das Tut durchgearbeitet und alle mir auffallenden Fehler korrigiert. Man hat da sofort bemerkt, von wo an die Texte von dir geschrieben wurden, da die Kommafehler schlagartig aufhörten ;)&lt;br /&gt;
Da sind auch ein paar Formulierungen, die ich persönlich nicht so passend finde (&amp;quot;voll krass&amp;quot;), die wollte ich aber nicht ändern, da das hier eher dein Baby ist, es sei denn, du hast nichts dagegen, dass man da etwas rumbastelt. Will dir hier nicht dazwischenpfuschen und deine Pläne durcheinander bringen.&lt;br /&gt;
--[[Benutzer:Oxygene|Oxygene]] 02:21, 15. Nov 2004 (CET)&lt;br /&gt;
&lt;br /&gt;
Habe in naechster Zeit nicht vor, an dem Tut. weiterzuarbeiten. Vielleicht dann am ehesten im Abschnitt &amp;quot;Assembler/C mixed-language&amp;quot;. Mach&#039; was du fuer richtig haellst. &lt;br /&gt;
Go ahead. Wird sich schon alles &amp;quot;ergeben&amp;quot;. --mt&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Aufteilung in Kapitel==&lt;br /&gt;
Ich habe das Tutorial mal auf kleinere Unterkapitel aufgeteilt. Das ist IMHO&lt;br /&gt;
* übersichtlicher&lt;br /&gt;
* modemfreundlicher&lt;br /&gt;
* einladender (ein Monsterartikel schreckt ab)&lt;br /&gt;
Einziger Nachteil: Das Inhaltsverzeichnis muss manuell auf dem neuesten Stand gehalten werden.&lt;br /&gt;
&lt;br /&gt;
Vorhin im Chat wurde mir geraten, vorher zu fragen. Daran hab ich leider nicht gedacht, also hole ich das jetzt nach. ;-)&lt;br /&gt;
--[[Benutzer:84.167.145.172|Chris]] (unregistriert) 17:42, 23. Apr 2005 (CEST)&lt;br /&gt;
&lt;br /&gt;
Prima, das &amp;quot;;-)&amp;quot;. Ist man mal einen Tag nicht in dem Chat, schon wird gefuhrwerkt. Kurz: dagegen. Lang: Es gab vorher schon ein uebersichtliches Inhaltsverzeichnis. Modemfreundlicher - na ja, ich bin von zu Hause auch ueber Modem/ISDN &amp;quot;drin&amp;quot;, so gross ist der Text nun auch wieder nicht, ich habe von zu Hause gelegentlich Kleinigkeiten korrigiert ohne das mich die Geschwindigkeit gestoert hat. De facto wird &amp;quot;Seite speichern&amp;quot; auf die lokale Platte und danach offline durchlesen fuer Modemnutzer (non-flatrater) ohnehin die uebliche Vorgehensweise gewesen sein. Gelesen wird der Artikel um ein vielfaches mehr als bearbeitet. Nun heisst es, x-mal &amp;quot;Seite speichern&amp;quot; und danach durch die gespeicherten html-Seiten wurschteln. Einladend: mag sein, ist subjektiv. Es war fuer mich einfacher, ueber den ganzen Artikel drueberzuschauen, eventuell zu verweisen, zu verschieben oder eine neues Kapitel dazuzwischenzuschieben. Die abschnittweise Bearbeitung war ebenfalls zumindest fuer mich gut genug. Ein Kapitel einzufuegen heisst jetzt auch, die Verlinkung ordentlich wieder zusammenzubauen und an den angeblich &amp;quot;einzigen Nachteil&amp;quot; zu denken. Der schnelle pdf-Export fuer &#039;Korrekturabzuege&#039; wird jetzt zur Qual. Nun denn, entweder wieder ein langer Artikel oder ich werde mein Engagement fuer dieses Tutorial deutlich einschraenken, bzw. einen &#039;Fork&#039; weiterpflegen. Aber es gibt ja noch andere Wiki-Nutzer, die Inhalt beizusteuern. Vieleicht fuehrt ja das zerrissene Tutorial dazu, dass deren Anzahl steigt.&lt;br /&gt;
Martin Thomas (mthomas/131.246.51.xx)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Nicht so resignierend. Erstens steht in dem Wiki, dass jeder mitmachen kann (da steht nix von vorher nachfragen), zweitens kann man Aenderungen ja jederzeit rueckgaengig machen. Also, nicht (gleich?) entmutigen lassen :)&lt;br /&gt;
Ich persoenlich finde die aufgeteilte Version praktischer. Ich kann mir einfach eine Adresse aufschreiben, wo ich gerade war - ohne dann ewig lang dort hin scrollen zu muessen, wo ich wirklich war. Ich denke auch, dass die armen Modem-Benutzer und/oder die, die nicht staendig die Moeglichkeit haben, online zu sein/gehen, immer weniger werden und man deshalb - so grob es klingen mag - auch weniger Ruecksicht auf sie zu nehmen braucht (kann man jetzt als Argument sowohl fuer als auch gegen die Aufteilung sehen..)&lt;br /&gt;
--[[Benutzer:80.108.115.184|80.108.115.184]] 00:27, 24. Apr 2005 (CEST) sym&lt;br /&gt;
&lt;br /&gt;
Ich find die zusammenhängende version auch besser.&lt;br /&gt;
Zar kann jeder am wiki mitarbeiten, aber wenn es um so gro�?e umstellungen geht, sollte man zufor nachfragen, sonst kann die arbeit schnell umsonst gewesen sein.&lt;br /&gt;
Ich winn für eine widerherstellung der zusammenhängenden Version. --[[Benutzer:84.57.135.238|84.57.135.238]] 11:51, 24. Apr 2005 (CEST) scout&lt;br /&gt;
&lt;br /&gt;
Die �?nderung wurde jetzt also reverted, ohne ein Meinungsbild abzuwarten. Nagut. Dann bitte ich hiermit um eine offizielle Abstimmung, um diesen Sachverhalt zu klären, ohne es nach Willkür-Entscheidung (meinerseits oder von anderen) aussehen zu lassen. Ich schlage als Laufzeit 1 Woche vor, Stichtag wäre dann also der 1. Mai 2005 um 12:00.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Abstimmung&#039;&#039;&#039; über die Frage: Soll das Tutorial in Kapitel aufgeteilt werden? --Chris 12:45, 24. Apr 2005 (CEST)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Dafür&#039;&#039;&#039;:&lt;br /&gt;
* Chris&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Dagegen&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
Der Hauptautor dieses Artikels (Martin Thomas) ist dagegen, das ist für mich Grund genug. Ich sehe auch keine gro�?en Vorteile an der Aufteilung, nur viel zusätzliche Arbeit durch das manuelle Anpassen des Inhaltsverzeichnisses. Die vor/zurück/hoch-Links erhöhen das Rauschen und tragen auch nicht gerade zur �?bersicht bei. -[[Benutzer:Andreas|Andreas]] 15:24, 24. Apr 2005 (CEST)&lt;br /&gt;
&lt;br /&gt;
Ohne jetzt zu Aufteilung/Nichtaufteilung Stellunge nehmen zu wollen und mthomas&#039; Arbeit in Ehren, aber _das_ sehe ich nicht als Argument. Von mir sind auch schon Artikel entfernt/geloescht/etc. worden, ohne mich zu fragen. So lauft&#039;s in einem offenen wiki! --15:30, 24. Apr 2005 (CEST)sym&lt;br /&gt;
&lt;br /&gt;
Man sollte sich von der Vorstellung freimachen, dass jedes Wiki nur weil es ein Wiki ist automatisch per Mehrheitsentscheidung verwaltet werden muss. Wenn jemand in einen Artikel so viel Arbeit reingesteckt hat wie Martin, dann hat seine Stimme nun mal mehr Gewicht. -[[Benutzer:Andreas|Andreas]] 15:50, 24. Apr 2005 (CEST)&lt;br /&gt;
&lt;br /&gt;
Von Mehrheitsentscheidung hab ich gar nicht gesprochen.&lt;br /&gt;
Aus der Sicht als (potentieller) &amp;quot;Konsument&amp;quot; des Tutorials: Ich hab erstmals zu lesen angefangen, als es unterteilt war. Und mit der Zurueck-Umstellung auf die endlos lange Seite hab ich wieder das Interesse daran verloren. Schade - danke aber trotzdem fuer die Muehe. --[[Benutzer:80.108.115.184|80.108.115.184]] 21:36, 24. Apr 2005 (CEST)sym&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Frage 2 zum Codebsp.==&lt;br /&gt;
&lt;br /&gt;
Hallo zusammen,&lt;br /&gt;
ich nutze beruflich (ab und an) den IAR-Compiler für die AVRs.&lt;br /&gt;
Nun steige ich privat in den AVR-GCC ein. Donglefrei halt 8-).&lt;br /&gt;
Euer Tutorial ist eine echte Hilfe dabei! Super, wie die ganze&lt;br /&gt;
Seite. Ich würde gerne auch mithelfen, will aber nicht einfach so&lt;br /&gt;
rumeditieren. Daher erst einmal nachgefragt:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;zu 16.2.2. (Programmspeicher) Wort lesen.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
ptrToArray = (uint8_t*)(pgm_read_word(&amp;amp;pgmPointerToArray1)); &amp;lt;br/&amp;gt;&lt;br /&gt;
// ptrToArray zeigt nun auf das erste Element des Byte-Arrays pgmPointerToArray1&lt;br /&gt;
&lt;br /&gt;
1. Das Byte Array, auf das gezeigt werden soll, ist doch eigentlich pgmFooByteArray1[]. pgmPointerToArray1 ist ein Pointer. Könnte gerade Anfänger verwirren&amp;lt;br/&amp;gt;&lt;br /&gt;
2. ptrToArray ist eine Pointervariable, die im SRAM liegt und die&lt;br /&gt;
in das SRAM zeigt. Sie zeigt damit NICHT auf pgmFooByteArray1[].&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit ARV-GCC compiliert und in AVRStudio geladen, ergibt sich folgendes, wenn man die entsprechenden Variablen ins Watchfenster holt:&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
pgmFooByteArray1&amp;lt;br/&amp;gt;&lt;br /&gt;
 Value [...]  /  Type const unsigned char[3]  /  Location 0x001A [FLASH]&amp;lt;br/&amp;gt;&lt;br /&gt;
 [0] 18       /  Type const unsigned char     /  Location 0x001A [FLASH]&amp;lt;br/&amp;gt; &lt;br /&gt;
 [0] 3        /  Type const unsigned char     /  Location 0x001B [FLASH]&amp;lt;br/&amp;gt; &lt;br /&gt;
 [0] 70       /  Type const unsigned char     /  Location 0x001C [FLASH]&amp;lt;br/&amp;gt; &lt;br /&gt;
&lt;br /&gt;
pgmPointerToArray1&amp;lt;br/&amp;gt;&lt;br /&gt;
 Value 0x001A  /  Type const unsigned char * const /  Location 0x0018 [FLASH]&amp;lt;br/&amp;gt;-&amp;gt; Value 18   /  Type const unsigned char         /  Location 0x001A [FLASH]&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ptrToArray&amp;lt;br/&amp;gt;&lt;br /&gt;
 Value 0x001A  /  Type unsigned char *  /  Location 0x0060 [SRAM]&amp;lt;br/&amp;gt;&lt;br /&gt;
 -&amp;gt; Value 98   /  Type unsigned char    /  Location 0x001A [SRAM]&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Man kann mit pgm_read_byte(ptrToArray+i) natürlich pgmFooByteArray1[] lesen, da nur der Wert von ptrToArray interessiert, da er im Macro wieder auf unit16_t umgecastet wird. Es wäre aber einfacher, wenn man das Resultat von pgm_read_word(&amp;amp;pgmPointerToArray1) in eine uint16_t einliest und diese dann an pgm_read_byte() übergibt.&lt;br /&gt;
&lt;br /&gt;
Das Beispiel hat (zumindest mir am Anfang) suggeriert, dass es wirklich möglich ist, einen Pointer zu deklarieren, über den man direkt, also ohne Macros aus pgmspace.h, aus dem Flash lesen kann. &amp;quot;...ptrToArray zeigt nun auf das erste Element des Byte-Arrays... &amp;quot;&lt;br /&gt;
&lt;br /&gt;
Vielleicht sollte man das etwas klarer machen. Zum Beispiel mit dem expliziten Hinweis, dass es einen solchen Pointer nicht gibt und immer Code bemüht werden mu�?, um das Flash zu lesen. Vielleicht kann man das Beispiel ja auch mit einer unit16_t Variablen, statt mit einer uint8_t * Variablen machen.&lt;br /&gt;
&lt;br /&gt;
Falls erwünscht, schreibe ich es gerne um.&lt;br /&gt;
--[[Benutzer:EdeC|EdeC]] 19:39, 2. Sep 2005 (CEST)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Glaube, dieser Textabschnitt ist noch relativ unveraendert von mir, sorry, falls es zu unklar ist. Sinn des ganzen Abschnitts und er Beispiele ist es, zu verdeutlichen dass eben diese &amp;quot;direkten&amp;quot; Pointer (noch) nicht im funktionieren. Ja, Programmspeicherzugriff ist beim IAR-Compiler anders und v.a. einfacher. Aber das Grundprinzip und die Problematik ist wenn recht erinnert schon erlaeutert (explizit und mit etwas &amp;quot;Plappertext&amp;quot;). Vermute, die Verwirrung kommt eher durch die IAR-&amp;quot;Vorbelastung&amp;quot;. Falls die Beispiele also tatsaechlich suggerieren, dass es diese Funktionalitaet gibt, bitte Aenderungsvorschlag einfach einbauen. Code aber bitte nur aendern, wenn die Beispiele falsch sind, ansonsten einfach /*Kommentare*/ und/oder ein paar zusaetzliche Beispiele einbauen. Ich habe absichtlich einige nicht-triviale Beispiele eingetragen, die &amp;quot;einfachen Sachen&amp;quot; stehen ja auch da und in vielen anderen Beispielen/Tutorials ebenfalls.&lt;br /&gt;
&lt;br /&gt;
Martin Thomas&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ich finde, der Abschnitt erklärt sehr gut und verständlich!&lt;br /&gt;
Lediglich bei dem Code-Beispiel waren IMHO ein paar Unsauberkeiten,&lt;br /&gt;
die mich zuerst in die Wüste geschickt haben. Das hatte allerdings&lt;br /&gt;
den positiven Effekt, da�? ich mich ziemlich drin verbissen und dadurch &lt;br /&gt;
etliches dazu gelernt habe 8-) .&lt;br /&gt;
&lt;br /&gt;
--[[Benutzer:EdeC|EdeC]] 13:54, 10. Sep 2005 (CEST)&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
Fuse-Bits&lt;br /&gt;
Ich hage mal gehört der atmega habe soetwas. Wovor schützt das genau? hann ich sie auch wieder löschen??&lt;br /&gt;
&lt;br /&gt;
Stelle solche Fragen lieber im Forum. Hier ist es a) Zufall, wenn mal jemand über deine Frage stolpert und b) zerfretzelt es das Wiki. Also zu den [[AVR Fuses]] gibt es einen eigenen Artikel. Grundsätzlich dienen die Fuses dazu eine bestimmte Hardwarekonfiguration des AVR einzurichten. Wenn man dabei einen Fehler macht, ist der AVR u.U. Schrott. Daher gilt besonders bei Thema Fuses: &#039;&#039;&#039;Datenblatt sorgfältig lesen&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
--[[Benutzer:Stefan|Stefan]] 17:58, 28. Aug 2006 (CEST)&lt;br /&gt;
&lt;br /&gt;
== Baudraten Macros mit UL ==&lt;br /&gt;
&lt;br /&gt;
Die Baudraten-Macros aus dem Tutorial scheinen recht populär zu sein, ich habe sie schon in mehreren Projekten gesehen. Leider funktionieren sie nur, wenn F_CPU als signed Long definiert ist. Sowohl Mfile, AVR Studio als auch mein AVR Eclipse Plugin definieren F_CPU aber als UL.&lt;br /&gt;
&lt;br /&gt;
Wenn man die Formel minimal ändert, dann funktioniert es auch mit UL:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
/* UART-Init beim AT90S2313 */&lt;br /&gt;
&lt;br /&gt;
#ifndef F_CPU&lt;br /&gt;
/* In neueren Version der WinAVR/Mfile Makefile-Vorlage kann&lt;br /&gt;
   F_CPU im Makefile definiert werden, eine nochmalige Definition&lt;br /&gt;
   hier wuerde zu einer Compilerwarnung fuehren. Daher &amp;quot;Schutz&amp;quot; durch&lt;br /&gt;
   #ifndef/#endif &lt;br /&gt;
&lt;br /&gt;
   Dieser &amp;quot;Schutz&amp;quot; kann zu Debugsessions führen, wenn AVRStudio &lt;br /&gt;
   verwendet wird und dort eine andere, nicht zur Hardware passende &lt;br /&gt;
   Taktrate eingestellt ist: Dann wird die folgende Definition &lt;br /&gt;
   nicht verwendet, sondern stattdessen der Defaultwert (8 MHz?) &lt;br /&gt;
   von AVRStudio - daher Ausgabe einer Warnung falls F_CPU&lt;br /&gt;
   noch nicht definiert: */&lt;br /&gt;
#warning &amp;quot;F_CPU war noch nicht definiert, wird nun nachgeholt mit 4000000&amp;quot;&lt;br /&gt;
#define F_CPU 4000000UL    // Systemtakt in Hz &lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
#define BAUD 9600UL          // Baudrate&lt;br /&gt;
&lt;br /&gt;
// Berechnungen&lt;br /&gt;
#define UBRR_VAL ((F_CPU+BAUD*8)/(BAUD*16)-1)   // clever runden&lt;br /&gt;
#define BAUD_REAL (F_CPU/(16*(UBRR_VAL+1)))     // Reale Baudrate&lt;br /&gt;
#define BAUD_ERROR ((BAUD_REAL*1000)/BAUD) // Fehler in Promille, 1000 = kein Fehler.&lt;br /&gt;
&lt;br /&gt;
#if ((BAUD_ERROR&amp;lt;990) || (BAUD_ERROR&amp;gt;1010))&lt;br /&gt;
  #error Systematischer Fehler der Baudrate grösser 1% und damit zu hoch! &lt;br /&gt;
#endif&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Irgendwelche Einwände wenn ich das im Tutorial ändere?&lt;br /&gt;
&lt;br /&gt;
Thomas&lt;/div&gt;</summary>
		<author><name>Thymythos</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=Schaltplaneditoren&amp;diff=32348</id>
		<title>Schaltplaneditoren</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=Schaltplaneditoren&amp;diff=32348"/>
		<updated>2008-11-06T16:39:12Z</updated>

		<summary type="html">&lt;p&gt;Thymythos: /* Weblinks */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Eagle ==&lt;br /&gt;
&lt;br /&gt;
[[Bild:Eagle.png|right|thumb|Screenshot]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;&amp;lt;i&amp;gt;Eagle&amp;lt;/i&amp;gt;&amp;lt;/b&amp;gt; von Cadsoft ist nicht nur ein &amp;lt;b&amp;gt;Schaltplaneditor&amp;lt;/b&amp;gt;, sondern ein komplettes Paket mit &amp;lt;b&amp;gt;Layoutprogramm&amp;lt;/b&amp;gt; und &amp;lt;b&amp;gt;Autorouter&amp;lt;/b&amp;gt;. Das hat den Vorteil, dass man einen erstellten Schaltplan gleich zur Platine weiterverarbeiten kann.&lt;br /&gt;
&lt;br /&gt;
Mitgeliefert werden umfangreiche Symbol- bzw. Bauteilbibliotheken, von Widerständen in allen Bauformen über Taster bis hin zu [[AVR]]s. Eine Library für viele aktuelle AVRs findet sich im Download-Bereich &lt;br /&gt;
von [http://www.embedit.de http://www.embedit.de].&lt;br /&gt;
&lt;br /&gt;
Eagle läuft unter Linux, Windows und Mac OS X.&lt;br /&gt;
&lt;br /&gt;
Eine für nichtkommerzielle Anwendungen kostenlose Version ist von [http://www.cadsoft.de/ CadSoft] erhältlich. Diese ist auf zweilagige Platinen im halben Euro-Format (80x100mm) sowie Schaltpläne mit nur einer Seite beschränkt.&lt;br /&gt;
&lt;br /&gt;
Zum Betrachten des fertigen, bestückten Platinenentwurfs als 3D-Bild bietet sich [http://www.matwei.de/doku.php?id=en:eagle3d:eagle3d eagle3D] an. Mit Hilfe eines ULP wird eine Beschreibungsdatei für &amp;lt;i&amp;gt;POVray&amp;lt;/i&amp;gt; erzeugt, die dann anschließend gerendert wird. Eine große Zahl an Bauteilen wird unterstützt.&lt;br /&gt;
&lt;br /&gt;
Anwendungshinweise:&lt;br /&gt;
* [[Eagle im Hobbybereich]]&lt;br /&gt;
* [http://gaussmarkov.net/wordpress/category/tools/software/eagle/ Eagle CAD Tutorial] im Blog von gaussmarkov: diy fx (englisch)&lt;br /&gt;
&lt;br /&gt;
== PCB ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;&amp;lt;i&amp;gt;PCB&amp;lt;/i&amp;gt;&amp;lt;/b&amp;gt; ist ein freies (open source) Layoutprogramm inklusive Autorouter. Zum Zeichnen der Schaltpläne kann [[Schaltplaneditoren#Gschem|Gschem]] verwendet werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;PCB&amp;lt;/i&amp;gt; wurde ursprünglich für den Atari ST entwickelt und später nach &lt;br /&gt;
Unix portiert. &amp;lt;i&amp;gt;PCB&amp;lt;/i&amp;gt; läuft meist unter Linux, kann allerdings mit [http://www.cygwin.com/ Cygwin] auch unter Windows betrieben werden.&lt;br /&gt;
&lt;br /&gt;
Als Ausgabeformate stehen [http://de.wikipedia.org/wiki/Postscript Postscript] und Gerber RS-274-X zur Verfügung.&lt;br /&gt;
&lt;br /&gt;
Ein großer Vorteil von &amp;lt;i&amp;gt;PCB&amp;lt;/i&amp;gt; ist, dass alle Funktionen auch über &lt;br /&gt;
Hotkeys gesteuert werden können, was insbesondere nach längerer Einarbeitungszeit ein großer Gewinn gegenüber manchen Windows-Programmen ist.&lt;br /&gt;
&lt;br /&gt;
Zur Einarbeitung ist es meines Erachtens sehr wichtig, sich das [http://www.geda.seul.org/wiki/geda:gsch2pcb_tutorial Tutorial] durchzulesen. &amp;lt;i&amp;gt;PCB&amp;lt;/i&amp;gt; und &amp;lt;i&amp;gt;Gschem&amp;lt;/i&amp;gt; sind nicht besonders einfach zu benutzen. Gerade am Anfang, wenn man sich versucht damit einzuarbeiten. Aber wenn man einmal mit dem Werkzeug arbeiten kann, wird man es nicht mehr missen wollen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Wichtige Einstellungen &amp;amp; Tips ===&lt;br /&gt;
&lt;br /&gt;
Die neue GTK+ Version aus dem CVS Archiv ist der alten etwas angestaubten Version vorzuziehen. Auch das kompilieren ist nicht wirklich schwierig. Alles was dazu notwendig ist (und das Programm hat keine grossen Abhängigkeiten), ist in der Readme erklaert. Somit faellt die Kompilation recht einfach gehalten aus.&lt;br /&gt;
&lt;br /&gt;
Auf der linken Seite befindet sich die Auswahl der jeweiligen Layer. Gerade bei Verwendung des Autorouters sollte man hier den 2. Layer deaktivieren. Dies kann ganz einfach mit einem Klick auf die Beschriftung erfolgen (component, GND-comp und VCC-comp). Ebenso sollte man unused (grün) und unused (blau) dekativiert werden.&lt;br /&gt;
&lt;br /&gt;
Als &#039;&#039;Route Style&#039;&#039; verwende ich den Power Style mit einer Dicke von 25 Mil (0.6 mm). Der &#039;&#039;Signal Style&#039;&#039;scheint mir gerade bei schlechten Belichtungsverhältnissen nicht ganz optimal zu sein.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Autorouter ===&lt;br /&gt;
&lt;br /&gt;
Der Autorouter von &amp;lt;i&amp;gt;PCB&amp;lt;/i&amp;gt; hat einige Schwächen, welche allerdings bei Hobby-Projekten völlig belanglos sind: Beispielsweise kann es bei TQFP-Gehäusen mit 100 Pins u. 0.5mm Pinabstand zu Problemen kommen, 64polige TQFP-Gehäuse (z.B. vom ATmega 128) gehen jedoch ohne Probleme. &lt;br /&gt;
&lt;br /&gt;
Hat man sich soweit im [http://www.geda.seul.org/wiki/geda:gsch2pcb_tutorial Tutorial] durchgearbeitet und seine Bauteile positioniert, kann der Autorouter zum Einsatz kommen. Auch hier ist ein wenig Experimentierfreude erforderlich, um zu zufriedenstellenden Ergebnissen zu kommen.&lt;br /&gt;
&lt;br /&gt;
Unter &#039;&#039;&#039;Connects / Optimize routed Tracks / Miter&#039;&#039;&#039; können die geroutet Linien in 45 Grad Winkel modifiziert werden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Footprints ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Bild:Pcbgtk.png|right|thumb|Screenshot]]&lt;br /&gt;
&lt;br /&gt;
Sehr wichtig für das Zusammenspiel zwischen dem Schaltplaneditor [http://www.geda.seul.org/tools/gschem/ Gschem] und dem [http://pcb.sourceforge.net PCB] ist die Verwendung der richtigen Footprints.&lt;br /&gt;
&lt;br /&gt;
Mir persönlich ist aufgefallen, daß viele Pads zu klein sind. Gerade im Bereich der Hobbyätzerei könnten sie ruhig größer ausfallen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table border=1&amp;gt;&lt;br /&gt;
 &amp;lt;tr&amp;gt;&lt;br /&gt;
   &amp;lt;th&amp;gt;Element&amp;lt;/th&amp;gt;&lt;br /&gt;
   &amp;lt;th&amp;gt;Footprint&amp;lt;/th&amp;gt;&lt;br /&gt;
   &amp;lt;th&amp;gt;Alternativer Footprint&amp;lt;/th&amp;gt;&lt;br /&gt;
   &amp;lt;th&amp;gt;Beschreibung&amp;lt;/th&amp;gt;&lt;br /&gt;
 &amp;lt;/tr&amp;gt;&lt;br /&gt;
 &amp;lt;tr&amp;gt;&lt;br /&gt;
   &amp;lt;td&amp;gt;Widerstand 1/4 Watt&amp;lt;/td&amp;gt;&lt;br /&gt;
   &amp;lt;td&amp;gt;R0w4&amp;lt;/td&amp;gt;&lt;br /&gt;
   &amp;lt;td&amp;gt;R025&amp;lt;/td&amp;gt;&lt;br /&gt;
   &amp;lt;td&amp;gt;Ich benutze R0w4, weil es die Pads größer sind.&amp;lt;/td&amp;gt;&lt;br /&gt;
 &amp;lt;/tr&amp;gt;&lt;br /&gt;
 &amp;lt;tr&amp;gt;&lt;br /&gt;
   &amp;lt;td&amp;gt;Elko&amp;lt;/td&amp;gt;&lt;br /&gt;
   &amp;lt;td&amp;gt;CR200&amp;lt;/td&amp;gt;&lt;br /&gt;
   &amp;lt;td&amp;gt;RADIAL_CAN 200&amp;lt;/td&amp;gt;&lt;br /&gt;
   &amp;lt;td&amp;gt;CR200 ist für größere Elkos (Umfang), während bei RADIAL_CAN 200 der Umfang kleiner ist. Leider fehlt die Polarität bei diesem Symbol.  Allgemein jedoch sind bei beiden Elementen die Pads zu klein.&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Bild:Pcb_widerstand.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Mir waren irgendwie alle Widerstände nicht ideal genug.&lt;br /&gt;
Die Löcher werden ja meist mit 0.8mm gebohrt: (0.8 mm * (1 mil/ 0.0254 mm) = 31 mil. Eine Richtlinie für den gesamten Paddurchmesser habe ich nicht gefunden. Aus einer Elektor Platine habe ich mit Meßschieber ungefähr 2 mm gemessen, also 78 mil.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Element[&amp;quot;&amp;quot; &amp;quot;R__0w4_10.16mm&amp;quot; &amp;quot;&amp;quot; &amp;quot;&amp;quot; 0 0 0 -10300 0 100 &amp;quot;&amp;quot;]&lt;br /&gt;
(&lt;br /&gt;
    Pin[0 0 7800 3100 6100 3500 &amp;quot;&amp;quot; &amp;quot;1&amp;quot; &amp;quot;edge2&amp;quot;]&lt;br /&gt;
    Pin[40000 0 7800 3100 6100 3500 &amp;quot;&amp;quot; &amp;quot;2&amp;quot; &amp;quot;edge2&amp;quot;]&lt;br /&gt;
    ElementLine [7900 0 4400 0 1000]&lt;br /&gt;
    ElementLine [32000 0 35500 0 1000]&lt;br /&gt;
    ElementLine [7900 -3300 7900 3300 1000]&lt;br /&gt;
    ElementLine [32000 -3300 32000 3300 1000]&lt;br /&gt;
    ElementLine [7900 -3300 32000 -3300 1000]&lt;br /&gt;
    ElementLine [7900 3300 32000 3300 1000]&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für Kapazitäten mit einer Breite von 2.54 mm oder 5.08 mm nutze ich folgendes Element&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Element[&amp;quot;&amp;quot; &amp;quot;&amp;quot; &amp;quot;&amp;quot; &amp;quot;&amp;quot; 65000 78500 0 0 0 100 &amp;quot;&amp;quot;]&lt;br /&gt;
(&lt;br /&gt;
    Pin[2000 -2500 7000 3000 4200 2000 &amp;quot;&amp;quot; &amp;quot;cap_2&amp;quot; &amp;quot;edge2&amp;quot;]&lt;br /&gt;
    Pin[-8000 -2500 7000 3000 4200 2000 &amp;quot;&amp;quot; &amp;quot;cap_1&amp;quot; &amp;quot;edge2&amp;quot;]&lt;br /&gt;
    Pin[-18000 -2500 7000 3000 4200 2000 &amp;quot;&amp;quot; &amp;quot;cap_1&amp;quot; &amp;quot;edge2&amp;quot;]&lt;br /&gt;
    Pad[-16000 -2500 -10000 -2500 1000 2000 3000 &amp;quot;&amp;quot; &amp;quot;1&amp;quot; &amp;quot;&amp;quot;]&lt;br /&gt;
    ElementLine [-4000 -6500 -4000 2500 1399]&lt;br /&gt;
    ElementLine [-2000 -6500 -2000 2500 1399]&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für eine Breite von 5.08 mm oder 7.62 mm nutze ich folgendes Element:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Element[&amp;quot;&amp;quot; &amp;quot;&amp;quot; &amp;quot;&amp;quot; &amp;quot;&amp;quot; 63000 93500 0 0 0 100 &amp;quot;&amp;quot;]&lt;br /&gt;
(&lt;br /&gt;
    Pin[14000 -4500 7000 3000 4200 2000 &amp;quot;&amp;quot; &amp;quot;cap_2&amp;quot; &amp;quot;edge2&amp;quot;]&lt;br /&gt;
    Pin[4000 -4500 7000 3000 4200 2000 &amp;quot;&amp;quot; &amp;quot;cap_2&amp;quot; &amp;quot;edge2&amp;quot;]&lt;br /&gt;
    Pin[-16000 -4500 7000 3000 4200 2000 &amp;quot;&amp;quot; &amp;quot;cap_1&amp;quot; &amp;quot;edge2&amp;quot;]&lt;br /&gt;
    Pad[5500 -4500 12500 -4500 1000 2000 3000 &amp;quot;&amp;quot; &amp;quot;1&amp;quot; &amp;quot;edge2&amp;quot;]&lt;br /&gt;
    ElementLine [-7500 -8500 -7500 500 1399]&lt;br /&gt;
    ElementLine [-5500 -8500 -5500 500 1399]&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Gschem ==&lt;br /&gt;
&lt;br /&gt;
[[Bild:Gschem.png|right|thumb|Screenshot]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;&amp;lt;i&amp;gt;gschem&amp;lt;/i&amp;gt;&amp;lt;/b&amp;gt; ist der Schaltplaneditor aus dem Open Source Projekt gEDA. &amp;lt;i&amp;gt;gschem&amp;lt;/i&amp;gt; wird hauptsächlich auf Linux Rechnern entwickelt, läuft aber auch auf anderen Unix-Betriebssystemen und unter Windows. &amp;lt;i&amp;gt;gschem&amp;lt;/i&amp;gt; ist für die Linuxdistributionen RedHat und Debian als Paket verfügbar, für Windows ist nur eine ältere Version erhältlich und für alle anderen ist selber kompilieren angesagt.&lt;br /&gt;
&lt;br /&gt;
Die Bedienung ist nicht sonderlich anfängerfreundlich. Hat man sich aber mal daran gewöhnt, dass jeder Menupunkt mit 1 oder 2 Tasten erreichbar ist, läßt sich&#039;s mit &amp;lt;i&amp;gt;gschem&amp;lt;/i&amp;gt; prima arbeiten. &lt;br /&gt;
&lt;br /&gt;
In der Symbolbibliothek (die auch online betrachtet werden kann) sind etwas mehr als 1000 Symbole; das Selbsterzeugen von Symbolen ist jedoch problemlos möglich. Insbesondere ist es aufgrund des gut dokumentierten und einfachen Datei-Formates möglich, mit einfachen Perl-Programmen z.B. aus Reports von Xilinx ISE Symbole zu erzeugen und automatisch zu aktualisieren, wenn sich die Pinzuordnung ändert. Das fehlerhafte Eingeben der Pinbelegung von CPLDs und FPGAs von Hand und die Änderung derselben ist damit für &amp;lt;i&amp;gt;gschem&amp;lt;/i&amp;gt; User Geschichte.&lt;br /&gt;
&lt;br /&gt;
Die Schaltpläne lassen sich als png und als Postscript exportieren. &lt;br /&gt;
&lt;br /&gt;
Netzlisten (insgesamt über 20 Formate für PCB, Protel, Eagle, BAE, spice, pads, ... ) lassen sich mit dem Programm &amp;lt;i&amp;gt;gnetlist&amp;lt;/i&amp;gt; generieren. Aus diesem Grund ist man (bis auf die Namen der Footprints) unabhängig von der verwendeten Layout-Software und kann diese auch sehr leicht wechseln.&lt;br /&gt;
&lt;br /&gt;
Ein großer Vorteil der gEDA-Suite sind die Dateiformate, welche alle reiner ASCII-Text sind. Dies macht die Entwicklung von Helper-Tools zur Lösung von speziellen Aufgaben sehr leicht. Außerdem können die Dateien deswegen sehr einfach in Versionsverwaltungssystemen wie CVS verwaltet werden, was insbesondere die Entwickler größerer Projekte zu schätzen wissen.&lt;br /&gt;
&lt;br /&gt;
Nähere Informationen über &amp;lt;i&amp;gt;gschem&amp;lt;/i&amp;gt; (gEDA) gibt es unter [[http://www.geda.seul.org/ http://www.geda.seul.org/]].&lt;br /&gt;
&lt;br /&gt;
== BAE ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Bartels AutoEngineer&amp;lt;/b&amp;gt; (&amp;lt;b&amp;gt;&amp;lt;i&amp;gt;BAE&amp;lt;/i&amp;gt;&amp;lt;/b&amp;gt;) unterstützt die Erstellung von Schaltplänen, Leiterplatten und integrierten Schaltungen und läuft unter Windows, Linux und verschiedenen X11-/Unix-Systemen.&lt;br /&gt;
&lt;br /&gt;
Eine auf Schaltplaneingabe beschränkte Version und eine kastrierte Evaluierungsversion sind auf der [http://www.bartels.de/bae/bae_de.htm BAE Homepage] downloadbar.&lt;br /&gt;
&lt;br /&gt;
Die [http://www.bartels.de/bae/baeprice_de.htm preiswerteste] kostenpflichtige Version ist das &amp;lt;b&amp;gt;&amp;lt;i&amp;gt;BAE Light&amp;lt;/i&amp;gt;&amp;lt;/b&amp;gt;. Diese Version ist auf Leiterplatten der Groesse 160x100 und auf 2 Layer beschränkt, eine Beschränkung auf eine bestimmte Pinanzahl gibt es aber nicht.&lt;br /&gt;
&lt;br /&gt;
Ansonsten wird eine Economy-, Professional- und Highendversion angeboten, die jeweiligen Eigenschaften sind im Abschnitt [http://www.bartels.de/baedoc/inst_de.htm Bartels AutoEngineer Softwarekonfigurationen] erklärt. Interessant ist z.B. der Bauteilhöhencheck.&lt;br /&gt;
&lt;br /&gt;
Mit dem &amp;lt;b&amp;gt;&amp;lt;i&amp;gt;BAE IC Design&amp;lt;/i&amp;gt;&amp;lt;/b&amp;gt; dringt man bis in den Bereich der IC-Entwicklung vor.&lt;br /&gt;
&lt;br /&gt;
== TARGET 3001! == &lt;br /&gt;
[[Bild:target3001.png|right|thumb|Screenshot]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;&amp;lt;i&amp;gt;TARGET 3001!&amp;lt;/i&amp;gt;&amp;lt;/b&amp;gt; für Windows bietet folgende Funktionen&lt;br /&gt;
&lt;br /&gt;
* Schaltplan&lt;br /&gt;
* Bauteilerstellung &lt;br /&gt;
* Schaltungssimulation (PSPICE-Syntax)&lt;br /&gt;
* Platinen-Layout mit Autoplatzierer&lt;br /&gt;
* Autorouter &lt;br /&gt;
* Anzeige der Platine in 3D&lt;br /&gt;
* Frontplattenentwurf direkt an oder über der Platine&lt;br /&gt;
&lt;br /&gt;
Die Platinen-Layout-Software ist in deutscher, englischer oder französischer Sprache. Es gibt eine für nicht kommerzielle Anwendungen kostenlose Version: &amp;lt;b&amp;gt;TARGET 3001! discover&amp;lt;/b&amp;gt; ist beschränkt auf 250 Pins/Pads, 2 Kupferlagen&lt;br /&gt;
und 30 Signale sind simulierbar, die Fläche ist unbeschränkt (1,2m x 1,2m).&lt;br /&gt;
&lt;br /&gt;
Auf der c&#039;t 11/07 CD ist eine &amp;lt;b&amp;gt;SE Version&amp;lt;/b&amp;gt; von TARGET 3001! verfügbar welche 400 Pins/Pads verarbeiten kann. &lt;br /&gt;
&lt;br /&gt;
Die &amp;lt;b&amp;gt;PCB-Pool Edition&amp;lt;/b&amp;gt; hat keine Beschränkungen, speichert aber die Layouts in einem von normalen Target Versionen nicht lesbaren Format. Diese Layouts können dann allerdings nur zum selbst Ätzen ausgedruckt werden oder vom PCB-POOL® produziert werden.&lt;br /&gt;
&lt;br /&gt;
Links:&lt;br /&gt;
* [http://server.ibfriedrich.com/wiki/ibfwikide Target3001 Homepage]&lt;br /&gt;
* [http://www.pcb-pool.com/ppde/service_downloads.html Target3001 PCB-Pool-Edition]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;TARGET 3001!&amp;lt;/i&amp;gt; bietet ein typisches Windows Look-And-Feel. Eine einfache Einführung findet sich &#039;&#039;&#039;[http://server.ibfriedrich.com/wiki/ibfwikide/index.php?title=Kurzeinführung2 hier]&#039;&#039;&#039;. Wer sich schon mit Eagle auskennt, kann auch &#039;&#039;&#039;[http://server.ibfriedrich.com/wiki/ibfwikide/index.php?title=Eagle hier]&#039;&#039;&#039; schauen. Es gibt kostenlosen direkten Service durch den Hersteller telefonisch oder per E-Mail auch für Einsteiger oder Demo-User.&lt;br /&gt;
&lt;br /&gt;
== ExpressPCB ==&lt;br /&gt;
&lt;br /&gt;
Die Firma &amp;lt;b&amp;gt;ExpressPCB&amp;lt;/b&amp;gt; bietet den kostenlosen Schaltplaneditor &amp;lt;b&amp;gt;&amp;lt;i&amp;gt;ExpressSCH&amp;lt;/i&amp;gt;&amp;lt;/b&amp;gt; an. Zusätzlich gibt es das kostenlose Layoutprogramm &amp;lt;b&amp;gt;&amp;lt;i&amp;gt;ExpressPCB&amp;lt;/i&amp;gt;&amp;lt;/b&amp;gt; zum Erstellen von zwei- und vierlagigen Leiterplatten. Die beiden Programme sind auf Windows beschränkt. &lt;br /&gt;
&lt;br /&gt;
Die Firma bietet auf der [http://www.expresspcb.com/ ExpressPCB Homepage] ausserdem einen kommerziellen Service für die Herstellung von zwei- und vierlagigen Leiterplatten an. &lt;br /&gt;
&lt;br /&gt;
Auf der Seite finden sich [http://www.expresspcb.com/ExpressPCBHtm/Tips.htm hier] einige Hinweise zum Entwurf von Leiterplatten.&lt;br /&gt;
&lt;br /&gt;
== JFig ==&lt;br /&gt;
&lt;br /&gt;
[[Bild:Jfig.png|right|thumb|Screenshot]]&lt;br /&gt;
&amp;lt;b&amp;gt;&amp;lt;i&amp;gt;JFig&amp;lt;/i&amp;gt;&amp;lt;/b&amp;gt; ist eigentlich ein &amp;quot;ganz normales&amp;quot; Vektorzeichenprogramm. Um Schaltpläne zu zeichnen benötigt man deshalb zusätzliche Symbolbibliotheken. &lt;br /&gt;
&lt;br /&gt;
Die Exportmöglichkeiten für das weitverbreitete fig-Format sind sehr vielfältig: mit dem Zusatzprogramm &amp;lt;i&amp;gt;fig2dev&amp;lt;/i&amp;gt;, das direkt aus dem &amp;lt;i&amp;gt;jfig&amp;lt;/i&amp;gt;-Menü aufgerufen kann, bleiben von Postscript über PNG bis hin zu [[LaTeX]] kaum Wünsche offen. Für kleine Schaltpläne oder Diagramme, die ausgedruckt oder in PDF-Dateien verbreitet werden sollen, gibt es deshalb nichts besseres.&lt;br /&gt;
&lt;br /&gt;
Das Programm ist ein komplett in [http://java.sun.com/ Java] geschriebener 1:1-Klon des [[Linux]]-Programms &amp;lt;i&amp;gt;xfig&amp;lt;/i&amp;gt; und sollte daher mit jedem Betriebssystem von Windows bis Mac OS laufen. Es ist kostenlos auf [http://tech-www.informatik.uni-hamburg.de/applets/javafig/ http://tech-www.informatik.uni-hamburg.de/applets/javafig/] erhältlich.&lt;br /&gt;
&lt;br /&gt;
Die Bedienung wird für Windows-Benutzer am Anfang wohl ziemlich ungewohnt sein, aber wenn man mal das Grundprinzip verstanden, hat findet man sich durch die eindeutig beschrifteten Schaltflächen schnell zurecht.&lt;br /&gt;
&lt;br /&gt;
== Kicad ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Kicad&#039;&#039;&#039; ist ein Paket aus GPL Design / Layout / Routing Programmen, basierend auf wxWidgets und damit plattformübergreifend. Die Progamme sind unter der Lizenz von GPL veröffentlicht und damit Open Source.&lt;br /&gt;
&lt;br /&gt;
http://www.lis.inpg.fr/realise_au_lis/kicad/&lt;br /&gt;
&lt;br /&gt;
Eine User-Group findet sich unter: http://groups.yahoo.com/group/kicad-users/. Eine Anmeldung erfolgt erst, nachdem man vom Besitzer der User-Group freigeschaltet wurde (wie üblich für die meisten Yahoo-Groups).&lt;br /&gt;
&lt;br /&gt;
Kicad liefert eine schöne 3D-Ansicht des fertigen Layouts einschließlich der bestückten Bauteile, so dass man an dieser Stelle schon einmal einen Überblick bekommt, ob vielleicht nicht doch etwas vergessen wurde. Es gibt zwar nicht für alle Bauformen 3D-Modell, allerdings lassen sich diese selbst erstellen.&lt;br /&gt;
&lt;br /&gt;
Neben der bereits umfangreichen Bibliothek gibt es auf vielen anderen Seiten weitere Bibliotheken zum Download, die einfach integriert werden können.&lt;br /&gt;
&lt;br /&gt;
Für Umsteiger von anderen Programmen sollten sich nach wenigen Stunden bereits die gleichen Ergebnisse erzielen lassen.&lt;br /&gt;
&lt;br /&gt;
Als Nachteil ließe sich noch aufführen, dass der PCB-Layouter in der neusten Version (Januar-2006) etwas instabil ist und gerne abstürzt. Ebenso sind die Autorouterfunktionen nicht gut dokumentiert.&lt;br /&gt;
&lt;br /&gt;
== TinyCAD ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;TinyCAD&#039;&#039;&#039; ist ein weiterer &#039;&#039;open source&#039;&#039; Schaltplaneditor für Windows. Mehr Infos gibt es auf der Projektseite http://tinycad.sourceforge.net&lt;br /&gt;
&lt;br /&gt;
TinyCAD kann z.B. mit dem freien Layoutprogramm [http://www.geocities.com/rogerlasau/VCad.html VCad Stripboard Layout Editor] (bzw. der kommerziellen Variante VeeCad) kombiniert werden, um Streifenplatinen zu entwerfen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== AACircuit ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;AACircuit&#039;&#039;&#039; ist ein Schaltplaneditor mit einer Ausgabe als ASCII-Grafik. Das Programm wurde dafür entwickelt, um mal eben eine Frage oder eine Antwort in &#039;&#039;newsgroups&#039;&#039;, Chats oder Foren zu veranschaulichen, wenn keine Upload-Möglichkeit von Bilddateien da ist. AACircuit gibt es bei http://www.tech-chat.de/&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  .---o----o------o---o---------------o---o----o------------o 12-15V&lt;br /&gt;
  |   |    |  22uF| + |               |   |    |&lt;br /&gt;
 .-.  |   .-.    ###  |              .-.  |    |    .-------o&lt;br /&gt;
 | |&amp;lt;-&#039;   | |    ---  |              | |  |    |    |   .---o&lt;br /&gt;
 | |5k    | |5k6  |   |              | |  |    |    |   |&lt;br /&gt;
 &#039;-&#039;      &#039;-&#039;     |   o--.           &#039;-&#039;  |   _|_   o  /o&lt;br /&gt;
  |        |     ===  |  |            |   |  |_/_|-   /&lt;br /&gt;
 .-.       |     GND  | ---100n   LED V   -    |     /&lt;br /&gt;
 | |       |          | ---           -   ^    |    o&lt;br /&gt;
 | |6k2    |          |  |            |   |    |    |&lt;br /&gt;
 &#039;-&#039;       |          | GND           &#039;---o----o    &#039;-------o&lt;br /&gt;
  |        |       2|\|7                       |&lt;br /&gt;
  o-----------------|-\ LM741      ___       |/&lt;br /&gt;
  |        |        |  &amp;gt;-------o--|___|--o---|&lt;br /&gt;
  |        o---o----|+/ 6      |   22k   |   |&amp;gt;  BC547&lt;br /&gt;
  |        |   |   3|/|4       |         |     |&lt;br /&gt;
 .-.       |   |     ===       o---.    .-.    |&lt;br /&gt;
 | |       |   o---. GND       |   |    | |5k6 |&lt;br /&gt;
 | |2k7   .-.  |   |   ___    _V_  |    | |    |&lt;br /&gt;
 &#039;-&#039;     KTY10 | + &#039;--|___|--|___|-&#039;    &#039;-&#039;    |&lt;br /&gt;
  |       | | ###      47k   220k        |     |&lt;br /&gt;
  |       &#039;-&#039; ---                        |     |&lt;br /&gt;
  |        |   |                         |     |&lt;br /&gt;
  |        |   |                         |     |&lt;br /&gt;
  &#039;--------o---o-------------------------o-----o------------o GND&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== sPlan ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;sPlan&#039;&#039;&#039; ist ein rel. preiswerter Schaltplaneditor für Windows (95,98,ME,NT,2000,XP)&lt;br /&gt;
Infos und eine Demoversion von sPlan gibt es u.a. bei http://www.abacom-online.de/html/splan.html&lt;br /&gt;
&lt;br /&gt;
== Basic Schematic == &lt;br /&gt;
&lt;br /&gt;
Basic Schematic (&#039;&#039;&#039;BSch3V&#039;&#039;&#039;) ist ein freier Schaltplaneditor für Windows. Ein ZIP-Archiv mit engl. Programm, Handbuch und Sourcecode gibt es bei http://www.suigyodo.com/online/e/index.htm. Ebenso ist dort eine Cross-Plattform Version &#039;&#039;&#039;Qt-BSch3V&#039;&#039;&#039; auf der Basis von Qt-Grafiklibraries erhältlich.&lt;br /&gt;
&lt;br /&gt;
== Fritzing ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Fritzing&#039;&#039;&#039; ist ein sich zur Zeit (Januar 2008) im Alpha-Stadium befindendes Programm, welches einmal zu einer vollwertigen Electronic Design Automation (EDA) Software ausgebaut werden soll. Der Editor verwende die Metapher eines Breadboards (Steckbretts), auf dem die Benutzer virtuell Bauteile einstecken. Fritzings Zielgruppe sind Künstler und Designer, nicht Elektroniker, und die Software soll speziell auf diese Zielgruppe zugeschnitten werden. Dabei wird auf eine niedrige Zugangsschwelle wert gelegt.&lt;br /&gt;
&lt;br /&gt;
Alpha-Versionen für Mac OS X, Linux und Windows sind bei http://www.fritzing.org/ erhältlich. Im jetzigen Zustand ist es eher für Neugierige geeignet, denn für ernsthafte Projektentwicklung.&lt;br /&gt;
&lt;br /&gt;
== Siehe auch ==&lt;br /&gt;
&lt;br /&gt;
* [[Schaltungssimulation]]&lt;br /&gt;
* [[Do&#039;s and dont&#039;s - Platinenlayout]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Weblinks ==&lt;br /&gt;
&lt;br /&gt;
* [http://www.cadsoft.de/ Eagle]&lt;br /&gt;
* [http://www.ibfriedrich.com/home.htm Target3001 Homepage]&lt;br /&gt;
* [http://www.bartels.de/bae/bae_de.htm BAE Homepage]&lt;br /&gt;
* [http://www.geda.seul.org gschem]&lt;br /&gt;
* [http://pcb.sourceforge.net/index.html PCB]&lt;br /&gt;
* [http://www.geda.seul.org/wiki/geda:gsch2pcb_tutorial Tutorial] über das Zusammenspiel von gschem und PCB. Inklusive Einführung in beide Programme (sehr ausführlich!)&lt;br /&gt;
* [http://www.expresspcb.com/ ExpressPCB Homepage]&lt;br /&gt;
* [http://tinycad.sourceforge.net/ TinyCAD.Sourceforge.net]&lt;br /&gt;
* [http://www.freerouting.net/ FreeRouting - Kostenloser Autorouter]&lt;br /&gt;
&lt;br /&gt;
[[Category:Platinen]]&lt;/div&gt;</summary>
		<author><name>Thymythos</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=AVR_Eclipse&amp;diff=31960</id>
		<title>AVR Eclipse</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=AVR_Eclipse&amp;diff=31960"/>
		<updated>2008-10-19T13:11:00Z</updated>

		<summary type="html">&lt;p&gt;Thymythos: /* Projekteinstellungen */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Dieser Artikel beschreibt erste Erfahrungen mit Eclipse und der AVR-Toolchain.&lt;br /&gt;
&lt;br /&gt;
== ! Achtung ! ==&lt;br /&gt;
Die Installation und benützung unter Windows wird in einen Neuen Artikel ausgelagert [[AVR Eclipse Windows]]&lt;br /&gt;
&lt;br /&gt;
==  Allgemeines zu Eclipse ==&lt;br /&gt;
Eclipse ist eine IDE, die sich alleine nicht zur Programmierung von C/C++ eignet. Dafür gibt es dann das Eclipse-Plugin CDT (auch von ECLIPSE.ORG). Die CDT erweitert Eclipse mit der Möglichkeit, C/C++ zu programmieren. Das aber erstmal nur mit dem GCC. Um jetzt die Toolchain AVR-GCC (WINAVR) einzubinden, benötigt man noch ein weiteres Plugin (CDT AVRGCC oder auch CDT AVR Plugin). Es ist auch möglich, ohne die beiden letzt genannten Plugins zu arbeiten, dann sind die Einstellungen für den GCC an AVR-GCC anzupassen (unkomfortabler).&lt;br /&gt;
&lt;br /&gt;
==  Was muss installiert sein ? ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Unter Linux: (Gentoo) ===&lt;br /&gt;
==== Eclipse-IDE ====&lt;br /&gt;
* [http://www.eclipse.org/downloads/index.php Eclipse-IDE] Version 3.1.0&lt;br /&gt;
* [http://www.eclipse.org/cdt/ Eclipse-CDT-Plugin] Version 3.0.0&lt;br /&gt;
* [http://sf.net/projects/avr-eclipse Eclipse-CDT-Addon for AVR] Version 20070404&lt;br /&gt;
&lt;br /&gt;
==== Compiler ====&lt;br /&gt;
* emerge crossdev&lt;br /&gt;
* crossdev --target avr&lt;br /&gt;
** binutils-2.16.1-r2&lt;br /&gt;
** gcc-3.4.6&lt;br /&gt;
** avr-libc-[latest]&lt;br /&gt;
&lt;br /&gt;
==== Programmer ====&lt;br /&gt;
* emerge uisp&lt;br /&gt;
&lt;br /&gt;
=== Unter Linux: (Debian) ===&lt;br /&gt;
==== Eclipse-IDE ====&lt;br /&gt;
* [http://www.eclipse.org/downloads/index.php Eclipse-IDE] Version 3.1.0&lt;br /&gt;
* [http://www.eclipse.org/cdt/ Eclipse-CDT-Plugin] Version 3.0.0&lt;br /&gt;
* [http://sf.net/projects/avr-eclipse Eclipse-CDT-Addon for AVR] Version 20070404&lt;br /&gt;
&lt;br /&gt;
==== Compiler ====&lt;br /&gt;
* binutils-avr 2.15-3&lt;br /&gt;
* gcc-avr 1:3.4.3-2&lt;br /&gt;
* avr-libc 1:1.2.3-3&lt;br /&gt;
&lt;br /&gt;
==== Debugger ====&lt;br /&gt;
* simulavr 0.1.2.2-1&lt;br /&gt;
* gdb-avr 6.3-2&lt;br /&gt;
* ? avra 0.7-1&lt;br /&gt;
&lt;br /&gt;
==== Programmer ====&lt;br /&gt;
* uisp 20050207&lt;br /&gt;
* ? avrp&lt;br /&gt;
* ? avrprog&lt;br /&gt;
&lt;br /&gt;
=== Unter Linux: (Ubuntu 8.10) ===&lt;br /&gt;
==== Eclipse-IDE ====&lt;br /&gt;
* [http://www.eclipse.org/downloads Eclipse IDE for C/C++ Developers] Version 3.3, CDT Version 4.0&lt;br /&gt;
* [http://sourceforge.net/projects/avr-eclipse AVR-Eclipse-Plugin] Version 2.2.0&lt;br /&gt;
&lt;br /&gt;
==== Compiler ====&lt;br /&gt;
* binutils-avr: 2.18-3&lt;br /&gt;
* gcc-avr: 1:4.3.0-2&lt;br /&gt;
* avr-libc: 1:1.6.2-1&lt;br /&gt;
&lt;br /&gt;
==== Debugger ====&lt;br /&gt;
* [ftp://ftp.gnu.org/gnu/gdb/gdb-6.6.tar.bz2 avr-gdb]: 6.6; &#039;&#039;&#039;In den Repositories ist 6.4.90!&#039;&#039;&#039; &lt;br /&gt;
* avarice: 2.7-2&lt;br /&gt;
* simulavr: 0.1.2.2-6.1 (nicht getestet, sollte aber genauso funktionieren)&lt;br /&gt;
&lt;br /&gt;
==== Programmer ====&lt;br /&gt;
* avrdude: 5.5-3&lt;br /&gt;
&lt;br /&gt;
==== Zusätzliche notwendige Programme/Libraries ====&lt;br /&gt;
* gcc&lt;br /&gt;
* binutils-avr&lt;br /&gt;
* build-essential&lt;br /&gt;
* ncurses-dev&lt;br /&gt;
&lt;br /&gt;
== Installation unter Ubuntu ==&lt;br /&gt;
=== AVR-Toolchain ===&lt;br /&gt;
Leider ist in den Repositories nur eine veraltete Version von avr-gdb (bzw. gdb-avr) enthalten. Diese Version hat bei mir zu Fehlern geführt. Deshalb wird die aktuelle Releaseversion 6.6 verwendet.&lt;br /&gt;
&lt;br /&gt;
==== Schritt für Schritt ====&lt;br /&gt;
Als erstes werden die notwendigen Programme aus den Repositories installiert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;sudo apt-get install gcc gcc-avr avr-libc avrdude binutils-avr avarice build-essential ncurses-dev&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ubuntu 6.10:&lt;br /&gt;
&amp;lt;pre&amp;gt;sudo apt-get install gcc gcc-avr avr-libc avrdude binutils-avr avarice build-essential libncurses5-dev&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zusätzlich können auch noch folgende Packages interessant sein:&lt;br /&gt;
* Simulavr: Ein Simulator für die AVR-Reihe&lt;br /&gt;
* uisp: Alternativer Downloader&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;sudo apt-get install simulavr uisp&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jetzt kann man bereits das AVR-Target ansprechen, um z.B. die Fuses auszulesen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;avarice -j /dev/ttyUSB0 -P atmega128 -r&amp;lt;/pre&amp;gt;&lt;br /&gt;
* -j: Gibt das Gerät an, mit dem das Target verbunden ist.&lt;br /&gt;
* -P: Zielarchitektur&lt;br /&gt;
* -r: Read Fuses&lt;br /&gt;
&lt;br /&gt;
Dazu ist die Manpage von avarice zu empfehlen: &lt;br /&gt;
&amp;lt;pre&amp;gt;man avarice&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Als nächstes muss gdb-avr heruntergeladen und dann kompiliert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;wget ftp://ftp.gnu.org/gnu/gdb/gdb-6.6.tar.bz2&lt;br /&gt;
tar jxf gdb-6.6.tar.bz2&lt;br /&gt;
cd gdb-6.6&lt;br /&gt;
./configure --target=avr --prefix=/usr/local/avr&lt;br /&gt;
make&lt;br /&gt;
sudo make install&lt;br /&gt;
cd ..&lt;br /&gt;
rm -rf gdb-6.6&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dies installiert die aktuelle Version von gdb-avr unter /usr/local/avr. Diesen Pfad könnte man zur PATH-Variable hinzufügen, dies ist allerdings nicht zwingend notwendig.&lt;br /&gt;
&lt;br /&gt;
== Installation von Eclipse ==&lt;br /&gt;
&lt;br /&gt;
Es sollte das [http://www.eclipse.org/downloads Eclipse IDE for C/C++ Developers]-Packet heruntergeladen und entpackt werden, da in diesem Packet bereits CDT vorinstalliert und keine (für diesen Einsatz) unnötigen Plugins installiert sind. Damit Eclipse für mehrere User zugänglich ist, sollte der entstandene Ordner nach /opt verschoben werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;sudo mv eclipse /opt&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Falls Eclipse langsam läuft oder Fehler hat, ist die Verwendung des propriertären Java-Packages von Sun einen Versuch wert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;sudo apt-get install sun-java6-jre&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Falls danach noch immer gij statt java verwendet wird, muss in der Datei /etc/eclipse/java_home diese Zeile am Beginn eingefügt werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;/usr/lib/jvm/java-6-sun&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Stand von 2008.02.08: &amp;lt;pre&amp;gt;sudo ln -s /usr/lib/jvm/java-6-sun /opt/eclipse/jre&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sollte die reguläre Installation auf Ubuntu 6.10 Amd-64  fehlschlagen (was bei mir der Fall war), kann [http://mirror.yoxos-eclipse-distribution.de/eclipse.org/technology/epp/downloads/release/20071103/eclipse-cpp-europa-fall2-linux-gtk.tar.gz    die 32-Bit-Version] mit der passenden Java Engine installiert werden:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sudo apt-get install ia32-sun-java6-bin&lt;br /&gt;
sudo update-alternatives --config java&lt;br /&gt;
#Folgende Frage mit [Enter] bestätigen (64-Bit-Version bleibt vorgabe).&lt;br /&gt;
&lt;br /&gt;
# link für eclipse setzen&lt;br /&gt;
sudo ln -s /usr/lib/jvm/ia32-java-6-sun /opt/eclipse/jre&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Alternative 1 ===&lt;br /&gt;
&lt;br /&gt;
Das AVR-Eclipse Plugin kann über die Update-Site http://avr-eclipse.sourceforge.net/updatesite/ installiert werden. (Help-&amp;gt;Software Updates...)&lt;br /&gt;
&lt;br /&gt;
Zum Schluss muss noch, die avr-objsplit.bat-Datei, wie folgt, umgeschrieben, nach /usr/bin/avr-objsplit kopiert und ausführbar gemacht werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
avr-objcopy -j .text -j .data -O ihex *.elf flash.hex&lt;br /&gt;
avr-objcopy -j .eeprom --change-section-lma .eeprom=0 -O ihex *.elf eeprom.hex&lt;br /&gt;
if [ ! -f eeprom.hex ]; then&lt;br /&gt;
        echo &amp;quot;:00000001FF&amp;quot; &amp;gt; eeprom.hex&lt;br /&gt;
fi&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ändern der Rechte:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
chmod +x avr-objsplit&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Einstellungen ====&lt;br /&gt;
Jetzt müssen noch gewisse Einstellungen in Eclipse angepasst werden:&lt;br /&gt;
Unter Window-&amp;gt;Preferences-&amp;gt;AVR-&amp;gt;AVRdude:&lt;br /&gt;
&lt;br /&gt;
* Programmer auswählen&lt;br /&gt;
* Programmerport auswählen&lt;br /&gt;
* Target MCU Type auswählen&lt;br /&gt;
&lt;br /&gt;
==== Projekteinstellungen ====&lt;br /&gt;
Jetzt kann ein neues C-Project angelegt werden, wobei als Projekttyp &amp;quot;AVR Cross-Target Project&amp;quot; ausgewählt werden muss.&amp;lt;/br&amp;gt;Im &amp;quot;New Project Wizard&amp;quot; kann der MCU-Typ und die Quarzfrequenz eingestellt werden. Weitere Compiler-Optionen sind in den Projekteinstellungen unter &amp;quot;C/C++ Build-&amp;gt;Settings&amp;quot; möglich.&lt;br /&gt;
&lt;br /&gt;
=== Alternative 2 ===&lt;br /&gt;
&lt;br /&gt;
Dabei werden die Projekteinstellungen eines Standard-C-Projekts so verändert, dass die AVR-Toolchain verwendet wird.&lt;br /&gt;
&lt;br /&gt;
Mein erster erfolgreicher Versuch lief mit einen &amp;quot;managed C Projekt&amp;quot;. Ich hoffe in der folgenden Beschreibung fehlt kein Schritt:&lt;br /&gt;
* File / New / Managed Make C Project&lt;br /&gt;
** Project Name &#039;&#039;&#039;&amp;quot;test2&amp;quot; [Next]&#039;&#039;&#039;&lt;br /&gt;
** Project Type &#039;&#039;&#039;&amp;quot;Executable (GNU)&amp;quot; [Next]&#039;&#039;&#039;&lt;br /&gt;
** C/C++ Indexer &#039;&#039;&#039;&amp;quot;full ...&amp;quot; [Finish]&#039;&#039;&#039; (hab ich später geändert siehe unten)&lt;br /&gt;
&lt;br /&gt;
==== Projekteinstellungen ====&lt;br /&gt;
* File / New / SourceFile&lt;br /&gt;
** &#039;&#039;&#039;[Browse] &amp;quot;test2&amp;quot; [OK]&#039;&#039;&#039;&lt;br /&gt;
** Source File: &#039;&#039;&#039;&amp;quot;test2.c&amp;quot; [Finish]&#039;&#039;&#039;&lt;br /&gt;
* Project / Properties&lt;br /&gt;
** C/C++ Build / ToolSettings&lt;br /&gt;
*** GCC-C-Compiler&lt;br /&gt;
**** Command:  &#039;&#039;&#039;gcc&#039;&#039;&#039; ändern auf &#039;&#039;&#039;avr-gcc -mmcu=atmega16 -c&#039;&#039;&#039;&lt;br /&gt;
**** Das &#039;&#039;&#039;-c&#039;&#039;&#039; ist wichtig, damit nur kompliert aber nicht gelinkt wird.&lt;br /&gt;
**** Directorys Eintrag &#039;&#039;&#039;/usr/avr/include&#039;&#039;&#039; einfügen&lt;br /&gt;
**** Debugging  gewünschten Wert einstellen (z.B. -g)&lt;br /&gt;
*** GCC-C-Linker &lt;br /&gt;
**** Command:  &#039;&#039;&#039;gcc&#039;&#039;&#039; auch ändern auf &#039;&#039;&#039;avr-gcc -mmcu=atmega16 &#039;&#039;&#039;&lt;br /&gt;
**** Libraries: Library Search Path= &#039;&#039;&#039;/usr/avr&#039;&#039;&#039;&lt;br /&gt;
**** Miscellaneous: Linker Flags = &#039;&#039;&#039;-Wl,-Map,avr.map&#039;&#039;&#039;&lt;br /&gt;
*** GCC Assembler&lt;br /&gt;
**** Command:  &#039;&#039;&#039;as&#039;&#039;&#039; ändern auf &#039;&#039;avr-as&#039;&#039;&lt;br /&gt;
** C/C++ Build / Build Steps&lt;br /&gt;
*** Post-Build-Step&lt;br /&gt;
**** Command: &#039;&#039;&#039;avr-objcopy -j .text -j .data -O ihex test2 test2.hex&#039;&#039;&#039;&lt;br /&gt;
** C/C++ Indexer&lt;br /&gt;
*** Available Indexers = &#039;&#039;&#039;CTags Indexer (declarations only)&#039;&#039;&#039;&lt;br /&gt;
*** Include Files: Index Include paths &#039;&#039;&#039; einschalten&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==== später eingefügt: ====&lt;br /&gt;
* Project / Properties&lt;br /&gt;
** C/C++ Build / Build Steps&lt;br /&gt;
*** Pre-Build-Step&lt;br /&gt;
**** Command: &#039;&#039;&#039;uisp -dprog=dasa2 -dserial=/dev/ttyS0 -dpart=atmega16 --erase&#039;&#039;&#039;&lt;br /&gt;
* Project / Properties&lt;br /&gt;
** C/C++ Build / Build Steps&lt;br /&gt;
*** Post-Build-Step&lt;br /&gt;
**** Command: &#039;&#039;&#039;avr_upload&#039;&#039;&#039;&lt;br /&gt;
* Project / Properties&lt;br /&gt;
** C/C++ Build / Build Settings&lt;br /&gt;
*** Build Output&lt;br /&gt;
**** Artifact Name: &#039;&#039;&#039;avr_main&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
avr_upload ist eine kleine Batchdatei im Verzeichniss &#039;&#039;&#039;/usr/bin &#039;&#039;&#039;, die ich neu angelegt hab:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/bin/sh&lt;br /&gt;
# .lst-Datei erzeugen (optional)&lt;br /&gt;
# avr-objdump -h -S avr_main &amp;gt; avr.lst&lt;br /&gt;
# Datei in Intel-hex erzeugen&lt;br /&gt;
avr-objcopy -j .text -j .data -O ihex avr_main avr.hex&lt;br /&gt;
# Intel-hex-Datei uploaden&lt;br /&gt;
#uisp -dprog=dasa2 -dserial=/dev/ttyS0 -dpart=atmega16 --upload if=avr.hex&lt;br /&gt;
# Intel-hex Datei uploaden und verifizieren.&lt;br /&gt;
uisp -dprog=dasa2 -dserial=/dev/ttyS0 -dpart=atmega16 --upload if=avr.hex --verify&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Eclipse Plugin ====&lt;br /&gt;
&lt;br /&gt;
Im Forum gibt es ein Plugin für Eclipse, das einen Großteil dieser Einstellungen bereits beinhaltet. Der Thread steht unter: &lt;br /&gt;
&lt;br /&gt;
http://www.mikrocontroller.net/forum/read-2-229419.html#new &lt;br /&gt;
&lt;br /&gt;
Das Plugin wird dort zum Download angeboten. Aber es ist sicher hilfreich die dortige Anleitung zu beachten.&lt;br /&gt;
&lt;br /&gt;
http://www.mikrocontroller.net/attachment.php/285349/org.eclipse.cdt.avrgcc_1.0.16.zip&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;HINWEIS:&#039;&#039;&#039; Bitte die aktuelle Version benutzen. Folgende Warnung bezieht sich auf die älteren Versionen (vor Version 1.0.14).&lt;br /&gt;
&#039;&#039;&#039;WARNUNG:&#039;&#039;&#039; Bei mir funktionierten Timer-Interrupts mit dem Plugin nicht (die jedoch tadellos mit der WinAVR Makefile funktionierten). Vielleicht habe ich nur eine Option übersehen, seid aber auf der Hut. Wenn ihr Unregelmäßigkeiten bei IRQs feststellt, versucht&#039;s erstmal ohne das Eclipse-Plugin (bevor ihr stundenlang an eurem Code und euch selbst zweifelt :-) ).&lt;br /&gt;
&lt;br /&gt;
== Erster Test ==&lt;br /&gt;
Die jeweiligen Alternativen beziehen sich auf die oben genannten verschiedenen Möglichkeiten.&lt;br /&gt;
&lt;br /&gt;
=== Alternative 1 ===&lt;br /&gt;
Wenn bereits ein Board zur Verfügung steht, ist es zu empfehlen, ein einfaches Programm zu schreiben, welches z.B. eine LED toggelt (siehe Alternative 2). Dieses Programm muss dann mittels &#039;&#039;&#039;Build Project&#039;&#039;&#039; kompiliert werden. Dann kann mittels &#039;&#039;&#039;AVR Target-&amp;gt;download&#039;&#039;&#039; der AVR bespielt werden.&lt;br /&gt;
&lt;br /&gt;
=== Alternative 2 ===&lt;br /&gt;
Die folgenden Angaben beziehen sich auf ein sehr einfache Entwicklungsboard mit SPI-Anschluss über die serielle Schnittstelle. Bestückt wurde von mir nur die Spannungsversorgung, der SPI auf RS232 Teil zum Programmieren des Prozessors, Prozessor und Quarz, sowie einige Taster und LEDs. Den Schaltplan gibts [http://www.pollin.de/shop/downloads/D810022B.PDF als PDF hier].&lt;br /&gt;
&lt;br /&gt;
==== Ziel: Eine LED soll blinken ====&lt;br /&gt;
Mein Test läuft auf einem ATMega16, der einen 8MHz-Quarz hat. Der Quarz wird aber nicht genutzt, weil bisher keine Fuses gesetzt sind. Die einzige verwendete LED ist an Port D (&#039;&#039;&#039;PD6&#039;&#039;&#039;) angeschlossen.&lt;br /&gt;
==== Das Kabel ====&lt;br /&gt;
Das Board hat eine 9-polige Buchse(Mama), der PC hat einen 9-poligen Stecker(Papa). Das Kabel muss somit direkt durchverbunden werden. Keines der Kabel wird gekreuzt. Am besten kauft man ein 9-polig beschaltetes &amp;quot;Verlängerungskabel&amp;quot; für die serielle Schnittstelle.&lt;br /&gt;
==== Prozessor erkennen ====&lt;br /&gt;
Zuerstmal wollte ich testen, ob mein selbstgelötetes Board auch funktioniert. Ohne Prozessor sind die 5 Volt da, und auch sonst keine &amp;quot;Rauchzeichen&amp;quot;. Prozessor eingesetzt, und an den PC angeschlossen.&lt;br /&gt;
&lt;br /&gt;
Unter Linux kann der Befehl &#039;&#039;&#039;uisp -dprog=dasa2 -dserial=/dev/ttyS0 -dpart=atmega16 --rd_fuses&#039;&#039;&#039; verwendet werden. Entscheidend ist die erste Zeile der Antwort. Da sollte stehen: &#039;&#039;&#039;Atmel AVR ATMega16 is found&#039;&#039;&#039;. Wenn nicht ??? --- Bei mir war einfach nur der Strom für das Board noch nicht wieder eingesteckt.&lt;br /&gt;
* &#039;&#039;&#039;uisp&#039;&#039;&#039; = Programm zum Programmieren, Lesen und Löschen des AVR&lt;br /&gt;
* &#039;&#039;&#039;-dprogr=dasa2&#039;&#039;&#039; = Angabe der Pinbelegung der seriellen Schnittstelle. Je nach Hersteller des Programmierboards werden unterschiedliche Pinbelegungen verwendet. &#039;&#039;&#039;dasa2&#039;&#039;&#039; ist die, die bei mir gepasst hat.&lt;br /&gt;
* &#039;&#039;&#039;-dserial=/dev/ttyS0&#039;&#039;&#039; = Ich verwende die Schnittstelle COM1(ttyS0). Wer COM2(ttyS1) verwendet, muss &#039;&#039;&#039;/dev/ttyS1&#039;&#039;&#039; angeben.&lt;br /&gt;
* &#039;&#039;&#039;-rd_fuses&#039;&#039;&#039; = lesen der FUSE-Bits&lt;br /&gt;
&lt;br /&gt;
==== Prozessor löschen ====&lt;br /&gt;
* &#039;&#039;&#039;uisp -dprog=dasa2 -dserial=/dev/ttyS0 -dpart=atmega16 --erase&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==== Programm eintippen ====&lt;br /&gt;
(oder einfach von hier kopieren)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
  &lt;br /&gt;
#define running  1  &lt;br /&gt;
&lt;br /&gt;
// Unterprogramm mit Zeitschleife fuer ATMega16 ohne Quarz&lt;br /&gt;
void delay_ms( unsigned int ms )&lt;br /&gt;
{&lt;br /&gt;
    unsigned int  i;&lt;br /&gt;
    unsigned int  j;&lt;br /&gt;
       &lt;br /&gt;
    for ( i = ms;  i;  i-- ) &lt;br /&gt;
    {&lt;br /&gt;
        for ( j = 51;  j;  j-- )&lt;br /&gt;
        {&lt;br /&gt;
        }&lt;br /&gt;
    }    &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int main( void )&lt;br /&gt;
{&lt;br /&gt;
    // PortD6 als Output konfigurieren&lt;br /&gt;
    DDRD |= _BV(PD6);&lt;br /&gt;
&lt;br /&gt;
    // Hauptschleife des Programms&lt;br /&gt;
    while ( running )&lt;br /&gt;
    {&lt;br /&gt;
    	// LED einschalten, und dann warten&lt;br /&gt;
        PORTD |= _BV(PD6);&lt;br /&gt;
        delay_ms( 1000 ); &lt;br /&gt;
        &lt;br /&gt;
    	// LED ausschalten, und dann warten&lt;br /&gt;
        PORTD &amp;amp;= ~_BV(PD6);&lt;br /&gt;
        delay_ms( 29000 );         &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&#039;&#039;&#039;Beim Speichern innerhalb Eclipse wird das Programm compiliert, und die Ausgabe sollte etwa wie folgt ausssehen:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
**** Incremental build of configuration Debug for project AVR_Test ****&lt;br /&gt;
&lt;br /&gt;
make -k -q main-build &lt;br /&gt;
make -k pre-build main-build &lt;br /&gt;
uisp -dprog=dasa2 -dserial=/dev/ttyS0 -dpart=atmega16 --erase&lt;br /&gt;
Atmel AVR ATmega16 is found.&lt;br /&gt;
Erasing device ...&lt;br /&gt;
Reinitializing device&lt;br /&gt;
Atmel AVR ATmega16 is found.&lt;br /&gt;
 &lt;br /&gt;
Building file: ../tests/test1.c&lt;br /&gt;
Invoking: GCC C Compiler&lt;br /&gt;
avr-gcc -mmcu=atmega16 -I/usr/avr -O0 -g -Wall -c -fmessage-length=0 -otests/test1.o ../tests/test1.c&lt;br /&gt;
Finished building: ../tests/test1.c&lt;br /&gt;
 &lt;br /&gt;
Building target: AVR_Test&lt;br /&gt;
Invoking: GCC C Linker&lt;br /&gt;
avr-gcc -mmcu=atmega16 -L/usr/avr -Wl,-Map,avr.map -oAVR_Test ./tests/test1.o&lt;br /&gt;
Finished building target: AVR_Test&lt;br /&gt;
 &lt;br /&gt;
make --no-print-directory post-build&lt;br /&gt;
avr_upload&lt;br /&gt;
Atmel AVR ATmega16 is found.&lt;br /&gt;
Uploading: flash&lt;br /&gt;
 &lt;br /&gt;
Build complete for project AVR_Test&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Mit etwas Glück blinkt jetzt die LED.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Debugging ==&lt;br /&gt;
Debuggen funktioniert mit Eclipse entweder mit &#039;&#039;&#039;avarice&#039;&#039;&#039; oder &#039;&#039;&#039;simulavr&#039;&#039;&#039;, wobei ersteres zum OnDeviceDebugging dient und zweiteres einen Simulator darstellt. Zusätzlich ist &#039;&#039;&#039;avr-gdb&#039;&#039;&#039; notwendig, welches wie unter &#039;&#039;&#039;Installation unter Ubuntu&#039;&#039;&#039; beschrieben, installiert werden kann.&lt;br /&gt;
&lt;br /&gt;
=== simulavr ===&lt;br /&gt;
&amp;lt;pre&amp;gt;simulavr -g -p 1212 -d atmega16 -P simulavr-disp&amp;lt;/pre&amp;gt;&lt;br /&gt;
startet den Simulator.&lt;br /&gt;
&lt;br /&gt;
=== avarice ===&lt;br /&gt;
&amp;lt;pre&amp;gt;avarice -j /dev/ttyS0 -P atmega128 :1212&amp;lt;/pre&amp;gt;&lt;br /&gt;
startet einen Server, der auf Port 1212 lauscht und das OnDeviceDebugging übernimmt.&lt;br /&gt;
&lt;br /&gt;
=== Eclipseeinstellungen ===&lt;br /&gt;
Unter Eclipse muss ein neues Debug-Target erzeugt werden, was in den Projekteinstellungen unter &#039;&#039;Run/Debug-Settings&#039;&#039; funktioniert. Es muss &#039;&#039;C/C++ application&#039;&#039; ausgewählt werden und folgende Einstellungen müssen geändert werden: &lt;br /&gt;
* Debugger&lt;br /&gt;
** gdbserver auswählen&lt;br /&gt;
** GDB debugger: Pfad zu avr-gdb (/usr/local/avr/bin/avr-gdb)&lt;br /&gt;
** &#039;&#039;verbose console mode&#039;&#039; einschalten&lt;br /&gt;
* Connection&lt;br /&gt;
** TCP, localhost, port 1212 (siehe simulavr/avarice-Aufruf).&lt;br /&gt;
&lt;br /&gt;
Unter Debugger muss für die Verwendung des Simulators Command-Datei mit folgendem Inhalt angegeben und daher auch erstellt werden:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
file link.elf&lt;br /&gt;
targ rem :1212&lt;br /&gt;
load&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
link.elf ist die Datei, welche durch den Build erstellt wird. Dies muss daher angepasst werden.&lt;br /&gt;
&lt;br /&gt;
Beim On Device Debugging muss keine Command-Datei angegeben werden.&lt;br /&gt;
&lt;br /&gt;
=== Auslesen von IO-Registern ===&lt;br /&gt;
Wenn &#039;&#039;verbose console mode&#039;&#039; eingeschaltet ist, kann in diesem Konsolenfenster direkt mit avr-gdb kommuniziert werden. Dadurch können unter anderem die Register ausgelesen werden:&lt;br /&gt;
&amp;lt;pre&amp;gt;p/x *(char *)Adresse&amp;lt;/pre&amp;gt; &lt;br /&gt;
gibt den Wert der Adresse als char aus.&lt;br /&gt;
&amp;lt;pre&amp;gt;p/t *(char *)Adresse&amp;lt;/pre&amp;gt;&lt;br /&gt;
returniert den Binärwert.&lt;br /&gt;
&lt;br /&gt;
Die Adresse setzt sich aus einer Startadresse und einem Offset zusammen, wobei diese sich im entsprechenden io-Header der Architektur befindet. Beispielweise setzt sich die Adresse für das UCSR0B-Register eines Atmega128 aus der Startadresse 0x800020 und dem Offset 0x0A zusammen.&lt;br /&gt;
&lt;br /&gt;
Für oft verwendete Register empfiehlt es sich, diesen mittels &lt;br /&gt;
&amp;lt;pre&amp;gt;set $name=(char *)Adresse&amp;lt;/pre&amp;gt;&lt;br /&gt;
einen Namen zuzuweisen. Diese könnte man in einer Datei speichern und diese als command-Datei beim Debugger angeben, wodurch man sich diese händischen Eingaben spart und mittels &lt;br /&gt;
&amp;lt;pre&amp;gt;p/x *$name&amp;lt;/pre&amp;gt; bzw. &amp;lt;pre&amp;gt;display *$name&amp;lt;/pre&amp;gt;&lt;br /&gt;
zugegreifen kann.&lt;br /&gt;
&lt;br /&gt;
== Weiteres ==&lt;br /&gt;
Bei Problemen kann dieser [http://www.mikrocontroller.net/topic/79965#667525 Thread] verwendet werden, in den ich, wann immer es sich bei mir ausgeht, schauen werde.&lt;br /&gt;
&lt;br /&gt;
Jeder ist aufgerufen hier weiterzumachen, wenn er mehr weiss, oder es besser gestalten kann.&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:AVR ]]&lt;/div&gt;</summary>
		<author><name>Thymythos</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=AVR_Eclipse&amp;diff=31959</id>
		<title>AVR Eclipse</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=AVR_Eclipse&amp;diff=31959"/>
		<updated>2008-10-19T13:08:18Z</updated>

		<summary type="html">&lt;p&gt;Thymythos: /* Einstellungen */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Dieser Artikel beschreibt erste Erfahrungen mit Eclipse und der AVR-Toolchain.&lt;br /&gt;
&lt;br /&gt;
== ! Achtung ! ==&lt;br /&gt;
Die Installation und benützung unter Windows wird in einen Neuen Artikel ausgelagert [[AVR Eclipse Windows]]&lt;br /&gt;
&lt;br /&gt;
==  Allgemeines zu Eclipse ==&lt;br /&gt;
Eclipse ist eine IDE, die sich alleine nicht zur Programmierung von C/C++ eignet. Dafür gibt es dann das Eclipse-Plugin CDT (auch von ECLIPSE.ORG). Die CDT erweitert Eclipse mit der Möglichkeit, C/C++ zu programmieren. Das aber erstmal nur mit dem GCC. Um jetzt die Toolchain AVR-GCC (WINAVR) einzubinden, benötigt man noch ein weiteres Plugin (CDT AVRGCC oder auch CDT AVR Plugin). Es ist auch möglich, ohne die beiden letzt genannten Plugins zu arbeiten, dann sind die Einstellungen für den GCC an AVR-GCC anzupassen (unkomfortabler).&lt;br /&gt;
&lt;br /&gt;
==  Was muss installiert sein ? ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Unter Linux: (Gentoo) ===&lt;br /&gt;
==== Eclipse-IDE ====&lt;br /&gt;
* [http://www.eclipse.org/downloads/index.php Eclipse-IDE] Version 3.1.0&lt;br /&gt;
* [http://www.eclipse.org/cdt/ Eclipse-CDT-Plugin] Version 3.0.0&lt;br /&gt;
* [http://sf.net/projects/avr-eclipse Eclipse-CDT-Addon for AVR] Version 20070404&lt;br /&gt;
&lt;br /&gt;
==== Compiler ====&lt;br /&gt;
* emerge crossdev&lt;br /&gt;
* crossdev --target avr&lt;br /&gt;
** binutils-2.16.1-r2&lt;br /&gt;
** gcc-3.4.6&lt;br /&gt;
** avr-libc-[latest]&lt;br /&gt;
&lt;br /&gt;
==== Programmer ====&lt;br /&gt;
* emerge uisp&lt;br /&gt;
&lt;br /&gt;
=== Unter Linux: (Debian) ===&lt;br /&gt;
==== Eclipse-IDE ====&lt;br /&gt;
* [http://www.eclipse.org/downloads/index.php Eclipse-IDE] Version 3.1.0&lt;br /&gt;
* [http://www.eclipse.org/cdt/ Eclipse-CDT-Plugin] Version 3.0.0&lt;br /&gt;
* [http://sf.net/projects/avr-eclipse Eclipse-CDT-Addon for AVR] Version 20070404&lt;br /&gt;
&lt;br /&gt;
==== Compiler ====&lt;br /&gt;
* binutils-avr 2.15-3&lt;br /&gt;
* gcc-avr 1:3.4.3-2&lt;br /&gt;
* avr-libc 1:1.2.3-3&lt;br /&gt;
&lt;br /&gt;
==== Debugger ====&lt;br /&gt;
* simulavr 0.1.2.2-1&lt;br /&gt;
* gdb-avr 6.3-2&lt;br /&gt;
* ? avra 0.7-1&lt;br /&gt;
&lt;br /&gt;
==== Programmer ====&lt;br /&gt;
* uisp 20050207&lt;br /&gt;
* ? avrp&lt;br /&gt;
* ? avrprog&lt;br /&gt;
&lt;br /&gt;
=== Unter Linux: (Ubuntu 8.10) ===&lt;br /&gt;
==== Eclipse-IDE ====&lt;br /&gt;
* [http://www.eclipse.org/downloads Eclipse IDE for C/C++ Developers] Version 3.3, CDT Version 4.0&lt;br /&gt;
* [http://sourceforge.net/projects/avr-eclipse AVR-Eclipse-Plugin] Version 2.2.0&lt;br /&gt;
&lt;br /&gt;
==== Compiler ====&lt;br /&gt;
* binutils-avr: 2.18-3&lt;br /&gt;
* gcc-avr: 1:4.3.0-2&lt;br /&gt;
* avr-libc: 1:1.6.2-1&lt;br /&gt;
&lt;br /&gt;
==== Debugger ====&lt;br /&gt;
* [ftp://ftp.gnu.org/gnu/gdb/gdb-6.6.tar.bz2 avr-gdb]: 6.6; &#039;&#039;&#039;In den Repositories ist 6.4.90!&#039;&#039;&#039; &lt;br /&gt;
* avarice: 2.7-2&lt;br /&gt;
* simulavr: 0.1.2.2-6.1 (nicht getestet, sollte aber genauso funktionieren)&lt;br /&gt;
&lt;br /&gt;
==== Programmer ====&lt;br /&gt;
* avrdude: 5.5-3&lt;br /&gt;
&lt;br /&gt;
==== Zusätzliche notwendige Programme/Libraries ====&lt;br /&gt;
* gcc&lt;br /&gt;
* binutils-avr&lt;br /&gt;
* build-essential&lt;br /&gt;
* ncurses-dev&lt;br /&gt;
&lt;br /&gt;
== Installation unter Ubuntu ==&lt;br /&gt;
=== AVR-Toolchain ===&lt;br /&gt;
Leider ist in den Repositories nur eine veraltete Version von avr-gdb (bzw. gdb-avr) enthalten. Diese Version hat bei mir zu Fehlern geführt. Deshalb wird die aktuelle Releaseversion 6.6 verwendet.&lt;br /&gt;
&lt;br /&gt;
==== Schritt für Schritt ====&lt;br /&gt;
Als erstes werden die notwendigen Programme aus den Repositories installiert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;sudo apt-get install gcc gcc-avr avr-libc avrdude binutils-avr avarice build-essential ncurses-dev&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ubuntu 6.10:&lt;br /&gt;
&amp;lt;pre&amp;gt;sudo apt-get install gcc gcc-avr avr-libc avrdude binutils-avr avarice build-essential libncurses5-dev&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zusätzlich können auch noch folgende Packages interessant sein:&lt;br /&gt;
* Simulavr: Ein Simulator für die AVR-Reihe&lt;br /&gt;
* uisp: Alternativer Downloader&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;sudo apt-get install simulavr uisp&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jetzt kann man bereits das AVR-Target ansprechen, um z.B. die Fuses auszulesen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;avarice -j /dev/ttyUSB0 -P atmega128 -r&amp;lt;/pre&amp;gt;&lt;br /&gt;
* -j: Gibt das Gerät an, mit dem das Target verbunden ist.&lt;br /&gt;
* -P: Zielarchitektur&lt;br /&gt;
* -r: Read Fuses&lt;br /&gt;
&lt;br /&gt;
Dazu ist die Manpage von avarice zu empfehlen: &lt;br /&gt;
&amp;lt;pre&amp;gt;man avarice&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Als nächstes muss gdb-avr heruntergeladen und dann kompiliert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;wget ftp://ftp.gnu.org/gnu/gdb/gdb-6.6.tar.bz2&lt;br /&gt;
tar jxf gdb-6.6.tar.bz2&lt;br /&gt;
cd gdb-6.6&lt;br /&gt;
./configure --target=avr --prefix=/usr/local/avr&lt;br /&gt;
make&lt;br /&gt;
sudo make install&lt;br /&gt;
cd ..&lt;br /&gt;
rm -rf gdb-6.6&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dies installiert die aktuelle Version von gdb-avr unter /usr/local/avr. Diesen Pfad könnte man zur PATH-Variable hinzufügen, dies ist allerdings nicht zwingend notwendig.&lt;br /&gt;
&lt;br /&gt;
== Installation von Eclipse ==&lt;br /&gt;
&lt;br /&gt;
Es sollte das [http://www.eclipse.org/downloads Eclipse IDE for C/C++ Developers]-Packet heruntergeladen und entpackt werden, da in diesem Packet bereits CDT vorinstalliert und keine (für diesen Einsatz) unnötigen Plugins installiert sind. Damit Eclipse für mehrere User zugänglich ist, sollte der entstandene Ordner nach /opt verschoben werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;sudo mv eclipse /opt&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Falls Eclipse langsam läuft oder Fehler hat, ist die Verwendung des propriertären Java-Packages von Sun einen Versuch wert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;sudo apt-get install sun-java6-jre&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Falls danach noch immer gij statt java verwendet wird, muss in der Datei /etc/eclipse/java_home diese Zeile am Beginn eingefügt werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;/usr/lib/jvm/java-6-sun&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Stand von 2008.02.08: &amp;lt;pre&amp;gt;sudo ln -s /usr/lib/jvm/java-6-sun /opt/eclipse/jre&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sollte die reguläre Installation auf Ubuntu 6.10 Amd-64  fehlschlagen (was bei mir der Fall war), kann [http://mirror.yoxos-eclipse-distribution.de/eclipse.org/technology/epp/downloads/release/20071103/eclipse-cpp-europa-fall2-linux-gtk.tar.gz    die 32-Bit-Version] mit der passenden Java Engine installiert werden:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sudo apt-get install ia32-sun-java6-bin&lt;br /&gt;
sudo update-alternatives --config java&lt;br /&gt;
#Folgende Frage mit [Enter] bestätigen (64-Bit-Version bleibt vorgabe).&lt;br /&gt;
&lt;br /&gt;
# link für eclipse setzen&lt;br /&gt;
sudo ln -s /usr/lib/jvm/ia32-java-6-sun /opt/eclipse/jre&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Alternative 1 ===&lt;br /&gt;
&lt;br /&gt;
Das AVR-Eclipse Plugin kann über die Update-Site http://avr-eclipse.sourceforge.net/updatesite/ installiert werden. (Help-&amp;gt;Software Updates...)&lt;br /&gt;
&lt;br /&gt;
Zum Schluss muss noch, die avr-objsplit.bat-Datei, wie folgt, umgeschrieben, nach /usr/bin/avr-objsplit kopiert und ausführbar gemacht werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
avr-objcopy -j .text -j .data -O ihex *.elf flash.hex&lt;br /&gt;
avr-objcopy -j .eeprom --change-section-lma .eeprom=0 -O ihex *.elf eeprom.hex&lt;br /&gt;
if [ ! -f eeprom.hex ]; then&lt;br /&gt;
        echo &amp;quot;:00000001FF&amp;quot; &amp;gt; eeprom.hex&lt;br /&gt;
fi&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ändern der Rechte:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
chmod +x avr-objsplit&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Einstellungen ====&lt;br /&gt;
Jetzt müssen noch gewisse Einstellungen in Eclipse angepasst werden:&lt;br /&gt;
Unter Window-&amp;gt;Preferences-&amp;gt;AVR-&amp;gt;AVRdude:&lt;br /&gt;
&lt;br /&gt;
* Programmer auswählen&lt;br /&gt;
* Programmerport auswählen&lt;br /&gt;
* Target MCU Type auswählen&lt;br /&gt;
&lt;br /&gt;
==== Projekteinstellungen ====&lt;br /&gt;
Jetzt kann ein neues C-Project angelegt werden, wobei als Projekttyp &amp;quot;AVR Cross-Target Project&amp;quot; ausgewählt werden muss. Mittels den &amp;quot;Next&amp;quot;- und &amp;quot;Advanced&amp;quot;-Buttons kommt man zu den Projekteinstellungen, wobei folgendes einzustellen ist:&lt;br /&gt;
* C/C++-Build-&amp;gt;Settings-&amp;gt;Tool settings-&amp;gt;Compiler-&amp;gt;Other Options:&lt;br /&gt;
** MCU Type, Frequenz. Außerdem sollte &amp;quot;Generate Debugging Info&amp;quot; aktiviert werden.&lt;br /&gt;
* C/C++-Build-&amp;gt;Settings-&amp;gt;Tool settings-&amp;gt;Linker-&amp;gt;Other Options:&lt;br /&gt;
** MCU Type&lt;br /&gt;
&lt;br /&gt;
Jetzt kann zum Punkt &amp;quot;Erster Test&amp;quot; gesprungen werden.&lt;br /&gt;
&lt;br /&gt;
=== Alternative 2 ===&lt;br /&gt;
&lt;br /&gt;
Dabei werden die Projekteinstellungen eines Standard-C-Projekts so verändert, dass die AVR-Toolchain verwendet wird.&lt;br /&gt;
&lt;br /&gt;
Mein erster erfolgreicher Versuch lief mit einen &amp;quot;managed C Projekt&amp;quot;. Ich hoffe in der folgenden Beschreibung fehlt kein Schritt:&lt;br /&gt;
* File / New / Managed Make C Project&lt;br /&gt;
** Project Name &#039;&#039;&#039;&amp;quot;test2&amp;quot; [Next]&#039;&#039;&#039;&lt;br /&gt;
** Project Type &#039;&#039;&#039;&amp;quot;Executable (GNU)&amp;quot; [Next]&#039;&#039;&#039;&lt;br /&gt;
** C/C++ Indexer &#039;&#039;&#039;&amp;quot;full ...&amp;quot; [Finish]&#039;&#039;&#039; (hab ich später geändert siehe unten)&lt;br /&gt;
&lt;br /&gt;
==== Projekteinstellungen ====&lt;br /&gt;
* File / New / SourceFile&lt;br /&gt;
** &#039;&#039;&#039;[Browse] &amp;quot;test2&amp;quot; [OK]&#039;&#039;&#039;&lt;br /&gt;
** Source File: &#039;&#039;&#039;&amp;quot;test2.c&amp;quot; [Finish]&#039;&#039;&#039;&lt;br /&gt;
* Project / Properties&lt;br /&gt;
** C/C++ Build / ToolSettings&lt;br /&gt;
*** GCC-C-Compiler&lt;br /&gt;
**** Command:  &#039;&#039;&#039;gcc&#039;&#039;&#039; ändern auf &#039;&#039;&#039;avr-gcc -mmcu=atmega16 -c&#039;&#039;&#039;&lt;br /&gt;
**** Das &#039;&#039;&#039;-c&#039;&#039;&#039; ist wichtig, damit nur kompliert aber nicht gelinkt wird.&lt;br /&gt;
**** Directorys Eintrag &#039;&#039;&#039;/usr/avr/include&#039;&#039;&#039; einfügen&lt;br /&gt;
**** Debugging  gewünschten Wert einstellen (z.B. -g)&lt;br /&gt;
*** GCC-C-Linker &lt;br /&gt;
**** Command:  &#039;&#039;&#039;gcc&#039;&#039;&#039; auch ändern auf &#039;&#039;&#039;avr-gcc -mmcu=atmega16 &#039;&#039;&#039;&lt;br /&gt;
**** Libraries: Library Search Path= &#039;&#039;&#039;/usr/avr&#039;&#039;&#039;&lt;br /&gt;
**** Miscellaneous: Linker Flags = &#039;&#039;&#039;-Wl,-Map,avr.map&#039;&#039;&#039;&lt;br /&gt;
*** GCC Assembler&lt;br /&gt;
**** Command:  &#039;&#039;&#039;as&#039;&#039;&#039; ändern auf &#039;&#039;avr-as&#039;&#039;&lt;br /&gt;
** C/C++ Build / Build Steps&lt;br /&gt;
*** Post-Build-Step&lt;br /&gt;
**** Command: &#039;&#039;&#039;avr-objcopy -j .text -j .data -O ihex test2 test2.hex&#039;&#039;&#039;&lt;br /&gt;
** C/C++ Indexer&lt;br /&gt;
*** Available Indexers = &#039;&#039;&#039;CTags Indexer (declarations only)&#039;&#039;&#039;&lt;br /&gt;
*** Include Files: Index Include paths &#039;&#039;&#039; einschalten&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==== später eingefügt: ====&lt;br /&gt;
* Project / Properties&lt;br /&gt;
** C/C++ Build / Build Steps&lt;br /&gt;
*** Pre-Build-Step&lt;br /&gt;
**** Command: &#039;&#039;&#039;uisp -dprog=dasa2 -dserial=/dev/ttyS0 -dpart=atmega16 --erase&#039;&#039;&#039;&lt;br /&gt;
* Project / Properties&lt;br /&gt;
** C/C++ Build / Build Steps&lt;br /&gt;
*** Post-Build-Step&lt;br /&gt;
**** Command: &#039;&#039;&#039;avr_upload&#039;&#039;&#039;&lt;br /&gt;
* Project / Properties&lt;br /&gt;
** C/C++ Build / Build Settings&lt;br /&gt;
*** Build Output&lt;br /&gt;
**** Artifact Name: &#039;&#039;&#039;avr_main&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
avr_upload ist eine kleine Batchdatei im Verzeichniss &#039;&#039;&#039;/usr/bin &#039;&#039;&#039;, die ich neu angelegt hab:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/bin/sh&lt;br /&gt;
# .lst-Datei erzeugen (optional)&lt;br /&gt;
# avr-objdump -h -S avr_main &amp;gt; avr.lst&lt;br /&gt;
# Datei in Intel-hex erzeugen&lt;br /&gt;
avr-objcopy -j .text -j .data -O ihex avr_main avr.hex&lt;br /&gt;
# Intel-hex-Datei uploaden&lt;br /&gt;
#uisp -dprog=dasa2 -dserial=/dev/ttyS0 -dpart=atmega16 --upload if=avr.hex&lt;br /&gt;
# Intel-hex Datei uploaden und verifizieren.&lt;br /&gt;
uisp -dprog=dasa2 -dserial=/dev/ttyS0 -dpart=atmega16 --upload if=avr.hex --verify&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Eclipse Plugin ====&lt;br /&gt;
&lt;br /&gt;
Im Forum gibt es ein Plugin für Eclipse, das einen Großteil dieser Einstellungen bereits beinhaltet. Der Thread steht unter: &lt;br /&gt;
&lt;br /&gt;
http://www.mikrocontroller.net/forum/read-2-229419.html#new &lt;br /&gt;
&lt;br /&gt;
Das Plugin wird dort zum Download angeboten. Aber es ist sicher hilfreich die dortige Anleitung zu beachten.&lt;br /&gt;
&lt;br /&gt;
http://www.mikrocontroller.net/attachment.php/285349/org.eclipse.cdt.avrgcc_1.0.16.zip&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;HINWEIS:&#039;&#039;&#039; Bitte die aktuelle Version benutzen. Folgende Warnung bezieht sich auf die älteren Versionen (vor Version 1.0.14).&lt;br /&gt;
&#039;&#039;&#039;WARNUNG:&#039;&#039;&#039; Bei mir funktionierten Timer-Interrupts mit dem Plugin nicht (die jedoch tadellos mit der WinAVR Makefile funktionierten). Vielleicht habe ich nur eine Option übersehen, seid aber auf der Hut. Wenn ihr Unregelmäßigkeiten bei IRQs feststellt, versucht&#039;s erstmal ohne das Eclipse-Plugin (bevor ihr stundenlang an eurem Code und euch selbst zweifelt :-) ).&lt;br /&gt;
&lt;br /&gt;
== Erster Test ==&lt;br /&gt;
Die jeweiligen Alternativen beziehen sich auf die oben genannten verschiedenen Möglichkeiten.&lt;br /&gt;
&lt;br /&gt;
=== Alternative 1 ===&lt;br /&gt;
Wenn bereits ein Board zur Verfügung steht, ist es zu empfehlen, ein einfaches Programm zu schreiben, welches z.B. eine LED toggelt (siehe Alternative 2). Dieses Programm muss dann mittels &#039;&#039;&#039;Build Project&#039;&#039;&#039; kompiliert werden. Dann kann mittels &#039;&#039;&#039;AVR Target-&amp;gt;download&#039;&#039;&#039; der AVR bespielt werden.&lt;br /&gt;
&lt;br /&gt;
=== Alternative 2 ===&lt;br /&gt;
Die folgenden Angaben beziehen sich auf ein sehr einfache Entwicklungsboard mit SPI-Anschluss über die serielle Schnittstelle. Bestückt wurde von mir nur die Spannungsversorgung, der SPI auf RS232 Teil zum Programmieren des Prozessors, Prozessor und Quarz, sowie einige Taster und LEDs. Den Schaltplan gibts [http://www.pollin.de/shop/downloads/D810022B.PDF als PDF hier].&lt;br /&gt;
&lt;br /&gt;
==== Ziel: Eine LED soll blinken ====&lt;br /&gt;
Mein Test läuft auf einem ATMega16, der einen 8MHz-Quarz hat. Der Quarz wird aber nicht genutzt, weil bisher keine Fuses gesetzt sind. Die einzige verwendete LED ist an Port D (&#039;&#039;&#039;PD6&#039;&#039;&#039;) angeschlossen.&lt;br /&gt;
==== Das Kabel ====&lt;br /&gt;
Das Board hat eine 9-polige Buchse(Mama), der PC hat einen 9-poligen Stecker(Papa). Das Kabel muss somit direkt durchverbunden werden. Keines der Kabel wird gekreuzt. Am besten kauft man ein 9-polig beschaltetes &amp;quot;Verlängerungskabel&amp;quot; für die serielle Schnittstelle.&lt;br /&gt;
==== Prozessor erkennen ====&lt;br /&gt;
Zuerstmal wollte ich testen, ob mein selbstgelötetes Board auch funktioniert. Ohne Prozessor sind die 5 Volt da, und auch sonst keine &amp;quot;Rauchzeichen&amp;quot;. Prozessor eingesetzt, und an den PC angeschlossen.&lt;br /&gt;
&lt;br /&gt;
Unter Linux kann der Befehl &#039;&#039;&#039;uisp -dprog=dasa2 -dserial=/dev/ttyS0 -dpart=atmega16 --rd_fuses&#039;&#039;&#039; verwendet werden. Entscheidend ist die erste Zeile der Antwort. Da sollte stehen: &#039;&#039;&#039;Atmel AVR ATMega16 is found&#039;&#039;&#039;. Wenn nicht ??? --- Bei mir war einfach nur der Strom für das Board noch nicht wieder eingesteckt.&lt;br /&gt;
* &#039;&#039;&#039;uisp&#039;&#039;&#039; = Programm zum Programmieren, Lesen und Löschen des AVR&lt;br /&gt;
* &#039;&#039;&#039;-dprogr=dasa2&#039;&#039;&#039; = Angabe der Pinbelegung der seriellen Schnittstelle. Je nach Hersteller des Programmierboards werden unterschiedliche Pinbelegungen verwendet. &#039;&#039;&#039;dasa2&#039;&#039;&#039; ist die, die bei mir gepasst hat.&lt;br /&gt;
* &#039;&#039;&#039;-dserial=/dev/ttyS0&#039;&#039;&#039; = Ich verwende die Schnittstelle COM1(ttyS0). Wer COM2(ttyS1) verwendet, muss &#039;&#039;&#039;/dev/ttyS1&#039;&#039;&#039; angeben.&lt;br /&gt;
* &#039;&#039;&#039;-rd_fuses&#039;&#039;&#039; = lesen der FUSE-Bits&lt;br /&gt;
&lt;br /&gt;
==== Prozessor löschen ====&lt;br /&gt;
* &#039;&#039;&#039;uisp -dprog=dasa2 -dserial=/dev/ttyS0 -dpart=atmega16 --erase&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==== Programm eintippen ====&lt;br /&gt;
(oder einfach von hier kopieren)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
  &lt;br /&gt;
#define running  1  &lt;br /&gt;
&lt;br /&gt;
// Unterprogramm mit Zeitschleife fuer ATMega16 ohne Quarz&lt;br /&gt;
void delay_ms( unsigned int ms )&lt;br /&gt;
{&lt;br /&gt;
    unsigned int  i;&lt;br /&gt;
    unsigned int  j;&lt;br /&gt;
       &lt;br /&gt;
    for ( i = ms;  i;  i-- ) &lt;br /&gt;
    {&lt;br /&gt;
        for ( j = 51;  j;  j-- )&lt;br /&gt;
        {&lt;br /&gt;
        }&lt;br /&gt;
    }    &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int main( void )&lt;br /&gt;
{&lt;br /&gt;
    // PortD6 als Output konfigurieren&lt;br /&gt;
    DDRD |= _BV(PD6);&lt;br /&gt;
&lt;br /&gt;
    // Hauptschleife des Programms&lt;br /&gt;
    while ( running )&lt;br /&gt;
    {&lt;br /&gt;
    	// LED einschalten, und dann warten&lt;br /&gt;
        PORTD |= _BV(PD6);&lt;br /&gt;
        delay_ms( 1000 ); &lt;br /&gt;
        &lt;br /&gt;
    	// LED ausschalten, und dann warten&lt;br /&gt;
        PORTD &amp;amp;= ~_BV(PD6);&lt;br /&gt;
        delay_ms( 29000 );         &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&#039;&#039;&#039;Beim Speichern innerhalb Eclipse wird das Programm compiliert, und die Ausgabe sollte etwa wie folgt ausssehen:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
**** Incremental build of configuration Debug for project AVR_Test ****&lt;br /&gt;
&lt;br /&gt;
make -k -q main-build &lt;br /&gt;
make -k pre-build main-build &lt;br /&gt;
uisp -dprog=dasa2 -dserial=/dev/ttyS0 -dpart=atmega16 --erase&lt;br /&gt;
Atmel AVR ATmega16 is found.&lt;br /&gt;
Erasing device ...&lt;br /&gt;
Reinitializing device&lt;br /&gt;
Atmel AVR ATmega16 is found.&lt;br /&gt;
 &lt;br /&gt;
Building file: ../tests/test1.c&lt;br /&gt;
Invoking: GCC C Compiler&lt;br /&gt;
avr-gcc -mmcu=atmega16 -I/usr/avr -O0 -g -Wall -c -fmessage-length=0 -otests/test1.o ../tests/test1.c&lt;br /&gt;
Finished building: ../tests/test1.c&lt;br /&gt;
 &lt;br /&gt;
Building target: AVR_Test&lt;br /&gt;
Invoking: GCC C Linker&lt;br /&gt;
avr-gcc -mmcu=atmega16 -L/usr/avr -Wl,-Map,avr.map -oAVR_Test ./tests/test1.o&lt;br /&gt;
Finished building target: AVR_Test&lt;br /&gt;
 &lt;br /&gt;
make --no-print-directory post-build&lt;br /&gt;
avr_upload&lt;br /&gt;
Atmel AVR ATmega16 is found.&lt;br /&gt;
Uploading: flash&lt;br /&gt;
 &lt;br /&gt;
Build complete for project AVR_Test&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Mit etwas Glück blinkt jetzt die LED.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Debugging ==&lt;br /&gt;
Debuggen funktioniert mit Eclipse entweder mit &#039;&#039;&#039;avarice&#039;&#039;&#039; oder &#039;&#039;&#039;simulavr&#039;&#039;&#039;, wobei ersteres zum OnDeviceDebugging dient und zweiteres einen Simulator darstellt. Zusätzlich ist &#039;&#039;&#039;avr-gdb&#039;&#039;&#039; notwendig, welches wie unter &#039;&#039;&#039;Installation unter Ubuntu&#039;&#039;&#039; beschrieben, installiert werden kann.&lt;br /&gt;
&lt;br /&gt;
=== simulavr ===&lt;br /&gt;
&amp;lt;pre&amp;gt;simulavr -g -p 1212 -d atmega16 -P simulavr-disp&amp;lt;/pre&amp;gt;&lt;br /&gt;
startet den Simulator.&lt;br /&gt;
&lt;br /&gt;
=== avarice ===&lt;br /&gt;
&amp;lt;pre&amp;gt;avarice -j /dev/ttyS0 -P atmega128 :1212&amp;lt;/pre&amp;gt;&lt;br /&gt;
startet einen Server, der auf Port 1212 lauscht und das OnDeviceDebugging übernimmt.&lt;br /&gt;
&lt;br /&gt;
=== Eclipseeinstellungen ===&lt;br /&gt;
Unter Eclipse muss ein neues Debug-Target erzeugt werden, was in den Projekteinstellungen unter &#039;&#039;Run/Debug-Settings&#039;&#039; funktioniert. Es muss &#039;&#039;C/C++ application&#039;&#039; ausgewählt werden und folgende Einstellungen müssen geändert werden: &lt;br /&gt;
* Debugger&lt;br /&gt;
** gdbserver auswählen&lt;br /&gt;
** GDB debugger: Pfad zu avr-gdb (/usr/local/avr/bin/avr-gdb)&lt;br /&gt;
** &#039;&#039;verbose console mode&#039;&#039; einschalten&lt;br /&gt;
* Connection&lt;br /&gt;
** TCP, localhost, port 1212 (siehe simulavr/avarice-Aufruf).&lt;br /&gt;
&lt;br /&gt;
Unter Debugger muss für die Verwendung des Simulators Command-Datei mit folgendem Inhalt angegeben und daher auch erstellt werden:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
file link.elf&lt;br /&gt;
targ rem :1212&lt;br /&gt;
load&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
link.elf ist die Datei, welche durch den Build erstellt wird. Dies muss daher angepasst werden.&lt;br /&gt;
&lt;br /&gt;
Beim On Device Debugging muss keine Command-Datei angegeben werden.&lt;br /&gt;
&lt;br /&gt;
=== Auslesen von IO-Registern ===&lt;br /&gt;
Wenn &#039;&#039;verbose console mode&#039;&#039; eingeschaltet ist, kann in diesem Konsolenfenster direkt mit avr-gdb kommuniziert werden. Dadurch können unter anderem die Register ausgelesen werden:&lt;br /&gt;
&amp;lt;pre&amp;gt;p/x *(char *)Adresse&amp;lt;/pre&amp;gt; &lt;br /&gt;
gibt den Wert der Adresse als char aus.&lt;br /&gt;
&amp;lt;pre&amp;gt;p/t *(char *)Adresse&amp;lt;/pre&amp;gt;&lt;br /&gt;
returniert den Binärwert.&lt;br /&gt;
&lt;br /&gt;
Die Adresse setzt sich aus einer Startadresse und einem Offset zusammen, wobei diese sich im entsprechenden io-Header der Architektur befindet. Beispielweise setzt sich die Adresse für das UCSR0B-Register eines Atmega128 aus der Startadresse 0x800020 und dem Offset 0x0A zusammen.&lt;br /&gt;
&lt;br /&gt;
Für oft verwendete Register empfiehlt es sich, diesen mittels &lt;br /&gt;
&amp;lt;pre&amp;gt;set $name=(char *)Adresse&amp;lt;/pre&amp;gt;&lt;br /&gt;
einen Namen zuzuweisen. Diese könnte man in einer Datei speichern und diese als command-Datei beim Debugger angeben, wodurch man sich diese händischen Eingaben spart und mittels &lt;br /&gt;
&amp;lt;pre&amp;gt;p/x *$name&amp;lt;/pre&amp;gt; bzw. &amp;lt;pre&amp;gt;display *$name&amp;lt;/pre&amp;gt;&lt;br /&gt;
zugegreifen kann.&lt;br /&gt;
&lt;br /&gt;
== Weiteres ==&lt;br /&gt;
Bei Problemen kann dieser [http://www.mikrocontroller.net/topic/79965#667525 Thread] verwendet werden, in den ich, wann immer es sich bei mir ausgeht, schauen werde.&lt;br /&gt;
&lt;br /&gt;
Jeder ist aufgerufen hier weiterzumachen, wenn er mehr weiss, oder es besser gestalten kann.&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:AVR ]]&lt;/div&gt;</summary>
		<author><name>Thymythos</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=AVR_Eclipse&amp;diff=31958</id>
		<title>AVR Eclipse</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=AVR_Eclipse&amp;diff=31958"/>
		<updated>2008-10-19T13:07:13Z</updated>

		<summary type="html">&lt;p&gt;Thymythos: /* Alternative 1 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Dieser Artikel beschreibt erste Erfahrungen mit Eclipse und der AVR-Toolchain.&lt;br /&gt;
&lt;br /&gt;
== ! Achtung ! ==&lt;br /&gt;
Die Installation und benützung unter Windows wird in einen Neuen Artikel ausgelagert [[AVR Eclipse Windows]]&lt;br /&gt;
&lt;br /&gt;
==  Allgemeines zu Eclipse ==&lt;br /&gt;
Eclipse ist eine IDE, die sich alleine nicht zur Programmierung von C/C++ eignet. Dafür gibt es dann das Eclipse-Plugin CDT (auch von ECLIPSE.ORG). Die CDT erweitert Eclipse mit der Möglichkeit, C/C++ zu programmieren. Das aber erstmal nur mit dem GCC. Um jetzt die Toolchain AVR-GCC (WINAVR) einzubinden, benötigt man noch ein weiteres Plugin (CDT AVRGCC oder auch CDT AVR Plugin). Es ist auch möglich, ohne die beiden letzt genannten Plugins zu arbeiten, dann sind die Einstellungen für den GCC an AVR-GCC anzupassen (unkomfortabler).&lt;br /&gt;
&lt;br /&gt;
==  Was muss installiert sein ? ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Unter Linux: (Gentoo) ===&lt;br /&gt;
==== Eclipse-IDE ====&lt;br /&gt;
* [http://www.eclipse.org/downloads/index.php Eclipse-IDE] Version 3.1.0&lt;br /&gt;
* [http://www.eclipse.org/cdt/ Eclipse-CDT-Plugin] Version 3.0.0&lt;br /&gt;
* [http://sf.net/projects/avr-eclipse Eclipse-CDT-Addon for AVR] Version 20070404&lt;br /&gt;
&lt;br /&gt;
==== Compiler ====&lt;br /&gt;
* emerge crossdev&lt;br /&gt;
* crossdev --target avr&lt;br /&gt;
** binutils-2.16.1-r2&lt;br /&gt;
** gcc-3.4.6&lt;br /&gt;
** avr-libc-[latest]&lt;br /&gt;
&lt;br /&gt;
==== Programmer ====&lt;br /&gt;
* emerge uisp&lt;br /&gt;
&lt;br /&gt;
=== Unter Linux: (Debian) ===&lt;br /&gt;
==== Eclipse-IDE ====&lt;br /&gt;
* [http://www.eclipse.org/downloads/index.php Eclipse-IDE] Version 3.1.0&lt;br /&gt;
* [http://www.eclipse.org/cdt/ Eclipse-CDT-Plugin] Version 3.0.0&lt;br /&gt;
* [http://sf.net/projects/avr-eclipse Eclipse-CDT-Addon for AVR] Version 20070404&lt;br /&gt;
&lt;br /&gt;
==== Compiler ====&lt;br /&gt;
* binutils-avr 2.15-3&lt;br /&gt;
* gcc-avr 1:3.4.3-2&lt;br /&gt;
* avr-libc 1:1.2.3-3&lt;br /&gt;
&lt;br /&gt;
==== Debugger ====&lt;br /&gt;
* simulavr 0.1.2.2-1&lt;br /&gt;
* gdb-avr 6.3-2&lt;br /&gt;
* ? avra 0.7-1&lt;br /&gt;
&lt;br /&gt;
==== Programmer ====&lt;br /&gt;
* uisp 20050207&lt;br /&gt;
* ? avrp&lt;br /&gt;
* ? avrprog&lt;br /&gt;
&lt;br /&gt;
=== Unter Linux: (Ubuntu 8.10) ===&lt;br /&gt;
==== Eclipse-IDE ====&lt;br /&gt;
* [http://www.eclipse.org/downloads Eclipse IDE for C/C++ Developers] Version 3.3, CDT Version 4.0&lt;br /&gt;
* [http://sourceforge.net/projects/avr-eclipse AVR-Eclipse-Plugin] Version 2.2.0&lt;br /&gt;
&lt;br /&gt;
==== Compiler ====&lt;br /&gt;
* binutils-avr: 2.18-3&lt;br /&gt;
* gcc-avr: 1:4.3.0-2&lt;br /&gt;
* avr-libc: 1:1.6.2-1&lt;br /&gt;
&lt;br /&gt;
==== Debugger ====&lt;br /&gt;
* [ftp://ftp.gnu.org/gnu/gdb/gdb-6.6.tar.bz2 avr-gdb]: 6.6; &#039;&#039;&#039;In den Repositories ist 6.4.90!&#039;&#039;&#039; &lt;br /&gt;
* avarice: 2.7-2&lt;br /&gt;
* simulavr: 0.1.2.2-6.1 (nicht getestet, sollte aber genauso funktionieren)&lt;br /&gt;
&lt;br /&gt;
==== Programmer ====&lt;br /&gt;
* avrdude: 5.5-3&lt;br /&gt;
&lt;br /&gt;
==== Zusätzliche notwendige Programme/Libraries ====&lt;br /&gt;
* gcc&lt;br /&gt;
* binutils-avr&lt;br /&gt;
* build-essential&lt;br /&gt;
* ncurses-dev&lt;br /&gt;
&lt;br /&gt;
== Installation unter Ubuntu ==&lt;br /&gt;
=== AVR-Toolchain ===&lt;br /&gt;
Leider ist in den Repositories nur eine veraltete Version von avr-gdb (bzw. gdb-avr) enthalten. Diese Version hat bei mir zu Fehlern geführt. Deshalb wird die aktuelle Releaseversion 6.6 verwendet.&lt;br /&gt;
&lt;br /&gt;
==== Schritt für Schritt ====&lt;br /&gt;
Als erstes werden die notwendigen Programme aus den Repositories installiert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;sudo apt-get install gcc gcc-avr avr-libc avrdude binutils-avr avarice build-essential ncurses-dev&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ubuntu 6.10:&lt;br /&gt;
&amp;lt;pre&amp;gt;sudo apt-get install gcc gcc-avr avr-libc avrdude binutils-avr avarice build-essential libncurses5-dev&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zusätzlich können auch noch folgende Packages interessant sein:&lt;br /&gt;
* Simulavr: Ein Simulator für die AVR-Reihe&lt;br /&gt;
* uisp: Alternativer Downloader&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;sudo apt-get install simulavr uisp&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jetzt kann man bereits das AVR-Target ansprechen, um z.B. die Fuses auszulesen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;avarice -j /dev/ttyUSB0 -P atmega128 -r&amp;lt;/pre&amp;gt;&lt;br /&gt;
* -j: Gibt das Gerät an, mit dem das Target verbunden ist.&lt;br /&gt;
* -P: Zielarchitektur&lt;br /&gt;
* -r: Read Fuses&lt;br /&gt;
&lt;br /&gt;
Dazu ist die Manpage von avarice zu empfehlen: &lt;br /&gt;
&amp;lt;pre&amp;gt;man avarice&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Als nächstes muss gdb-avr heruntergeladen und dann kompiliert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;wget ftp://ftp.gnu.org/gnu/gdb/gdb-6.6.tar.bz2&lt;br /&gt;
tar jxf gdb-6.6.tar.bz2&lt;br /&gt;
cd gdb-6.6&lt;br /&gt;
./configure --target=avr --prefix=/usr/local/avr&lt;br /&gt;
make&lt;br /&gt;
sudo make install&lt;br /&gt;
cd ..&lt;br /&gt;
rm -rf gdb-6.6&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dies installiert die aktuelle Version von gdb-avr unter /usr/local/avr. Diesen Pfad könnte man zur PATH-Variable hinzufügen, dies ist allerdings nicht zwingend notwendig.&lt;br /&gt;
&lt;br /&gt;
== Installation von Eclipse ==&lt;br /&gt;
&lt;br /&gt;
Es sollte das [http://www.eclipse.org/downloads Eclipse IDE for C/C++ Developers]-Packet heruntergeladen und entpackt werden, da in diesem Packet bereits CDT vorinstalliert und keine (für diesen Einsatz) unnötigen Plugins installiert sind. Damit Eclipse für mehrere User zugänglich ist, sollte der entstandene Ordner nach /opt verschoben werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;sudo mv eclipse /opt&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Falls Eclipse langsam läuft oder Fehler hat, ist die Verwendung des propriertären Java-Packages von Sun einen Versuch wert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;sudo apt-get install sun-java6-jre&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Falls danach noch immer gij statt java verwendet wird, muss in der Datei /etc/eclipse/java_home diese Zeile am Beginn eingefügt werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;/usr/lib/jvm/java-6-sun&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Stand von 2008.02.08: &amp;lt;pre&amp;gt;sudo ln -s /usr/lib/jvm/java-6-sun /opt/eclipse/jre&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sollte die reguläre Installation auf Ubuntu 6.10 Amd-64  fehlschlagen (was bei mir der Fall war), kann [http://mirror.yoxos-eclipse-distribution.de/eclipse.org/technology/epp/downloads/release/20071103/eclipse-cpp-europa-fall2-linux-gtk.tar.gz    die 32-Bit-Version] mit der passenden Java Engine installiert werden:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sudo apt-get install ia32-sun-java6-bin&lt;br /&gt;
sudo update-alternatives --config java&lt;br /&gt;
#Folgende Frage mit [Enter] bestätigen (64-Bit-Version bleibt vorgabe).&lt;br /&gt;
&lt;br /&gt;
# link für eclipse setzen&lt;br /&gt;
sudo ln -s /usr/lib/jvm/ia32-java-6-sun /opt/eclipse/jre&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Alternative 1 ===&lt;br /&gt;
&lt;br /&gt;
Das AVR-Eclipse Plugin kann über die Update-Site http://avr-eclipse.sourceforge.net/updatesite/ installiert werden. (Help-&amp;gt;Software Updates...)&lt;br /&gt;
&lt;br /&gt;
Zum Schluss muss noch, die avr-objsplit.bat-Datei, wie folgt, umgeschrieben, nach /usr/bin/avr-objsplit kopiert und ausführbar gemacht werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
avr-objcopy -j .text -j .data -O ihex *.elf flash.hex&lt;br /&gt;
avr-objcopy -j .eeprom --change-section-lma .eeprom=0 -O ihex *.elf eeprom.hex&lt;br /&gt;
if [ ! -f eeprom.hex ]; then&lt;br /&gt;
        echo &amp;quot;:00000001FF&amp;quot; &amp;gt; eeprom.hex&lt;br /&gt;
fi&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ändern der Rechte:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
chmod +x avr-objsplit&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Einstellungen ====&lt;br /&gt;
Jetzt müssen noch gewisse Einstellungen in Eclipse angepasst werden:&lt;br /&gt;
Unter Window-&amp;gt;Preferences-&amp;gt;AVRDUDE Preferences:&lt;br /&gt;
* AVRDUDE executable: /usr/bin/avrdude&lt;br /&gt;
* Programmer auswählen&lt;br /&gt;
* Programmerport auswählen&lt;br /&gt;
* Target MCU Type auswählen&lt;br /&gt;
&lt;br /&gt;
==== Projekteinstellungen ====&lt;br /&gt;
Jetzt kann ein neues C-Project angelegt werden, wobei als Projekttyp &amp;quot;AVR Cross-Target Project&amp;quot; ausgewählt werden muss. Mittels den &amp;quot;Next&amp;quot;- und &amp;quot;Advanced&amp;quot;-Buttons kommt man zu den Projekteinstellungen, wobei folgendes einzustellen ist:&lt;br /&gt;
* C/C++-Build-&amp;gt;Settings-&amp;gt;Tool settings-&amp;gt;Compiler-&amp;gt;Other Options:&lt;br /&gt;
** MCU Type, Frequenz. Außerdem sollte &amp;quot;Generate Debugging Info&amp;quot; aktiviert werden.&lt;br /&gt;
* C/C++-Build-&amp;gt;Settings-&amp;gt;Tool settings-&amp;gt;Linker-&amp;gt;Other Options:&lt;br /&gt;
** MCU Type&lt;br /&gt;
&lt;br /&gt;
Jetzt kann zum Punkt &amp;quot;Erster Test&amp;quot; gesprungen werden.&lt;br /&gt;
&lt;br /&gt;
=== Alternative 2 ===&lt;br /&gt;
&lt;br /&gt;
Dabei werden die Projekteinstellungen eines Standard-C-Projekts so verändert, dass die AVR-Toolchain verwendet wird.&lt;br /&gt;
&lt;br /&gt;
Mein erster erfolgreicher Versuch lief mit einen &amp;quot;managed C Projekt&amp;quot;. Ich hoffe in der folgenden Beschreibung fehlt kein Schritt:&lt;br /&gt;
* File / New / Managed Make C Project&lt;br /&gt;
** Project Name &#039;&#039;&#039;&amp;quot;test2&amp;quot; [Next]&#039;&#039;&#039;&lt;br /&gt;
** Project Type &#039;&#039;&#039;&amp;quot;Executable (GNU)&amp;quot; [Next]&#039;&#039;&#039;&lt;br /&gt;
** C/C++ Indexer &#039;&#039;&#039;&amp;quot;full ...&amp;quot; [Finish]&#039;&#039;&#039; (hab ich später geändert siehe unten)&lt;br /&gt;
&lt;br /&gt;
==== Projekteinstellungen ====&lt;br /&gt;
* File / New / SourceFile&lt;br /&gt;
** &#039;&#039;&#039;[Browse] &amp;quot;test2&amp;quot; [OK]&#039;&#039;&#039;&lt;br /&gt;
** Source File: &#039;&#039;&#039;&amp;quot;test2.c&amp;quot; [Finish]&#039;&#039;&#039;&lt;br /&gt;
* Project / Properties&lt;br /&gt;
** C/C++ Build / ToolSettings&lt;br /&gt;
*** GCC-C-Compiler&lt;br /&gt;
**** Command:  &#039;&#039;&#039;gcc&#039;&#039;&#039; ändern auf &#039;&#039;&#039;avr-gcc -mmcu=atmega16 -c&#039;&#039;&#039;&lt;br /&gt;
**** Das &#039;&#039;&#039;-c&#039;&#039;&#039; ist wichtig, damit nur kompliert aber nicht gelinkt wird.&lt;br /&gt;
**** Directorys Eintrag &#039;&#039;&#039;/usr/avr/include&#039;&#039;&#039; einfügen&lt;br /&gt;
**** Debugging  gewünschten Wert einstellen (z.B. -g)&lt;br /&gt;
*** GCC-C-Linker &lt;br /&gt;
**** Command:  &#039;&#039;&#039;gcc&#039;&#039;&#039; auch ändern auf &#039;&#039;&#039;avr-gcc -mmcu=atmega16 &#039;&#039;&#039;&lt;br /&gt;
**** Libraries: Library Search Path= &#039;&#039;&#039;/usr/avr&#039;&#039;&#039;&lt;br /&gt;
**** Miscellaneous: Linker Flags = &#039;&#039;&#039;-Wl,-Map,avr.map&#039;&#039;&#039;&lt;br /&gt;
*** GCC Assembler&lt;br /&gt;
**** Command:  &#039;&#039;&#039;as&#039;&#039;&#039; ändern auf &#039;&#039;avr-as&#039;&#039;&lt;br /&gt;
** C/C++ Build / Build Steps&lt;br /&gt;
*** Post-Build-Step&lt;br /&gt;
**** Command: &#039;&#039;&#039;avr-objcopy -j .text -j .data -O ihex test2 test2.hex&#039;&#039;&#039;&lt;br /&gt;
** C/C++ Indexer&lt;br /&gt;
*** Available Indexers = &#039;&#039;&#039;CTags Indexer (declarations only)&#039;&#039;&#039;&lt;br /&gt;
*** Include Files: Index Include paths &#039;&#039;&#039; einschalten&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==== später eingefügt: ====&lt;br /&gt;
* Project / Properties&lt;br /&gt;
** C/C++ Build / Build Steps&lt;br /&gt;
*** Pre-Build-Step&lt;br /&gt;
**** Command: &#039;&#039;&#039;uisp -dprog=dasa2 -dserial=/dev/ttyS0 -dpart=atmega16 --erase&#039;&#039;&#039;&lt;br /&gt;
* Project / Properties&lt;br /&gt;
** C/C++ Build / Build Steps&lt;br /&gt;
*** Post-Build-Step&lt;br /&gt;
**** Command: &#039;&#039;&#039;avr_upload&#039;&#039;&#039;&lt;br /&gt;
* Project / Properties&lt;br /&gt;
** C/C++ Build / Build Settings&lt;br /&gt;
*** Build Output&lt;br /&gt;
**** Artifact Name: &#039;&#039;&#039;avr_main&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
avr_upload ist eine kleine Batchdatei im Verzeichniss &#039;&#039;&#039;/usr/bin &#039;&#039;&#039;, die ich neu angelegt hab:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/bin/sh&lt;br /&gt;
# .lst-Datei erzeugen (optional)&lt;br /&gt;
# avr-objdump -h -S avr_main &amp;gt; avr.lst&lt;br /&gt;
# Datei in Intel-hex erzeugen&lt;br /&gt;
avr-objcopy -j .text -j .data -O ihex avr_main avr.hex&lt;br /&gt;
# Intel-hex-Datei uploaden&lt;br /&gt;
#uisp -dprog=dasa2 -dserial=/dev/ttyS0 -dpart=atmega16 --upload if=avr.hex&lt;br /&gt;
# Intel-hex Datei uploaden und verifizieren.&lt;br /&gt;
uisp -dprog=dasa2 -dserial=/dev/ttyS0 -dpart=atmega16 --upload if=avr.hex --verify&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Eclipse Plugin ====&lt;br /&gt;
&lt;br /&gt;
Im Forum gibt es ein Plugin für Eclipse, das einen Großteil dieser Einstellungen bereits beinhaltet. Der Thread steht unter: &lt;br /&gt;
&lt;br /&gt;
http://www.mikrocontroller.net/forum/read-2-229419.html#new &lt;br /&gt;
&lt;br /&gt;
Das Plugin wird dort zum Download angeboten. Aber es ist sicher hilfreich die dortige Anleitung zu beachten.&lt;br /&gt;
&lt;br /&gt;
http://www.mikrocontroller.net/attachment.php/285349/org.eclipse.cdt.avrgcc_1.0.16.zip&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;HINWEIS:&#039;&#039;&#039; Bitte die aktuelle Version benutzen. Folgende Warnung bezieht sich auf die älteren Versionen (vor Version 1.0.14).&lt;br /&gt;
&#039;&#039;&#039;WARNUNG:&#039;&#039;&#039; Bei mir funktionierten Timer-Interrupts mit dem Plugin nicht (die jedoch tadellos mit der WinAVR Makefile funktionierten). Vielleicht habe ich nur eine Option übersehen, seid aber auf der Hut. Wenn ihr Unregelmäßigkeiten bei IRQs feststellt, versucht&#039;s erstmal ohne das Eclipse-Plugin (bevor ihr stundenlang an eurem Code und euch selbst zweifelt :-) ).&lt;br /&gt;
&lt;br /&gt;
== Erster Test ==&lt;br /&gt;
Die jeweiligen Alternativen beziehen sich auf die oben genannten verschiedenen Möglichkeiten.&lt;br /&gt;
&lt;br /&gt;
=== Alternative 1 ===&lt;br /&gt;
Wenn bereits ein Board zur Verfügung steht, ist es zu empfehlen, ein einfaches Programm zu schreiben, welches z.B. eine LED toggelt (siehe Alternative 2). Dieses Programm muss dann mittels &#039;&#039;&#039;Build Project&#039;&#039;&#039; kompiliert werden. Dann kann mittels &#039;&#039;&#039;AVR Target-&amp;gt;download&#039;&#039;&#039; der AVR bespielt werden.&lt;br /&gt;
&lt;br /&gt;
=== Alternative 2 ===&lt;br /&gt;
Die folgenden Angaben beziehen sich auf ein sehr einfache Entwicklungsboard mit SPI-Anschluss über die serielle Schnittstelle. Bestückt wurde von mir nur die Spannungsversorgung, der SPI auf RS232 Teil zum Programmieren des Prozessors, Prozessor und Quarz, sowie einige Taster und LEDs. Den Schaltplan gibts [http://www.pollin.de/shop/downloads/D810022B.PDF als PDF hier].&lt;br /&gt;
&lt;br /&gt;
==== Ziel: Eine LED soll blinken ====&lt;br /&gt;
Mein Test läuft auf einem ATMega16, der einen 8MHz-Quarz hat. Der Quarz wird aber nicht genutzt, weil bisher keine Fuses gesetzt sind. Die einzige verwendete LED ist an Port D (&#039;&#039;&#039;PD6&#039;&#039;&#039;) angeschlossen.&lt;br /&gt;
==== Das Kabel ====&lt;br /&gt;
Das Board hat eine 9-polige Buchse(Mama), der PC hat einen 9-poligen Stecker(Papa). Das Kabel muss somit direkt durchverbunden werden. Keines der Kabel wird gekreuzt. Am besten kauft man ein 9-polig beschaltetes &amp;quot;Verlängerungskabel&amp;quot; für die serielle Schnittstelle.&lt;br /&gt;
==== Prozessor erkennen ====&lt;br /&gt;
Zuerstmal wollte ich testen, ob mein selbstgelötetes Board auch funktioniert. Ohne Prozessor sind die 5 Volt da, und auch sonst keine &amp;quot;Rauchzeichen&amp;quot;. Prozessor eingesetzt, und an den PC angeschlossen.&lt;br /&gt;
&lt;br /&gt;
Unter Linux kann der Befehl &#039;&#039;&#039;uisp -dprog=dasa2 -dserial=/dev/ttyS0 -dpart=atmega16 --rd_fuses&#039;&#039;&#039; verwendet werden. Entscheidend ist die erste Zeile der Antwort. Da sollte stehen: &#039;&#039;&#039;Atmel AVR ATMega16 is found&#039;&#039;&#039;. Wenn nicht ??? --- Bei mir war einfach nur der Strom für das Board noch nicht wieder eingesteckt.&lt;br /&gt;
* &#039;&#039;&#039;uisp&#039;&#039;&#039; = Programm zum Programmieren, Lesen und Löschen des AVR&lt;br /&gt;
* &#039;&#039;&#039;-dprogr=dasa2&#039;&#039;&#039; = Angabe der Pinbelegung der seriellen Schnittstelle. Je nach Hersteller des Programmierboards werden unterschiedliche Pinbelegungen verwendet. &#039;&#039;&#039;dasa2&#039;&#039;&#039; ist die, die bei mir gepasst hat.&lt;br /&gt;
* &#039;&#039;&#039;-dserial=/dev/ttyS0&#039;&#039;&#039; = Ich verwende die Schnittstelle COM1(ttyS0). Wer COM2(ttyS1) verwendet, muss &#039;&#039;&#039;/dev/ttyS1&#039;&#039;&#039; angeben.&lt;br /&gt;
* &#039;&#039;&#039;-rd_fuses&#039;&#039;&#039; = lesen der FUSE-Bits&lt;br /&gt;
&lt;br /&gt;
==== Prozessor löschen ====&lt;br /&gt;
* &#039;&#039;&#039;uisp -dprog=dasa2 -dserial=/dev/ttyS0 -dpart=atmega16 --erase&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==== Programm eintippen ====&lt;br /&gt;
(oder einfach von hier kopieren)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
  &lt;br /&gt;
#define running  1  &lt;br /&gt;
&lt;br /&gt;
// Unterprogramm mit Zeitschleife fuer ATMega16 ohne Quarz&lt;br /&gt;
void delay_ms( unsigned int ms )&lt;br /&gt;
{&lt;br /&gt;
    unsigned int  i;&lt;br /&gt;
    unsigned int  j;&lt;br /&gt;
       &lt;br /&gt;
    for ( i = ms;  i;  i-- ) &lt;br /&gt;
    {&lt;br /&gt;
        for ( j = 51;  j;  j-- )&lt;br /&gt;
        {&lt;br /&gt;
        }&lt;br /&gt;
    }    &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int main( void )&lt;br /&gt;
{&lt;br /&gt;
    // PortD6 als Output konfigurieren&lt;br /&gt;
    DDRD |= _BV(PD6);&lt;br /&gt;
&lt;br /&gt;
    // Hauptschleife des Programms&lt;br /&gt;
    while ( running )&lt;br /&gt;
    {&lt;br /&gt;
    	// LED einschalten, und dann warten&lt;br /&gt;
        PORTD |= _BV(PD6);&lt;br /&gt;
        delay_ms( 1000 ); &lt;br /&gt;
        &lt;br /&gt;
    	// LED ausschalten, und dann warten&lt;br /&gt;
        PORTD &amp;amp;= ~_BV(PD6);&lt;br /&gt;
        delay_ms( 29000 );         &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&#039;&#039;&#039;Beim Speichern innerhalb Eclipse wird das Programm compiliert, und die Ausgabe sollte etwa wie folgt ausssehen:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
**** Incremental build of configuration Debug for project AVR_Test ****&lt;br /&gt;
&lt;br /&gt;
make -k -q main-build &lt;br /&gt;
make -k pre-build main-build &lt;br /&gt;
uisp -dprog=dasa2 -dserial=/dev/ttyS0 -dpart=atmega16 --erase&lt;br /&gt;
Atmel AVR ATmega16 is found.&lt;br /&gt;
Erasing device ...&lt;br /&gt;
Reinitializing device&lt;br /&gt;
Atmel AVR ATmega16 is found.&lt;br /&gt;
 &lt;br /&gt;
Building file: ../tests/test1.c&lt;br /&gt;
Invoking: GCC C Compiler&lt;br /&gt;
avr-gcc -mmcu=atmega16 -I/usr/avr -O0 -g -Wall -c -fmessage-length=0 -otests/test1.o ../tests/test1.c&lt;br /&gt;
Finished building: ../tests/test1.c&lt;br /&gt;
 &lt;br /&gt;
Building target: AVR_Test&lt;br /&gt;
Invoking: GCC C Linker&lt;br /&gt;
avr-gcc -mmcu=atmega16 -L/usr/avr -Wl,-Map,avr.map -oAVR_Test ./tests/test1.o&lt;br /&gt;
Finished building target: AVR_Test&lt;br /&gt;
 &lt;br /&gt;
make --no-print-directory post-build&lt;br /&gt;
avr_upload&lt;br /&gt;
Atmel AVR ATmega16 is found.&lt;br /&gt;
Uploading: flash&lt;br /&gt;
 &lt;br /&gt;
Build complete for project AVR_Test&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Mit etwas Glück blinkt jetzt die LED.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Debugging ==&lt;br /&gt;
Debuggen funktioniert mit Eclipse entweder mit &#039;&#039;&#039;avarice&#039;&#039;&#039; oder &#039;&#039;&#039;simulavr&#039;&#039;&#039;, wobei ersteres zum OnDeviceDebugging dient und zweiteres einen Simulator darstellt. Zusätzlich ist &#039;&#039;&#039;avr-gdb&#039;&#039;&#039; notwendig, welches wie unter &#039;&#039;&#039;Installation unter Ubuntu&#039;&#039;&#039; beschrieben, installiert werden kann.&lt;br /&gt;
&lt;br /&gt;
=== simulavr ===&lt;br /&gt;
&amp;lt;pre&amp;gt;simulavr -g -p 1212 -d atmega16 -P simulavr-disp&amp;lt;/pre&amp;gt;&lt;br /&gt;
startet den Simulator.&lt;br /&gt;
&lt;br /&gt;
=== avarice ===&lt;br /&gt;
&amp;lt;pre&amp;gt;avarice -j /dev/ttyS0 -P atmega128 :1212&amp;lt;/pre&amp;gt;&lt;br /&gt;
startet einen Server, der auf Port 1212 lauscht und das OnDeviceDebugging übernimmt.&lt;br /&gt;
&lt;br /&gt;
=== Eclipseeinstellungen ===&lt;br /&gt;
Unter Eclipse muss ein neues Debug-Target erzeugt werden, was in den Projekteinstellungen unter &#039;&#039;Run/Debug-Settings&#039;&#039; funktioniert. Es muss &#039;&#039;C/C++ application&#039;&#039; ausgewählt werden und folgende Einstellungen müssen geändert werden: &lt;br /&gt;
* Debugger&lt;br /&gt;
** gdbserver auswählen&lt;br /&gt;
** GDB debugger: Pfad zu avr-gdb (/usr/local/avr/bin/avr-gdb)&lt;br /&gt;
** &#039;&#039;verbose console mode&#039;&#039; einschalten&lt;br /&gt;
* Connection&lt;br /&gt;
** TCP, localhost, port 1212 (siehe simulavr/avarice-Aufruf).&lt;br /&gt;
&lt;br /&gt;
Unter Debugger muss für die Verwendung des Simulators Command-Datei mit folgendem Inhalt angegeben und daher auch erstellt werden:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
file link.elf&lt;br /&gt;
targ rem :1212&lt;br /&gt;
load&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
link.elf ist die Datei, welche durch den Build erstellt wird. Dies muss daher angepasst werden.&lt;br /&gt;
&lt;br /&gt;
Beim On Device Debugging muss keine Command-Datei angegeben werden.&lt;br /&gt;
&lt;br /&gt;
=== Auslesen von IO-Registern ===&lt;br /&gt;
Wenn &#039;&#039;verbose console mode&#039;&#039; eingeschaltet ist, kann in diesem Konsolenfenster direkt mit avr-gdb kommuniziert werden. Dadurch können unter anderem die Register ausgelesen werden:&lt;br /&gt;
&amp;lt;pre&amp;gt;p/x *(char *)Adresse&amp;lt;/pre&amp;gt; &lt;br /&gt;
gibt den Wert der Adresse als char aus.&lt;br /&gt;
&amp;lt;pre&amp;gt;p/t *(char *)Adresse&amp;lt;/pre&amp;gt;&lt;br /&gt;
returniert den Binärwert.&lt;br /&gt;
&lt;br /&gt;
Die Adresse setzt sich aus einer Startadresse und einem Offset zusammen, wobei diese sich im entsprechenden io-Header der Architektur befindet. Beispielweise setzt sich die Adresse für das UCSR0B-Register eines Atmega128 aus der Startadresse 0x800020 und dem Offset 0x0A zusammen.&lt;br /&gt;
&lt;br /&gt;
Für oft verwendete Register empfiehlt es sich, diesen mittels &lt;br /&gt;
&amp;lt;pre&amp;gt;set $name=(char *)Adresse&amp;lt;/pre&amp;gt;&lt;br /&gt;
einen Namen zuzuweisen. Diese könnte man in einer Datei speichern und diese als command-Datei beim Debugger angeben, wodurch man sich diese händischen Eingaben spart und mittels &lt;br /&gt;
&amp;lt;pre&amp;gt;p/x *$name&amp;lt;/pre&amp;gt; bzw. &amp;lt;pre&amp;gt;display *$name&amp;lt;/pre&amp;gt;&lt;br /&gt;
zugegreifen kann.&lt;br /&gt;
&lt;br /&gt;
== Weiteres ==&lt;br /&gt;
Bei Problemen kann dieser [http://www.mikrocontroller.net/topic/79965#667525 Thread] verwendet werden, in den ich, wann immer es sich bei mir ausgeht, schauen werde.&lt;br /&gt;
&lt;br /&gt;
Jeder ist aufgerufen hier weiterzumachen, wenn er mehr weiss, oder es besser gestalten kann.&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:AVR ]]&lt;/div&gt;</summary>
		<author><name>Thymythos</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=AVR_Eclipse&amp;diff=31957</id>
		<title>AVR Eclipse</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=AVR_Eclipse&amp;diff=31957"/>
		<updated>2008-10-19T13:02:52Z</updated>

		<summary type="html">&lt;p&gt;Thymythos: /* Unter Linux: (Ubuntu 8.10) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Dieser Artikel beschreibt erste Erfahrungen mit Eclipse und der AVR-Toolchain.&lt;br /&gt;
&lt;br /&gt;
== ! Achtung ! ==&lt;br /&gt;
Die Installation und benützung unter Windows wird in einen Neuen Artikel ausgelagert [[AVR Eclipse Windows]]&lt;br /&gt;
&lt;br /&gt;
==  Allgemeines zu Eclipse ==&lt;br /&gt;
Eclipse ist eine IDE, die sich alleine nicht zur Programmierung von C/C++ eignet. Dafür gibt es dann das Eclipse-Plugin CDT (auch von ECLIPSE.ORG). Die CDT erweitert Eclipse mit der Möglichkeit, C/C++ zu programmieren. Das aber erstmal nur mit dem GCC. Um jetzt die Toolchain AVR-GCC (WINAVR) einzubinden, benötigt man noch ein weiteres Plugin (CDT AVRGCC oder auch CDT AVR Plugin). Es ist auch möglich, ohne die beiden letzt genannten Plugins zu arbeiten, dann sind die Einstellungen für den GCC an AVR-GCC anzupassen (unkomfortabler).&lt;br /&gt;
&lt;br /&gt;
==  Was muss installiert sein ? ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Unter Linux: (Gentoo) ===&lt;br /&gt;
==== Eclipse-IDE ====&lt;br /&gt;
* [http://www.eclipse.org/downloads/index.php Eclipse-IDE] Version 3.1.0&lt;br /&gt;
* [http://www.eclipse.org/cdt/ Eclipse-CDT-Plugin] Version 3.0.0&lt;br /&gt;
* [http://sf.net/projects/avr-eclipse Eclipse-CDT-Addon for AVR] Version 20070404&lt;br /&gt;
&lt;br /&gt;
==== Compiler ====&lt;br /&gt;
* emerge crossdev&lt;br /&gt;
* crossdev --target avr&lt;br /&gt;
** binutils-2.16.1-r2&lt;br /&gt;
** gcc-3.4.6&lt;br /&gt;
** avr-libc-[latest]&lt;br /&gt;
&lt;br /&gt;
==== Programmer ====&lt;br /&gt;
* emerge uisp&lt;br /&gt;
&lt;br /&gt;
=== Unter Linux: (Debian) ===&lt;br /&gt;
==== Eclipse-IDE ====&lt;br /&gt;
* [http://www.eclipse.org/downloads/index.php Eclipse-IDE] Version 3.1.0&lt;br /&gt;
* [http://www.eclipse.org/cdt/ Eclipse-CDT-Plugin] Version 3.0.0&lt;br /&gt;
* [http://sf.net/projects/avr-eclipse Eclipse-CDT-Addon for AVR] Version 20070404&lt;br /&gt;
&lt;br /&gt;
==== Compiler ====&lt;br /&gt;
* binutils-avr 2.15-3&lt;br /&gt;
* gcc-avr 1:3.4.3-2&lt;br /&gt;
* avr-libc 1:1.2.3-3&lt;br /&gt;
&lt;br /&gt;
==== Debugger ====&lt;br /&gt;
* simulavr 0.1.2.2-1&lt;br /&gt;
* gdb-avr 6.3-2&lt;br /&gt;
* ? avra 0.7-1&lt;br /&gt;
&lt;br /&gt;
==== Programmer ====&lt;br /&gt;
* uisp 20050207&lt;br /&gt;
* ? avrp&lt;br /&gt;
* ? avrprog&lt;br /&gt;
&lt;br /&gt;
=== Unter Linux: (Ubuntu 8.10) ===&lt;br /&gt;
==== Eclipse-IDE ====&lt;br /&gt;
* [http://www.eclipse.org/downloads Eclipse IDE for C/C++ Developers] Version 3.3, CDT Version 4.0&lt;br /&gt;
* [http://sourceforge.net/projects/avr-eclipse AVR-Eclipse-Plugin] Version 2.2.0&lt;br /&gt;
&lt;br /&gt;
==== Compiler ====&lt;br /&gt;
* binutils-avr: 2.18-3&lt;br /&gt;
* gcc-avr: 1:4.3.0-2&lt;br /&gt;
* avr-libc: 1:1.6.2-1&lt;br /&gt;
&lt;br /&gt;
==== Debugger ====&lt;br /&gt;
* [ftp://ftp.gnu.org/gnu/gdb/gdb-6.6.tar.bz2 avr-gdb]: 6.6; &#039;&#039;&#039;In den Repositories ist 6.4.90!&#039;&#039;&#039; &lt;br /&gt;
* avarice: 2.7-2&lt;br /&gt;
* simulavr: 0.1.2.2-6.1 (nicht getestet, sollte aber genauso funktionieren)&lt;br /&gt;
&lt;br /&gt;
==== Programmer ====&lt;br /&gt;
* avrdude: 5.5-3&lt;br /&gt;
&lt;br /&gt;
==== Zusätzliche notwendige Programme/Libraries ====&lt;br /&gt;
* gcc&lt;br /&gt;
* binutils-avr&lt;br /&gt;
* build-essential&lt;br /&gt;
* ncurses-dev&lt;br /&gt;
&lt;br /&gt;
== Installation unter Ubuntu ==&lt;br /&gt;
=== AVR-Toolchain ===&lt;br /&gt;
Leider ist in den Repositories nur eine veraltete Version von avr-gdb (bzw. gdb-avr) enthalten. Diese Version hat bei mir zu Fehlern geführt. Deshalb wird die aktuelle Releaseversion 6.6 verwendet.&lt;br /&gt;
&lt;br /&gt;
==== Schritt für Schritt ====&lt;br /&gt;
Als erstes werden die notwendigen Programme aus den Repositories installiert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;sudo apt-get install gcc gcc-avr avr-libc avrdude binutils-avr avarice build-essential ncurses-dev&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ubuntu 6.10:&lt;br /&gt;
&amp;lt;pre&amp;gt;sudo apt-get install gcc gcc-avr avr-libc avrdude binutils-avr avarice build-essential libncurses5-dev&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zusätzlich können auch noch folgende Packages interessant sein:&lt;br /&gt;
* Simulavr: Ein Simulator für die AVR-Reihe&lt;br /&gt;
* uisp: Alternativer Downloader&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;sudo apt-get install simulavr uisp&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jetzt kann man bereits das AVR-Target ansprechen, um z.B. die Fuses auszulesen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;avarice -j /dev/ttyUSB0 -P atmega128 -r&amp;lt;/pre&amp;gt;&lt;br /&gt;
* -j: Gibt das Gerät an, mit dem das Target verbunden ist.&lt;br /&gt;
* -P: Zielarchitektur&lt;br /&gt;
* -r: Read Fuses&lt;br /&gt;
&lt;br /&gt;
Dazu ist die Manpage von avarice zu empfehlen: &lt;br /&gt;
&amp;lt;pre&amp;gt;man avarice&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Als nächstes muss gdb-avr heruntergeladen und dann kompiliert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;wget ftp://ftp.gnu.org/gnu/gdb/gdb-6.6.tar.bz2&lt;br /&gt;
tar jxf gdb-6.6.tar.bz2&lt;br /&gt;
cd gdb-6.6&lt;br /&gt;
./configure --target=avr --prefix=/usr/local/avr&lt;br /&gt;
make&lt;br /&gt;
sudo make install&lt;br /&gt;
cd ..&lt;br /&gt;
rm -rf gdb-6.6&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dies installiert die aktuelle Version von gdb-avr unter /usr/local/avr. Diesen Pfad könnte man zur PATH-Variable hinzufügen, dies ist allerdings nicht zwingend notwendig.&lt;br /&gt;
&lt;br /&gt;
== Installation von Eclipse ==&lt;br /&gt;
&lt;br /&gt;
Es sollte das [http://www.eclipse.org/downloads Eclipse IDE for C/C++ Developers]-Packet heruntergeladen und entpackt werden, da in diesem Packet bereits CDT vorinstalliert und keine (für diesen Einsatz) unnötigen Plugins installiert sind. Damit Eclipse für mehrere User zugänglich ist, sollte der entstandene Ordner nach /opt verschoben werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;sudo mv eclipse /opt&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Falls Eclipse langsam läuft oder Fehler hat, ist die Verwendung des propriertären Java-Packages von Sun einen Versuch wert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;sudo apt-get install sun-java6-jre&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Falls danach noch immer gij statt java verwendet wird, muss in der Datei /etc/eclipse/java_home diese Zeile am Beginn eingefügt werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;/usr/lib/jvm/java-6-sun&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Stand von 2008.02.08: &amp;lt;pre&amp;gt;sudo ln -s /usr/lib/jvm/java-6-sun /opt/eclipse/jre&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sollte die reguläre Installation auf Ubuntu 6.10 Amd-64  fehlschlagen (was bei mir der Fall war), kann [http://mirror.yoxos-eclipse-distribution.de/eclipse.org/technology/epp/downloads/release/20071103/eclipse-cpp-europa-fall2-linux-gtk.tar.gz    die 32-Bit-Version] mit der passenden Java Engine installiert werden:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sudo apt-get install ia32-sun-java6-bin&lt;br /&gt;
sudo update-alternatives --config java&lt;br /&gt;
#Folgende Frage mit [Enter] bestätigen (64-Bit-Version bleibt vorgabe).&lt;br /&gt;
&lt;br /&gt;
# link für eclipse setzen&lt;br /&gt;
sudo ln -s /usr/lib/jvm/ia32-java-6-sun /opt/eclipse/jre&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Alternative 1 ===&lt;br /&gt;
&lt;br /&gt;
Jetzt sollte das neueste [http://sourceforge.net/projects/avr-eclipse AVR-Eclipse-plugin (20070813)] heruntergeladen und installiert werden. Dazu muss das Packet entpackt und der Inhalt in den Ordner plugins im Eclipse-Ordner verschoben werden.&lt;br /&gt;
&lt;br /&gt;
Zum Schluss muss noch, die avr-objsplit.bat-Datei, wie folgt, umgeschrieben, nach /usr/bin/avr-objsplit kopiert und ausführbar gemacht werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
avr-objcopy -j .text -j .data -O ihex *.elf flash.hex&lt;br /&gt;
avr-objcopy -j .eeprom --change-section-lma .eeprom=0 -O ihex *.elf eeprom.hex&lt;br /&gt;
if [ ! -f eeprom.hex ]; then&lt;br /&gt;
        echo &amp;quot;:00000001FF&amp;quot; &amp;gt; eeprom.hex&lt;br /&gt;
fi&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ändern der Rechte:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
chmod +x avr-objsplit&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Einstellungen ====&lt;br /&gt;
Jetzt müssen noch gewisse Einstellungen in Eclipse angepasst werden:&lt;br /&gt;
Unter Window-&amp;gt;Preferences-&amp;gt;AVRDUDE Preferences:&lt;br /&gt;
* AVRDUDE executable: /usr/bin/avrdude&lt;br /&gt;
* Programmer auswählen&lt;br /&gt;
* Programmerport auswählen&lt;br /&gt;
* Target MCU Type auswählen&lt;br /&gt;
&lt;br /&gt;
==== Projekteinstellungen ====&lt;br /&gt;
Jetzt kann ein neues C-Project angelegt werden, wobei als Projekttyp &amp;quot;AVR Cross-Target Project&amp;quot; ausgewählt werden muss. Mittels den &amp;quot;Next&amp;quot;- und &amp;quot;Advanced&amp;quot;-Buttons kommt man zu den Projekteinstellungen, wobei folgendes einzustellen ist:&lt;br /&gt;
* C/C++-Build-&amp;gt;Settings-&amp;gt;Tool settings-&amp;gt;Compiler-&amp;gt;Other Options:&lt;br /&gt;
** MCU Type, Frequenz. Außerdem sollte &amp;quot;Generate Debugging Info&amp;quot; aktiviert werden.&lt;br /&gt;
* C/C++-Build-&amp;gt;Settings-&amp;gt;Tool settings-&amp;gt;Linker-&amp;gt;Other Options:&lt;br /&gt;
** MCU Type&lt;br /&gt;
&lt;br /&gt;
Jetzt kann zum Punkt &amp;quot;Erster Test&amp;quot; gesprungen werden.&lt;br /&gt;
&lt;br /&gt;
=== Alternative 2 ===&lt;br /&gt;
&lt;br /&gt;
Dabei werden die Projekteinstellungen eines Standard-C-Projekts so verändert, dass die AVR-Toolchain verwendet wird.&lt;br /&gt;
&lt;br /&gt;
Mein erster erfolgreicher Versuch lief mit einen &amp;quot;managed C Projekt&amp;quot;. Ich hoffe in der folgenden Beschreibung fehlt kein Schritt:&lt;br /&gt;
* File / New / Managed Make C Project&lt;br /&gt;
** Project Name &#039;&#039;&#039;&amp;quot;test2&amp;quot; [Next]&#039;&#039;&#039;&lt;br /&gt;
** Project Type &#039;&#039;&#039;&amp;quot;Executable (GNU)&amp;quot; [Next]&#039;&#039;&#039;&lt;br /&gt;
** C/C++ Indexer &#039;&#039;&#039;&amp;quot;full ...&amp;quot; [Finish]&#039;&#039;&#039; (hab ich später geändert siehe unten)&lt;br /&gt;
&lt;br /&gt;
==== Projekteinstellungen ====&lt;br /&gt;
* File / New / SourceFile&lt;br /&gt;
** &#039;&#039;&#039;[Browse] &amp;quot;test2&amp;quot; [OK]&#039;&#039;&#039;&lt;br /&gt;
** Source File: &#039;&#039;&#039;&amp;quot;test2.c&amp;quot; [Finish]&#039;&#039;&#039;&lt;br /&gt;
* Project / Properties&lt;br /&gt;
** C/C++ Build / ToolSettings&lt;br /&gt;
*** GCC-C-Compiler&lt;br /&gt;
**** Command:  &#039;&#039;&#039;gcc&#039;&#039;&#039; ändern auf &#039;&#039;&#039;avr-gcc -mmcu=atmega16 -c&#039;&#039;&#039;&lt;br /&gt;
**** Das &#039;&#039;&#039;-c&#039;&#039;&#039; ist wichtig, damit nur kompliert aber nicht gelinkt wird.&lt;br /&gt;
**** Directorys Eintrag &#039;&#039;&#039;/usr/avr/include&#039;&#039;&#039; einfügen&lt;br /&gt;
**** Debugging  gewünschten Wert einstellen (z.B. -g)&lt;br /&gt;
*** GCC-C-Linker &lt;br /&gt;
**** Command:  &#039;&#039;&#039;gcc&#039;&#039;&#039; auch ändern auf &#039;&#039;&#039;avr-gcc -mmcu=atmega16 &#039;&#039;&#039;&lt;br /&gt;
**** Libraries: Library Search Path= &#039;&#039;&#039;/usr/avr&#039;&#039;&#039;&lt;br /&gt;
**** Miscellaneous: Linker Flags = &#039;&#039;&#039;-Wl,-Map,avr.map&#039;&#039;&#039;&lt;br /&gt;
*** GCC Assembler&lt;br /&gt;
**** Command:  &#039;&#039;&#039;as&#039;&#039;&#039; ändern auf &#039;&#039;avr-as&#039;&#039;&lt;br /&gt;
** C/C++ Build / Build Steps&lt;br /&gt;
*** Post-Build-Step&lt;br /&gt;
**** Command: &#039;&#039;&#039;avr-objcopy -j .text -j .data -O ihex test2 test2.hex&#039;&#039;&#039;&lt;br /&gt;
** C/C++ Indexer&lt;br /&gt;
*** Available Indexers = &#039;&#039;&#039;CTags Indexer (declarations only)&#039;&#039;&#039;&lt;br /&gt;
*** Include Files: Index Include paths &#039;&#039;&#039; einschalten&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==== später eingefügt: ====&lt;br /&gt;
* Project / Properties&lt;br /&gt;
** C/C++ Build / Build Steps&lt;br /&gt;
*** Pre-Build-Step&lt;br /&gt;
**** Command: &#039;&#039;&#039;uisp -dprog=dasa2 -dserial=/dev/ttyS0 -dpart=atmega16 --erase&#039;&#039;&#039;&lt;br /&gt;
* Project / Properties&lt;br /&gt;
** C/C++ Build / Build Steps&lt;br /&gt;
*** Post-Build-Step&lt;br /&gt;
**** Command: &#039;&#039;&#039;avr_upload&#039;&#039;&#039;&lt;br /&gt;
* Project / Properties&lt;br /&gt;
** C/C++ Build / Build Settings&lt;br /&gt;
*** Build Output&lt;br /&gt;
**** Artifact Name: &#039;&#039;&#039;avr_main&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
avr_upload ist eine kleine Batchdatei im Verzeichniss &#039;&#039;&#039;/usr/bin &#039;&#039;&#039;, die ich neu angelegt hab:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/bin/sh&lt;br /&gt;
# .lst-Datei erzeugen (optional)&lt;br /&gt;
# avr-objdump -h -S avr_main &amp;gt; avr.lst&lt;br /&gt;
# Datei in Intel-hex erzeugen&lt;br /&gt;
avr-objcopy -j .text -j .data -O ihex avr_main avr.hex&lt;br /&gt;
# Intel-hex-Datei uploaden&lt;br /&gt;
#uisp -dprog=dasa2 -dserial=/dev/ttyS0 -dpart=atmega16 --upload if=avr.hex&lt;br /&gt;
# Intel-hex Datei uploaden und verifizieren.&lt;br /&gt;
uisp -dprog=dasa2 -dserial=/dev/ttyS0 -dpart=atmega16 --upload if=avr.hex --verify&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Eclipse Plugin ====&lt;br /&gt;
&lt;br /&gt;
Im Forum gibt es ein Plugin für Eclipse, das einen Großteil dieser Einstellungen bereits beinhaltet. Der Thread steht unter: &lt;br /&gt;
&lt;br /&gt;
http://www.mikrocontroller.net/forum/read-2-229419.html#new &lt;br /&gt;
&lt;br /&gt;
Das Plugin wird dort zum Download angeboten. Aber es ist sicher hilfreich die dortige Anleitung zu beachten.&lt;br /&gt;
&lt;br /&gt;
http://www.mikrocontroller.net/attachment.php/285349/org.eclipse.cdt.avrgcc_1.0.16.zip&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;HINWEIS:&#039;&#039;&#039; Bitte die aktuelle Version benutzen. Folgende Warnung bezieht sich auf die älteren Versionen (vor Version 1.0.14).&lt;br /&gt;
&#039;&#039;&#039;WARNUNG:&#039;&#039;&#039; Bei mir funktionierten Timer-Interrupts mit dem Plugin nicht (die jedoch tadellos mit der WinAVR Makefile funktionierten). Vielleicht habe ich nur eine Option übersehen, seid aber auf der Hut. Wenn ihr Unregelmäßigkeiten bei IRQs feststellt, versucht&#039;s erstmal ohne das Eclipse-Plugin (bevor ihr stundenlang an eurem Code und euch selbst zweifelt :-) ).&lt;br /&gt;
&lt;br /&gt;
== Erster Test ==&lt;br /&gt;
Die jeweiligen Alternativen beziehen sich auf die oben genannten verschiedenen Möglichkeiten.&lt;br /&gt;
&lt;br /&gt;
=== Alternative 1 ===&lt;br /&gt;
Wenn bereits ein Board zur Verfügung steht, ist es zu empfehlen, ein einfaches Programm zu schreiben, welches z.B. eine LED toggelt (siehe Alternative 2). Dieses Programm muss dann mittels &#039;&#039;&#039;Build Project&#039;&#039;&#039; kompiliert werden. Dann kann mittels &#039;&#039;&#039;AVR Target-&amp;gt;download&#039;&#039;&#039; der AVR bespielt werden.&lt;br /&gt;
&lt;br /&gt;
=== Alternative 2 ===&lt;br /&gt;
Die folgenden Angaben beziehen sich auf ein sehr einfache Entwicklungsboard mit SPI-Anschluss über die serielle Schnittstelle. Bestückt wurde von mir nur die Spannungsversorgung, der SPI auf RS232 Teil zum Programmieren des Prozessors, Prozessor und Quarz, sowie einige Taster und LEDs. Den Schaltplan gibts [http://www.pollin.de/shop/downloads/D810022B.PDF als PDF hier].&lt;br /&gt;
&lt;br /&gt;
==== Ziel: Eine LED soll blinken ====&lt;br /&gt;
Mein Test läuft auf einem ATMega16, der einen 8MHz-Quarz hat. Der Quarz wird aber nicht genutzt, weil bisher keine Fuses gesetzt sind. Die einzige verwendete LED ist an Port D (&#039;&#039;&#039;PD6&#039;&#039;&#039;) angeschlossen.&lt;br /&gt;
==== Das Kabel ====&lt;br /&gt;
Das Board hat eine 9-polige Buchse(Mama), der PC hat einen 9-poligen Stecker(Papa). Das Kabel muss somit direkt durchverbunden werden. Keines der Kabel wird gekreuzt. Am besten kauft man ein 9-polig beschaltetes &amp;quot;Verlängerungskabel&amp;quot; für die serielle Schnittstelle.&lt;br /&gt;
==== Prozessor erkennen ====&lt;br /&gt;
Zuerstmal wollte ich testen, ob mein selbstgelötetes Board auch funktioniert. Ohne Prozessor sind die 5 Volt da, und auch sonst keine &amp;quot;Rauchzeichen&amp;quot;. Prozessor eingesetzt, und an den PC angeschlossen.&lt;br /&gt;
&lt;br /&gt;
Unter Linux kann der Befehl &#039;&#039;&#039;uisp -dprog=dasa2 -dserial=/dev/ttyS0 -dpart=atmega16 --rd_fuses&#039;&#039;&#039; verwendet werden. Entscheidend ist die erste Zeile der Antwort. Da sollte stehen: &#039;&#039;&#039;Atmel AVR ATMega16 is found&#039;&#039;&#039;. Wenn nicht ??? --- Bei mir war einfach nur der Strom für das Board noch nicht wieder eingesteckt.&lt;br /&gt;
* &#039;&#039;&#039;uisp&#039;&#039;&#039; = Programm zum Programmieren, Lesen und Löschen des AVR&lt;br /&gt;
* &#039;&#039;&#039;-dprogr=dasa2&#039;&#039;&#039; = Angabe der Pinbelegung der seriellen Schnittstelle. Je nach Hersteller des Programmierboards werden unterschiedliche Pinbelegungen verwendet. &#039;&#039;&#039;dasa2&#039;&#039;&#039; ist die, die bei mir gepasst hat.&lt;br /&gt;
* &#039;&#039;&#039;-dserial=/dev/ttyS0&#039;&#039;&#039; = Ich verwende die Schnittstelle COM1(ttyS0). Wer COM2(ttyS1) verwendet, muss &#039;&#039;&#039;/dev/ttyS1&#039;&#039;&#039; angeben.&lt;br /&gt;
* &#039;&#039;&#039;-rd_fuses&#039;&#039;&#039; = lesen der FUSE-Bits&lt;br /&gt;
&lt;br /&gt;
==== Prozessor löschen ====&lt;br /&gt;
* &#039;&#039;&#039;uisp -dprog=dasa2 -dserial=/dev/ttyS0 -dpart=atmega16 --erase&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==== Programm eintippen ====&lt;br /&gt;
(oder einfach von hier kopieren)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
  &lt;br /&gt;
#define running  1  &lt;br /&gt;
&lt;br /&gt;
// Unterprogramm mit Zeitschleife fuer ATMega16 ohne Quarz&lt;br /&gt;
void delay_ms( unsigned int ms )&lt;br /&gt;
{&lt;br /&gt;
    unsigned int  i;&lt;br /&gt;
    unsigned int  j;&lt;br /&gt;
       &lt;br /&gt;
    for ( i = ms;  i;  i-- ) &lt;br /&gt;
    {&lt;br /&gt;
        for ( j = 51;  j;  j-- )&lt;br /&gt;
        {&lt;br /&gt;
        }&lt;br /&gt;
    }    &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int main( void )&lt;br /&gt;
{&lt;br /&gt;
    // PortD6 als Output konfigurieren&lt;br /&gt;
    DDRD |= _BV(PD6);&lt;br /&gt;
&lt;br /&gt;
    // Hauptschleife des Programms&lt;br /&gt;
    while ( running )&lt;br /&gt;
    {&lt;br /&gt;
    	// LED einschalten, und dann warten&lt;br /&gt;
        PORTD |= _BV(PD6);&lt;br /&gt;
        delay_ms( 1000 ); &lt;br /&gt;
        &lt;br /&gt;
    	// LED ausschalten, und dann warten&lt;br /&gt;
        PORTD &amp;amp;= ~_BV(PD6);&lt;br /&gt;
        delay_ms( 29000 );         &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&#039;&#039;&#039;Beim Speichern innerhalb Eclipse wird das Programm compiliert, und die Ausgabe sollte etwa wie folgt ausssehen:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
**** Incremental build of configuration Debug for project AVR_Test ****&lt;br /&gt;
&lt;br /&gt;
make -k -q main-build &lt;br /&gt;
make -k pre-build main-build &lt;br /&gt;
uisp -dprog=dasa2 -dserial=/dev/ttyS0 -dpart=atmega16 --erase&lt;br /&gt;
Atmel AVR ATmega16 is found.&lt;br /&gt;
Erasing device ...&lt;br /&gt;
Reinitializing device&lt;br /&gt;
Atmel AVR ATmega16 is found.&lt;br /&gt;
 &lt;br /&gt;
Building file: ../tests/test1.c&lt;br /&gt;
Invoking: GCC C Compiler&lt;br /&gt;
avr-gcc -mmcu=atmega16 -I/usr/avr -O0 -g -Wall -c -fmessage-length=0 -otests/test1.o ../tests/test1.c&lt;br /&gt;
Finished building: ../tests/test1.c&lt;br /&gt;
 &lt;br /&gt;
Building target: AVR_Test&lt;br /&gt;
Invoking: GCC C Linker&lt;br /&gt;
avr-gcc -mmcu=atmega16 -L/usr/avr -Wl,-Map,avr.map -oAVR_Test ./tests/test1.o&lt;br /&gt;
Finished building target: AVR_Test&lt;br /&gt;
 &lt;br /&gt;
make --no-print-directory post-build&lt;br /&gt;
avr_upload&lt;br /&gt;
Atmel AVR ATmega16 is found.&lt;br /&gt;
Uploading: flash&lt;br /&gt;
 &lt;br /&gt;
Build complete for project AVR_Test&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Mit etwas Glück blinkt jetzt die LED.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Debugging ==&lt;br /&gt;
Debuggen funktioniert mit Eclipse entweder mit &#039;&#039;&#039;avarice&#039;&#039;&#039; oder &#039;&#039;&#039;simulavr&#039;&#039;&#039;, wobei ersteres zum OnDeviceDebugging dient und zweiteres einen Simulator darstellt. Zusätzlich ist &#039;&#039;&#039;avr-gdb&#039;&#039;&#039; notwendig, welches wie unter &#039;&#039;&#039;Installation unter Ubuntu&#039;&#039;&#039; beschrieben, installiert werden kann.&lt;br /&gt;
&lt;br /&gt;
=== simulavr ===&lt;br /&gt;
&amp;lt;pre&amp;gt;simulavr -g -p 1212 -d atmega16 -P simulavr-disp&amp;lt;/pre&amp;gt;&lt;br /&gt;
startet den Simulator.&lt;br /&gt;
&lt;br /&gt;
=== avarice ===&lt;br /&gt;
&amp;lt;pre&amp;gt;avarice -j /dev/ttyS0 -P atmega128 :1212&amp;lt;/pre&amp;gt;&lt;br /&gt;
startet einen Server, der auf Port 1212 lauscht und das OnDeviceDebugging übernimmt.&lt;br /&gt;
&lt;br /&gt;
=== Eclipseeinstellungen ===&lt;br /&gt;
Unter Eclipse muss ein neues Debug-Target erzeugt werden, was in den Projekteinstellungen unter &#039;&#039;Run/Debug-Settings&#039;&#039; funktioniert. Es muss &#039;&#039;C/C++ application&#039;&#039; ausgewählt werden und folgende Einstellungen müssen geändert werden: &lt;br /&gt;
* Debugger&lt;br /&gt;
** gdbserver auswählen&lt;br /&gt;
** GDB debugger: Pfad zu avr-gdb (/usr/local/avr/bin/avr-gdb)&lt;br /&gt;
** &#039;&#039;verbose console mode&#039;&#039; einschalten&lt;br /&gt;
* Connection&lt;br /&gt;
** TCP, localhost, port 1212 (siehe simulavr/avarice-Aufruf).&lt;br /&gt;
&lt;br /&gt;
Unter Debugger muss für die Verwendung des Simulators Command-Datei mit folgendem Inhalt angegeben und daher auch erstellt werden:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
file link.elf&lt;br /&gt;
targ rem :1212&lt;br /&gt;
load&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
link.elf ist die Datei, welche durch den Build erstellt wird. Dies muss daher angepasst werden.&lt;br /&gt;
&lt;br /&gt;
Beim On Device Debugging muss keine Command-Datei angegeben werden.&lt;br /&gt;
&lt;br /&gt;
=== Auslesen von IO-Registern ===&lt;br /&gt;
Wenn &#039;&#039;verbose console mode&#039;&#039; eingeschaltet ist, kann in diesem Konsolenfenster direkt mit avr-gdb kommuniziert werden. Dadurch können unter anderem die Register ausgelesen werden:&lt;br /&gt;
&amp;lt;pre&amp;gt;p/x *(char *)Adresse&amp;lt;/pre&amp;gt; &lt;br /&gt;
gibt den Wert der Adresse als char aus.&lt;br /&gt;
&amp;lt;pre&amp;gt;p/t *(char *)Adresse&amp;lt;/pre&amp;gt;&lt;br /&gt;
returniert den Binärwert.&lt;br /&gt;
&lt;br /&gt;
Die Adresse setzt sich aus einer Startadresse und einem Offset zusammen, wobei diese sich im entsprechenden io-Header der Architektur befindet. Beispielweise setzt sich die Adresse für das UCSR0B-Register eines Atmega128 aus der Startadresse 0x800020 und dem Offset 0x0A zusammen.&lt;br /&gt;
&lt;br /&gt;
Für oft verwendete Register empfiehlt es sich, diesen mittels &lt;br /&gt;
&amp;lt;pre&amp;gt;set $name=(char *)Adresse&amp;lt;/pre&amp;gt;&lt;br /&gt;
einen Namen zuzuweisen. Diese könnte man in einer Datei speichern und diese als command-Datei beim Debugger angeben, wodurch man sich diese händischen Eingaben spart und mittels &lt;br /&gt;
&amp;lt;pre&amp;gt;p/x *$name&amp;lt;/pre&amp;gt; bzw. &amp;lt;pre&amp;gt;display *$name&amp;lt;/pre&amp;gt;&lt;br /&gt;
zugegreifen kann.&lt;br /&gt;
&lt;br /&gt;
== Weiteres ==&lt;br /&gt;
Bei Problemen kann dieser [http://www.mikrocontroller.net/topic/79965#667525 Thread] verwendet werden, in den ich, wann immer es sich bei mir ausgeht, schauen werde.&lt;br /&gt;
&lt;br /&gt;
Jeder ist aufgerufen hier weiterzumachen, wenn er mehr weiss, oder es besser gestalten kann.&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:AVR ]]&lt;/div&gt;</summary>
		<author><name>Thymythos</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=RFM12&amp;diff=31818</id>
		<title>RFM12</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=RFM12&amp;diff=31818"/>
		<updated>2008-10-12T12:43:25Z</updated>

		<summary type="html">&lt;p&gt;Thymythos: /* Links */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Beschreibung der Funkmodule RFM01, RFM02 und RFM12.&lt;br /&gt;
&lt;br /&gt;
Benötigt werden in der Minimal-Version im FIFO-Modus nur die Anschlüsse nSEL, SDO, SDI und SCK, eben das komplette SPI-Interface. Der Zugriff auf das Sende- und Empfangs-FIFO ist per Software möglich, ebenso die Abfrage der Statusbits. Deshalb werden z.B. nIRQ und nFFS nicht unbedingt benötigt. nIRQ signalisiert unter anderem, dass das Modul bereit ist Daten zu empfangen. Wenn Daten empfangen wurden, kann dies über den FFIT-Pin abgefragt werden (falls die Füllschwelle eingestellt wurde). nFFS dient dazu das FIFO direkt anzusprechen (es ist quasi der Chipselect für das FIFO), davon wird in der Minimalversion aber kein Gebrauch gemacht. Der Pin muss daher auf high-Pegel gelegt werden!&lt;br /&gt;
An CLK kann eine Frequenz von 1MHz bis 10MHz eingestellt werden. Hiermit kann dann z.B. der Mikrocontroller versorgt werden.&lt;br /&gt;
Reset ist ein Open-Collector-Ausgang und gleichzeitig der Reset-Eingang. Er sollte daher entweder gar nicht, oder aber hochohmig angeschlossen werden.&lt;br /&gt;
&lt;br /&gt;
Im FIFO-Mode kann das Modul konfiguriert werden mit dem Empfang zu warten, bis die Daten 0x2DD4 empfangen wurden. Sobald dieses Bitmuster empfangen wurde, werden Daten in das FIFO geschrieben, bis man das FIFO abschaltet und die Mustererkennung neu startet.&lt;br /&gt;
&lt;br /&gt;
Als weitere Modi stehen unter anderem ein synchroner Modus zur Verfügung (no FIFO mode), in dem der Sender/Empfänger den Bittakt ausgibt, und synchron dazu die zu sendenden Daten einliest bzw. die empfangenen Daten ausgibt. Der SPI Bus ist trotzdem zur Initialisierung des Moduls notwendig.&lt;br /&gt;
&lt;br /&gt;
== FAQ ==&lt;br /&gt;
&lt;br /&gt;
=== SPI Interface ===&lt;br /&gt;
&lt;br /&gt;
* Maximale Datenrate: 2,5MHz (10MHz Quarz / 4)&lt;br /&gt;
&lt;br /&gt;
=== CLK-Ausgang bleibt bei 1 MHz ===&lt;br /&gt;
&lt;br /&gt;
* Vor dem Umschalten (mit 0xC0E0) länger warten.&lt;br /&gt;
&lt;br /&gt;
=== RFM12 empfängt ein paar Bytes, dann nur Müll ===&lt;br /&gt;
&lt;br /&gt;
* Es wird zu langsam gesendet (TX FIFO underrun)&lt;br /&gt;
* Es wird zu langsam empfangen (RX FIFO overrun)&lt;br /&gt;
&lt;br /&gt;
Die Status-Bits helfen hier beim Debuggen. SPI sollte auf maximaler Transferrate stehen.&lt;br /&gt;
&lt;br /&gt;
=== RFM empfängt nur Müll ===&lt;br /&gt;
&lt;br /&gt;
http://www.mikrocontroller.net/topic/73560#605528&lt;br /&gt;
&lt;br /&gt;
Deine Module verhalten sich normal. Man muß mit den Gain- und AFC-Bits&lt;br /&gt;
eine ganze Weile spielen, bis die Module korrekt laufen (kommt auf die&lt;br /&gt;
Anwendung an). Fakt ist: der Empfänger empfängt ständig Datenmüll als&lt;br /&gt;
Rauschen. Wenn der FIFO durch die Präambel getriggert wird, sind die&lt;br /&gt;
Daten im FIFO ziemlich korrekt, wenn alles &amp;quot;gut&amp;quot; eingestellt ist. Der&lt;br /&gt;
FIFO sollte per Interrupt dann auch sofort abgeholt werden, da sonst das&lt;br /&gt;
nächste Byte das alte direkt überschreibt. Jeder zusammenhängende&lt;br /&gt;
Datensatz (mehrere Bytes an einem Stück) muß von einer Präambel&lt;br /&gt;
eingeleitet werden. Nach dem kompletten Einlesen eines Datensatzes muß&lt;br /&gt;
der FIFO abgeschaltet, wieder eingeschaltet und für den Empfang der&lt;br /&gt;
nächsten Präambel neu scharf gemacht werden.&lt;br /&gt;
&lt;br /&gt;
=== RFM hängt sich auf ===&lt;br /&gt;
&lt;br /&gt;
Wenn man die AFC nicht begrenzt, also keinen Wertebereich vorgibt, die eine maximale Abweichung korrigiert wird passiert es nach einer Weile, dass sich der Empfänger aufhängt, die Offsetbits im Status werden maximal und dann geht gar nichts mehr, er hängt fest.&lt;br /&gt;
&lt;br /&gt;
Siehe auch &lt;br /&gt;
* Forenbeitrag [http://www.mikrocontroller.net/topic/82456#689660 RFM12: Erfahrungen ]&lt;br /&gt;
&lt;br /&gt;
== Register ==&lt;br /&gt;
&lt;br /&gt;
Von https://www.mikrocontroller.net/attachment/24947/RFM12.txt&lt;br /&gt;
&lt;br /&gt;
Dieses Dokument beschreibt die Nutzung des RFM12 TRX Moduls!&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039; WICHTIG &#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Dieses Dokument wurde aus mehreren Quellen zusammengestellt, und kann Fehler enthalten!&lt;br /&gt;
Es können Abweichungen in Bezug auf RF01 / RF02 / RF12 / RFM01 / RFM02 und andere Module auftreten!&lt;br /&gt;
Es wurde das Datenblatt vom RFM12B und RF12 von www.hoperf.com als Basis genuzt. Zusätzlich wurden diese Informationen mit Hilfe von Forums-Nutzern (https://www.mikrocontroller.net/topic/71682) weiter vervollständigt!&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039; WICHTIG &#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Hinweis:&#039;&#039;&#039; Die LNA-Eingangsimpedanz beträgt 250 Ohm, und muss beim Anschluss einer 50-Ohm-Antenne entsprechend angepasst werden, um das Rauschen zu minimieren! &#039;&#039; -- (Auf den Pollin-Modulen bereits vorhanden)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Configuration Setting ===&lt;br /&gt;
 Hex = 80 &amp;amp; xx&lt;br /&gt;
 Bit-Syntax: 10000000 | el | ef | b1 | b0 | x3 | x2 | x1 | x0&lt;br /&gt;
 el (TX FIFO) = Sendepuffer für Datentransfer nutzen (1 = An / 0 = Aus)&lt;br /&gt;
 ef (RX FIFO) = Empfangspuffer für Datenspeicherung nutzen (1 = An / 0 = Aus)&lt;br /&gt;
 b... = Zu nutzende Basisfrequenz (00=315MHz / 01=433MHz / 10=868MHz / 11=915MHz)&lt;br /&gt;
 x... = Interner Clock des Chips kann durch verschieben einer Kondensator-Anpass-Stufe bestimmt werden.&lt;br /&gt;
        0,5pF pro Schritt. Basis ist 8,5pF -&amp;gt; (0000=8,5 / 0001=9,0 / 0010=9,5 / ...)&lt;br /&gt;
&lt;br /&gt;
=== Power-Managment ===&lt;br /&gt;
 Hex = 82 &amp;amp; xx&lt;br /&gt;
 Bit-Syntax: 10000010 | er | ebb | et | es | ex | eb | ew | dc&lt;br /&gt;
 er = Empfänger einschalten (1 = an / 0 = Aus)&lt;br /&gt;
 ebb = ... (Synthesizer muss aktiv sein!) (1 = an / 0 = aus)&lt;br /&gt;
 et = Sender einschalten (1 = an / 0 = Aus) (Wenn das TX-Register aktiv und mit Daten gefüllt ist/wurde,&lt;br /&gt;
      werden diese Daten sofort gesendet) (1 = an / 0 = aus)&lt;br /&gt;
 es = Schaltet den Synthesizer ein. (1 = an / 0 = aus)&lt;br /&gt;
 ex = Schaltet den Quarz-Oszilator ein. (1 = an / 0 = aus)&lt;br /&gt;
 eb = Vergleichbar mit BrownOutDetection -&amp;gt; Erkennt eine zu geringe Betriebsspannung und erzeugt einen Interrupt,&lt;br /&gt;
      um einen drohenden Spannungsaufall anzukündigen (1 = An / 0 = Aus)&lt;br /&gt;
 ew = Aktiviert den WakeUpTimer des Prozessors. (1 = an / 0 = aus)&lt;br /&gt;
 dc = Deaktiviert die Ausgabe des SystemClocks auf dem CLK Pin am Chip (1 = Keine ClockAusgabe / 0 = Clock ausgeben)&lt;br /&gt;
&lt;br /&gt;
=== PLL Setting ===&lt;br /&gt;
 Hex = 198 + y&lt;br /&gt;
 Bit-Syntax: 110011000 | ob1 | ob0 | lpx | ddy | ddit | bw1 | bw0&lt;br /&gt;
 ob... = ... (00= 5 oder 10MHz [standard] / 01=3.3MHz / 1x=2.5MHz oder weniger)&lt;br /&gt;
 lpx = Wählt den Low-Power-Mode für den Quarz-Oszilator aus. (0=1ms [620µA] / 1=2ms [460µA])&lt;br /&gt;
 ddy = ...&lt;br /&gt;
 ddi = Schaltet das Dithering in PLL-Schleife ab. (1=abgeschaltet / 0=eingeschaltet)&lt;br /&gt;
 bw... = Wählt die Bandbreite des PLL-Signals aus. (00=86.2kbps [-107dBc/Hz] / 01=256kbps [-102dBc/Hz]) Bei 1MHz Offset Phasenrauschen.&lt;br /&gt;
&lt;br /&gt;
=== LowBatt / µC Clock Control ===&lt;br /&gt;
 Hex = c0 &amp;amp; xx&lt;br /&gt;
 Bit-Syntax: 11000000 | d2 | d1 | d0 | v4 | v3 | v2 | v1 | v0&lt;br /&gt;
 d... = Bestimmt den Teilungsfaktor für die Clockausgabe am CLK-Pin in Abhängigkeit des Internen SystemTakts.&lt;br /&gt;
        (000=1 / 001=1.25 / 010=1.66 / 011=2 / 100=2.5 / 101=3.33 / 110=5 / 111=10)&lt;br /&gt;
 v... = Bestimmt die Minimalspannung, ab der ein Interrupt durchgeführt werden&lt;br /&gt;
 muss. (Ähnlich einer BrownOutDetection). Im Power-Managment muss das eb-Bit&lt;br /&gt;
 aktiv sein, damit dies funktioniert.&lt;br /&gt;
&lt;br /&gt;
=== Frequency-setting ===&lt;br /&gt;
Bestimmt den Offset der Sende- und Empfangsfrequenz. Dieser Offset wird auf das Basisband im Configuration Setting hinzu gerechnet.&lt;br /&gt;
 Hex = a &amp;amp; xxx&lt;br /&gt;
 Bit-Syntax: 1010 | f11 | f10 | f9 | f8 | f7 | f6 | f5 | f4 | f3 | f2 | f1 | f0&lt;br /&gt;
 f... = Bestimmt den Offsetwert der Frequenz.&lt;br /&gt;
        Als Basis gilt das eingestellte Band im Configuration-Settings-Kommando&lt;br /&gt;
&lt;br /&gt;
=== Data-Rate ===&lt;br /&gt;
 Hex = c6 &amp;amp; xx&lt;br /&gt;
 Bit-Syntax: 11000110 | cs | r6 | r5 | r4 | r3 | r2 | r1 | r0&lt;br /&gt;
 cs =  Vorteiler, Faktor 7. Hiermit kann ein Vorteiler aktiviert werden,&lt;br /&gt;
       der die errechnete Baudrate (r...) durch 7 teilt.&lt;br /&gt;
 r... = Baudratenteilerfaktor&lt;br /&gt;
&lt;br /&gt;
=== RX Control ===&lt;br /&gt;
 Hex = 94 &amp;amp; xx&lt;br /&gt;
 Bit-Syntax: 10010 | p20 | d1 | d2 | i2 | i1 | i0 | g1 | g0 | r2 | r1 | r0&lt;br /&gt;
 p20 = Bestimmt die Funktion des Pin20 (nINT / VDI) am RFM12 Chip (1 = VDI-Ausgang / 0 = Interrupt-Eingang)&lt;br /&gt;
 d... = (Valid Data Indicator). Definiert die Geschwindigkeit, mit der bestimmt wird, ob ein Signal korrekt ist, oder nicht.&lt;br /&gt;
        (00=schnell / 01=mittel / 10=langsam / 11=immer an). Je nach eingestellter Variante werden&lt;br /&gt;
        unterschiedliche Hardware- und Software-Kombinationen genuzt.&lt;br /&gt;
        Fast:  CR_Lock  OR  DQD  ... Medium:  CR_Lock  AND ( DRSSI  OR  DQD ) ... &lt;br /&gt;
        SLOW: R/S FlipFlop aus (SET)  DRSSI  OR  DQD  OR  CR_Lock  und (CLR)  DRSSI  AND  DQD  AND  CR_Lock .&lt;br /&gt;
 i... = Bestimmt die Bandbreite des Empfängers in KHz (KiloHertz).&lt;br /&gt;
        (000=Reserviert / 001=400 / 010=340 / 011=270 / 100=200 / 101=134 / 110=67 / 111=Reserviert)&lt;br /&gt;
 g... = (LNA-Gain) Verstärkungsfaktor des Rauscharmen-Eingangs-Signal-Verstärkers (LNA Low Noise Amplifier).&lt;br /&gt;
        Werte in dBm (Dezibel [Grösse: Milliwatt]) Mögliche Werte sind: 0 / -6 / -14 / -20&lt;br /&gt;
 r... = (DRSSI = Digital Received Signal Strength Indication) Minimale Empfangssignalfeldstärke.&lt;br /&gt;
        6 dBm pro Schritt: (000=-103 / 001=-97 / 010=-91 / ...)&lt;br /&gt;
&lt;br /&gt;
=== Synchron Pattern ===&lt;br /&gt;
 Hex = ce &amp;amp; xx&lt;br /&gt;
 Bit-Syntax: 11001110 | b7 | b6 | b5 | b4 | b3 | b2 | b1 | b0&lt;br /&gt;
 b... = Legt den Wert fest, der als Synchronisations-Byte für die Datenfilterung verwendet werden soll.&lt;br /&gt;
&lt;br /&gt;
=== Data Filter ===&lt;br /&gt;
 Hex = c2 &amp;amp; xx&lt;br /&gt;
 Bit-Syntax: 11000010 | al | ml | -unknow- (1) | s | -unknow- (1) | f2 | f1 | f0&lt;br /&gt;
 al = Baudratenregenerator schaltet automatisch in den langsamen Modus, &lt;br /&gt;
      sobald er einen Takt erkannt hat.&lt;br /&gt;
 ml = schneller/langsamer Modus&lt;br /&gt;
 -unknown- (1) = ??? (Standard = 1) (Auch im Datenblatt von IA4420 so beschrieben)&lt;br /&gt;
 s = (DataFilter) Typ des Datenfilters (0=DigitalFilter / 1=AnalogFilter).&lt;br /&gt;
     Bei Nutzung des Analog-Filters kann kein FIFO sowie kein ClockRecovery genuzt werden.&lt;br /&gt;
 -unknown- (1) = ??? (Standard = 1) (Auch im Datenblatt von IA4420 so beschrieben)&lt;br /&gt;
 f... = (DQD Threshold) Bestimmt den Schwellwert, ab dem ein Signal als gut empfunden wird,&lt;br /&gt;
         und der Empfänger dieses weiterverarbeiten soll.&lt;br /&gt;
         DQD (data quality detection) zählt die &amp;quot;Spikes&amp;quot; des ungefilterten Signals, und bestimmt darüber die Qualität der Daten.&lt;br /&gt;
&lt;br /&gt;
=== FIFO und RESET-Mode ===&lt;br /&gt;
 Hex = ca &amp;amp; xx&lt;br /&gt;
 Bit-Syntax: 11001010 | f3 | f2 | f1 | f0 | -unknow- (0) | al | ff | dr&lt;br /&gt;
 f... = (FIFO interrupt Level)&lt;br /&gt;
 -unknown- (0) = ??? (Standard = 0) (Auch im Datenblatt von IA4420 so beschrieben)&lt;br /&gt;
 al = (FIFO Fill Condition) Legt den Wert fest, ab dem das Füllen des FIFOs beginnt.&lt;br /&gt;
      (0=Synchron / 1=Ständig). Bei Nutzung des Synchron-Modus, werden erst dann Daten in den FIFO geschrieben,&lt;br /&gt;
      wenn eine definierte 16Bit-Datenfolge empfangen wurde (Standard ist Hex: 2dd4).&lt;br /&gt;
 ff = (FIFO Fill) Startet das Einlesen der empfangenen Daten in den FIFO-Puffer.&lt;br /&gt;
      Wenn al (FIFO Fill Condition) auf synchron steht, dann startet das Setzen dieses Bits die Synchronisation-Bit-Erkennung.&lt;br /&gt;
 dr = (Sens Reset Mode) Wenn dieses Bit auf 1 steht, wird bei einer Schwankung von 200mV auf&lt;br /&gt;
      der VCC-Leitung (Spannungsversorgung des Chips), ein System-Reset ausgelöst.&lt;br /&gt;
&lt;br /&gt;
=== Automatic Frequency Control ===&lt;br /&gt;
 Hex = c4 &amp;amp; xx&lt;br /&gt;
 Bit-Syntax: 11000100 | a1 | a0 | rl1 | rl0 | st | fi | oe | en&lt;br /&gt;
 a... = Modus der AFC-Schaltung, 0=Auto, 1=einmalig nach Einschalten, 2=Solange VDI low ist, 3=unabhängig von VDI&lt;br /&gt;
 r... = (Range Limit) Frequenzraster (00=KeineBegrenzung / 01=+15 &amp;gt; -16 / 10=+7 &amp;gt; -8 / 11=+3 &amp;gt; -4)&lt;br /&gt;
 st = Berechneten Offset-Wert übernehmen&lt;br /&gt;
 fi = Genauer Berechnungsmodus (besser aber lansgamer)&lt;br /&gt;
 oe = AFC-Offset freischalten&lt;br /&gt;
 en = AFC-Berechnung aktivieren&lt;br /&gt;
&lt;br /&gt;
=== TX Configuration Control ===&lt;br /&gt;
 Hex = 98 &amp;amp; xx&lt;br /&gt;
 Bit-Syntax: 1001100 | mp | m3 | m2 | m1 | m0 | -unknow- (0) | p2 | p1 | p0&lt;br /&gt;
 mp = (Modulation Polarity) Bestimmt die Richtung der FSK-Erzeugung (invertiert das Spektrum).&lt;br /&gt;
 m... = (fDeviation) Bestimmt den Frequenzabstand des High- und Low-Wertes bei der Ubertragung im FSK-Betrieb. Basis ist der mp-Wert.&lt;br /&gt;
 -unknown- (0) = ??? (Standard = 0) (Auch im Datenblatt von IA4420 so beschrieben)&lt;br /&gt;
 p... = Bestimmt die relative Ausgangsleistung des Senders anhand des dBm-Wertes (Dezibel [Grösse: Milliwat]) 3-dBm-Schritte.&lt;br /&gt;
        (000=0 / 001=-3 / 010=-6 / ...). Der Wert steht im Zusammenhang mit der angeschlossenen Antennen-Impedanz.&lt;br /&gt;
&lt;br /&gt;
=== Wake-Up Timer ===&lt;br /&gt;
 Bestimmt die Zeitperiode der zyklischen Einschaltung des WakeUp-Timers&lt;br /&gt;
 Hex = e &amp;amp; xxx&lt;br /&gt;
 Bit-Syntax: 111 | R4 | R3 | R2 | R1 | R0 | M7 | M6 | M5 | M4 | M3 | M2 | M1 | M0&lt;br /&gt;
 R = Exponent der Zeit&lt;br /&gt;
 M = Zeit&lt;br /&gt;
&lt;br /&gt;
=== Low Duty-Cycle ===&lt;br /&gt;
&lt;br /&gt;
Bestimmt die maximale Sendezeit pro Stunde. Dies ist wichtig, um sich an gesetzliche Frequenzzuteilungsrichtlinien zu halten, die bestimmen, wie lang jemand mit einer definierten Sendeleistung auf einer bestimmten Frequenz (mit eventuell definierter Betriebsart [Modulationstyp]) senden darf.)&lt;br /&gt;
&lt;br /&gt;
 hex = 6400 + Bits&lt;br /&gt;
 Bit-Syntax: 1100100 | r| d6 | d5 | d4 | d3 | d2 | d1 | d0 | en&lt;br /&gt;
 r =  ??????????????????&lt;br /&gt;
 d... = Einschaltdauer während der zyklischen Einschaltung&lt;br /&gt;
 en = zyklische Einschaltung aktivieren&lt;br /&gt;
&lt;br /&gt;
=== RX FIFO Read ===&lt;br /&gt;
 Hex = b000&lt;br /&gt;
 Bit-Syntax: 1011000000000000&lt;br /&gt;
&lt;br /&gt;
Dieses Kommando löst die Rückgabe eines Datenbytes (synchron mit dem 8. Bit) aus. Es ist nötig, dass das ef-Bit (RX-FIFO) im Configuration Setting gesetzt wurde, um diese Funktion nutzen zu können!&lt;br /&gt;
&lt;br /&gt;
=== TX Register Write ===&lt;br /&gt;
Dieses Kommando schreibt Daten in den TX-Puffer. Wenn der Sender aktiv ist, wird dieses sofort gesendet. el (TX-Register) muss im Configuration-Setting-Kommando aktiv sein.&lt;br /&gt;
 Hex = b8 &amp;amp; xx&lt;br /&gt;
 Bit-Syntax: 10111000 | DataByteToSend&lt;br /&gt;
 DataByteToSend = Das Datenbyte, welches gesendet werden soll.&lt;br /&gt;
&lt;br /&gt;
=== Status Read ===&lt;br /&gt;
Dieses Kommando löst die Rückgabe des Statusregisters aus, welches nach der ersten 0 im ersten Bit synchron übertragen wird.&lt;br /&gt;
 Hex = 0000&lt;br /&gt;
 Bit-Syntax: 0000000000000000&amp;lt;000&amp;gt;&lt;br /&gt;
 Rückgabe-Syntax: x0 | x1 | x2 | x3 | x4 | x5 | x6 | x7 | x8 | x9 | x10 | x11 | x12 | x13 | x14 | x15 | x16 | x17 | x18&lt;br /&gt;
 x0 -&amp;gt; x5 = Interrupt bits&lt;br /&gt;
 x6 -&amp;gt; x15 = Status Bits&lt;br /&gt;
 x16 -&amp;gt; x18 = FIFO&lt;br /&gt;
 x0 = FFIT / RGIT (RGIT = TX-Register ist bereit neue Daten zu senden ... kann mit dem TX-Register gelöscht werden)&lt;br /&gt;
     (FFIT = Die Anzahl der Datenbits im FIFO-Puffer hat das eingestellte Limit erreicht.&lt;br /&gt;
      Kann mit einer der FIFO-Lesemethoden gelöscht werden)&lt;br /&gt;
 x1 = POR (PowerOnReset)&lt;br /&gt;
 x2 = FFOV / RGUR (RGUR = Der Datenstrom beim Senden ist abgerissen, da nicht schnell genug Daten nachgeladen wurden)&lt;br /&gt;
      (FFOV = Der RX-FIFO ist übergelaufen)&lt;br /&gt;
 x3 = WKUP&lt;br /&gt;
 x4 = EXT&lt;br /&gt;
 x5 = LBD&lt;br /&gt;
 x6 = FFBM (Der FIFO-Puffer ist leer)&lt;br /&gt;
 x7 = RSSI/ATS (ATS = )(RSSI = Die Signalstärke ist über dem eingestelltem Limit)&lt;br /&gt;
 x8 = DQD&lt;br /&gt;
 x9 = CRL&lt;br /&gt;
 x10 = ATGL&lt;br /&gt;
 x11 = OFFS_4&lt;br /&gt;
 x12 = OFFS_3&lt;br /&gt;
 x13 = OFFS_2&lt;br /&gt;
 x14 = OFFS_1&lt;br /&gt;
 x15 = OFFS_0&lt;br /&gt;
 x16 = FO&lt;br /&gt;
 x17 = FO+1&lt;br /&gt;
 x18 = FO+2&lt;br /&gt;
&lt;br /&gt;
== Bezugsquellen ==&lt;br /&gt;
* [[Elektronikversender#csd-electronics|csd-electronics]]&lt;br /&gt;
* [[Elektronikversender#IT-WNS|IT-WNS]]&lt;br /&gt;
* [[Elektronikversender#Pollin_Electronic|Pollin Electronic]]&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
* [[AVR RFM12]]&lt;br /&gt;
* [[RFM12 Protokoll Stack]]&lt;br /&gt;
* [http://www.mikrocontroller.net/topic/93801 Bezugsquellen]&lt;br /&gt;
&lt;br /&gt;
Folgende Links sind mit Vorsicht zu genießen, da die Datenblätter teilweise  fehlerbehaftet sind. Es empfiehlt sich, direkt mit dem Datenblatt des RF12 (das ist das IC auf dem Modul) zu arbeiten. Dieses ist so gut wie fehlerfrei.&lt;br /&gt;
&lt;br /&gt;
* [http://www.hoperf.com/pdf/RF12.pdf Datenblatt des ICs RF12] (PDF)&lt;br /&gt;
* [http://www.hoperf.com/pdf/RFM12.pdf Datenblatt des Moduls RFM12] (PDF)&lt;br /&gt;
* [http://www.hoperf.com/pdf/RF12_code.pdf Programming Guide] (PDF)&lt;br /&gt;
* [http://www.hoperf.com/pdf/RF12TOOLS.pdf Demo Kit User Manual] (PDF)&lt;br /&gt;
* [http://www.pollin.de/shop/downloads/D810047S.ZIP Beispielprogramm von Pollin] (ZIP)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Bauteile]]&lt;br /&gt;
[[Kategorie:Funk]]&lt;/div&gt;</summary>
		<author><name>Thymythos</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=AVR_RFM12&amp;diff=31817</id>
		<title>AVR RFM12</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=AVR_RFM12&amp;diff=31817"/>
		<updated>2008-10-12T12:42:54Z</updated>

		<summary type="html">&lt;p&gt;Thymythos: /* Links teilweise nach RFM12 Artikel verschoben */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Schaltungen und Software für AVR und das Funkmodul [[RFM12]].&lt;br /&gt;
&lt;br /&gt;
== SVN ==&lt;br /&gt;
&lt;br /&gt;
svn://mikrocontroller.net/rfm12&lt;br /&gt;
&lt;br /&gt;
Wegen Zugangsdaten bitte bei [http://www.mikrocontroller.net/user/show/andreas Andreas Schwarz] melden.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Software ==&lt;br /&gt;
&lt;br /&gt;
=== Treiber ===&lt;br /&gt;
&lt;br /&gt;
[http://www.mikrocontroller.net/attachment/22473/rfm12_pc.zip Firmware v1.0.0] von Benedikt K.&lt;br /&gt;
&lt;br /&gt;
[http://www.mikrocontroller.net/attachment/23542/RMxx_Driver.tar.bz2 Firmware v2.0.1] von Jürgen Eckert&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot;&lt;br /&gt;
|+ Funktionalität&lt;br /&gt;
|-&lt;br /&gt;
!  || Beschreibung || Software&lt;br /&gt;
|-&lt;br /&gt;
!1. Stufe:&lt;br /&gt;
| Die Daten von der seriellen Schnittstelle werden über die Funkstrecke auf die serielle Schnittstelle der anderen Seite übertragen. (Wir freuen uns über jedes Byte das ankommt)&lt;br /&gt;
| [http://www.mikrocontroller.net/topic/67273#564945 Claude Schwarz], [http://www.mikrocontroller.net/topic/71682#584915 Benedikt K.] oder [http://www.mikrocontroller.net/attachment/36742/RFM12_V3.zip Manuel Stahl]&lt;br /&gt;
|-&lt;br /&gt;
! 2. Stufe:&lt;br /&gt;
| Es findet eine Fehlererkennung (z.B. mit CRC-Summen) statt. Fehlerhafte Daten werden erneut angefordert. Dadurch gehen auf der Funkstrecke keine Daten verloren und es werden keine Daten verfälscht.&lt;br /&gt;
| [http://www.mikrocontroller.net/topic/71682#585851 Benedikt K.]&lt;br /&gt;
|-&lt;br /&gt;
! 3. Stufe:&lt;br /&gt;
| Die Datenübertragung wird individualisiert. Dadurch können zwei Funkstrecken, die im gleichen Empfangsbereich liegen nebeneinander arbeiten, ohne sich zu beeinträchtigen.&lt;br /&gt;
| [[RFM12_Protokoll_Stack]]&lt;br /&gt;
|-&lt;br /&gt;
! 4. Stufe: &lt;br /&gt;
| Die Datenübertragung wird verschlüsselt und damit abhörsicher.&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
!5. Stufe:&lt;br /&gt;
| Neben den Daten der seriellen Schnittstelle werden auch Änderungen der Statusleitungen übertragen. Damit erhält man eine &amp;quot;RS232-Verlängerung&amp;quot; über eine Funkstrecke, die fehlerfrei arbeitet und zu einer Drahtverbindung weitestgehend kompatibel ist.&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== RS232 &amp;lt;-&amp;gt; RFM12 ===&lt;br /&gt;
&lt;br /&gt;
TODO&lt;br /&gt;
&lt;br /&gt;
=== USB &amp;lt;-&amp;gt; RFM12 ===&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;&#039;[http://www.obdev.at/products/avrusb/index.html avrusb]&#039;&#039;&#039; lässt sich ein USB-Slave in Software emulieren.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;[http://www.recursion.jp/avrcdc/ AVR-CDC]&#039;&#039;&#039; läuft mit Anpassung der USB-Pins. &#039;&#039;(Zumindest unter Windows an einem USB2.0-Port)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Adapter für &#039;&#039;&#039;[http://www.embedded-projects.net/?page_id=135 USBprog]:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Funktionierender Code liegt im oben genannten SVN&lt;br /&gt;
* Implementiert die USB-CDC-Klasse (kein Treiber nötig)&lt;br /&gt;
* Sicherung der Übertragung durch Hamming-Code&lt;br /&gt;
* Work in progress... (Manuel Stahl)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Hardware ==&lt;br /&gt;
&lt;br /&gt;
=== Basismodul V1.0 ===&lt;br /&gt;
&lt;br /&gt;
==== Prozessor ====&lt;br /&gt;
&lt;br /&gt;
ATmega8 TQFP32 (kompatibel ATmega48, ATmega88, ATmega168)&lt;br /&gt;
&lt;br /&gt;
==== Schnittstellen ====&lt;br /&gt;
&lt;br /&gt;
* RS232&lt;br /&gt;
* I²C:&lt;br /&gt;
* USB&lt;br /&gt;
* GPIO&lt;br /&gt;
&lt;br /&gt;
==== Platine ====&lt;br /&gt;
&lt;br /&gt;
[[Bild:AVR RFM12 Schematic.png|200px|ATmega48 + USB]]&lt;br /&gt;
[[Bild:AVR RFM12 Board TOP.png|220px|2-lagig top]]&lt;br /&gt;
[[Bild:AVR RFM12 Board BOTTOM.png|240px|2-lagig bottom]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Bauteile:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Größe: SMD 0603&lt;br /&gt;
&lt;br /&gt;
* R1, R2: 68R (nur USB)&lt;br /&gt;
* R3, R4: 10k&lt;br /&gt;
* R5: 1k5 (nur USB)&lt;br /&gt;
* C1, C2: 22pF&lt;br /&gt;
* C3 - C9: 100nF&lt;br /&gt;
* Q1: 12Mhz (nur USB)&lt;br /&gt;
* D1, D2: beliebig, Minimelf&lt;br /&gt;
* IC3: MAX3221CUE&lt;br /&gt;
&lt;br /&gt;
==== Bugs / Erweiterungen ====&lt;br /&gt;
&lt;br /&gt;
* Der 1,5k Widerstand muss direkt an den VCC-Pin angelötet werden (Pad ist nicht verbunden)&lt;br /&gt;
* Beim Fertigen wurde das Polygon, welches das VCC-Signal durch die eine Ecke des ATmega48 leitet, unterbrochen. Hier hilft nur eine Drahtbrücke.&lt;br /&gt;
* Unter den RFM12 und unter das Quarz am Besten Isolierband kleben!&lt;br /&gt;
* Beim Programmieren sollte der SEL des RFM12 (J1 der zweite Pin vom RS232 aus) auf VCC gelegt werden&lt;br /&gt;
&lt;br /&gt;
==== Fertigung ====&lt;br /&gt;
&lt;br /&gt;
Kosten:&lt;br /&gt;
&lt;br /&gt;
* MiniUSB SMD: &#039;&#039;&#039;1,25€&#039;&#039;&#039;&lt;br /&gt;
* HF-Buchse MMCX: &#039;&#039;&#039;4,25€&#039;&#039;&#039;&lt;br /&gt;
* ATmega48: &#039;&#039;&#039;2,85€&#039;&#039;&#039;&lt;br /&gt;
* MAX3221CUE: &#039;&#039;&#039;1,10€&#039;&#039;&#039;&lt;br /&gt;
* Quarz 12Mhz 30ppm: &#039;&#039;&#039;1,19€&#039;&#039;&#039;&lt;br /&gt;
* Kleinkram: &#039;&#039;&#039;&amp;lt; 1,10€&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* habe ein verbindliches Angebot für 24 Stück von http://mme-pcb.de/: &#039;&#039;&#039;4,00€ pro Platine&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[http://www.mikrocontroller.net/attachment/24012/RFM12.brd Board]:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Board bottom bestuecken.png|200px|bottom]]&lt;br /&gt;
[[Bild:AVR RFM12 Board top bestuecken.png|200px|top]]&lt;br /&gt;
&lt;br /&gt;
=== USBprogRFM12 ===&lt;br /&gt;
&lt;br /&gt;
Da der USBprog genau das SPI-Interface des ATmega32 zur Verfügung stellt, eignet er sich perfekt als USB-RFM12-Adapter.&lt;br /&gt;
&lt;br /&gt;
[[Bild:USBprogRFM12_schematic.png|200px|USBprogRFM12]] [[Bild:USBprogRFM12_board.png|200px|USBprogRFM12]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
* [http://www.mikrocontroller.net/topic/65984 Allgemeine Diskussion]&lt;br /&gt;
* [http://www.mikrocontroller.net/topic/71682  bidirektionale RS232 Funkbrücke mit RFM12]&lt;br /&gt;
* [http://www.das-labor.org/wiki/Datenfunk_mit_dem_AVR Datenfunk mit dem AVR] bei das-labor.org&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Projekte]]&lt;br /&gt;
[[Kategorie:AVR]]&lt;br /&gt;
[[Kategorie:Funk]]&lt;/div&gt;</summary>
		<author><name>Thymythos</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=Diskussion:RFM12_Protokoll_Stack&amp;diff=31287</id>
		<title>Diskussion:RFM12 Protokoll Stack</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=Diskussion:RFM12_Protokoll_Stack&amp;diff=31287"/>
		<updated>2008-09-21T12:52:32Z</updated>

		<summary type="html">&lt;p&gt;Thymythos: Formatierung&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Fehler ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;F:&#039;&#039;&#039; &#039;&#039;(17.09.2008)&#039;&#039; Im IE haben die Hamming-Tabellen alle einen schwarzen Hintergrund und schwarze Schrift (Im Firefox ist die Darstellung i.o.)&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;A:&#039;&#039;&#039; Ich hab die Kurzschreibweise für Farben verwendet (#f12 statt #ff1122), ist aber eigentlich leider nur in CSS erlaubt... (Aber es scheint eine gute Methode zu sein um Inhalte vor IE nutzern zu verstecken *g*)&lt;br /&gt;
&lt;br /&gt;
== Anregungen ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;F:&#039;&#039;&#039; &#039;&#039;(31.08.2008)&#039;&#039; Ist der Code bereits benutzbar? Falls ja fände ein Beispielprogramm sehr hilfreich.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;A:&#039;&#039;&#039; Im LLC fehlt noch ein bisschen was, aber PHY und MAC sind benutzbar.&lt;br /&gt;
&lt;br /&gt;
== Fragen ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;F:&#039;&#039;&#039; &#039;&#039;(04.09.2008)&#039;&#039; Warum gibt es auf LLC-Ebene keine Paketlängeninformation? (Jörg Wunsch)&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;A:&#039;&#039;&#039; Overhead. Durch das Paketendezeichen ist die Länge definiert. Zugegeben, in manchen Applikationen erscheint es sinnvoll vor dem Empfang des Paketes die Länge zu wissen, aber IP hat z.B. dafür ein eigenes Feld.&lt;/div&gt;</summary>
		<author><name>Thymythos</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=AVR_FAT32&amp;diff=31286</id>
		<title>AVR FAT32</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=AVR_FAT32&amp;diff=31286"/>
		<updated>2008-09-21T12:47:59Z</updated>

		<summary type="html">&lt;p&gt;Thymythos: /* Siehe Auch */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== FAT 16/32 ==&lt;br /&gt;
&lt;br /&gt;
Dies ist eine freie FAT 16 / 32 Bibliothek.&lt;br /&gt;
&lt;br /&gt;
Die Bibliothek ist modular und besteht aus folgenden Modulen:&lt;br /&gt;
&lt;br /&gt;
* MMC/SD    (Hardware abhängig)&lt;br /&gt;
* FAT16/32  &lt;br /&gt;
* File&lt;br /&gt;
&lt;br /&gt;
das MMC/SD Modul ist dafür zuständig die Kommunikation mit der MMC/SD Karte zu managen und ist das einzige hardwareabhängige.&lt;br /&gt;
&lt;br /&gt;
das FAT16/32 Modul bietet die Grundlegenden Funktionen für den FAT Zugriff.&lt;br /&gt;
&lt;br /&gt;
das File Modul bietet Funktionen wie man sie von Datei Zugriffen kennt, wie z.B.&lt;br /&gt;
ffopen/ffclose um eine Datei zu öffnen oder um an eine Datei etwas anzuhängen und diese wieder zu schließen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== FAT 32 Grundlegendes ==&lt;br /&gt;
&lt;br /&gt;
Ein Dateisystem des Typs FAT besteht aus mehreren Bereichen.&lt;br /&gt;
FAT ist immer little Endian [http://de.wikipedia.org/wiki/Byte-Reihenfolge].&lt;br /&gt;
 &lt;br /&gt;
* Der erste Teil, der einem begegnet ist der Sektor 0 oder LBA, in dem alle wichtigen Informationen zum Auslesen des Dateisystems stehen.&lt;br /&gt;
* Dann die FAT selber, also die Dateizuordnungstabelle.&lt;br /&gt;
* Der dritte Teil ist der &amp;quot;Daten&amp;quot; Bereich.&lt;br /&gt;
&lt;br /&gt;
=== Sektor 0 oder LBA ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Sektor 0 (512 Byte) bei einer unpartitionierten Karte sieht wie folgt aus:&lt;br /&gt;
&lt;br /&gt;
[[Bild:sektor0.jpeg]]&lt;br /&gt;
&amp;lt;br&amp;gt;(Bild 1)&lt;br /&gt;
&lt;br /&gt;
Um das Dateisystem lesen zu können muss man wissen wo was steht. Die nötigsten Informationen sind: &lt;br /&gt;
&lt;br /&gt;
Sektoren pro Cluster (rot).&amp;lt;br&amp;gt;&lt;br /&gt;
Reservierte Sektoren nach Sektor 0 (orange).&amp;lt;br&amp;gt;&lt;br /&gt;
Anzahl der FATs (gelb).&amp;lt;br&amp;gt;&lt;br /&gt;
Wieviele Sektoren von einer FAT belegt werden (grün).&amp;lt;br&amp;gt;&lt;br /&gt;
Der Root-Dir Cluster (blau).&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Aus diesen Daten ergibt sich demnach:&lt;br /&gt;
&lt;br /&gt;
* 1. Sektor der 1. FAT ist Sektor 32 (Bild 2), also der erste Sektor nach den Reservierten (orange).&lt;br /&gt;
&lt;br /&gt;
* Der erste Daten Cluster ist 1003, weil die Anzahl der FATs 1 ist, also einmal die Sektoren, die von einer FAT belegt werden (grün) (00003cb=971) 971 + 32 (orange) = 1003.&lt;br /&gt;
&lt;br /&gt;
* Das Root-Dir ist Cluster 2, also Sektor 1003.&lt;br /&gt;
&lt;br /&gt;
* Die Anzahl der Sektoren pro Cluster ist 4 (2048 Bytes/Cluster).&lt;br /&gt;
&lt;br /&gt;
damit sind alle nötigen Daten vorhanden.&lt;br /&gt;
&lt;br /&gt;
Bei FAT Dateisystemen können mehrere Sektoren (512 Bytes) logisch zu Clustern zusammengeschlossen werden. Die rote Zahl gibt an wieviele Sektoren ein Cluster bilden. Der Daten Bereich wird immer in Clustern angegeben, das macht die Umrechnung von Sektoren zu Clustern nötig. In diesem Fall ist Cluster 2 der absolute Sektor 1003.&lt;br /&gt;
&lt;br /&gt;
=== Die FAT ===&lt;br /&gt;
&lt;br /&gt;
FAT bedeutet File Allocation Table ( Dateizuordnungstabelle ) und ist little Endian. Dateizuordnungstabelle beschreibt schon das Prinzip der FAT. &lt;br /&gt;
Kern des Dateisystems ist eine einfach verkettete Liste, in der festgehalten wird wo sich die Daten wie Ordner oder Dateien befinden. &lt;br /&gt;
Folgendes Bild zeigt den ersten FAT Sektor (512 Bytes) eines FAT32 Dateisystems (nicht den ersten Sektor der Karte!). Eingetragen sind: Root-Dir und zwei darin enthaltene Ordner sowie eine Datei mit 60.000 Byte Größe.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Bild:fat32.jpeg]]&lt;br /&gt;
&amp;lt;br&amp;gt;(Bild 2)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die Einträge 0-7 sind immer reserviert (Quasi Cluster 0 und 1)! Also beginnt die FAT ab 8 (rot)(Cluster Nummer 2). Der erste Eintrag (rot) ist 4 Byte groß und zu lesen von Stelle 8 zu Stelle 11 weil little Endian, also umgedrehte Wertigkeit. 8 niedrigste Wertigkeit, dann 9 eins höher, 10 noch eine höher und 11 höchste (dazu später noch ein Beispiel).&amp;lt;br&amp;gt;&lt;br /&gt;
Wie von Microsoft empfohlen ist der erste mögliche Cluster das Root-Dir hier rot und nur einen Cluster lang.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
An den gelben Einträgen wird die einfach verkettete Liste der FAT deutlich. Der erste gelbe Eintag steht an der Stelle des Clusters Nummer 5 und hat als Inhalt eine 6. Das bedeutet: Cluster 5 und 6 gehören zusammen. Würde an der Stelle des Clusters Nummer 5 ein FFFFFFF0 stehen (little Endian) ist nur der Cluster 5 mit Daten belegt (wie bei rot, blau und grün). So tastet man sich vom 1. Cluster einer Datei zum Ende der Datei vor. Das ist der einzige Zweck der FAT.&amp;lt;br&amp;gt;&lt;br /&gt;
Woher bekommt man aber den 1. Cluster einer Datei?&lt;br /&gt;
&lt;br /&gt;
=== Daten Bereich ===&lt;br /&gt;
&lt;br /&gt;
Folgendes Bild zeigt den Inhalt eines Ordners/Dirs (Cluster 4) :&lt;br /&gt;
&lt;br /&gt;
[[Bild:Data.jpeg]]&lt;br /&gt;
&amp;lt;br&amp;gt;(Bild 3)&lt;br /&gt;
&lt;br /&gt;
Ein Dateieintrag besteht aus 32 Bytes und liegt im Datenbereich des Dateisystems ( 32Byte = eine Zeile). &amp;lt;br&amp;gt;&lt;br /&gt;
Die dritte Zeile des Bilds zeigt eine Datei namens TEST3.TXT (grün) mit 60.000 kBytes Größe (blau) und dem 1. Cluster 5 (rot)(Folgecluster siehe Bild 2).&amp;lt;br&amp;gt;&lt;br /&gt;
Speziell ist hier, dass die 4 Bytes des ersten Clusters aufgeteilt sind auf 2 unterschiedliche &amp;quot;Orte&amp;quot; im 32 Byte Eintrag (Wertigkeit: 26:27:20:21). &amp;lt;br&amp;gt;&lt;br /&gt;
Um nun die Daten der Datei lesen zu können, muss man die weiteren Cluster kennen. Dazu sieht man in der FAT nach, an der Stelle 5 (siehe Bild 2). Dort steht der Folgecluster der Datei (Cluster 6). Wenn in der FAT der letzte Cluster erreicht ist (FFFFFFF0), liest man den letzten Sektor bis man die Größe der Datei (blau) gelesen hat und ist fertig.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
bald mehr...&lt;br /&gt;
&lt;br /&gt;
== Der Source Code der Lib ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* Sourcecode: http://www.mikrocontroller.net/attachment/40180/mmc-0.4.6.zip&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Siehe Auch ==&lt;br /&gt;
&lt;br /&gt;
* Thread:  http://www.mikrocontroller.net/topic/105869#new&lt;br /&gt;
&lt;br /&gt;
* Infos (englisch):  https://www.pjrc.com/tech/8051/ide/fat32.html&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Weitere Projekte mit FAT/SD-CARD:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* [http://www.roland-riegel.de/sd-reader/index.html MMC/SD card reader example application]&lt;br /&gt;
* [http://www.ulrichradig.de/home/index.php/avr/mmc-sd MMC/SD (Ulrich Radig)]&lt;/div&gt;</summary>
		<author><name>Thymythos</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=AVR_FAT32&amp;diff=31285</id>
		<title>AVR FAT32</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=AVR_FAT32&amp;diff=31285"/>
		<updated>2008-09-21T12:45:31Z</updated>

		<summary type="html">&lt;p&gt;Thymythos: /* Siehe Auch */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== FAT 16/32 ==&lt;br /&gt;
&lt;br /&gt;
Dies ist eine freie FAT 16 / 32 Bibliothek.&lt;br /&gt;
&lt;br /&gt;
Die Bibliothek ist modular und besteht aus folgenden Modulen:&lt;br /&gt;
&lt;br /&gt;
* MMC/SD    (Hardware abhängig)&lt;br /&gt;
* FAT16/32  &lt;br /&gt;
* File&lt;br /&gt;
&lt;br /&gt;
das MMC/SD Modul ist dafür zuständig die Kommunikation mit der MMC/SD Karte zu managen und ist das einzige hardwareabhängige.&lt;br /&gt;
&lt;br /&gt;
das FAT16/32 Modul bietet die Grundlegenden Funktionen für den FAT Zugriff.&lt;br /&gt;
&lt;br /&gt;
das File Modul bietet Funktionen wie man sie von Datei Zugriffen kennt, wie z.B.&lt;br /&gt;
ffopen/ffclose um eine Datei zu öffnen oder um an eine Datei etwas anzuhängen und diese wieder zu schließen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== FAT 32 Grundlegendes ==&lt;br /&gt;
&lt;br /&gt;
Ein Dateisystem des Typs FAT besteht aus mehreren Bereichen.&lt;br /&gt;
FAT ist immer little Endian [http://de.wikipedia.org/wiki/Byte-Reihenfolge].&lt;br /&gt;
 &lt;br /&gt;
* Der erste Teil, der einem begegnet ist der Sektor 0 oder LBA, in dem alle wichtigen Informationen zum Auslesen des Dateisystems stehen.&lt;br /&gt;
* Dann die FAT selber, also die Dateizuordnungstabelle.&lt;br /&gt;
* Der dritte Teil ist der &amp;quot;Daten&amp;quot; Bereich.&lt;br /&gt;
&lt;br /&gt;
=== Sektor 0 oder LBA ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Sektor 0 (512 Byte) bei einer unpartitionierten Karte sieht wie folgt aus:&lt;br /&gt;
&lt;br /&gt;
[[Bild:sektor0.jpeg]]&lt;br /&gt;
&amp;lt;br&amp;gt;(Bild 1)&lt;br /&gt;
&lt;br /&gt;
Um das Dateisystem lesen zu können muss man wissen wo was steht. Die nötigsten Informationen sind: &lt;br /&gt;
&lt;br /&gt;
Sektoren pro Cluster (rot).&amp;lt;br&amp;gt;&lt;br /&gt;
Reservierte Sektoren nach Sektor 0 (orange).&amp;lt;br&amp;gt;&lt;br /&gt;
Anzahl der FATs (gelb).&amp;lt;br&amp;gt;&lt;br /&gt;
Wieviele Sektoren von einer FAT belegt werden (grün).&amp;lt;br&amp;gt;&lt;br /&gt;
Der Root-Dir Cluster (blau).&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Aus diesen Daten ergibt sich demnach:&lt;br /&gt;
&lt;br /&gt;
* 1. Sektor der 1. FAT ist Sektor 32 (Bild 2), also der erste Sektor nach den Reservierten (orange).&lt;br /&gt;
&lt;br /&gt;
* Der erste Daten Cluster ist 1003, weil die Anzahl der FATs 1 ist, also einmal die Sektoren, die von einer FAT belegt werden (grün) (00003cb=971) 971 + 32 (orange) = 1003.&lt;br /&gt;
&lt;br /&gt;
* Das Root-Dir ist Cluster 2, also Sektor 1003.&lt;br /&gt;
&lt;br /&gt;
* Die Anzahl der Sektoren pro Cluster ist 4 (2048 Bytes/Cluster).&lt;br /&gt;
&lt;br /&gt;
damit sind alle nötigen Daten vorhanden.&lt;br /&gt;
&lt;br /&gt;
Bei FAT Dateisystemen können mehrere Sektoren (512 Bytes) logisch zu Clustern zusammengeschlossen werden. Die rote Zahl gibt an wieviele Sektoren ein Cluster bilden. Der Daten Bereich wird immer in Clustern angegeben, das macht die Umrechnung von Sektoren zu Clustern nötig. In diesem Fall ist Cluster 2 der absolute Sektor 1003.&lt;br /&gt;
&lt;br /&gt;
=== Die FAT ===&lt;br /&gt;
&lt;br /&gt;
FAT bedeutet File Allocation Table ( Dateizuordnungstabelle ) und ist little Endian. Dateizuordnungstabelle beschreibt schon das Prinzip der FAT. &lt;br /&gt;
Kern des Dateisystems ist eine einfach verkettete Liste, in der festgehalten wird wo sich die Daten wie Ordner oder Dateien befinden. &lt;br /&gt;
Folgendes Bild zeigt den ersten FAT Sektor (512 Bytes) eines FAT32 Dateisystems (nicht den ersten Sektor der Karte!). Eingetragen sind: Root-Dir und zwei darin enthaltene Ordner sowie eine Datei mit 60.000 Byte Größe.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Bild:fat32.jpeg]]&lt;br /&gt;
&amp;lt;br&amp;gt;(Bild 2)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die Einträge 0-7 sind immer reserviert (Quasi Cluster 0 und 1)! Also beginnt die FAT ab 8 (rot)(Cluster Nummer 2). Der erste Eintrag (rot) ist 4 Byte groß und zu lesen von Stelle 8 zu Stelle 11 weil little Endian, also umgedrehte Wertigkeit. 8 niedrigste Wertigkeit, dann 9 eins höher, 10 noch eine höher und 11 höchste (dazu später noch ein Beispiel).&amp;lt;br&amp;gt;&lt;br /&gt;
Wie von Microsoft empfohlen ist der erste mögliche Cluster das Root-Dir hier rot und nur einen Cluster lang.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
An den gelben Einträgen wird die einfach verkettete Liste der FAT deutlich. Der erste gelbe Eintag steht an der Stelle des Clusters Nummer 5 und hat als Inhalt eine 6. Das bedeutet: Cluster 5 und 6 gehören zusammen. Würde an der Stelle des Clusters Nummer 5 ein FFFFFFF0 stehen (little Endian) ist nur der Cluster 5 mit Daten belegt (wie bei rot, blau und grün). So tastet man sich vom 1. Cluster einer Datei zum Ende der Datei vor. Das ist der einzige Zweck der FAT.&amp;lt;br&amp;gt;&lt;br /&gt;
Woher bekommt man aber den 1. Cluster einer Datei?&lt;br /&gt;
&lt;br /&gt;
=== Daten Bereich ===&lt;br /&gt;
&lt;br /&gt;
Folgendes Bild zeigt den Inhalt eines Ordners/Dirs (Cluster 4) :&lt;br /&gt;
&lt;br /&gt;
[[Bild:Data.jpeg]]&lt;br /&gt;
&amp;lt;br&amp;gt;(Bild 3)&lt;br /&gt;
&lt;br /&gt;
Ein Dateieintrag besteht aus 32 Bytes und liegt im Datenbereich des Dateisystems ( 32Byte = eine Zeile). &amp;lt;br&amp;gt;&lt;br /&gt;
Die dritte Zeile des Bilds zeigt eine Datei namens TEST3.TXT (grün) mit 60.000 kBytes Größe (blau) und dem 1. Cluster 5 (rot)(Folgecluster siehe Bild 2).&amp;lt;br&amp;gt;&lt;br /&gt;
Speziell ist hier, dass die 4 Bytes des ersten Clusters aufgeteilt sind auf 2 unterschiedliche &amp;quot;Orte&amp;quot; im 32 Byte Eintrag (Wertigkeit: 26:27:20:21). &amp;lt;br&amp;gt;&lt;br /&gt;
Um nun die Daten der Datei lesen zu können, muss man die weiteren Cluster kennen. Dazu sieht man in der FAT nach, an der Stelle 5 (siehe Bild 2). Dort steht der Folgecluster der Datei (Cluster 6). Wenn in der FAT der letzte Cluster erreicht ist (FFFFFFF0), liest man den letzten Sektor bis man die Größe der Datei (blau) gelesen hat und ist fertig.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
bald mehr...&lt;br /&gt;
&lt;br /&gt;
== Der Source Code der Lib ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* Sourcecode: http://www.mikrocontroller.net/attachment/40180/mmc-0.4.6.zip&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Siehe Auch ==&lt;br /&gt;
&lt;br /&gt;
* Thread:  http://www.mikrocontroller.net/topic/105869#new&lt;br /&gt;
&lt;br /&gt;
* Infos (englisch):  https://www.pjrc.com/tech/8051/ide/fat32.html&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Weitere Projekte mit FAT/SD-CARD:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* [http://www.roland-riegel.de/sd-reader/index.html MMC/SD card reader example application]&lt;/div&gt;</summary>
		<author><name>Thymythos</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=RFM12_Protokoll_Stack&amp;diff=30333</id>
		<title>RFM12 Protokoll Stack</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=RFM12_Protokoll_Stack&amp;diff=30333"/>
		<updated>2008-08-16T17:11:10Z</updated>

		<summary type="html">&lt;p&gt;Thymythos: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Bild:RFM12 Stack.svg|right]]&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel beschreibt einen [http://de.wikipedia.org/wiki/ISO/OSI ISO/OSI] Protokoll [http://de.wikipedia.org/wiki/Protokollstack Stack] für den [[RFM12]] Funkchip.&amp;lt;br/&amp;gt;&lt;br /&gt;
Einige Hardwarebeispiele finden sich in [[AVR RFM12]].&amp;lt;br/&amp;gt;&lt;br /&gt;
Fehler und Anregungen können gerne auf der [[Diskussion:RFM12_Protokoll_Stack|Diskussionsseite]] besprochen werden.&lt;br /&gt;
&lt;br /&gt;
Eine Referenz-Implementierung für den [[AVR]] wird bereitgestellt:&lt;br /&gt;
{| style=&amp;quot;border:1px dashed green&amp;quot;&lt;br /&gt;
|&#039;&#039;svn://mikrocontroller.net/rfm12/trunk/RFM12_Stack&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
;Implementierungskriterien&lt;br /&gt;
* Wo möglich werden [http://de.wikipedia.org/wiki/R%C3%BCckruffunktion Callback]-Funktionen anstatt [http://de.wikipedia.org/wiki/First_In_%E2%80%93_First_Out FIFOs] verwendet um RAM zu sparen.&lt;br /&gt;
* Interruptgesteuerter Ablauf des Stacks&lt;br /&gt;
* Funktionen sollten nicht blockieren&lt;br /&gt;
&lt;br /&gt;
== Layer 1: Physical ==&lt;br /&gt;
&lt;br /&gt;
[[Bild:RFM12 PHY StateMachine.svg|thumb|320px|Layer1 State Diagram]]&lt;br /&gt;
&lt;br /&gt;
Der Physical-Layer kümmert sich um die direkte Ansteuerung des RFM12. Alle Funktionen des Chips werden als Software-API bereitgestellt.&lt;br /&gt;
&lt;br /&gt;
Folgende Eigenschaften sind bereits vom RFM12 vorgegeben:&lt;br /&gt;
&lt;br /&gt;
* [http://de.wikipedia.org/wiki/ISM-Band 70cm Band (433MHz)]&lt;br /&gt;
* [http://de.wikipedia.org/wiki/Frequenzumtastung FSK]-Modulation&lt;br /&gt;
* Sync-Erkennung auf &#039;&#039;0x2D 0xD4&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Definiert werden muss jedoch noch:&lt;br /&gt;
&lt;br /&gt;
* Baudrate&lt;br /&gt;
* Zuordnung von Frequenzen zu [[#Kanalzuordnung|Kanälen]]&lt;br /&gt;
* Bandbreite der Kanäle&lt;br /&gt;
* Management der Sendeleistung/Empfangsempfindlichkeit&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;API&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
void RFM12_PHY_modeTX(void);&lt;br /&gt;
&lt;br /&gt;
void RFM12_PHY_modeRX(void);&lt;br /&gt;
&lt;br /&gt;
bool RFM12_PHY_busy(void);&lt;br /&gt;
&lt;br /&gt;
void RFM12_setBaudrate(uint32_t baud);&lt;br /&gt;
&lt;br /&gt;
void RFM12_setCenterFrequency(uint16_t freq);&lt;br /&gt;
&lt;br /&gt;
void RFM12_setDataFilter(bool autoLock, bool fastMode, bool analog, uint8_t dqdThres);&lt;br /&gt;
&lt;br /&gt;
void RFM12_setReceiverBandwidth(RFM12_VDI_t vdi, RFM12_RxBW_t bandwidth, RFM12_GAIN_t gain, RFM12_RSSI_t drssi);&lt;br /&gt;
&lt;br /&gt;
void RFM12_setPowerManagement(bool enRX, bool enBB, bool startTX, bool enSynth, bool enOSC, bool enBat, bool enWkT, bool clkOff);&lt;br /&gt;
&lt;br /&gt;
void RFM12_setTransmitPower(RFM12_Power_t power, RFM12_TxDev_t deviation);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Layer 2: Data Link ==&lt;br /&gt;
&lt;br /&gt;
=== Media Access Control (MAC) ===&lt;br /&gt;
&lt;br /&gt;
Der MAC-Layer ist sehr einfach gehalten und regelt den Zugriff auf das Medium. Hier soll ein [http://de.wikipedia.org/wiki/CSMA-CA CSMA/CA] Verfahren eingesetzt werden.&lt;br /&gt;
&lt;br /&gt;
# Im Grundzustand befindet sich der RFM12 im Empfangsmodus und wartet auf eine SYNC-Sequenz.&lt;br /&gt;
# Kommt eine Sendeanforderung, wird so lange gewartet bis das Medium frei ist, dann darf nach Ablauf einer (pseudo) zufälligen Zeitspanne gesendet werden.&lt;br /&gt;
# Wurde gerade ein Paket empfangen, darf sofort ein ACK gesendet werden.&lt;br /&gt;
&lt;br /&gt;
Der Frameaufbau ist teilweise vom RFM12 vorgegeben (SYNC-Erkennung). Der Start-Of-Frame (SOF) dient der Synchronisation. Als End-Of-Frame (EOF) wird ebenfalls die Sequenz &#039;&#039;0xAA&#039;&#039; verwendet. Diese darf im Datenteil nicht vorkommen!&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|+ MAC Frameaufbau&lt;br /&gt;
|-&lt;br /&gt;
!&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; | SOF&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; | Sync&lt;br /&gt;
! &#039;&#039;n Byte Daten&#039;&#039;&lt;br /&gt;
! EOF&lt;br /&gt;
|----&lt;br /&gt;
! Bits&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; | 16 || colspan=&amp;quot;2&amp;quot; | 16 || 0 - 512    || 8&lt;br /&gt;
|----&lt;br /&gt;
! Wert&lt;br /&gt;
| 0xAA || 0xAA     || 0x2D || 0xD4     || &#039;&#039;Daten&#039;&#039;  || 0xAA&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;API&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
void RFM12_MAC_setChannel(uint8_t channel);&lt;br /&gt;
&lt;br /&gt;
bool RFM12_MAC_isReceiving(void);&lt;br /&gt;
&lt;br /&gt;
bool RFM12_MAC_mediaBusy(void);&lt;br /&gt;
&lt;br /&gt;
void RFM12_MAC_startCtrlTransmission(void);&lt;br /&gt;
&lt;br /&gt;
void RFM12_MAC_endCtrlTransmission(void);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Logical Link Control (LLC) ===&lt;br /&gt;
&lt;br /&gt;
Der LLC-Layer kümmert sich um die Sicherung der zu übertragenden Daten.&lt;br /&gt;
Außerdem können Geräte direkt mit ihrer Adresse (8-Bit) angesprochen werden.&lt;br /&gt;
&lt;br /&gt;
;[http://de.wikipedia.org/wiki/Vorw%C3%A4rtsfehlerkorrektur FEC]&lt;br /&gt;
:Alle Bytes werden auf eine [[#Hamming-Tabelle|16-Bit Hamming-Sequenz]] erweitert, wodurch die Datenrate halbiert wird.&lt;br /&gt;
:Dies erlaubt es einzelne Bitfehler zu korrigieren.&lt;br /&gt;
:Bei zu vielen Fehlern können diese jedoch nicht erkannt werden.&lt;br /&gt;
:Im Hamming-Code kommt die Sequenz &#039;&#039;0xAA&#039;&#039; nicht vor (siehe MAC-Layer).&lt;br /&gt;
&lt;br /&gt;
;[http://de.wikipedia.org/wiki/Cyclic_Redundancy_Check CRC]&lt;br /&gt;
:Der gesamte Frame wird nochmals durch eine Checksumme gesichert. (CRC-8: &#039;&#039;x&amp;lt;sup&amp;gt;8&amp;lt;/sup&amp;gt; + x&amp;lt;sup&amp;gt;5&amp;lt;/sup&amp;gt; + x&amp;lt;sup&amp;gt;4&amp;lt;/sup&amp;gt; + 1&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Es werden mehrere Frame-Typen zur Verfügung gestellt:&lt;br /&gt;
&lt;br /&gt;
* Broadcast an alle Geräte (immer ohne ACK)&lt;br /&gt;
* Nachricht an ein bestimmtes Gerät (mit oder ohne ACK)&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|+ LLC Frameaufbau&lt;br /&gt;
|-&lt;br /&gt;
!&lt;br /&gt;
! Empfänger&lt;br /&gt;
! Sender&lt;br /&gt;
! need ACK&lt;br /&gt;
! is ACK&lt;br /&gt;
!&lt;br /&gt;
!&lt;br /&gt;
! TypeID&lt;br /&gt;
! &#039;&#039;n Byte Daten&#039;&#039;&lt;br /&gt;
! CRC-8&lt;br /&gt;
|----&lt;br /&gt;
! Bits&lt;br /&gt;
| 8      || 8      || 1 || 1 || 1 || 1 || 4 || 0-480 || 8&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039; API &#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
void RFM12_LLC_registerType(RFM12_ProtocolID_t typeID, RFM12_L3_Protocol_t proto);&lt;br /&gt;
&lt;br /&gt;
uint8_t RFM12_LLC_sendFrame(RFM12_ProtocolID_t proto, uint8_t receiver, bool requireACK);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Layer 3: Network ==&lt;br /&gt;
&lt;br /&gt;
Für den Network-Layer werden nur einige Beispiele angeführt. Ab hier können beliebige eigene Protokolle eingesetzt werden. Das verwendete Protokoll wird durch die &#039;&#039;TypeID&#039;&#039; im LLC-Layer angegeben. Die Layer-3-Protokolle sollten nach Möglichkeit nur über die LLC-API mit dem Rest des Stacks kommunizieren.&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;TypeID&#039;&#039;s sind wie folgt definiert:&lt;br /&gt;
&lt;br /&gt;
=== Typ 0: Management ===&lt;br /&gt;
&lt;br /&gt;
Management Protokoll: Beacons etc.&lt;br /&gt;
&lt;br /&gt;
=== Typ 1: Bytestream ===&lt;br /&gt;
&lt;br /&gt;
Die Einteilung in Pakete wird aufgehoben. Daten kommen 1:1 in der Reihenfolge an, wie sie gesendet wurden.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;API&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
void RFM12_Serial_setPeer(uint8_t peer);&lt;br /&gt;
&lt;br /&gt;
bool RFM12_Serial_txAvailable(void);&lt;br /&gt;
&lt;br /&gt;
void RFM12_Serial_txData(uint8_t data);&lt;br /&gt;
&lt;br /&gt;
bool RFM12_Serial_rxAvailable(void);&lt;br /&gt;
&lt;br /&gt;
uint8_t RFM12_Serial_rxData(void);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Typ 3: IPv4 ===&lt;br /&gt;
&lt;br /&gt;
z.B. [http://www.sics.se/~adam/uip/index.php/Main_Page uIP TCP/IP Stack] von Adam Dunkels &amp;lt;adam@dunkels.com&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Anhänge ==&lt;br /&gt;
&lt;br /&gt;
=== Sequenzdiagramme ===&lt;br /&gt;
&lt;br /&gt;
Empfang:&lt;br /&gt;
[[Bild:RFM12 RX Sequence.svg|center|800px|RX Sequenz]]&lt;br /&gt;
&lt;br /&gt;
Senden:&lt;br /&gt;
[[Bild:RFM12 TX Sequence.svg|center|800px|TX Sequenz]]&lt;br /&gt;
&lt;br /&gt;
=== Frames ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Beachte:&#039;&#039;&#039; Durch die Hamming-Codierung sind alle Bytes innerhalb des MAC-Layer doppelt so lang wie angegeben!&lt;br /&gt;
{|&lt;br /&gt;
! bgcolor=&amp;quot;#9fffa8&amp;quot; | MAC || bgcolor=&amp;quot;#a9f3f2&amp;quot; | LLC || bgcolor=&amp;quot;#d28787&amp;quot; | L3&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; align=&amp;quot;center&amp;quot; style=&amp;quot;text-align:center&amp;quot;&lt;br /&gt;
|+ Frameaufbau&lt;br /&gt;
|-&lt;br /&gt;
!&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; bgcolor=&amp;quot;#9fffa8&amp;quot; | SOF&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; bgcolor=&amp;quot;#9fffa8&amp;quot; | Sync&lt;br /&gt;
! bgcolor=&amp;quot;#a9f3f2&amp;quot; | Empfänger&lt;br /&gt;
! bgcolor=&amp;quot;#a9f3f2&amp;quot; | Sender&lt;br /&gt;
! bgcolor=&amp;quot;#a9f3f2&amp;quot; | need ACK | is ACK | | | TypeID&lt;br /&gt;
! bgcolor=&amp;quot;#d28787&amp;quot; | &#039;&#039;n Byte Daten&#039;&#039;&lt;br /&gt;
! bgcolor=&amp;quot;#a9f3f2&amp;quot; | CRC-8&lt;br /&gt;
! bgcolor=&amp;quot;#9fffa8&amp;quot; | EOF&lt;br /&gt;
|----&lt;br /&gt;
! Bits&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; bgcolor=&amp;quot;#9fffa8&amp;quot; | 16 || colspan=&amp;quot;2&amp;quot; bgcolor=&amp;quot;#9fffa8&amp;quot; | 16&lt;br /&gt;
| bgcolor=&amp;quot;#a9f3f2&amp;quot; | 8 || bgcolor=&amp;quot;#a9f3f2&amp;quot; | 8 || bgcolor=&amp;quot;#a9f3f2&amp;quot; | &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; 1 &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; | &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; 1 &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; |1|1| &amp;amp;nbsp;&amp;amp;nbsp; 4 &amp;amp;nbsp;&amp;amp;nbsp;&lt;br /&gt;
| bgcolor=&amp;quot;#d28787&amp;quot; | 0-480&lt;br /&gt;
| bgcolor=&amp;quot;#a9f3f2&amp;quot; | 8&lt;br /&gt;
| bgcolor=&amp;quot;#9fffa8&amp;quot; | 8&lt;br /&gt;
|----&lt;br /&gt;
! Wert&lt;br /&gt;
| bgcolor=&amp;quot;#9fffa8&amp;quot; | 0xAA || bgcolor=&amp;quot;#9fffa8&amp;quot; | 0xAA || bgcolor=&amp;quot;#9fffa8&amp;quot; | 0x2D || bgcolor=&amp;quot;#9fffa8&amp;quot; | 0xD4&lt;br /&gt;
| bgcolor=&amp;quot;#a9f3f2&amp;quot; | || bgcolor=&amp;quot;#a9f3f2&amp;quot; | || bgcolor=&amp;quot;#a9f3f2&amp;quot; | &lt;br /&gt;
| bgcolor=&amp;quot;#d28787&amp;quot; | &lt;br /&gt;
| bgcolor=&amp;quot;#a9f3f2&amp;quot; |&lt;br /&gt;
| bgcolor=&amp;quot;#9fffa8&amp;quot; | 0xAA&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Kanalzuordnung ===&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|+ 433MHz Band&lt;br /&gt;
|-&lt;br /&gt;
! Kanal&lt;br /&gt;
| 0 || 1 || 2 || 3 || 4 || 5 || 6 || 7 || 8 || 9 || 10 || 11 || 12 || 13 || 14 || 15&lt;br /&gt;
|-&lt;br /&gt;
! Mittenfrequenz&lt;br /&gt;
|  431.0 || 431.5 || 432.0 || 432.5 || 433.0 || 433.5 || 434.0 || 434.5 || 435.0 || 435.5 || 436.0 || 436.5 || 437.0 || 437.5 || 438.0 || 438.5&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Hamming-Tabelle ===&lt;br /&gt;
&lt;br /&gt;
==== Encodieren ====&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;3&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|&lt;br /&gt;
! colspan=&amp;quot;4&amp;quot; | Algorithmus&lt;br /&gt;
! colspan=&amp;quot;4&amp;quot; | Beispiel&lt;br /&gt;
|-&lt;br /&gt;
| 1:&lt;br /&gt;
| width=&amp;quot;80&amp;quot; |&lt;br /&gt;
| width=&amp;quot;160&amp;quot; colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 8-Bit Wert&lt;br /&gt;
| width=&amp;quot;160&amp;quot; colspan=&amp;quot;2&amp;quot; |&lt;br /&gt;
| width=&amp;quot;160&amp;quot; colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 10010110&lt;br /&gt;
| width=&amp;quot;80&amp;quot; |&lt;br /&gt;
|-&lt;br /&gt;
| 2: || || align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 4-7 ||  align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 0-3 || colspan=&amp;quot;2&amp;quot; | ||  align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 1001 || align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 0110 || &lt;br /&gt;
|-&lt;br /&gt;
| 3:&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | HammingE[(4-7)]&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | HammingE[(0-3)]&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 0xC7&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 0x38&lt;br /&gt;
|-&lt;br /&gt;
| 4:&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | high&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | low&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 11000111&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 00111000&lt;br /&gt;
|-&lt;br /&gt;
| 5:&lt;br /&gt;
| colspan=&amp;quot;4&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 16-Bit Codewort&lt;br /&gt;
| colspan=&amp;quot;4&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 11000111 00111000&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;3&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|+ HammingE&lt;br /&gt;
|-&lt;br /&gt;
!  0 || 1 || 2  || 3 || 4 || 5 || 6 || 7 || 8 || 9 || A || B || C || D || E || F&lt;br /&gt;
|-&lt;br /&gt;
|bgcolor=&amp;quot;#f00&amp;quot;|0x15||bgcolor=&amp;quot;#f11&amp;quot;|0x02||bgcolor=&amp;quot;#f22&amp;quot;|0x49||bgcolor=&amp;quot;#f33&amp;quot;|0x5E||bgcolor=&amp;quot;#f44&amp;quot;|0x64||bgcolor=&amp;quot;#f55&amp;quot;|0x73||bgcolor=&amp;quot;#f66&amp;quot;|0x38||bgcolor=&amp;quot;#f77&amp;quot;|0x2F||bgcolor=&amp;quot;#f88&amp;quot;|0xD0||bgcolor=&amp;quot;#f99&amp;quot;|0xC7||bgcolor=&amp;quot;#faa&amp;quot;|0x8C||bgcolor=&amp;quot;#fbb&amp;quot;|0x9B||bgcolor=&amp;quot;#fcc&amp;quot;|0xA1||bgcolor=&amp;quot;#fdd&amp;quot;|0xB6||bgcolor=&amp;quot;#fee&amp;quot;|0xFD||bgcolor=&amp;quot;#fff&amp;quot;|0xEA&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Die Einträge in der Tabelle sind so gewählt, dass der Code den maximalen [http://de.wikipedia.org/wiki/Hamming-Abstand#Hamming-Abstand_eines_Codes Hamming-Abstand] von 4 Bit hat.&lt;br /&gt;
&lt;br /&gt;
==== Dekodieren ====&lt;br /&gt;
&lt;br /&gt;
In der Tabelle &#039;&#039;HammingD&#039;&#039; stehen nur 4-Bit breite Werte. Um einen 8-Bit Wert zu erhalten müssen also 2 Einträge aus der Tabelle ausgewählt werden.&lt;br /&gt;
&lt;br /&gt;
Wird nun ein 16-Bit Wert empfangen, bestimmt das High-Byte den ersten Eintrag, das Low-Byte den zweiten.&lt;br /&gt;
&lt;br /&gt;
Es können bis zu zwei gekippte Bits im High- und im Low-Byte korrigiert werden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;3&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|&lt;br /&gt;
! colspan=&amp;quot;4&amp;quot; | Algorithmus || colspan=&amp;quot;4&amp;quot; | Beispiel (mit Bitfehlern)&lt;br /&gt;
|-&lt;br /&gt;
| 1:&lt;br /&gt;
| colspan=&amp;quot;4&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 16-Bit Codewort&lt;br /&gt;
| colspan=&amp;quot;4&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 110&#039;&#039;&#039;1&#039;&#039;&#039;0111 001&#039;&#039;&#039;0&#039;&#039;&#039;100&#039;&#039;&#039;1&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 2:&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | high&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | low&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 110&#039;&#039;&#039;1&#039;&#039;&#039;0111&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 001&#039;&#039;&#039;0&#039;&#039;&#039;100&#039;&#039;&#039;1&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 3:&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | HammingD[high]&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | HammingD[low]&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 0x09&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 0x06&lt;br /&gt;
|-&lt;br /&gt;
| 4: || || align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 4-7&lt;br /&gt;
| align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 0-3 || &lt;br /&gt;
| || align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 1001&lt;br /&gt;
| align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 0110 || &lt;br /&gt;
|-&lt;br /&gt;
| 5:&lt;br /&gt;
| width=&amp;quot;80&amp;quot; |&lt;br /&gt;
| width=&amp;quot;160&amp;quot; colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightblue&amp;quot; | 8-Bit Wert&lt;br /&gt;
| width=&amp;quot;80&amp;quot; | || width=&amp;quot;80&amp;quot; |&lt;br /&gt;
| width=&amp;quot;160&amp;quot; colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; bgcolor=&amp;quot;lightgreen&amp;quot; | 10010110&lt;br /&gt;
| width=&amp;quot;80&amp;quot; |&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;3&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|+ HammingD&lt;br /&gt;
|-&lt;br /&gt;
!  || 0 || 1 || 2  || 3 || 4 || 5 || 6 || 7 || 8 || 9 || A || B || C || D || E || F&lt;br /&gt;
|-&lt;br /&gt;
! 0&lt;br /&gt;
|bgcolor=&amp;quot;#f11&amp;quot;|0x01||bgcolor=&amp;quot;#f00&amp;quot;|0x00||bgcolor=&amp;quot;#f11&amp;quot;|0x01||bgcolor=&amp;quot;#f11&amp;quot;|0x01||bgcolor=&amp;quot;#f00&amp;quot;|0x00||bgcolor=&amp;quot;#f00&amp;quot;|0x00||bgcolor=&amp;quot;#f11&amp;quot;|0x01||bgcolor=&amp;quot;#f11&amp;quot;|0x01||bgcolor=&amp;quot;#f22&amp;quot;|0x02||bgcolor=&amp;quot;#f22&amp;quot;|0x02||bgcolor=&amp;quot;#f11&amp;quot;|0x01||bgcolor=&amp;quot;#f33&amp;quot;|0x03||bgcolor=&amp;quot;#fAA&amp;quot;|0x0A||bgcolor=&amp;quot;#f22&amp;quot;|0x02||bgcolor=&amp;quot;#f33&amp;quot;|0x03||bgcolor=&amp;quot;#f77&amp;quot;|0x07&lt;br /&gt;
|-&lt;br /&gt;
! 1&lt;br /&gt;
|bgcolor=&amp;quot;#f00&amp;quot;|0x00||bgcolor=&amp;quot;#f00&amp;quot;|0x00||bgcolor=&amp;quot;#f11&amp;quot;|0x01||bgcolor=&amp;quot;#f11&amp;quot;|0x01||bgcolor=&amp;quot;#f00&amp;quot;|0x00||bgcolor=&amp;quot;#f00&amp;quot;|0x00||bgcolor=&amp;quot;#f11&amp;quot;|0x01||bgcolor=&amp;quot;#f00&amp;quot;|0x00||bgcolor=&amp;quot;#f66&amp;quot;|0x06||bgcolor=&amp;quot;#f22&amp;quot;|0x02||bgcolor=&amp;quot;#f33&amp;quot;|0x03||bgcolor=&amp;quot;#fBB&amp;quot;|0x0B||bgcolor=&amp;quot;#f22&amp;quot;|0x02||bgcolor=&amp;quot;#f00&amp;quot;|0x00||bgcolor=&amp;quot;#f33&amp;quot;|0x03||bgcolor=&amp;quot;#f33&amp;quot;|0x03&lt;br /&gt;
|-&lt;br /&gt;
! 2&lt;br /&gt;
|bgcolor=&amp;quot;#f44&amp;quot;|0x04||bgcolor=&amp;quot;#fCC&amp;quot;|0x0C||bgcolor=&amp;quot;#f11&amp;quot;|0x01||bgcolor=&amp;quot;#f55&amp;quot;|0x05||bgcolor=&amp;quot;#f44&amp;quot;|0x04||bgcolor=&amp;quot;#f44&amp;quot;|0x04||bgcolor=&amp;quot;#f55&amp;quot;|0x05||bgcolor=&amp;quot;#f77&amp;quot;|0x07||bgcolor=&amp;quot;#f66&amp;quot;|0x06||bgcolor=&amp;quot;#f66&amp;quot;|0x06||bgcolor=&amp;quot;#f77&amp;quot;|0x07||bgcolor=&amp;quot;#f77&amp;quot;|0x07||bgcolor=&amp;quot;#f66&amp;quot;|0x06||bgcolor=&amp;quot;#f77&amp;quot;|0x07||bgcolor=&amp;quot;#f77&amp;quot;|0x07||bgcolor=&amp;quot;#f77&amp;quot;|0x07&lt;br /&gt;
|-&lt;br /&gt;
! 3&lt;br /&gt;
|bgcolor=&amp;quot;#f66&amp;quot;|0x06||bgcolor=&amp;quot;#f44&amp;quot;|0x04||bgcolor=&amp;quot;#f55&amp;quot;|0x05||bgcolor=&amp;quot;#f55&amp;quot;|0x05||bgcolor=&amp;quot;#f44&amp;quot;|0x04||bgcolor=&amp;quot;#f00&amp;quot;|0x00||bgcolor=&amp;quot;#fDD&amp;quot;|0x0D||bgcolor=&amp;quot;#f55&amp;quot;|0x05||bgcolor=&amp;quot;#f66&amp;quot;|0x06||bgcolor=&amp;quot;#f66&amp;quot;|0x06||bgcolor=&amp;quot;#f66&amp;quot;|0x06||bgcolor=&amp;quot;#f77&amp;quot;|0x07||bgcolor=&amp;quot;#f66&amp;quot;|0x06||bgcolor=&amp;quot;#f66&amp;quot;|0x06||bgcolor=&amp;quot;#f77&amp;quot;|0x07||bgcolor=&amp;quot;#f77&amp;quot;|0x07&lt;br /&gt;
|-&lt;br /&gt;
! 4&lt;br /&gt;
|bgcolor=&amp;quot;#f00&amp;quot;|0x00||bgcolor=&amp;quot;#f22&amp;quot;|0x02||bgcolor=&amp;quot;#f11&amp;quot;|0x01||bgcolor=&amp;quot;#f11&amp;quot;|0x01||bgcolor=&amp;quot;#f44&amp;quot;|0x04||bgcolor=&amp;quot;#f00&amp;quot;|0x00||bgcolor=&amp;quot;#f11&amp;quot;|0x01||bgcolor=&amp;quot;#f99&amp;quot;|0x09||bgcolor=&amp;quot;#f22&amp;quot;|0x02||bgcolor=&amp;quot;#f22&amp;quot;|0x02||bgcolor=&amp;quot;#f33&amp;quot;|0x03||bgcolor=&amp;quot;#f22&amp;quot;|0x02||bgcolor=&amp;quot;#f22&amp;quot;|0x02||bgcolor=&amp;quot;#f22&amp;quot;|0x02||bgcolor=&amp;quot;#f33&amp;quot;|0x03||bgcolor=&amp;quot;#f33&amp;quot;|0x03&lt;br /&gt;
|-&lt;br /&gt;
! 5&lt;br /&gt;
|bgcolor=&amp;quot;#f88&amp;quot;|0x08||bgcolor=&amp;quot;#f00&amp;quot;|0x00||bgcolor=&amp;quot;#f11&amp;quot;|0x01||bgcolor=&amp;quot;#f55&amp;quot;|0x05||bgcolor=&amp;quot;#f00&amp;quot;|0x00||bgcolor=&amp;quot;#f00&amp;quot;|0x00||bgcolor=&amp;quot;#f33&amp;quot;|0x03||bgcolor=&amp;quot;#f11&amp;quot;|0x01||bgcolor=&amp;quot;#f22&amp;quot;|0x02||bgcolor=&amp;quot;#f22&amp;quot;|0x02||bgcolor=&amp;quot;#f33&amp;quot;|0x03||bgcolor=&amp;quot;#f33&amp;quot;|0x03||bgcolor=&amp;quot;#f33&amp;quot;|0x03||bgcolor=&amp;quot;#f22&amp;quot;|0x02||bgcolor=&amp;quot;#f33&amp;quot;|0x03||bgcolor=&amp;quot;#f33&amp;quot;|0x03&lt;br /&gt;
|-&lt;br /&gt;
! 6&lt;br /&gt;
|bgcolor=&amp;quot;#f44&amp;quot;|0x04||bgcolor=&amp;quot;#f44&amp;quot;|0x04||bgcolor=&amp;quot;#f55&amp;quot;|0x05||bgcolor=&amp;quot;#f55&amp;quot;|0x05||bgcolor=&amp;quot;#f44&amp;quot;|0x04||bgcolor=&amp;quot;#f44&amp;quot;|0x04||bgcolor=&amp;quot;#f44&amp;quot;|0x04||bgcolor=&amp;quot;#f55&amp;quot;|0x05||bgcolor=&amp;quot;#f66&amp;quot;|0x06||bgcolor=&amp;quot;#f22&amp;quot;|0x02||bgcolor=&amp;quot;#fFF&amp;quot;|0x0F||bgcolor=&amp;quot;#f77&amp;quot;|0x07||bgcolor=&amp;quot;#f44&amp;quot;|0x04||bgcolor=&amp;quot;#f66&amp;quot;|0x06||bgcolor=&amp;quot;#f77&amp;quot;|0x07||bgcolor=&amp;quot;#f77&amp;quot;|0x07&lt;br /&gt;
|-&lt;br /&gt;
! 7&lt;br /&gt;
|bgcolor=&amp;quot;#f44&amp;quot;|0x04||bgcolor=&amp;quot;#f55&amp;quot;|0x05||bgcolor=&amp;quot;#f55&amp;quot;|0x05||bgcolor=&amp;quot;#f55&amp;quot;|0x05||bgcolor=&amp;quot;#f44&amp;quot;|0x04||bgcolor=&amp;quot;#f44&amp;quot;|0x04||bgcolor=&amp;quot;#f55&amp;quot;|0x05||bgcolor=&amp;quot;#f55&amp;quot;|0x05||bgcolor=&amp;quot;#f66&amp;quot;|0x06||bgcolor=&amp;quot;#f66&amp;quot;|0x06||bgcolor=&amp;quot;#f77&amp;quot;|0x07||bgcolor=&amp;quot;#f55&amp;quot;|0x05||bgcolor=&amp;quot;#f66&amp;quot;|0x06||bgcolor=&amp;quot;#fEE&amp;quot;|0x0E||bgcolor=&amp;quot;#f33&amp;quot;|0x03||bgcolor=&amp;quot;#f77&amp;quot;|0x07&lt;br /&gt;
|-&lt;br /&gt;
! 8&lt;br /&gt;
|bgcolor=&amp;quot;#f88&amp;quot;|0x08||bgcolor=&amp;quot;#fCC&amp;quot;|0x0C||bgcolor=&amp;quot;#f11&amp;quot;|0x01||bgcolor=&amp;quot;#f99&amp;quot;|0x09||bgcolor=&amp;quot;#fAA&amp;quot;|0x0A||bgcolor=&amp;quot;#f88&amp;quot;|0x08||bgcolor=&amp;quot;#f99&amp;quot;|0x09||bgcolor=&amp;quot;#f99&amp;quot;|0x09||bgcolor=&amp;quot;#fAA&amp;quot;|0x0A||bgcolor=&amp;quot;#fAA&amp;quot;|0x0A||bgcolor=&amp;quot;#fBB&amp;quot;|0x0B||bgcolor=&amp;quot;#fBB&amp;quot;|0x0B||bgcolor=&amp;quot;#fAA&amp;quot;|0x0A||bgcolor=&amp;quot;#fAA&amp;quot;|0x0A||bgcolor=&amp;quot;#fAA&amp;quot;|0x0A||bgcolor=&amp;quot;#fBB&amp;quot;|0x0B&lt;br /&gt;
|-&lt;br /&gt;
! 9&lt;br /&gt;
|bgcolor=&amp;quot;#f88&amp;quot;|0x08||bgcolor=&amp;quot;#f88&amp;quot;|0x08||bgcolor=&amp;quot;#f99&amp;quot;|0x09||bgcolor=&amp;quot;#fBB&amp;quot;|0x0B||bgcolor=&amp;quot;#f88&amp;quot;|0x08||bgcolor=&amp;quot;#f00&amp;quot;|0x00||bgcolor=&amp;quot;#fDD&amp;quot;|0x0D||bgcolor=&amp;quot;#f99&amp;quot;|0x09||bgcolor=&amp;quot;#fAA&amp;quot;|0x0A||bgcolor=&amp;quot;#fBB&amp;quot;|0x0B||bgcolor=&amp;quot;#fBB&amp;quot;|0x0B||bgcolor=&amp;quot;#fBB&amp;quot;|0x0B||bgcolor=&amp;quot;#fAA&amp;quot;|0x0A||bgcolor=&amp;quot;#fAA&amp;quot;|0x0A||bgcolor=&amp;quot;#fBB&amp;quot;|0x0B||bgcolor=&amp;quot;#fBB&amp;quot;|0x0B&lt;br /&gt;
|-&lt;br /&gt;
! A&lt;br /&gt;
|bgcolor=&amp;quot;#fCC&amp;quot;|0x0C||bgcolor=&amp;quot;#fCC&amp;quot;|0x0C||bgcolor=&amp;quot;#fDD&amp;quot;|0x0D||bgcolor=&amp;quot;#fCC&amp;quot;|0x0C||bgcolor=&amp;quot;#fCC&amp;quot;|0x0C||bgcolor=&amp;quot;#fCC&amp;quot;|0x0C||bgcolor=&amp;quot;#fDD&amp;quot;|0x0D||bgcolor=&amp;quot;#fDD&amp;quot;|0x0D||bgcolor=&amp;quot;#fEE&amp;quot;|0x0E||bgcolor=&amp;quot;#fCC&amp;quot;|0x0C||bgcolor=&amp;quot;#fFF&amp;quot;|0x0F||bgcolor=&amp;quot;#fFF&amp;quot;|0x0F||bgcolor=&amp;quot;#fAA&amp;quot;|0x0A||bgcolor=&amp;quot;#fEE&amp;quot;|0x0E||bgcolor=&amp;quot;#fFF&amp;quot;|0x0F||bgcolor=&amp;quot;#f77&amp;quot;|0x07&lt;br /&gt;
|-&lt;br /&gt;
! B&lt;br /&gt;
|bgcolor=&amp;quot;#fCC&amp;quot;|0x0C||bgcolor=&amp;quot;#fCC&amp;quot;|0x0C||bgcolor=&amp;quot;#fDD&amp;quot;|0x0D||bgcolor=&amp;quot;#fDD&amp;quot;|0x0D||bgcolor=&amp;quot;#fDD&amp;quot;|0x0D||bgcolor=&amp;quot;#fCC&amp;quot;|0x0C||bgcolor=&amp;quot;#fDD&amp;quot;|0x0D||bgcolor=&amp;quot;#fDD&amp;quot;|0x0D||bgcolor=&amp;quot;#f66&amp;quot;|0x06||bgcolor=&amp;quot;#fEE&amp;quot;|0x0E||bgcolor=&amp;quot;#fFF&amp;quot;|0x0F||bgcolor=&amp;quot;#fBB&amp;quot;|0x0B||bgcolor=&amp;quot;#fEE&amp;quot;|0x0E||bgcolor=&amp;quot;#fEE&amp;quot;|0x0E||bgcolor=&amp;quot;#fDD&amp;quot;|0x0D||bgcolor=&amp;quot;#fFF&amp;quot;|0x0F&lt;br /&gt;
|-&lt;br /&gt;
! C&lt;br /&gt;
|bgcolor=&amp;quot;#f88&amp;quot;|0x08||bgcolor=&amp;quot;#f88&amp;quot;|0x08||bgcolor=&amp;quot;#f99&amp;quot;|0x09||bgcolor=&amp;quot;#f99&amp;quot;|0x09||bgcolor=&amp;quot;#f88&amp;quot;|0x08||bgcolor=&amp;quot;#f99&amp;quot;|0x09||bgcolor=&amp;quot;#f99&amp;quot;|0x09||bgcolor=&amp;quot;#f99&amp;quot;|0x09||bgcolor=&amp;quot;#fAA&amp;quot;|0x0A||bgcolor=&amp;quot;#f22&amp;quot;|0x02||bgcolor=&amp;quot;#fFF&amp;quot;|0x0F||bgcolor=&amp;quot;#fBB&amp;quot;|0x0B||bgcolor=&amp;quot;#fAA&amp;quot;|0x0A||bgcolor=&amp;quot;#fAA&amp;quot;|0x0A||bgcolor=&amp;quot;#fBB&amp;quot;|0x0B||bgcolor=&amp;quot;#f99&amp;quot;|0x09&lt;br /&gt;
|-&lt;br /&gt;
! D&lt;br /&gt;
|bgcolor=&amp;quot;#f88&amp;quot;|0x08||bgcolor=&amp;quot;#f88&amp;quot;|0x08||bgcolor=&amp;quot;#f88&amp;quot;|0x08||bgcolor=&amp;quot;#f99&amp;quot;|0x09||bgcolor=&amp;quot;#f88&amp;quot;|0x08||bgcolor=&amp;quot;#f88&amp;quot;|0x08||bgcolor=&amp;quot;#f99&amp;quot;|0x09||bgcolor=&amp;quot;#f99&amp;quot;|0x09||bgcolor=&amp;quot;#f88&amp;quot;|0x08||bgcolor=&amp;quot;#fAA&amp;quot;|0x0A||bgcolor=&amp;quot;#fBB&amp;quot;|0x0B||bgcolor=&amp;quot;#fBB&amp;quot;|0x0B||bgcolor=&amp;quot;#fAA&amp;quot;|0x0A||bgcolor=&amp;quot;#fEE&amp;quot;|0x0E||bgcolor=&amp;quot;#f33&amp;quot;|0x03||bgcolor=&amp;quot;#fBB&amp;quot;|0x0B&lt;br /&gt;
|-&lt;br /&gt;
! E&lt;br /&gt;
|bgcolor=&amp;quot;#fCC&amp;quot;|0x0C||bgcolor=&amp;quot;#fCC&amp;quot;|0x0C||bgcolor=&amp;quot;#fFF&amp;quot;|0x0F||bgcolor=&amp;quot;#fDD&amp;quot;|0x0D||bgcolor=&amp;quot;#f44&amp;quot;|0x04||bgcolor=&amp;quot;#fCC&amp;quot;|0x0C||bgcolor=&amp;quot;#fDD&amp;quot;|0x0D||bgcolor=&amp;quot;#f99&amp;quot;|0x09||bgcolor=&amp;quot;#fFF&amp;quot;|0x0F||bgcolor=&amp;quot;#fEE&amp;quot;|0x0E||bgcolor=&amp;quot;#fFF&amp;quot;|0x0F||bgcolor=&amp;quot;#fFF&amp;quot;|0x0F||bgcolor=&amp;quot;#fEE&amp;quot;|0x0E||bgcolor=&amp;quot;#fEE&amp;quot;|0x0E||bgcolor=&amp;quot;#fFF&amp;quot;|0x0F||bgcolor=&amp;quot;#fFF&amp;quot;|0x0F&lt;br /&gt;
|-&lt;br /&gt;
! F&lt;br /&gt;
|bgcolor=&amp;quot;#f88&amp;quot;|0x08||bgcolor=&amp;quot;#fCC&amp;quot;|0x0C||bgcolor=&amp;quot;#fDD&amp;quot;|0x0D||bgcolor=&amp;quot;#f55&amp;quot;|0x05||bgcolor=&amp;quot;#fCC&amp;quot;|0x0C||bgcolor=&amp;quot;#fEE&amp;quot;|0x0E||bgcolor=&amp;quot;#fDD&amp;quot;|0x0D||bgcolor=&amp;quot;#fDD&amp;quot;|0x0D||bgcolor=&amp;quot;#fEE&amp;quot;|0x0E||bgcolor=&amp;quot;#fEE&amp;quot;|0x0E||bgcolor=&amp;quot;#fFF&amp;quot;|0x0F||bgcolor=&amp;quot;#fFF&amp;quot;|0x0F||bgcolor=&amp;quot;#fEE&amp;quot;|0x0E||bgcolor=&amp;quot;#fEE&amp;quot;|0x0E||bgcolor=&amp;quot;#fFF&amp;quot;|0x0F||bgcolor=&amp;quot;#fEE&amp;quot;|0x0E&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Funk]]&lt;br /&gt;
[[Kategorie:Wettbewerb]]&lt;/div&gt;</summary>
		<author><name>Thymythos</name></author>
	</entry>
</feed>