<?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=Df2au</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=Df2au"/>
	<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/articles/Spezial:Beitr%C3%A4ge/Df2au"/>
	<updated>2026-04-12T10:41:24Z</updated>
	<subtitle>Benutzerbeiträge</subtitle>
	<generator>MediaWiki 1.39.7</generator>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=Wanderkiste_(Widlar)&amp;diff=97387</id>
		<title>Wanderkiste (Widlar)</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=Wanderkiste_(Widlar)&amp;diff=97387"/>
		<updated>2017-09-16T16:35:38Z</updated>

		<summary type="html">&lt;p&gt;Df2au: /* Idee */ Typos&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Idee=&lt;br /&gt;
Die Idee, die hinter einer Wanderkiste steckt, ist, dass die Teilnehmer elektronische Bauteile und Module tauschen und&lt;br /&gt;
sich ein Netzwerk von Gleichgesinnten bildet.&lt;br /&gt;
&lt;br /&gt;
=Name=&lt;br /&gt;
Der Name geht auf den Elektronikpionier [https://en.wikipedia.org/wiki/Bob_Widlar Bob Widlar] zurück.&lt;br /&gt;
&lt;br /&gt;
=Regeln:=&lt;br /&gt;
&lt;br /&gt;
;Inhalt&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;u&amp;gt;Neu&amp;lt;/u&amp;gt; Ware THT, SMD + &amp;lt;u&amp;gt;Neue/Funktionierende&amp;lt;/u&amp;gt; Gebrauchte PCBs sowie Arduino Zubehör und Co&lt;br /&gt;
* &amp;lt;u&amp;gt;Kein&amp;lt;/u&amp;gt; Elektroschrott, keine Schlachtplatinen, kein vergammelter Müll der Jahre lang im Keller lag. ,keine Batterien / Akkus, keine Transformatoren &amp;amp; schwere Spulen, kein Gefahrengut&lt;br /&gt;
* In/Out-Liste in Form eines aus sagekräftigen Fotos im Thread (je ein Bild)&lt;br /&gt;
* Wer die Regln nicht akzeptieren kann oder will macht nicht mit!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;Versand&lt;br /&gt;
&lt;br /&gt;
* nur &amp;lt;u&amp;gt;DHL Paket (versichert!)&amp;lt;/u&amp;gt;&lt;br /&gt;
* &amp;lt;u&amp;gt;Sendungs Nummer&amp;lt;/u&amp;gt; sowie Sendungs Eingang/Ausgang (Datum) trägt jeder in die Liste unten ein&lt;br /&gt;
* &amp;lt;u&amp;gt;Kein&amp;lt;/u&amp;gt; Ausland, &amp;lt;u&amp;gt;keine&amp;lt;/u&amp;gt; Inseln und &amp;lt;u&amp;gt;keine&amp;lt;/u&amp;gt; Packstation und &amp;lt;u&amp;gt;keine&amp;lt;/u&amp;gt; Postämter&lt;br /&gt;
=Teilnehmer=&lt;br /&gt;
&lt;br /&gt;
Die Teilnehmer tragen sich selbst ein, der Weg der Kiste ergibt sich automatisch.&lt;br /&gt;
&lt;br /&gt;
Wer einen anderen Teilnehmer austrägt oder sich vor jemanden setzt (also eine Zeile einfügt), an eine Stelle die vergeben ist, der fliegt raus.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Teilnehmer&lt;br /&gt;
|- &lt;br /&gt;
! style=&amp;quot;width:60px&amp;quot; | Nr. !! Name !! style=&amp;quot;width:80px&amp;quot; | IN !! style=&amp;quot;width:80px&amp;quot; | OUT !! DHL Code&lt;br /&gt;
|-&lt;br /&gt;
| 1 || [https://www.mikrocontroller.net/user/show/sven_rvbg sven_rvbg] || - || ||&lt;br /&gt;
|-&lt;br /&gt;
| 2 || [https://www.mikrocontroller.net/user/show/dl3yc dl3yc]|| - || ||   &lt;br /&gt;
|-&lt;br /&gt;
| 3 || [https://www.mikrocontroller.net/user/show/NormalZeit NormalZeit] || - || ||  &lt;br /&gt;
|-&lt;br /&gt;
| 4 || [https://www.mikrocontroller.net/user/show/chfreund chfreund] || - || ||  &lt;br /&gt;
|-&lt;br /&gt;
| 5 || [https://www.mikrocontroller.net/user/show/bastler-david bastler-david] ||folgt noch|| || &lt;br /&gt;
|-&lt;br /&gt;
| 6 || [https://www.mikrocontroller.net/user/show/JoergL JoergL]|| - || ||    &lt;br /&gt;
|-&lt;br /&gt;
| 7 || [https://www.mikrocontroller.net/user/show/Erlang Erlang] || || ||  &lt;br /&gt;
|-&lt;br /&gt;
| 8 || [https://www.mikrocontroller.net/user/show/da_miez da_miez] || || ||    &lt;br /&gt;
|-&lt;br /&gt;
| 9 || || || ||    &lt;br /&gt;
|-&lt;br /&gt;
| 10 || || || ||      &lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Df2au</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=Platinenhersteller&amp;diff=92974</id>
		<title>Platinenhersteller</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=Platinenhersteller&amp;diff=92974"/>
		<updated>2016-05-17T14:12:15Z</updated>

		<summary type="html">&lt;p&gt;Df2au: /* smart prototyping */&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;
&#039;&#039;&#039;Eigentümer oder Mitarbeiter von Firmen dürfen diese gerne eintragen, falls sie in der Liste noch nicht vorhanden sind. Beim Eintrag oder Änderungen bitte in der Zusammenfassung unbedingt darauf hinweisen, dass Sie über Ihre eigene Firma schreiben.&#039;&#039;&#039; Und 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;
&#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;
Verschiedene Threads deuten an, dass &amp;quot;normaler&amp;quot; grüner Stopplack meistens die besseren Ergebnisse erzielt (http://www.mikrocontroller.net/topic/329356, http://www.mikrocontroller.net/topic/321295). Das kann je nach Hersteller schwanken. &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;
{| class=&amp;quot;wikitable sortable&amp;quot; style=&amp;quot;text-align:center&amp;quot;&lt;br /&gt;
|+ Schnellübersicht von Anbietern mit Online-Calculator (Lötstopplack, kein Bestückungsdruck, inkl. MwSt &amp;amp; Porto)&lt;br /&gt;
|-&lt;br /&gt;
! Anbieter !! Lagenanzahl !! Breite / mm !! Höhe / mm !! Dicke / mm !! Arbeitstage !! Preis / Euro !! ermittelt am&lt;br /&gt;
|-&lt;br /&gt;
| [[#Ätzwerk_GmbH|Ätzwerk]] || 2 || 160 || 100 || 1.6 || 2 || 148.73 || 2014-09-16&lt;br /&gt;
|-&lt;br /&gt;
| [[#Ätzwerk_GmbH|Ätzwerk]] || 2 || 160 || 100 || 1.6 || 3 || 133.85 || 2014-09-16&lt;br /&gt;
|-&lt;br /&gt;
| [[#Ätzwerk_GmbH|Ätzwerk]] || 2 || 160 || 100 || 1.6 || 4 || 113.03 || 2014-09-16&lt;br /&gt;
|-&lt;br /&gt;
| [[#Ätzwerk_GmbH|Ätzwerk]] || 2 || 160 || 100 || 1.6 || 5 || 95.18 || 2014-09-16&lt;br /&gt;
|-&lt;br /&gt;
| [[#Ätzwerk_GmbH|Ätzwerk]] || 2 || 160 || 100 || 1.6 || 6 || 83.29 || 2014-09-16&lt;br /&gt;
|-&lt;br /&gt;
| [[#Ätzwerk_GmbH|Ätzwerk]] || 2 || 160 || 100 || 1.6 || 7 || 59.49 || 2014-09-16&lt;br /&gt;
|-&lt;br /&gt;
| [[#Ätzwerk_GmbH|Ätzwerk]] || 4 || 160 || 100 || 1.6 || 3 || 294.50 || 2014-09-16&lt;br /&gt;
|-&lt;br /&gt;
| [[#Ätzwerk_GmbH|Ätzwerk]] || 4 || 160 || 100 || 1.6 || 4 || 248.69 || 2014-09-16&lt;br /&gt;
|-&lt;br /&gt;
| [[#Ätzwerk_GmbH|Ätzwerk]] || 4 || 160 || 100 || 1.6 || 5 || 209.42 || 2014-09-16&lt;br /&gt;
|-&lt;br /&gt;
| [[#Ätzwerk_GmbH|Ätzwerk]] || 4 || 160 || 100 || 1.6 || 6 || 183.25 || 2014-09-16&lt;br /&gt;
|-&lt;br /&gt;
| [[#Ätzwerk_GmbH|Ätzwerk]] || 4 || 160 || 100 || 1.6 || 7 || 130.89 || 2014-09-16&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| [[#Basista_Leiterplatten|Basista]] || 2 || 160 || 100 || 1.6 || 1 || 261.61 || 2014-09-16&lt;br /&gt;
|-&lt;br /&gt;
| [[#Basista_Leiterplatten|Basista]] || 2 || 160 || 100 || 1.6 || 2 || 233.75 || 2014-09-16&lt;br /&gt;
|-&lt;br /&gt;
| [[#Basista_Leiterplatten|Basista]] || 2 || 160 || 100 || 1.6 || 3 || 205.92 || 2014-09-16&lt;br /&gt;
|-&lt;br /&gt;
| [[#Basista_Leiterplatten|Basista]] || 2 || 160 || 100 || 1.6 || 4 || 178.09 || 2014-09-16&lt;br /&gt;
|-&lt;br /&gt;
| [[#Basista_Leiterplatten|Basista]] || 2 || 160 || 100 || 1.6 || 5 || 150.26 || 2014-09-16&lt;br /&gt;
|-&lt;br /&gt;
| [[#Basista_Leiterplatten|Basista]] || 2 || 160 || 100 || 1.6 || 7 || 127.98 || 2014-09-16&lt;br /&gt;
|-&lt;br /&gt;
| [[#Basista_Leiterplatten|Basista]] || 2 || 160 || 100 || 1.6 || 8|| 94.57 || 2014-09-16&lt;br /&gt;
|-&lt;br /&gt;
| [[#Basista_Leiterplatten|Basista]] || 2 || 160 || 100 || 1.6 || 10 || 91.23 || 2014-09-16&lt;br /&gt;
|-&lt;br /&gt;
| [[#Basista_Leiterplatten|Basista]] || 2 || 160 || 100 || 1.6 || 12 || 89.02 || 2014-09-16&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| [[#Becker_und_Müller|Becker und Müller]] || 2 || 160 || 100 || 1.6 || 4 || 195.26 || 2015-07-06&lt;br /&gt;
|-&lt;br /&gt;
| [[#Becker_und_Müller|Becker und Müller]] || 2 || 160 || 100 || 1.6 || 5 || 132.95 || 2015-07-06&lt;br /&gt;
|-&lt;br /&gt;
| [[#Becker_und_Müller|Becker und Müller]] || 2 || 160 || 100 || 1.6 || 7 || 120.49 || 2015-07-06&lt;br /&gt;
|-&lt;br /&gt;
| [[#Becker_und_Müller|Becker und Müller]] || 2 || 160 || 100 || 1.6 || 10 || 108.02 || 2015-07-06&lt;br /&gt;
|-&lt;br /&gt;
| [[#Becker_und_Müller|Becker und Müller]] || 2 || 160 || 100 || 1.6 || 12 || 101.79 || 2015-07-06&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| [[#Eurocircuits_GmbH|Eurocircuits]] || 2 || 160 || 100 || 1.6 || 8 || 68.87 || 2014-09-16&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| [[#LEITON|LeitOn]] || 2 || 160 || 100 || 1.6 || 3 || 192.93 || 2014-09-16&lt;br /&gt;
|-&lt;br /&gt;
| [[#LEITON|LeitOn]] || 2 || 160 || 100 || 1.6 || 5 || 91.86 || 2014-09-16&lt;br /&gt;
|-&lt;br /&gt;
| [[#LEITON|LeitOn]] || 2 || 160 || 100 || 1.6 || 8 || 61.24 || 2014-09-16&lt;br /&gt;
|-&lt;br /&gt;
| [[#LEITON|LeitOn]] || 2 || 160 || 100 || 1.6 || 12 || 48.99 || 2014-09-16&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| [[#Multi_Printed_Circuit_Boards_Ltd.|Multi-CB]] ||	1	|| 160 || 100 || 1.6 ||	5	||	55.22	|| 2016-02-16&lt;br /&gt;
|-&lt;br /&gt;
| [[#Multi_Printed_Circuit_Boards_Ltd.|Multi-CB]] ||	2	|| 160 || 100 || 1.6 ||	2	||	165.65	|| 2016-02-16&lt;br /&gt;
|-&lt;br /&gt;
| [[#Multi_Printed_Circuit_Boards_Ltd.|Multi-CB]] ||	2	|| 160 || 100 || 1.6 ||	5	||	55.22	|| 2016-02-16&lt;br /&gt;
|-&lt;br /&gt;
| [[#Multi_Printed_Circuit_Boards_Ltd.|Multi-CB]] ||	4	|| 160 || 100 || 1.6 ||	2	||	290.54	|| 2016-02-16&lt;br /&gt;
|-&lt;br /&gt;
| [[#Multi_Printed_Circuit_Boards_Ltd.|Multi-CB]] ||	4	|| 160 || 100 || 1.6 ||	5	||	110.98	|| 2016-02-16&lt;br /&gt;
|-&lt;br /&gt;
| [[#Multi_Printed_Circuit_Boards_Ltd.|Multi-CB]] ||	6	|| 160 || 100 || 1.6 ||	2	||	336.89	|| 2016-02-16&lt;br /&gt;
|-&lt;br /&gt;
| [[#Multi_Printed_Circuit_Boards_Ltd.|Multi-CB]] ||	6	|| 160 || 100 || 1.6 ||	6	||	177.31	|| 2016-02-16&lt;br /&gt;
|-&lt;br /&gt;
| [[#Multi_Printed_Circuit_Boards_Ltd.|Multi-CB]] ||	8	|| 160 || 100 || 1.6 ||	2	||	486.57	|| 2016-02-16&lt;br /&gt;
|-&lt;br /&gt;
| [[#Multi_Printed_Circuit_Boards_Ltd.|Multi-CB]] ||	8	|| 160 || 100 || 1.6 ||	6	||	256.09	|| 2016-02-16&lt;br /&gt;
|-&lt;br /&gt;
| [[#Multi_Printed_Circuit_Boards_Ltd.|Multi-CB]] ||	10	|| 160 || 100 || 1.6 ||	3	||	1058.03	|| 2016-02-16&lt;br /&gt;
|-&lt;br /&gt;
| [[#Multi_Printed_Circuit_Boards_Ltd.|Multi-CB]] ||	10	|| 160 || 100 || 1.6 ||	7	||	622.37	|| 2016-02-16&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| [[#PCB Pool|PCB Pool]] || 2 || 160 || 100 || 1.6 || 1 || 320.48 || 2014-09-21&lt;br /&gt;
|-&lt;br /&gt;
| [[#PCB Pool|PCB Pool]] || 2 || 160 || 100 || 1.6 || 2 || 268.96 || 2014-09-21&lt;br /&gt;
|-&lt;br /&gt;
| [[#PCB Pool|PCB Pool]] || 2 || 160 || 100 || 1.6 || 3 || 243.19 || 2014-09-21&lt;br /&gt;
|-&lt;br /&gt;
| [[#PCB Pool|PCB Pool]] || 2 || 160 || 100 || 1.6 || 4 || 217.43 || 2014-09-21&lt;br /&gt;
|-&lt;br /&gt;
| [[#PCB Pool|PCB Pool]] || 2 || 160 || 100 || 1.6 || 5 || 165.90 || 2014-09-21&lt;br /&gt;
|-&lt;br /&gt;
| [[#PCB Pool|PCB Pool]] || 2 || 160 || 100 || 1.6 || 7 || 145.29 || 2014-09-21&lt;br /&gt;
|-&lt;br /&gt;
| [[#PCB Pool|PCB Pool]] || 2 || 160 || 100 || 1.6 || 8 || 114.37 || 2014-09-21&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| [[#Onlineshop WEdirekt|WEdirekt]] || 2 || 160 || 100 || 1.6 || 2 || 270.67 || 2014-09-21&lt;br /&gt;
|-&lt;br /&gt;
| [[#Onlineshop WEdirekt|WEdirekt]] || 2 || 160 || 100 || 1.6 || 3 || 215.21 || 2014-09-21&lt;br /&gt;
|-&lt;br /&gt;
| [[#Onlineshop WEdirekt|WEdirekt]] || 2 || 160 || 100 || 1.6 || 4 || 178.25 || 2014-09-21&lt;br /&gt;
|-&lt;br /&gt;
| [[#Onlineshop WEdirekt|WEdirekt]] || 2 || 160 || 100 || 1.6 || 5 || 131.44 || 2014-09-21&lt;br /&gt;
|-&lt;br /&gt;
| [[#Onlineshop WEdirekt|WEdirekt]] || 2 || 160 || 100 || 1.6 || 6 || 120.87 || 2014-09-21&lt;br /&gt;
|-&lt;br /&gt;
| [[#Onlineshop WEdirekt|WEdirekt]] || 2 || 160 || 100 || 1.6 || 7 || 89.19 || 2014-09-21&lt;br /&gt;
|-&lt;br /&gt;
| [[#Onlineshop WEdirekt|WEdirekt]] || 2 || 160 || 100 || 1.6 || 8 || 89.19 || 2014-09-21&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Liste der Hersteller ==&lt;br /&gt;
&lt;br /&gt;
=== Deutschland ===&lt;br /&gt;
==== Übersicht ====&lt;br /&gt;
{| class=&amp;quot;wikitable sortable&amp;quot; style=&amp;quot;text-align:center&amp;quot;&lt;br /&gt;
|+ Übersicht von Anbietern aus Deutschland&lt;br /&gt;
|-&lt;br /&gt;
! Anbieter !! PLZ !! Ort !! privat !! gewerblich !! Online-Calculator !! produziert in Deutschland !! ermittelt am&lt;br /&gt;
|-&lt;br /&gt;
| [[#Accent PCB GmbH|Accent PCB GmbH]] || 40212 || Düsseldorf || ? || ja || nein || [http://www.accentpcb.com/about-us.html teilweise] || 2014-09-21&lt;br /&gt;
|-&lt;br /&gt;
| [[#Ätzwerk GmbH|Ätzwerk GmbH]] || 81925 || München || ? || ja || ja || ? || 2014-09-21&lt;br /&gt;
|-&lt;br /&gt;
| [[#am2s|am2s]] || 88376 || Königseggwald || ja || ja || nein || [http://www.am2s.de/pcb.html teilweise] || 2014-09-21&lt;br /&gt;
|-&lt;br /&gt;
| [[#andus electronic|Andus Electronic]] || 10997 || Berlin || ? || ja || nein || ja? || 2014-09-21&lt;br /&gt;
|-&lt;br /&gt;
| [[#ANTtronic|ANTtronic]] || 53844 || Troisdorf || ? || ja || nein || ? || 2014-09-21&lt;br /&gt;
|-&lt;br /&gt;
| [[#Basista Leiterplatten|Basista Leiterplatten]] || 46236 || Bottrop || ja || ja || ja || ja? || 2014-09-21&lt;br /&gt;
|-&lt;br /&gt;
| [[#Bauer-Elektronik|Bauer-Elektronik]] || 66557 || Illingen || ja? || ja || nein || ja? || 2014-09-21&lt;br /&gt;
|-&lt;br /&gt;
| [[#Britze|Britze]] || 12099? || Berlin || ? || ja || ja || [http://www.britze.de/unternehmen-produktion.html ja] || 2014-09-21&lt;br /&gt;
|-&lt;br /&gt;
| [[#B&amp;amp;B Gruppe|B&amp;amp;B Gruppe]] || 09648 || Mittweida || ? || ja || nein || [http://www.bb-gruppe.de/handel/ teilweise] || 2014-09-21&lt;br /&gt;
|-&lt;br /&gt;
| [[#Becker und Müller|Becker und Müller]] || 77790 || Steinach i.K. || ja || ja || ja || ja || 2014-09-21&lt;br /&gt;
|-&lt;br /&gt;
| [[#Contag|Contag]] || 13581 || Berlin || ? || ja || nein || ja? || 2014-09-21&lt;br /&gt;
|-&lt;br /&gt;
| [[#Christian Enzmann Gmbh|Christian Enzmann Gmbh]] || 82538 || Geretsried || ? || ja || nein || teilweise || 2014-09-21&lt;br /&gt;
|-&lt;br /&gt;
| [[#Deutschlaender Electronic GmbH|Deutschlaender Electronic GmbH]] || 74924 || Neckarbischofsheim || ? || ja || ja || ja? || 2014-09-21&lt;br /&gt;
|-&lt;br /&gt;
| [[#EPN Electroprint GmbH|EPN Electroprint GmbH]] ||  07806 ||  Neustadt an der Orla || ja? || ja || ja || [http://www.epn.de/de/home/geschichte.html ja] || 2014-09-21&lt;br /&gt;
|-&lt;br /&gt;
| [[#Elischer Leiterplatten|Elischer Leiterplatten]] ||  72574 || Bad Urach || ? || ? || nein || ? || 2014-09-21&lt;br /&gt;
|-&lt;br /&gt;
| [[#Fischer Leiterplatten GmbH|Fischer Leiterplatten GmbH]] || 58454 || Witten || nein || ja || ja || [http://www.fischer-leiterplatten.de/ueber-uns.htm ja] || 2014-09-21&lt;br /&gt;
|-&lt;br /&gt;
| [[#GLS Leiterplatten-Service GmbH|GLS Leiterplatten-Service GmbH]] || 09221 || Neukirchen || ja? || ja || nein || ja || 2014-09-21&lt;br /&gt;
|-&lt;br /&gt;
| [[#HAKA Elektronik-Leiterplatten GmbH|HAKA Elektronik-Leiterplatten GmbH]] || 66583 || Spiesen-Elversberg || ja? || ja || ja || ja? || 2014-09-21&lt;br /&gt;
|-&lt;br /&gt;
| [[#IBR Leiterplatten GmbH &amp;amp; Co. KG|IBR Leiterplatten GmbH &amp;amp; Co. KG]] || 74906 || Bad Rappenau || nein || ja || ja || ja? || 2014-09-21&lt;br /&gt;
|-&lt;br /&gt;
| [[#ILFA Feinstleitertechnik GmbH|ILFA Feinstleitertechnik GmbH]] || 30559 || Hannover || ? || ja || nein || teilweise || 2014-09-21&lt;br /&gt;
|-&lt;br /&gt;
| [[#Eurocircuits GmbH|Eurocircuits GmbH]] || 57612 || Kettenhausen || ? || ja || ja || teilweise || 2014-09-21&lt;br /&gt;
|-&lt;br /&gt;
| [[#Entwicklung &amp;amp; CNC|Entwicklung &amp;amp; CNC]] || 72805 || Lichtenstein || ? || ja || nein || ja || 2014-09-21&lt;br /&gt;
|-&lt;br /&gt;
| [[#kessler systems GmbH|kessler systems GmbH]] || 88376 || Königseggwald || ? || ja || nein || teilweise || 2014-09-21&lt;br /&gt;
|-&lt;br /&gt;
| [[#LEITON|LEITON]] || 12099 || Berlin || ja || ja || ja || teilweise || 2014-09-21&lt;br /&gt;
|-&lt;br /&gt;
| [[#Leiterplatten-Express-Service GmbH|Leiterplatten-Express-Service GmbH]] || 63329 || Egelsbach || ? || ja || nein || ja || 2014-09-21&lt;br /&gt;
|-&lt;br /&gt;
| [[#Microcirtec|Microcirtec]] ||  47805 || Krefeld || nein || ja || ja || ja || 2014-09-21&lt;br /&gt;
|-&lt;br /&gt;
| [[#MME-Leiterplatten|MME-Leiterplatten]] || 53604 || Bad Honnef || ? || ja || ja || ja? || 2014-09-21&lt;br /&gt;
|-&lt;br /&gt;
| [[#M &amp;amp; V Leiterplatten - Vertriebs GmbH|M &amp;amp; V Leiterplatten - Vertriebs GmbH]] || 56355 || Bettendorf || ? || ja || ja || ja || 2014-09-20&lt;br /&gt;
|-&lt;br /&gt;
| [[#Multi_Printed_Circuit_Boards_Ltd.|Multi-CB]] ||  85649 || Brunnthal || nein || ja || ja || ? || 2015-02-16&lt;br /&gt;
|-&lt;br /&gt;
| [[#PCB Joker|PCB Joker GmbH]] || 12099 || Berlin || ? || ja || ja || ja || 2014-09-20&lt;br /&gt;
|-&lt;br /&gt;
| [[#PCB Pool|PCB Pool]] || 65326 || Aarbergen || ja || ja || ja || teilweise || 2014-09-20&lt;br /&gt;
|-&lt;br /&gt;
| [[#Precoplat|Precoplat]] || 47805 || Krefeld || ? || ja || ja || ja || 2014-09-20&lt;br /&gt;
|-&lt;br /&gt;
| [[#Q-print/Q-PCB|Q-print/Q-PCB]] || 68542 || Heddesheim || ? || ja || ja || nein? || 2014-09-20&lt;br /&gt;
|-&lt;br /&gt;
| [[#Rinde PCB GmbH|Rinde PCB GmbH]] || 42899 || Remscheid || ? || ja || ja || ja || 2015-01-23&lt;br /&gt;
|-&lt;br /&gt;
| [[#Ruwel|Ruwel]] || 47608 || Geldern || nein? || ja || nein || teilweise || 2014-09-20&lt;br /&gt;
|-&lt;br /&gt;
| [[#Steimer Leiterplatten GmbH|Steimer Leiterplatten GmbH]] || 42327 || Wuppertal || ja || ja || ja || ja || 2014-09-20&lt;br /&gt;
|-&lt;br /&gt;
| [[#Onlineshop WEdirekt|Onlineshop WEdirekt]] || 74585 || Rot am See || ja || ja || ja || [http://www.wedirekt.de/index.php/web/live/de/wedirekt/ueberuns/die_produktion/die_produktion_1.php ja] || 2014-09-20&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== 2PrintBeta ====&lt;br /&gt;
Homepage: http://www.2printbeta.de/Dienstleistungen/PCB-Stencil-Service::337.html&lt;br /&gt;
* SMD-Schablonen aus Mylar gelasert, preiswert und schnell. Masken bis zu 0.5mm Pitch problemlos möglich. &lt;br /&gt;
* Super günstig, super flott!&lt;br /&gt;
* Keine Begrenzung der Padanzahl.&lt;br /&gt;
* Als Student erhalten Sie 25% Rabatt! (Nur gegen Nachweis des Studentenausweises!)&lt;br /&gt;
&lt;br /&gt;
==== Accent PCB GmbH ====&lt;br /&gt;
Homepage: http://www.accentpcb.com/duitsland-home.html&lt;br /&gt;
&lt;br /&gt;
Eigendarstellung (vgl. auch [http://www.mikrocontroller.net/topic/316646 Forenthread]):&lt;br /&gt;
* Leiterplatten &amp;quot;ab 75€ - €99€&amp;quot; &lt;br /&gt;
* erfahrene Techniker&lt;br /&gt;
* Beratung gratis&lt;br /&gt;
* Produktion in Asien und Europa&lt;br /&gt;
* auch flexible und &amp;quot;starr-flexible&amp;quot; Platinen&lt;br /&gt;
* Standort: Niederlande&lt;br /&gt;
&lt;br /&gt;
==== Ätzwerk GmbH ====&lt;br /&gt;
Homepage: http://www.aetzwerk.de&lt;br /&gt;
&lt;br /&gt;
Eigendarstellung:&lt;br /&gt;
* 100x160mm, Lötstopp doppelseitig, Bestückungsdruck einseitig, Stuktur&amp;gt;0,15mm, Bohrungen&amp;gt;0,3mm, 7AT, 59€&lt;br /&gt;
* scheint auch an privat zu liefern&lt;br /&gt;
* SMD-Schablonen&lt;br /&gt;
* Expressfertigung&lt;br /&gt;
&lt;br /&gt;
Erfahrungen:&lt;br /&gt;
* verschicken unaufgeforderte Newsletter&lt;br /&gt;
* [https://www.mikrocontroller.net/topic/246385 Diskussionsfaden &amp;quot;Ätzwerk GmbH&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
==== am2s ====&lt;br /&gt;
Homepage: http://www.am2s.de&lt;br /&gt;
* Leiterplatten (Prototypen und Kleinserien, bis hin zur Großserie)&lt;br /&gt;
* Eildienst möglich&lt;br /&gt;
* Ein- und doppelseitige Leiterplatten, Multilayer. &lt;br /&gt;
* Layoutservice&lt;br /&gt;
* günstige Preise&lt;br /&gt;
* sehr gute Qualität&lt;br /&gt;
* Lieferzeit ab 3 AT&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/ früher: http://www.gsel.de&lt;br /&gt;
* gute Preise, aber Lieferzeit beachten!&lt;br /&gt;
* 1 Europlatine einseitig kein Lötstoplack 17€ inkl. MwSt +7€ Versand&lt;br /&gt;
* 1 Europlatine doppelseitig &#039;&#039;nicht durchkontaktiert&#039;&#039; kein Lötstoplack 23€ inkl. MwSt +7€ Versand; 2Stück 37€&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;
* Onlinekalkulator&lt;br /&gt;
* 100x160mm, zweiseitig, durchkontaktiert, mit Lötstop, 8AT, 82€&lt;br /&gt;
&lt;br /&gt;
==== Bauer-Elektronik ====&lt;br /&gt;
Homepage: http://www.bauer-leiterplatten.de&lt;br /&gt;
* Eurokarte doppelseitig für 61€ inkl. MwSt 8AT Lieferzeit / Stopplack +10% / Best.Druck +10%&lt;br /&gt;
* Prototypen aktivzinnbehandelt, dieses lässt sich laut Firmenangaben noch nach Jahren löten&lt;br /&gt;
* Eildienst 2h: Versand am selben Tag bei Einsendung bis 13:00 400€ für 2dm²&lt;br /&gt;
&lt;br /&gt;
==== Britze ====&lt;br /&gt;
Homepage: http://www.britze.de&lt;br /&gt;
* Leiterplatten in kleinen und mittlere Serien&lt;br /&gt;
* Musterleiterplatten / Prototypen&lt;br /&gt;
* 1- und 2-lagige Leiterplatten&lt;br /&gt;
* Multilayer bis 10 Lagen&lt;br /&gt;
* Aluminiumträgerleiterplatten&lt;br /&gt;
* &#039;&#039;Online-Kalkulator&#039;&#039; für Multinutzen und Leiterplatten&lt;br /&gt;
* Beratung/Layout/Entflechtung von Leiterplatten&lt;br /&gt;
* 100x160mm, zweiseitig, durchkontaktiert, mit Lötstop, 10AT, 73€&lt;br /&gt;
* scheint auch an privat zu liefern&lt;br /&gt;
&amp;quot;Seit dem 17.9.2012 werden alle Leiterplatten von Britze durch die Firma LeitOn GmbH vertrieben, mit der schon eine langjährige Zusammenarbeit besteht.&amp;quot; Bestellungen direkt bei britze.de offenbar nur noch für Bestandskunden möglich.&lt;br /&gt;
&lt;br /&gt;
==== B&amp;amp;B Sachsenelektronik GmbH ====&lt;br /&gt;
Homepage: http://www.bb-gruppe.de&lt;br /&gt;
* Klein- und Musterserien, Spezialist Sondertechniken&lt;br /&gt;
* Zusätzliche Partner für Großserien in Asien mit eigenen Mitarbeitern&lt;br /&gt;
* Ein- und Doppelseitige Leiterplatten&lt;br /&gt;
* Multilayer&lt;br /&gt;
* Schleifringe&lt;br /&gt;
* Starrflex&lt;br /&gt;
* Hochstromleiterplatte&lt;br /&gt;
* Dickkupfer&lt;br /&gt;
* Flexlam&lt;br /&gt;
* Dünnstleiterplatte&lt;br /&gt;
* IMS&lt;br /&gt;
* HDI Leiterplatte&lt;br /&gt;
* E-Test inklusive&lt;br /&gt;
* Datenformate: Ger­ber, Eagle, Excel­lon, Sieb &amp;amp; Meier&lt;br /&gt;
* Eildienst möglich&lt;br /&gt;
* Abrufeinteilung und Konsignationslager möglich&lt;br /&gt;
* Standort: 09648 Mittweida/Sachsen&lt;br /&gt;
&lt;br /&gt;
==== Becker und Müller ====&lt;br /&gt;
Homepage: https://www.becker-mueller.de&lt;br /&gt;
* Online Kalkulator (2Lagen, 4 Lagen, 6 Lagen)&lt;br /&gt;
* Sonderbauformen (Alu, etc.) möglich&lt;br /&gt;
* Qualität gut&lt;br /&gt;
* Hochfrequenzschaltungen&lt;br /&gt;
* Eildienst möglich&lt;br /&gt;
&lt;br /&gt;
==== Contag====&lt;br /&gt;
Homepage: http://www.contag.de&lt;br /&gt;
* SAUSCHNELL- ab 4 STUNDEN(!)&lt;br /&gt;
* Aber auch sehr teuer&lt;br /&gt;
* Qualität sehr gut&lt;br /&gt;
&lt;br /&gt;
==== Christian Enzmann Gmbh ====&lt;br /&gt;
Hompage: http://www.enzmann.de&lt;br /&gt;
&lt;br /&gt;
Prototypen&lt;br /&gt;
* Schnelle Reaktion auf individuelle Kundenwünsche&lt;br /&gt;
* Liefertermine werden eingehalten&lt;br /&gt;
Serienfertigung&lt;br /&gt;
* gefertigten Prototypen sollen später in Produktion von Großserien gehen&lt;br /&gt;
* Kunden können mit großen Stückzahlen versorgt werden&lt;br /&gt;
&lt;br /&gt;
==== Deutschlaender Electronic GmbH ====&lt;br /&gt;
Homepage: http://www.deutschlaender.net&lt;br /&gt;
* Leiterbahnbreite und -abstand ab 100 µm&lt;br /&gt;
* Bohrdurchmesser (Endmaß) ab 0,2 mm&lt;br /&gt;
* Sacklöcher, Halblöcher, Tiefenfräsung&lt;br /&gt;
* Materialstärke ab 0,5 mm bis 2,4mm&lt;br /&gt;
* Kupferauflagen: 35 µm, 70 µm, 105 µm,145 µm und 235 µm&lt;br /&gt;
* Hoch-Tg oder Aluminiummaterial&lt;br /&gt;
* Fotosensitiver Lötstoplack (grün,schwarz,rot und weiß)&lt;br /&gt;
* Bestückungsdruck (weiß,gelb,schwarz und rot)&lt;br /&gt;
* Carbondruck (Kontaktflächen)&lt;br /&gt;
* Abziehlack&lt;br /&gt;
* Viadruck&lt;br /&gt;
* Konturfräsen&lt;br /&gt;
* Schlitze fräsen - auch durchkontaktiert&lt;br /&gt;
* Kerb Ritzen für Kontur, Sollbruchstellen, Sprungritzen&lt;br /&gt;
* Kontur anfasen, z.B. für Steckerkamm&lt;br /&gt;
* Oberflächenveredelung:&lt;br /&gt;
** HAL bleifrei / PbSn&lt;br /&gt;
** Chemisch Nickel/Gold(Ni/Au)&lt;br /&gt;
** Chemisch Zinn (Sn)&lt;br /&gt;
** Galvanisch Nickel/Gold (Ni/Au, Hartgold)&lt;br /&gt;
* Datenformate: Ger­ber, Eagle, Target, Autocad, Excel­lon, Sieb &amp;amp; Meier&lt;br /&gt;
* Eildienst möglich (3AT/5AT/7AT)&lt;br /&gt;
&lt;br /&gt;
==== EPN Electroprint GmbH ====&lt;br /&gt;
Homepage: http://www.epn.de&lt;br /&gt;
* 8 Tage Lieferzeit, Eilservice 24h auch möglich&lt;br /&gt;
* Single-Layer, Multi-Layer (bis 22 Lagen als Spezialanfertigung!), Dickkupfer&lt;br /&gt;
* Verzinnung: Hot-Air-Leveling oder chemisch Zinn&lt;br /&gt;
* Lötstopplack verschiedene Farben nach Absprache möglich&lt;br /&gt;
* Stencil-Fertigung&lt;br /&gt;
* Thüringer Staatspreis für Qualität&lt;br /&gt;
* Standort: Neustadt an der Orla/Thüringen&lt;br /&gt;
&lt;br /&gt;
==== Elischer Leiterplatten ====&lt;br /&gt;
mailto:aurel-elischer@t-online.de&lt;br /&gt;
* Firmensitz / Post-Adresse: Dipl.-Ing. Aurel Elischer, Leiterplatten, Am Forst 7, 72574 Bad Urach, Tel. 07125/4498, Ust.Id.-Nr.: DE 223 09 4959&lt;br /&gt;
* Layoutentwurf, LP Entwicklung, herstellen, bestücken, löten, prüfen&lt;br /&gt;
* 3 KW Lieferzeit (nach Vereinbarung auch kürzer)&lt;br /&gt;
* sehr gute Preise, Qual.1A&lt;br /&gt;
* einen Preis zu nennen, wäre Unfair. Es ist abhängig davon ob:&lt;br /&gt;
** 1 oder 2-seitig&lt;br /&gt;
** Leiterbahnenabstand und Lötflächenanstände größer als 0,3 mm&lt;br /&gt;
** Cu 30, 70, 110 µm&lt;br /&gt;
** Stärke der LP 1,0; 1,6; 2,0; ... mm&lt;br /&gt;
** mit (1- oder 2-seitig, grün, blau, weiß, schwarz,...)oder ohne Beschriftung&lt;br /&gt;
** mit oder ohne Stoplack&lt;br /&gt;
** gefräst oder nur geritzt&lt;br /&gt;
** einzeln oder X-Fach-Montage&lt;br /&gt;
* unbedingt Gerber 274X und Exellon für die Anfrage (Angebot kostenlos) beifügen; keine Angst: Gerber 274X und Exellon kann man aus jedem Programm generieren&lt;br /&gt;
&lt;br /&gt;
==== Elk Tronic ====&lt;br /&gt;
Homepage http://www.elk-tronic.de&lt;br /&gt;
* Entwicklung und Fertigung von Kleingeräten und Kleinserien&lt;br /&gt;
* Verkauf von IC-Adaptern und Bauteilen&lt;br /&gt;
&lt;br /&gt;
==== Eurocircuits GmbH ====&lt;br /&gt;
Hompage: http://www.eurocircuits.de&lt;br /&gt;
* ideal für kleine Stückzahlen ab 1 Stück&lt;br /&gt;
* Lieferzeit ab 2 AT&lt;br /&gt;
* gute Preise bei Prototypen aber auch bei mittleren Stückzahlen&lt;br /&gt;
* Online Datenvisualisierung und DRC Check&lt;br /&gt;
* SMD - Schablonen&lt;br /&gt;
* Preisberechnung eindeutig ohne versteckte Kosten&lt;br /&gt;
* Europakarte, 2-lagig, 68.87€ (2014-09-16)&lt;br /&gt;
&lt;br /&gt;
==== Entwicklung &amp;amp; CNC (gewerblich) ====&lt;br /&gt;
Hompage: http://www.entwicklung-cnc.de&amp;lt;br&amp;gt;&lt;br /&gt;
mailto:julian.huesing85@googlemail.com&lt;br /&gt;
* Europlatine 100x160 1 bis 2 Seitig ca. 20-40€ (Berechnung Maschinenzeit)&lt;br /&gt;
* Auch große Platinen möglich.&lt;br /&gt;
* Isolationsbreiten abhängig vom Stichel: minimale Isolationsbreite ca. 0,15 mm&lt;br /&gt;
* Bohr und Fräsarbeiten, auch aufwändige Konturen realisierbar&lt;br /&gt;
* Lieferzeit 8AT, ansonsten Aufpreis bei schnellerer Lieferung&lt;br /&gt;
* CNC Fräsarbeiten in PCB, Alu, Holz, Kunststoff, GFK, etc. max. Verfahrwege: 1150x720mm (Fräsmaschine: BZT PFE1000)&lt;br /&gt;
* Fertigung erfolgt auf Rechnung mit ausgewiesener Mehrwertsteuer&lt;br /&gt;
* USt-IdNr.: DE293952582&lt;br /&gt;
&lt;br /&gt;
==== Fischer Leiterplatten GmbH ====&lt;br /&gt;
Homepage: http://www.fischer-leiterplatten.de&lt;br /&gt;
* 1 Europlatine inkl. Lack, E-Test, ohne Bestückungsdruck für 46,41€ inkl. MwSt in 10 Tagen + Versand&lt;br /&gt;
* 1 Europlatine inkl. Lack, E-Test, Best.-Druck top oder bottom für 58,31€ inkl. MwSt in 10 Tagen + Versand&lt;br /&gt;
* 1 Europlatine inkl. Lack, E-Test, Best.-Druck doppelseitig für 117,81€ inkl. MwSt in 10 Tagen + Versand&lt;br /&gt;
* max. 4 lagig&lt;br /&gt;
* Bestückungsdruck doppelseitig&lt;br /&gt;
* Bohrungen no limit&lt;br /&gt;
* min Clearance 0,15mm (Standard)&lt;br /&gt;
* min Bohrdurchmesser 0,3mm (Standard)&lt;br /&gt;
* Gerber/Eagle/Protel/Target&lt;br /&gt;
* mehrere Leiterplatten können auf einer Europakarte, zum Preis einer Europakarte, zusammengefasst werden und werden automatisch vereinzelt.&lt;br /&gt;
* Überlieferung wird kostenlos beigelegt. (Sprich: in der Regel werden mehr Leiterplatten geliefert als bestellt.)&lt;br /&gt;
* Verkauf nur an Gewerbetreibende (aber es wird kein Gewerbenachweis verlangt ;) )&lt;br /&gt;
* Erfahrungen: [http://www.mikrocontroller.net/topic/209947#2078731]&lt;br /&gt;
&lt;br /&gt;
==== GLS Leiterplatten-Service GmbH ====&lt;br /&gt;
Homepage: &amp;lt;strike&amp;gt;http://www.leiterplattenprototypen.de&amp;lt;/strike&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
(URL defekt am 16.3.2015, Redirect zur DeNIC).&lt;br /&gt;
&lt;br /&gt;
* Top Qualität (mittleres Preisniveau)&lt;br /&gt;
* Top Service&lt;br /&gt;
* Prüfung der Layoutdaten in der CAM&lt;br /&gt;
* Standardlieferzeit: 10 Arbeitstage&lt;br /&gt;
* Eilservice bis 3 Arbeitstage (mit Aufpreis)&lt;br /&gt;
* Oberfläche Standard: HAL bleifrei; aber auch z.&amp;amp;nbsp;B. chem. Gold, chem. Zinn und HAL bleihaltig&lt;br /&gt;
* einseitige, nichtdurchkontaktierte Leiterplatten &lt;br /&gt;
* durchkontaktierte Leiterplatten&lt;br /&gt;
* Multilayer: bis 8-Lagen&lt;br /&gt;
* bietet zusätzlichen Service rund um die Leiterplatte: Erstellung von Leiterplattenlayouts und Digitalisierung/Scannen von alten Fertigungsfilmen, Papierausdrucken oder vorhandenen Musterleiterplatten&lt;br /&gt;
* SMD Schablonen&lt;br /&gt;
* Prototypenfertigung bei Chemnitz&lt;br /&gt;
&lt;br /&gt;
==== HAKA Elektronik-Leiterplatten GmbH ====&lt;br /&gt;
Homepage: http://www.haka-lp.de&lt;br /&gt;
* Zwillingsangebot: 2 identische Europakarten für 50€ (durchkontaktiert, Lötstop, kein Bestückungsdruck, nur Eagle- oder Target-Dateien), auch hierbei kostenlose Duplizierung kleinerer Layouts&lt;br /&gt;
* Zwillingsangebot: 2 identische Doppel-Eurokarten (200x160) für 90€, gleiche Bedingungen wie oben&lt;br /&gt;
* Prototypenangebot (min. Abstand 0,15 mm, min. Leiterbahnbreite 0,15 mm, kleinste Bohrung 0,3 mm, durchkontaktiert, Lötstop), 160x100mm in 2AT = 260EUR .. 8AT = 72 EUR .. 15AT = 63 EUR&lt;br /&gt;
* bei Platinen kleiner 1 qdm gibt es entsprechend mehr ohne Aufpreis&lt;br /&gt;
* Lieferzeit ab 3 Werktage; Achtung: Lieferzeit sind nur Circa-Werte und nicht verbindlich. Auch bei Aufpreis (AGB)!&lt;br /&gt;
* sehr gute Qualität&lt;br /&gt;
&lt;br /&gt;
==== LED-Hobby ====&lt;br /&gt;
Homepage: http://www.led-hobby.de (ebay-Shop)&lt;br /&gt;
* keine Platinen&lt;br /&gt;
* SMD Bestückung, Reflowlöten, Lohnbestückung&lt;br /&gt;
* Laserschne​iden in Plexiglas, Acryl, Sperrholz&lt;br /&gt;
&lt;br /&gt;
==== IBR Leiterplatten GmbH &amp;amp; Co. KG ====&lt;br /&gt;
Homepage: http://www.ringler.de&lt;br /&gt;
* sehr freundlicher und kompetenter Service&lt;br /&gt;
* reagiert sehr schnell&lt;br /&gt;
* Qualität TOP&lt;br /&gt;
* Preise TOP - günstige Einmalkosten/Setup&lt;br /&gt;
* kann auch Dinge wie Alu, Starrflex, fine pitch oder 0,1 er vias&lt;br /&gt;
* Lieferzeit ab 2 Tage&lt;br /&gt;
* 2 Lagen in 10 Tagen - 10 Lagen Multilayer ohne besondere Nachfrage binnen 18 Tagen geliefert&lt;br /&gt;
* liefert generell schneller als bestätigt / macht auch Rahmenaufträge&lt;br /&gt;
* Mehrmengen bei Prototypen werden kostenlos geliefert&lt;br /&gt;
* SMD-Schablonen&lt;br /&gt;
&lt;br /&gt;
==== ILFA Feinstleitertechnik GmbH ====&lt;br /&gt;
Homepage: http://www.ilfa.de&lt;br /&gt;
&lt;br /&gt;
==== kessler systems GmbH ====&lt;br /&gt;
Homepage: http://www.kesslersystems.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;
==== LEITON ====&lt;br /&gt;
Homepage: http://www.leiton.de &amp;lt;br&amp;gt;&lt;br /&gt;
http://www.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;
* Gute Qualität&lt;br /&gt;
* Bis 8-lagig und ab 12 Std.&lt;br /&gt;
&lt;br /&gt;
==== Leiterplatten-Express-Service GmbH ====&lt;br /&gt;
Homepage: http://www.les-gmbh.com&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;
* Allerdings ist die Anmelde-Prozedur ein Drama&lt;br /&gt;
* Preiswert&lt;br /&gt;
&lt;br /&gt;
==== MME-Leiterplatten ====&lt;br /&gt;
Homepage: http://mme-pcb.de&lt;br /&gt;
* [http://www.mikrocontroller.net/topic/73790 Thread &#039;MME-PCB, Erfahrungen&#039;](bereits 4 Jahre alt)&lt;br /&gt;
* Verkauft über seine Homepage (Onlinekalkulator)&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 inklusive&lt;br /&gt;
* 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;
* 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;
* Die auf der Seite beworbene Lierferzeit wird meist eingehalten.&lt;br /&gt;
* Bis zu zehn unterschiedliche Karten können in einem Auftrag gepoolt werden -&amp;gt; preiswerter weil dm² kosten über alle gerechnet werden.&lt;br /&gt;
* Antwortet bei mir nicht auf emails, telefonisch kaum zu erreichen.&lt;br /&gt;
*Kommunikation hat sich erheblich verbesssert.&lt;br /&gt;
* Kommunikation wieder schleppend ( stand: August 2013 )&lt;br /&gt;
&lt;br /&gt;
==== M &amp;amp; V Leiterplatten - Vertriebs GmbH ====&lt;br /&gt;
Homepage: http://pcb-center.de früher: 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;
* Eurokarte doppelseitig 2xStopplack FR4 bleifrei konturgefräst  63€ inkl. MwSt zzgl. Versand&lt;br /&gt;
* Eurokarte einseitig    1xStopplack FR4 bleifrei konturgefräst  44€ inkl. MwSt zzgl. Versand&lt;br /&gt;
&lt;br /&gt;
* Freundlicher Kontakt, Leiterplatten sehen gut aus, lieferten 6 Tage zu frueh!&lt;br /&gt;
* Bis zu fünf unterschiedliche Karten können in einem Auftrag gepoolt werden -&amp;gt; preiswerter weil dm² kosten über alle gerechnet werden.&lt;br /&gt;
&lt;br /&gt;
==== Multi Printed Circuit Boards Ltd. ====&lt;br /&gt;
Homepage: http://www.multi-cb.de&lt;br /&gt;
&lt;br /&gt;
Eigendarstellung:&lt;br /&gt;
* Online Kalkulator&lt;br /&gt;
* nur für Gewerbetreibende&lt;br /&gt;
* 1-48 Lagen Leiterplatten und SMD-Schablonen ab 48h&lt;br /&gt;
* Standard 2L &amp;amp; 4L: 5AT Produktionszeit, 6L &amp;amp; 8L: 6AT Produktionszeit&lt;br /&gt;
* Standard: 125µm Leiter, 0.2mm Bohren&lt;br /&gt;
* Inklusive: Kompletter Design-Rule-Check, Tooling, Lötstopp 2x grün, Posidruck 1x weiß&lt;br /&gt;
* Möglich: 75µm Leiter, Blind- &amp;amp; Buried Vias, 0.1mm Bohren, Dickkupfer, ...&lt;br /&gt;
* Diverse Spezialfertigungen wie Flex, Starrflex, Metallkern, HF, Hoch-Tg, etc.&lt;br /&gt;
* Impedanzkontrolle inkl. Testcoupon&lt;br /&gt;
* UL-Zertifizierung&lt;br /&gt;
&lt;br /&gt;
==== PCB Joker ====&lt;br /&gt;
Homepage: http://www.pcb-joker.com&lt;br /&gt;
* Poolkonzept extrem! &lt;br /&gt;
* 1- bis 4 Lagen Multilayer&lt;br /&gt;
* Allgemein schnell und geringe Terminzuschläge&lt;br /&gt;
* Leiterplatten werden bei verschiedenen deutschen Herstellern platziert&lt;br /&gt;
* Sehr günstig , sehr übersichtliche Onlinekalkulation&lt;br /&gt;
* Bezahlung per PayPal oder Vorkasse&lt;br /&gt;
* Farbe, Dicke, Kupferauflage und Oberfläche können nicht festgelegt werden, sondern sind &amp;quot;Joker&amp;quot;&lt;br /&gt;
&lt;br /&gt;
==== PCB Pool ====&lt;br /&gt;
Homepage: http://www.pcb-pool.de&lt;br /&gt;
Alternativname: BETA Layout&lt;br /&gt;
* Standort: Im Aartal 14, 65326 Aarbergen, [http://www.openstreetmap.de/karte.html?zoom=17&amp;amp;lat=50.23705&amp;amp;lon=8.06361&amp;amp;layers=B000TT Link zur Openstreetmap Karte]&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;
* Aktzeptieren von den gängigsten Layoutprogrammen die Boarddaten direkt. AUCH von KiCAD. Siehe http://www.pcb-pool.com/ppde/info_dataformat.html&lt;br /&gt;
* Bietet als Service das (Platz optimierte) Zusammensetzten verschiedener Platinen/Projekte. (Stichwort: Ausnutzen von konkaven Polygonen oder Platinen mit &amp;quot;Loch&amp;quot; durch andere Kleinstplatinen) Es können auch Projektdateien verschiedener Programme kombiniert werden (Dafür unbedingt manuelles Angebot per Mail einholen und als Kommentar anmerken. ACHTUNG: Der Online-Kalkulator erstellt hier pro Upload einen Auftrag! Daher für eine solche Kombination NICHT verwenden)&lt;br /&gt;
&lt;br /&gt;
==== Precoplat ====&lt;br /&gt;
Homepage: http://www.precoplat.de&lt;br /&gt;
&lt;br /&gt;
* Standort: [http://www.openstreetmap.de/karte.html?zoom=17&amp;amp;lat=51.32818&amp;amp;lon=6.58062&amp;amp;layers=B000TT Oberdiessemer Str. 15, 47805 Krefeld]&lt;br /&gt;
* Prototypen, Großserien und alles dazwischen.&lt;br /&gt;
* Extrem flexibel im Angebot (Fläche/Lieferzeit, Blitz-Prototyping, Rapid-Mass-Produktion) &lt;br /&gt;
* Online Bestellung&lt;br /&gt;
* sehr gute Qualität&lt;br /&gt;
* bis 24 Lagen&lt;br /&gt;
* Mikro-Vias 100-200u&lt;br /&gt;
* Carbonlack&lt;br /&gt;
* Elektrischer Test (Flying probe + Nadelbett)&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 ~5€ Nachnahme&lt;br /&gt;
* Platine 85mm x 58mm, doppelseitig: 33€ zzgl 6,80 Versand&lt;br /&gt;
* Platine 100mm x 160mm, doppelseitig: 49€ +7€ für Lötstopp +6,80€ Versand&lt;br /&gt;
&lt;br /&gt;
==== Rinde PCB GmbH ====&lt;br /&gt;
Homepage: http://www.rinde.de&lt;br /&gt;
* Mitglied der chinesischen Sunshine PCB Group&lt;br /&gt;
&lt;br /&gt;
==== Ruwel ====&lt;br /&gt;
Homepage: http://www.ruwel.com&lt;br /&gt;
* Standort: Am Holländer See 70, 47608 Geldern, [http://www.openstreetmap.de/karte.html?zoom=17&amp;amp;lat=51.50451&amp;amp;lon=6.32046&amp;amp;layers=B000TT Link zur Openstreetmap Karte]&lt;br /&gt;
* Werke in Deutschland und China&lt;br /&gt;
* Überwiegend Großserien.&lt;br /&gt;
* Hochtemperatur, Dickkupfer, Kupferinlays, Semiflex, Sacklochbohren.&lt;br /&gt;
&lt;br /&gt;
==== SMTstencil (Großbritannien) ====&lt;br /&gt;
Homepage: http://smtstencil.co.uk&lt;br /&gt;
* SMD-Schablonen aus Polyester gelasert&lt;br /&gt;
* preiswert&lt;br /&gt;
* kleinste Strukturen 0,25 x 0,25 mm²&lt;br /&gt;
* kleinster Abstand 0,3 mm&lt;br /&gt;
&lt;br /&gt;
==== Steimer Leiterplatten GmbH ====&lt;br /&gt;
Homepage: http://www.steimer.de&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 (bis auf pcb-devboards) &#039;&#039;&#039;keine Durchkontaktierungen&#039;&#039;&#039; herstellen.&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;
* Geometrie: Leiterbahnabstand/-breite &amp;gt;0.3/0.3mm; Bohrdurchmesser &amp;gt;0.8mm?; Bohrrestring &amp;gt;? = D-d; Leiterplattengröße &amp;lt;160x100mm?; ein- und doppelseitig&lt;br /&gt;
* doppelseitige Platinen sind nicht durchkontaktiert !&lt;br /&gt;
* eigentlich ein Ladengeschäft, versendet jedoch auch&lt;br /&gt;
&lt;br /&gt;
==== Platinenbelichter ====&lt;br /&gt;
Homepage: http://www.platinenbelichter.de&lt;br /&gt;
* eine doppelseitige Europlatine kostet 14,90 EUR Grundpreis + Bohrungen (Preis je Bohrung 0,026cent)&lt;br /&gt;
* Geometrie: Leiterbahnabstand/-breite &amp;gt;0.18/0.18mm; Bohrdurchmesser &amp;gt;0.4mm; Bohrrestring &amp;gt;0.25mm = D-d; Leiterplattengröße &amp;lt;300x200mm; ein- und doppelseitig&lt;br /&gt;
* Lötstopplack grün auf anfrage möglich&lt;br /&gt;
* Scannservice&lt;br /&gt;
* Layoutherstellung vom Schaltplan bis zur fertigen Platine&lt;br /&gt;
&lt;br /&gt;
==== Platinendesign ====&lt;br /&gt;
Homepage: http://www.platinendesign.de&lt;br /&gt;
* Geometrie: Leiterbahnabstand/-breite &amp;gt; 0.25/0.25mm; Bohrdurchmesser &amp;gt;?; Bohrrestring &amp;gt; 0.3mm = D-d; Leiterplattengröße &amp;lt; 300×200mm; ein- und doppelseitig&lt;br /&gt;
* eine doppelseitige Europlatine kostet 14 EUR Grundpreis + Bohrung 2cent + Optionen&lt;br /&gt;
* keine Durchkontaktierungen möglich&lt;br /&gt;
* Lötstopplack grün&lt;br /&gt;
* Lieferzeit von bis zu 8 Arbeitstagen nach Geldeingang&lt;br /&gt;
* Zeitweise geschlossen, Neueröffnung am 31.3.2013&lt;br /&gt;
&lt;br /&gt;
==== Ertürk Electronic ====&lt;br /&gt;
Website: http://www.erturk.de&lt;br /&gt;
&lt;br /&gt;
[mailto:info@erturk.de info@erturk.de]&lt;br /&gt;
* Wir rechnen nach dm², Platinenbestellung nur per E-Mail oder telefon möglich. E-Mails werden sehr schnell beantwortet!&lt;br /&gt;
* Platine 1seitig FR4, 10,00€/dm²&lt;br /&gt;
* Platine 2seitig FR4, 14,00€/dm²&lt;br /&gt;
* Kupfer-Endstärke 35µm oder 70µm oder 105µm&lt;br /&gt;
* Chemische Verzinnung optional erhältlich&lt;br /&gt;
* Geometrie: Leiterbahnabstand/-breite &amp;gt; 0,16/0,16mm; Bohrdurchmesser &amp;gt; 0,4mm; Bohrrestring &amp;gt;0,3mm, Leiterplattengröße &amp;lt; 220×330mm; ein- und doppelseitig &lt;br /&gt;
* Sehr hohe Qualität&lt;br /&gt;
* Bohrung möglich (ab 20 dm² CNC gesteuert), 0,03 Euro pro Bohrung&lt;br /&gt;
* Lieferzeit meistens nach Geldeingang oder bis 3 Arbeitstage&lt;br /&gt;
* Ab 15 Platinen sind Durchkontaktierungen, Lötstoplack, Bohrungen und Positionsdruck möglich (Lieferzeit bis zu 2 Wochen). Anfrage und Auftragsannahme nur mit Gerberdaten oder Eagle Daten möglich.&lt;br /&gt;
* Für ein Prototyp-Angebot reicht eine Eagle, Sprintlayout- Target3001 oder PDF-Datei schon aus. PDF muss im Maßstab 1:1 und schwarz/weiß sein&lt;br /&gt;
* Bestückung möglich (THT / SMD oder gemischt) SMD-Bestückung mit Reflow Verfahren!&lt;br /&gt;
* SMD Schablonenherstellung&lt;br /&gt;
* Verpackung und Versand von 0,00 bis 5,90 Euro innerhalb Deutschland egal wieviel Sie bestellen&lt;br /&gt;
* Mindestauftragsannahme ab 15,00 Euro Inklusiver Verpackung/Versand.&lt;br /&gt;
* Stand: Juli 2014&lt;br /&gt;
&lt;br /&gt;
==== Cadgrafik Bauriedl (nur Filme) ====&lt;br /&gt;
Homepage: [http://cadgrafik-bauriedl.de/leiterplattenfilme.htm]&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;
==== pcb-devboards.de ====&lt;br /&gt;
Shop ab 30.10.2015 auf unbestimmte Zeit geschlossen.&lt;br /&gt;
Homepage: http://www.pcb-devboards.de/catalog/index.php?cPath=38_55_157&lt;br /&gt;
* Einseitige oder doppelseitige durchkontaktierte Leiterplatten mit 0,5-3,20mm Dicke&lt;br /&gt;
* Fertigung nur alle 10-15 Arbeitstage&lt;br /&gt;
* Eagle, Target (freeware) oder extended Gerberdaten&lt;br /&gt;
* Basismaterial FR4 (standard oder schwarz) oder RO4003C (weiß)&lt;br /&gt;
* bestimmte Stückzahl von Einzelplatinen ist inklusive, bei sehr vielen Platinen wird eine Fräspauschale erhoben&lt;br /&gt;
* Leiterbahnabstand/-breite Standard: 0,2mm Optional: 0,15mm&lt;br /&gt;
* Kleinster Restring umlaufend Standard: 0,2mm Optional: 0,15mm&lt;br /&gt;
* Kleinster Bohrdurchmesser: 0,4mm&lt;br /&gt;
* Optional 35µm Lötstopplaminat&lt;br /&gt;
* Bestückungsdruck nicht verfügbar&lt;br /&gt;
* Oberfläche: chemisch Zinn oder Silber&lt;br /&gt;
* Kupfer-Endstärke 35µm oder 70µm&lt;br /&gt;
* Maximale Größe 290x195mm = 5,65dm²&lt;br /&gt;
* Versand nach Deutschland ab 6 € (für Stammkunden ab 3,40 €), EU ab 8 €, weltweit ab 8 € &lt;br /&gt;
&lt;br /&gt;
Preisbeispiele:&lt;br /&gt;
* FR4 1,60mm 44x44mm doppelseitig 5 €&lt;br /&gt;
* FR4 1,60mm 160x100mm einseitig 16,50 €, doppelseitig 23,50 €&lt;br /&gt;
* FR4 0,5mm 0,8mm 1,0mm 1,6mm 290x195mm doppelseitig 50 €, Dicke: 3,2mm 60 €&lt;br /&gt;
&lt;br /&gt;
Erfahrungsbericht von [http://www.mikrocontroller.net/articles/Spezial:Beitr%C3%A4ge/Voga2073 Voga2073]: sehr gute Qualität auch bei feinen Strukturen. Der Lötstoplack ist auflaminiert, aber sehr gut positioniert. Leider ist kein Bestückungsdruck möglich. Besonders hervorzuheben ist die Erstellungsdauer: montags bis 12 bestellt, am folgenden Samstag war der Brief in meinem Briefkasten (dies jetzt schon nach drei Bestellungen wiederholt so gelaufen). Preislich ist dieser Anbieter recht attraktiv, ich bin hierhin gewechselt, seit Jakob seine Preisstrategie verschlechtert hat und ich werde wohl bei diesem Anbieter bleiben. Noch positiv zu erwähnen ist das Shopsystem, für jeden wesentlichen Schritt im Herstellungsprozess wird man benachrichtigt. Alles in allem ein sehr guter Anbieter.&lt;br /&gt;
&lt;br /&gt;
=== EU ===&lt;br /&gt;
Einfacher, parametrisierbarer Preisvergleich für aktuell 21 weltweite Platinenhersteller (inkl. Abschätzung der Versandkosten): http://pcbshopper.com&lt;br /&gt;
&lt;br /&gt;
==== BILEX-LP (Bulgarien) ====&lt;br /&gt;
Homepage http://www.bilex-lp.com&lt;br /&gt;
* deutschsprechender Ansprechpartner&lt;br /&gt;
* liefern bleifreie Platinen(RoHs konform)&lt;br /&gt;
* 26€ für eine doppelseitige Eurokarte ohne Lack und Druck&lt;br /&gt;
* ca. 19 euro fuer eine 80x100mm 2-lagige Platine inkl. dukos &lt;br /&gt;
* Stencils ab 15.00€&lt;br /&gt;
* SMD- und THT Bestückung, Beschaffung der Bauteile&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), DHL ab 20,-Euro, besser DHL nehmen&lt;br /&gt;
* Löcher größer 6 mm wurden nicht gebohrt, sondern gefräst(gegen Anfrage)&lt;br /&gt;
* Berichtete Qualitätsmängel (in Einzelfällen): ausgefranste Platinenfräsung, Lötstoplack hebt ab(nur bei Sn-Pb beschichtung, nicht bei Ni-Au).&lt;br /&gt;
* Fräsungen müssen extra bestellt werden! Aber trotzdem günstig&lt;br /&gt;
&lt;br /&gt;
==== CUBE CZ s.r.o. (Tschechische Republik) ====&lt;br /&gt;
Homepage http://www.cube.cz&lt;br /&gt;
&lt;br /&gt;
* kein Termineinhaltung bei Eilservice - Lieferung hat sich durch wiederholte DRC Checks (dauern jeweils einen Tag) und Vorauskassa statt Zahlungsziel 20 Tage wie auf der Rechnung angegeben von 4AT auf 10AT verzögert&lt;br /&gt;
* Keine Design Rules auf der Homepage verfügbar&lt;br /&gt;
* UL Zertifikat aus 2001 für nur 6 Mil Traces&lt;br /&gt;
* für Deutsche Verhältnisse günstig&lt;br /&gt;
&lt;br /&gt;
==== LNAFIN (Finnland) ====&lt;br /&gt;
Homepage: http://electronics-pcb.com&amp;lt;br&amp;gt; &lt;br /&gt;
Produkte: http://electronics-pcb.com/shop &amp;lt;br&amp;gt;&lt;br /&gt;
mailto:pcb@lnafin.com&lt;br /&gt;
* PCB Vertrieb mit Mikrowellenbereich und Multilagig HDI Kompetenz&lt;br /&gt;
* Leiterplatten fuer Industrie und auch als Kleinserien (kein MOQ)&lt;br /&gt;
* Elektronik und Layout Design Hilfe (bitte siehe Produkte)&lt;br /&gt;
* Auch ASIC design und PCBA (14 ASIC Erfahrung)&lt;br /&gt;
* Sicher Service auf Deutsch&lt;br /&gt;
&lt;br /&gt;
==== PIU-Printex (Österreich) ====&lt;br /&gt;
Homepage http://www.piu-printex.at&lt;br /&gt;
* Bei größeren Mengen (&amp;gt; 20 Stück, einseitig, viele Bohrungen) günstig&lt;br /&gt;
* Bearbeitung innerhalb 6 AT&lt;br /&gt;
* Telefonische Kontaktaufnahme bei Rückfragen&lt;br /&gt;
* Ich war sehr positiv überrascht.&lt;br /&gt;
&lt;br /&gt;
==== PRIONIK (Österreich) ====&lt;br /&gt;
Homepage: noch in Arbeit &amp;lt;br&amp;gt;&lt;br /&gt;
mailto:office@prionik.at&lt;br /&gt;
* Erstellung von hochwertigen Folien/Filmen zum selberätzen&lt;br /&gt;
* 1,25 € / 1dm² Film, 2,50 € Mindestbestellwert (Stand September 2013)&lt;br /&gt;
* 2 € Porto Österreich (Stand September 2013)&lt;br /&gt;
* 4 € Porto Deutschland (Stand September 2013) &lt;br /&gt;
* Leiterplattenfertigung auf Anfrage&lt;br /&gt;
&lt;br /&gt;
==== Ragworm (GB) ====&lt;br /&gt;
Homepage http://www.ragworm.eu&lt;br /&gt;
* &amp;quot;All-inclusive&amp;quot;-Angebot mit:&lt;br /&gt;
:*orangenem Lötstopplack&lt;br /&gt;
:*weißem Bestückungsdruck&lt;br /&gt;
:*(beides beidseitig)&lt;br /&gt;
:*2-lagig&lt;br /&gt;
:*internationalem Versand (bei mir 2 Tage, Luftpolsterumschlag)&lt;br /&gt;
:*Fräsen/Trennen&lt;br /&gt;
:*Check der Gerber-Daten (innerhalb von ein paar Stunden bei mir)&lt;br /&gt;
* 10 Stück 5x5: je 8,53 Pfund (~ 10,40€ 23.01.14)&lt;br /&gt;
* Bearbeitung innerhalb von 10 AT&lt;br /&gt;
* sehr schneller und netter Mail-Kontakt&lt;br /&gt;
* gratis Geschenk (bei mir eine 7*9cm große Experimentierplatine + 2 Sticker)&lt;br /&gt;
* es wird ein unauffälliger, kleiner, süßer Wurm (der Ragworm) auf den Lötstopp hinzugefügt&lt;br /&gt;
&lt;br /&gt;
==== The PCB Shop (Belgien) ====&lt;br /&gt;
Homepage http://www.thepcbshop.com&lt;br /&gt;
* Für einfache Sachen&lt;br /&gt;
* Preisrechner funktioniert nur mit IE&lt;br /&gt;
&lt;br /&gt;
==== Vi&amp;amp;Rus International (Bulgarien) ====&lt;br /&gt;
Homepage: http://www.vrint-pcb.com&lt;br /&gt;
* 160x100 für Euro 58,- incl. Express-Versand&lt;br /&gt;
* 3 (!) Arbeitstage&lt;br /&gt;
* RoHS, ENIG&lt;br /&gt;
* 2 Lagen, durchkontaktiert&lt;br /&gt;
* Lötstop beideitig&lt;br /&gt;
* Bestückungsdruck&lt;br /&gt;
* E-Test&lt;br /&gt;
* incl. Vereinzelungen (gefräst)&lt;br /&gt;
* incl. Versand (1 AT), also am 4. AT geliefert&lt;br /&gt;
* Erstklassige Qualität, auch bei Fine-Pitch; schneller, freundlicher Support.&lt;br /&gt;
&lt;br /&gt;
==== SET - Steiner Elektronik Technologie (Bulgarien) ====&lt;br /&gt;
Homepage: http://www.setpcb.bg und http://setgmbh.de&lt;br /&gt;
* Werk in Bulgarien&lt;br /&gt;
* Leiterplatten und Bestückung&lt;br /&gt;
* Standardlieferzeit: 8AT&lt;br /&gt;
* Gute Qualität, schneller unkomplizierter Support (deutsch und englisch)&lt;br /&gt;
&lt;br /&gt;
==== Multi Circuit Boards Ltd. (GB) ====&lt;br /&gt;
Homepage: http://www.multi-circuit-boards.eu&lt;br /&gt;
* Versand erfolgt aus Deutschland, Herstellung in GB&lt;br /&gt;
* nur für Gewerbetreibende&lt;br /&gt;
* Eurokarte doppelseitig mit Lötstopplack, Bestückungsdruck und E-Test in 6AT:  68,54€ 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;
* Liefertermine werden gerne etwas überschritten (auch bei Eilservice)&lt;br /&gt;
* Standard 125µm und 5 AT&lt;br /&gt;
&lt;br /&gt;
==== Euro PCB Ltd. (GB) - obsolet ====&lt;br /&gt;
Homepage http://www.europcb.com&lt;br /&gt;
* Günstige Leiterplatten&lt;br /&gt;
* Schnelle Lieferung&lt;br /&gt;
* Qualitativ OK&lt;br /&gt;
12.02.2012: Webseite ist leer;&lt;br /&gt;
2015: Webseite verweist auf http://www.multi-circuit-boards.eu&lt;br /&gt;
&lt;br /&gt;
==== Top-Tec-PCB (GB) - obsolet ====&lt;br /&gt;
&#039;&#039;&#039;Geschäftsbetrieb eingestellt&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Homepage http://www.top-tec-pcb.com&lt;br /&gt;
* Günstig für Klein- bis Großserien&lt;br /&gt;
* Discount bei Nachbestellung&lt;br /&gt;
* sehr gute Technik (z.&amp;amp;nbsp;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;
==== OLIMEX Ltd. (Bulgarien) - obsolet ====&lt;br /&gt;
&#039;&#039;&#039;Zur Zeit keine PCB-Fertigung (07.01.2015, 3.2015)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Homepage http://www.olimex.com&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;
=== USA ===&lt;br /&gt;
&lt;br /&gt;
==== OSH Park ====&lt;br /&gt;
Homepage: http://oshpark.com (USA)&lt;br /&gt;
* Vermittler und keine eigene Herstellung (&amp;quot;PCB pooling service&amp;quot;). Die Fertigung erfolgt in den USA.&lt;br /&gt;
* Nachfolger von BatchPCB.&lt;br /&gt;
* $5.00 pro Quadratzoll für drei Platinen inkl. Versand nach Deutschland. (2 Lagen, doppelseitiger Bestückungsdruck, Lila)&lt;br /&gt;
* An den Platinen sind noch Stege von der Fertigung, die sich allerdings gut entfernen lassen.&lt;br /&gt;
* Herstellung dauert meist ca. 1 Woche. &lt;br /&gt;
* Versand in der kostengünstigen Version nochmals ca. 2 Wochen. Schneller geht es mit Aufpreis.&lt;br /&gt;
* Auch Fertigung von 4 Layer und Kleinserien möglich.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Erfahrungsbericht 2015-12&#039;&#039;&#039;&lt;br /&gt;
Hatte IS51 Platine als Eagle BRD Datei in Auftrag gegeben (100x80 2-Layer). Es werden immer 3 Stk. gefertigt.&lt;br /&gt;
Kosten ca. 60€ (aufgrund des aktuell fast 1:1 Kurses). Das ganze Bestellsystem auf der Webseite hat mit sehr gut gefallen. Vor der Bestellung bekommt man Ansichten der Platine (Top/Bottom/etc.) was grobe Fehler vermeiden sollte. Auch danach bekommt man per Mail Statuswechsel seiner Bestellung (in Arbeit; gefertigt; Versandstatus+Trackingnummer). Macht Alles einen wohldurchdachten und professionellen Eindruck!&lt;br /&gt;
Platinen kamen insgesamt nach ca. 2,5 Wochen (davon ca. 1 Woche Transport von USA nach DE+Zoll).&lt;br /&gt;
Die Platinen sehen sehr gut aus. Violetter Lötstoplack und vergoldete Pads. Qualität ist auch sehr gut.&lt;br /&gt;
Die Platinen hatten allerdings ein vom Layout verursachtes Problem. Es wurden SMD Widerstände verwendet, die&lt;br /&gt;
eine Ausfräsung im Milling-Layer hatten. Analyse wurde nach Ticketaufgabe durch OSHPark durchgeführt.&lt;br /&gt;
Dabei sehr nett, zügige Antworten und professionell. Obwohl der Fehler im Layout lag und nicht beim Fertiger,&lt;br /&gt;
wurde trotzdem eine Nachfertigung ohne Kosten auf Kulanzbasis durchgeführt!&lt;br /&gt;
&lt;br /&gt;
Also alles TOP! Nur mit der englischen Sprache sollte man gut zurecht kommen.&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;
==== PCBPro ====&lt;br /&gt;
Homepage http://www.pcbpro.com (USA)&lt;br /&gt;
* Bei größeren Mengen (z.&amp;amp;nbsp;B. 100 Stück) sehr niedrige Preise&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== China ===&lt;br /&gt;
&lt;br /&gt;
==== dfrobot ====&lt;br /&gt;
Homepage http://www.dfrobot.com (China)&lt;br /&gt;
&lt;br /&gt;
* Mindestens 10Stk&lt;br /&gt;
* Größe in 5cm Preisrasterung&lt;br /&gt;
* 10Stk 5x5 cm 9.9USD =&amp;gt; 1USD/Stk&lt;br /&gt;
* 200Stk 5x5 cm 69.5USD =&amp;gt; 0.35USD/Stk&lt;br /&gt;
* 4 Lagig 10Stk 5x5 cm 64.90USD =&amp;gt; 6.49USD/Stk&lt;br /&gt;
&lt;br /&gt;
Bemerkung: auf der angegebenen Webseite sind jede Menge Robotik-Gadgets zu finden, von Leiterplattenherstellung keine Spur. Ist der Eintrag noch gültig? --[[Benutzer:Traumflug|Traumflug]] ([[Benutzer Diskussion:Traumflug|Diskussion]]) 21:24, 16. Aug. 2015 (CEST) &lt;br /&gt;
Er ist noch gültig http://www.dfrobot.com/index.php?route=product/category&amp;amp;path=135_134&lt;br /&gt;
&lt;br /&gt;
==== Dirtypcbs ====&lt;br /&gt;
Homepage http://dirtypcbs.com (China)&lt;br /&gt;
* Mindestens 5Stk&lt;br /&gt;
* 2 Layer ca. 10Stk  5x5  cm $14&lt;br /&gt;
* 2 Layer ca. 10Stk 10x10 cm $25&lt;br /&gt;
* 4 Layer ca. 10Stk  5x5  cm $30 (nur grün)&lt;br /&gt;
* 4 Layer ca. 10Stk 10x10 cm $50 (nur grün)&lt;br /&gt;
* Versand: kostenlos 8 Wochen, DHL 30$ 9 Tage&lt;br /&gt;
* Thread: https://www.mikrocontroller.net/topic/362576#4071490&lt;br /&gt;
&lt;br /&gt;
==== Elecrow ====&lt;br /&gt;
Homepage http://www.elecrow.com/services-c-73.html (China)&lt;br /&gt;
* Mindestens 5Stk&lt;br /&gt;
* Andere Farben ohne Aufpreis&lt;br /&gt;
* Größe in 5cm Preisrasterung&lt;br /&gt;
* 2 Layer 10Stk  5x5  cm $10&lt;br /&gt;
* 2 Layer 10Stk 10x10 cm $24&lt;br /&gt;
* 2 Layer 10Stk 10x10 cm $13 (nur grün)&lt;br /&gt;
* 4 Layer 10Stk 10x10 cm $24&lt;br /&gt;
* Nutzen sind möglich: http://www.elecrow.com/blog/pcb-panelize/&lt;br /&gt;
* Thread mit Bildern: https://www.mikrocontroller.net/topic/319266&lt;br /&gt;
&lt;br /&gt;
==== Gold Phoenix ====&lt;br /&gt;
Homepage http://www.goldphoenixpcb.biz (VR China)&lt;br /&gt;
&lt;br /&gt;
==== ITead Studio PCB prototyping service ====&lt;br /&gt;
Homepage http://iteadstudio.com/store/index.php?main_page=index&amp;amp;cPath=19_20 (VR China)&lt;br /&gt;
* Sehr günstige Leiterplatten&lt;br /&gt;
* Relativ günstige Lieferung&lt;br /&gt;
* 10 Stück mit jeweils 5x5cm für 9,90€&lt;br /&gt;
* Qulität relativ gut&lt;br /&gt;
* 100% E-Test&lt;br /&gt;
* Teilweise Probleme mit Gerberdateien, die knapp am Limit (6 mil) sind&lt;br /&gt;
* Testvideo: [http://www.eevblog.com/2011/03/11/eevblog-155-itead-studio-pcb-prototype-goof/ EEVBlog #155]&lt;br /&gt;
&lt;br /&gt;
==== MakePCB ====&lt;br /&gt;
Homepage http://www.makepcb.com (Shanghai, VR China)&lt;br /&gt;
* Ich habe bei MakePCB Platinen geordert und als Zahlungsart Paypal angegeben. Die automatische Bestaetigung kam, es stand nochmal explizit drin dass ich Paypal als Zahlungsart gewaehlt habe und die Bemerkung, dass bei Zahlungsart Paypal in 2 Tagen eine Mail an die gleiche Adresse kaeme mit den Daten für Paypal. Naja, nach 4 Tagen war immernoch nichts da, ich habe denen eine Mail geschrieben und nochmal nach den &amp;quot;versprochenen&amp;quot; Paypaldaten gefragt. Drei Tage spaeter war immernoch nichts da, also habe ich die Bestellung abgebrochen. Am 8. Tag kam die Zahlungsforderung über Paypal, kein Wort der Erklaerung. Am 10. Tag kamen zwei identische Mails, die sagten man haette die PayPal-Zahlungsaufforderung schon geschickt. Irgendwas laeuft in dem Laden also schief.&lt;br /&gt;
* Weiterer Erfahrungsbericht zu MakePCB: Nach einiger Überlegung habe ich mich entschieden, es zu wagen, bei MakePCB Platinen zu bestellen. Meine Platine hatte halbes Euro-Format, aus Kostengründen habe ich gleich 5 Stück bestellt. Der gesamte Preis betrug ca. 45 €, Zahlung per PayPal funktionierte ohne Probleme. Auf der Internetseite von MakePCB wurde für die Produktion 14 Tage, für Shipment 10-14 Tage veranschlagt. Nach der Bestellung konnte ich den Status der Bestellung online in einer Tabelle einsehen. Nach etwas mehr als den veranschlagten 4 Wochen kamen heute die Platinen am. Die Verpackung wirkte nicht sehr professionell (gepolsterter Umschlag, auf den mit Filzstift meine Anschrift geschrieben war), nach dem Aufreissen des Umschlags hielt ich ein mehrfach mit gepolsterter Folie und Klebeband umklebtes Päckchen in der Hand. Erst als ich die Folie entfernt hatte kam eine professionell mit Luftpolsterfolie verschweisste Packung zum Vorschein. Die Platinen sehen, so weit ich bisher beurteilen kann, gut aus, lediglich der Bestückungsdruck ist ein wenig versetzt. Ein kurzer exemplarischer Test mit dem Multimeter sah auch in Ordnung aus. Alles in allem macht das Angebot, insbesondere zu dem Preis, einen echt guten Eindruck. Ich kann es nur empfehlen. &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;
* Eurokarte doppelseitig mit Lötstopp beidseitig und Bestückungsdruck kostet 60€ ohne MwSt +15€ Versand&lt;br /&gt;
* 2Stück 64€ ohne MwSt +15€ Versand&lt;br /&gt;
* 10Stück 90€ ohne MwSt +15€ Versand&lt;br /&gt;
* Eurokarte einseitig ohne Lötstopp und ohne Bestückungsdruck kosten 10Stück 71€ ohne MwSt +19€ Versand&lt;br /&gt;
* Preiskalkulation inzwischen auch ohne Anmeldung (18.12.2015)&lt;br /&gt;
&lt;br /&gt;
==== Seeed ====&lt;br /&gt;
Homepage http://www.seeedstudio.com (China)&lt;br /&gt;
* Mindestens 10Stk&lt;br /&gt;
* Größe in 5cm Preisrasterung&lt;br /&gt;
* 10Stk 5x5 cm 9.9USD =&amp;gt; 1USD/Stk&lt;br /&gt;
* 4 Lagig  5Stk 5x5 cm 39.90USD =&amp;gt; 8USD/Stk&lt;br /&gt;
* 4 Lagig 10Stk 5x5 cm 49.90USD =&amp;gt; 5USD/Stk&lt;br /&gt;
* Blaue, weiße, rote, gelbe, schwarze platinen für 10USD Aufpreis&lt;br /&gt;
* Überproduktion wird mit geliefert, bei einer 2cmx1cm Platine wurden 24Stk anstatt 10Stk geliefert.&lt;br /&gt;
* Kostenloser Standardversand bei Bestellungen über 50USD&lt;br /&gt;
&lt;br /&gt;
==== ShenZhen2u ====&lt;br /&gt;
Homepage http://www.shenzhen2u.com (China)&lt;br /&gt;
* Mindestens 10Stk&lt;br /&gt;
* Auch 6 lagige boards&lt;br /&gt;
* Größe in 5cm Preisrasterung&lt;br /&gt;
* Maximal 30x30cm&lt;br /&gt;
* 10Stk 5x5 cm 8.9 USD =&amp;gt; 0.9 USD/Stk&lt;br /&gt;
* 2 Lagig 500Stk 5x5 cm 139 USD =&amp;gt; 0.27 USD/Stk&lt;br /&gt;
* 4 Lagig 10Stk 5x5 cm 33 USD =&amp;gt; 3.3 USD/Stk&lt;br /&gt;
* Dieser Eintrag wurde [http://www.mikrocontroller.net/articles/Spezial:Beitr%C3%A4ge/Shenzhen2u vom Hersteller] selbst erstellt.&lt;br /&gt;
&lt;br /&gt;
Anmerkung: sehr günstige Preise, dafür hohe Versandkosten (&amp;quot;Swiss Post&amp;quot; 27 USD, keine kostenlose Versandoption)&lt;br /&gt;
&lt;br /&gt;
==== smart prototyping ====&lt;br /&gt;
Homepage: http://smart-prototyping.com (China)&lt;br /&gt;
* Mindestens 10Stk&lt;br /&gt;
* Größe in 5cm Preisrasterung&lt;br /&gt;
* Auch 6 lagige boards&lt;br /&gt;
* Maximal 40x40cm&lt;br /&gt;
* 10Stk 5x5 cm 8.9USD =&amp;gt; 0.9USD/Stk&lt;br /&gt;
* 500Stk 5x5 cm 132.92USD =&amp;gt; 0.27USD/Stk&lt;br /&gt;
* 4 Lagig 10Stk 5x5 cm 39.9USD =&amp;gt; 4USD/Stk&lt;br /&gt;
* 6 Lagig 10Stk 5x5 cm 239.9USD =&amp;gt; 24USD/Stk&lt;br /&gt;
* Lieferzeit ca. 10 Tage (Standardversand mit der Deutschen Post nach DE)&lt;br /&gt;
* Schnellere Bearbeitung bei Aufpreis möglich&lt;br /&gt;
* Eagle *.brd Dateien werden akzeptiert&lt;br /&gt;
* Design Rules für Eagle von der Homepage ladbar&lt;br /&gt;
* Problemloser und schneller Kontakt per Mail (englisch)&lt;br /&gt;
&lt;br /&gt;
== Preisvergleichstabellen (Stand Februar 2010) ==&lt;br /&gt;
&lt;br /&gt;
Preise für 1, 2 Europlatinen (160x100), FR4 1.6mm, HAL bleifrei, 150µm Leiter, 0.3mm Bohren, doppelseitig, 8AT, kein Bestückungsdruck, inkl. MwSt, ohne Versand.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&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;
|-&lt;br /&gt;
!style=&amp;quot;text-align:left&amp;quot; |Hersteller !!Preis (€) 1x !!Preis (€) 2x&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;text-align:left&amp;quot; colspan=&amp;quot;3&amp;quot; |&#039;&#039;ohne Lötstopp, ohne E-Test&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;text-align:left&amp;quot; |&#039;&#039;&#039;Basista Leiterplatten&#039;&#039;&#039;|| 43,66 || 81,61&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;text-align:left&amp;quot; |&#039;&#039;&#039;Fischer Leiterplatten GmbH&#039;&#039;&#039; (10AT, immer mit LS.+E-T.)|| 46,41 || 73,07&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;text-align:left&amp;quot; |&#039;&#039;&#039;HAKA Elektronik-Leiterplatten GmbH&#039;&#039;&#039;|| 64,54 || 106,13&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;text-align:left&amp;quot; |&#039;&#039;&#039;LEITON&#039;&#039;&#039;|| 54,98 || 104,51&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;text-align:left&amp;quot; |&#039;&#039;&#039;MME-Leiterplatten&#039;&#039;&#039; (200µm Leiter)|| 41,44 || ?&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;text-align:left&amp;quot; |&#039;&#039;&#039;PCB Pool&#039;&#039;&#039;|| 50,27 || 100,54&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;text-align:left&amp;quot; |&#039;&#039;&#039;Q-print/Q-PCB&#039;&#039;&#039;|| 55,62 || 95,89&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;text-align:left&amp;quot; colspan=&amp;quot;3&amp;quot; |&#039;&#039;mit Lötstopp, mit E-Test&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;text-align:left&amp;quot; |&#039;&#039;&#039;Basista Leiterplatten&#039;&#039;&#039;|| 77,66 || 115,61&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;text-align:left&amp;quot; |&#039;&#039;&#039;Fischer Leiterplatten GmbH&#039;&#039;&#039; (10AT)|| 46,41 || 73,07&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;text-align:left&amp;quot; |&#039;&#039;&#039;LEITON&#039;&#039;&#039;|| 88,79 || 147,39&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;text-align:left&amp;quot; |&#039;&#039;&#039;Multi PCB Ltd. Leiterplatten&#039;&#039;&#039; (6AT)|| 78,06 || 156,13&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;text-align:left&amp;quot; |&#039;&#039;&#039;M &amp;amp; V Leiterplatten - Vertriebs GmbH&#039;&#039;&#039;|| 62,83 || 125,66 &lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;text-align:left&amp;quot; |&#039;&#039;&#039;Onlineshop WEdirekt&#039;&#039;&#039;|| 128,75 || 172,38&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Preise für 1, 2, 10 Europlatinen (160x100), FR4 1.6mm, HAL bleifrei, 150µm Leiter, 0.3mm Bohren, doppelseitig, 8AT, 1x Bestückungsdruck, 2x Lötstopp, E-Test, inkl. MwSt, ohne Versand.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&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;
|-&lt;br /&gt;
!Hersteller !! Preis (€) 1x !!Preis (€) 2x !!Preis (€) 10x !! Nachbest. (€) 10x&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;text-align:left&amp;quot; colspan=&amp;quot;5&amp;quot; |&#039;&#039;mit Lötstopp, mit Bestückungsdruck, mit E-Test&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;text-align:left&amp;quot; |&#039;&#039;&#039;Fischer Leiterplatten GmbH&#039;&#039;&#039; (10AT)|| 58,31 || 84,97 || 337,72 || 219,91 &lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;text-align:left&amp;quot; |&#039;&#039;&#039;HAKA Elektronik-Leiterplatten GmbH&#039;&#039;&#039;|| 82,54 || 124,13 || 302,08 || 284,08 &lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;text-align:left&amp;quot; |&#039;&#039;&#039;LEITON&#039;&#039;&#039;|| 124,37 || 187,15 || 389,84 || x &lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;text-align:left&amp;quot; |&#039;&#039;&#039;Multi PCB Ltd. Leiterplatten&#039;&#039;&#039;|| 78,06 || 156,13 || 272,27 || 180,64&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;text-align:left&amp;quot; |&#039;&#039;&#039;M &amp;amp; V Leiterplatten - Vertriebs GmbH&#039;&#039;&#039;|| 110,43 || 173,26 || ? || ? &lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;text-align:left&amp;quot; |&#039;&#039;&#039;PCB Pool&#039;&#039;&#039;|| 122,29 || 129,26 || 407,58 || x &lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;text-align:left&amp;quot; |&#039;&#039;&#039;Q-print/Q-PCB&#039;&#039;&#039;|| 96,80 || 166,90 || 834,48 || x &lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;text-align:left&amp;quot; |&#039;&#039;&#039;Onlineshop WEdirekt&#039;&#039;&#039;|| 145,18 || 190,64 || 379,49 || x&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Lohnbestücker - Kleinserien ==&lt;br /&gt;
&lt;br /&gt;
=== Deutschland ===&lt;br /&gt;
&lt;br /&gt;
==== PCB Pool ====&lt;br /&gt;
Homepage: http://www.pcb-pool.com/ppde/info_pcb_assembling.html&lt;br /&gt;
* Prototyp &amp;amp; Kleinserien, Größere Stückzahlen auf Anfrage&lt;br /&gt;
* SMD bis 0402, THT&lt;br /&gt;
* 5 Tage ab Eingang aller Bauteile &lt;br /&gt;
* Produktionsstandort: ??&lt;br /&gt;
&lt;br /&gt;
==== D-E-K Dischereit GmbH &amp;amp; Co. KG ====&lt;br /&gt;
Homepage: http://www.dischereit.de&lt;br /&gt;
* Prototyp, Kleinserien, Serie&lt;br /&gt;
* SMD bis 0402, THT&lt;br /&gt;
* Bauteilbeschaffung&lt;br /&gt;
* Standort: Ascheberg, Coesfeld, Deutschland&lt;br /&gt;
&lt;br /&gt;
==== kessler systems GmbH ====&lt;br /&gt;
Homepage: http://www.kesslersystems.de&lt;br /&gt;
* SMD bis 0201, THT&lt;br /&gt;
* BGAs&lt;br /&gt;
* macht auch Großserien&lt;br /&gt;
* 5 Tage ab Eingang aller Bauteile, Express möglich&lt;br /&gt;
* Standort: Königseggwald nähe Ravensburg, Deutschland&lt;br /&gt;
&lt;br /&gt;
==== PBS-Electronic ====&lt;br /&gt;
Homepage: http://www.pbs-electronic.de&lt;br /&gt;
* Prototyp, Kleinserien, Serie&lt;br /&gt;
* BGA, QFN, TQPF, Fine Pitch, SMD bis 0402, THT&lt;br /&gt;
* Einzel IC Bestückung möglich&lt;br /&gt;
* Spezialist für LED Technik&lt;br /&gt;
* Standort: Arnsberg, Hochsauerland, Deutschland&lt;br /&gt;
&lt;br /&gt;
==== riese electronic GmbH ====&lt;br /&gt;
Homepage: http://www.riese-electronic.de&lt;br /&gt;
* SMD bis 0201, THT&lt;br /&gt;
* BGAs inkl Röntgen&lt;br /&gt;
* macht auch Großserien&lt;br /&gt;
* 5 Tage ab Eingang aller Bauteile, Express möglich&lt;br /&gt;
* Standort: Horb am Neckar, Deutschland&lt;br /&gt;
&lt;br /&gt;
==== Gardow Engineering ====&lt;br /&gt;
Homepage: http://www.gardow-engineering.de&lt;br /&gt;
* SMD ab 0201, THT, THR, Mischbestückung, BGA Bestückung &lt;br /&gt;
* ab 1 Stück bis zur Serie&lt;br /&gt;
* Frontplattenfertigung &lt;br /&gt;
* Materialbeschaffung, Lieferzeiten zwischen 1-6AT, niedrige Einmalkosten&lt;br /&gt;
* Onlinekalkulator zur schnellen Kostenermittlung &lt;br /&gt;
* http://www.gardow-engineering.de/leiterplattenbestückung/onlinekalkulation.html&lt;br /&gt;
* Standort: Nordheim bei Heilbronn, Deutschland&lt;br /&gt;
&lt;br /&gt;
==== M.Richter GmbH&amp;amp;Co.&amp;amp;KG ====&lt;br /&gt;
Homepage: http://www.richter-pforzheim.de&lt;br /&gt;
* SMD ab0201, THT, THR, Mischbestückung&lt;br /&gt;
* ab 1 Stück bis zur mittleren Serie&lt;br /&gt;
* Wickeln von Sonderspulen und Kabelkonfektion &lt;br /&gt;
* Materialbeschaffung, Schnelldienste möglich&lt;br /&gt;
* Standort: Pforzheim, Deutschland&lt;br /&gt;
&lt;br /&gt;
==== SYSTART GmbH ====&lt;br /&gt;
Homepage: http://www.systart.de&lt;br /&gt;
* Online-Kalkulator für Prototypen- und Kleinserienbestückung: http://www.systart.de/prototypen-kalkulator&lt;br /&gt;
* Größere Stückzahlen auf Anfrage&lt;br /&gt;
* 4 Tage ab Eingang aller Bauteile&lt;br /&gt;
* Günstige Einmalkosten&lt;br /&gt;
* SMD- und THT-Bestückung, beidseitig&lt;br /&gt;
* Gerätemontage&lt;br /&gt;
* Materialbeschaffung (falls gewünscht)&lt;br /&gt;
* Ingenieurbüro und Fertigung in einem Haus: bei technischen Rückfragen stehen auch Entwickler zur Verfügung&lt;br /&gt;
* Standort: Emmering bei München&lt;br /&gt;
&lt;br /&gt;
==== Traffitec ====&lt;br /&gt;
Homepage: http://www.traffitec.de&lt;br /&gt;
* Bestückt Prototypen, Kleinserien, Normalserien&lt;br /&gt;
* In THT, SMD und gemischt.&lt;br /&gt;
* und von allen Seiten&lt;br /&gt;
* Einpresstechnik&lt;br /&gt;
* Starrflex&lt;br /&gt;
* Komponentenbau&lt;br /&gt;
* Standort: [http://www.openstreetmap.de/karte.html?zoom=17&amp;amp;lat=51.6904&amp;amp;lon=6.14378&amp;amp;layers=B000TT Goch nähe Moers, Deutschland]&lt;br /&gt;
&lt;br /&gt;
==== VTS Elektronik GmbH ====&lt;br /&gt;
Homepage: http://www.vts-elektronik.de&lt;br /&gt;
* SMD bis 0402, BGA, THT auch gemischt und beidseitig&lt;br /&gt;
* Dampfphasenlöten&lt;br /&gt;
* Prototyp, Kleinserien, Serie&lt;br /&gt;
* Komplette Materialbeschaffung&lt;br /&gt;
* Schnell und flexibel&lt;br /&gt;
* Standort: Fürstenau nähe Osnarbrück, Deutschland&lt;br /&gt;
&lt;br /&gt;
==== JL-Elektronik ====&lt;br /&gt;
Homepage: http://www.jl-elektronik.de&amp;lt;br /&amp;gt;&lt;br /&gt;
mailto:info@jl-elektronik.de&lt;br /&gt;
* Prototyp, Kleinserien&lt;br /&gt;
* ab 1 Stück&lt;br /&gt;
* SMD bis 0402, THT, gemischt und beidseitig&lt;br /&gt;
* Gerätemontage&lt;br /&gt;
* Standort: Rheinland Pfalz, Deutschland&lt;br /&gt;
&lt;br /&gt;
=== International ===&lt;br /&gt;
&lt;br /&gt;
==== Kaufmann Automotive GmbH ====&lt;br /&gt;
Homepage: http://www.kaufmann-automotive.ch&lt;br /&gt;
* SMD bis 0201, THT&lt;br /&gt;
* BGA, QFN, TQFP, Fine Pitch, SMD bis 0402&lt;br /&gt;
* Prototyp, Kleinserien, Serie&lt;br /&gt;
* Komplette Materialbeschaffung&lt;br /&gt;
* Standort: Eichberg nähe Bregenz, Schweiz&lt;br /&gt;
&lt;br /&gt;
==== Profiants ====&lt;br /&gt;
Homepage: http://www.ProfiAnts.com&lt;br /&gt;
* SMD bis 0201, THT&lt;br /&gt;
* ab 1 Stück&lt;br /&gt;
* macht auch Großserien&lt;br /&gt;
* Komplette Materialbeschaffung&lt;br /&gt;
* 5 Tage ab Eingang aller Bauteile&lt;br /&gt;
* Standort: Bulgarien&lt;br /&gt;
&lt;br /&gt;
==== REDER Domotic GmbH ====&lt;br /&gt;
Homepage: http://reder.eu&lt;br /&gt;
* Prototypen, Kleinserie, Serie&lt;br /&gt;
* THT, SMD ab 0201 Baugröße&lt;br /&gt;
* Komplette Materialbeschaffung&lt;br /&gt;
* Prototypen über Nacht möglich&lt;br /&gt;
* riesen Vorteil: der Mann an der Maschine ist selbst Entwickler&lt;br /&gt;
* Standort: Berndorf, Österreich&lt;br /&gt;
&lt;br /&gt;
== Siehe auch ==&lt;br /&gt;
* [http://www.cadsoft.de/services/board-houses/?language=de Übersicht von Cadsoft, sortiert nach PLZ]&lt;br /&gt;
* [http://www.mikrocontroller.net/topic/245590 Forum: Platinensammler - Leiterkarten für 30ct/cm²]&lt;br /&gt;
* [http://www.elektroniknet.de/anbieterkompass/produktuebersicht/?tx_wmvs_pi1%5Bid%5D=1130 Übersichtsseite von www.elektroniknet.de]&lt;br /&gt;
* [[Elektronikversender]]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Platinen]]&lt;br /&gt;
[[Kategorie:Lieferanten]]&lt;br /&gt;
[[Kategorie:Listen]]&lt;/div&gt;</summary>
		<author><name>Df2au</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=AVR_Net-IO_Bausatz_von_Pollin&amp;diff=88484</id>
		<title>AVR Net-IO Bausatz von Pollin</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=AVR_Net-IO_Bausatz_von_Pollin&amp;diff=88484"/>
		<updated>2015-05-03T08:16:13Z</updated>

		<summary type="html">&lt;p&gt;Df2au: /* Funktionsumfang der Originalsoftware */ Typo&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Hier steht eine Beschreibung des Pollin Bausatzes [http://www.pollin.de/shop/shop.php?cf=detail.php&amp;amp;pg=NQ==&amp;amp;a=MTQ5OTgxOTk= AVR-NET-IO. Best.Nr. 810 058], oder als aufgebautes Fertigmodul, Best.Nr. 810 073. &lt;br /&gt;
&lt;br /&gt;
Einige Features: Ethernet-Platine mit ATmega32 und Netzwerkcontroller ENC28J60. Die Platine verfügt über 8 digitale Ausgänge, 4 digitale und 4 ADC-Eingänge, welche alle über einen Netzwerkanschluss (TCP/IP) abgerufen bzw. geschaltet werden können.&lt;br /&gt;
&lt;br /&gt;
[[Datei:AVR-NET-IO ADD-ON.JPG|thumb|right|400px|AVR-NET-IO (links) mit zusätzlicher SUB-D Anschlussplatine (rechts, nicht im Lieferumfang)und Add-On-Board (oben, mit aufgelötetem RFM12-433-Modul, beides nicht im Lieferumfang). Ebenso ist zusätzlich ein nicht im Lieferumfang enthaltener kleiner Kühlkörper auf einem der Spannungsregler montiert und die Schraubklemmen zur Stromversorgung wurden durch Buchsen ersetzt.]]&lt;br /&gt;
&lt;br /&gt;
== Technische Daten ==&lt;br /&gt;
&lt;br /&gt;
* Betriebsspannung 9 V AC/DC&lt;br /&gt;
* Stromaufnahme ca. 190 mA&lt;br /&gt;
* bzw. 5V DC, 1A (Steckernetzteil) an J6&lt;br /&gt;
* 8 digitale Ausgänge (0/5 V) [PC0-PC7 an J3]&lt;br /&gt;
* 4 digitale Eingänge (0/5 V) [PA0-PA3 an J3]&lt;br /&gt;
* 4 ADC-Eingänge (10 Bit) [PA4-PA7 an Schraubklemmen]&lt;br /&gt;
* LCD-Anschluss (HD44780 komp. Controller nötig) [PD2-7,PB0,PB3 an EXT]&lt;br /&gt;
* [[ENC28J60]]&lt;br /&gt;
* [http://www.atmel.com/dyn/Products/Product_card.asp?part_id=2014 ATmega32] Mikrocontroller&lt;br /&gt;
&lt;br /&gt;
Maße (L×B×H): 108×76×22 mm.&lt;br /&gt;
&lt;br /&gt;
== Hardware ==&lt;br /&gt;
=== AVR-NET-IO ===&lt;br /&gt;
&lt;br /&gt;
Die Schaltung des AVR-NET-IO ist recht einfach:&lt;br /&gt;
* Ein ATmega32 Mikrocontroller enthält die gesamte Software&lt;br /&gt;
* Ein ENC28J60 Ethernet-Controller für das Senden und Empfangen von Ethernet Frames (MAC und PHY Ethernet Layer) ist über [[SPI]] mit dem ATmega32 verbunden&lt;br /&gt;
* Ein Ethernet RJ-45 MagJack TRJ 0011 BA NL von [http://www.trxcom.com/ Trxcom] mit eingebautem Übertrager und Anzeige-LEDs am ENC28J60.&lt;br /&gt;
* Ein MAX232 für die serielle Schnittstelle&lt;br /&gt;
* Zwei Spannungsregler, 5 V und 3,3 V&lt;br /&gt;
* &amp;quot;Hühnerfutter&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Fast alle I/O Pins des ATmega32 sind irgendwo auf Anschlüssen herausgeführt. Entweder auf dem SUB-D Stecker, dem EXT oder ISP Wannensteckern oder den blauen Anschlussklemmen. Eine Schutzbeschaltung gibt es nicht.&lt;br /&gt;
&lt;br /&gt;
Die blauen Anschlussklemmen haben eine Nut und eine Feder mit denen man&lt;br /&gt;
sie zusammenstecken kann, dadurch ist das Anlöten wesentlich leichter&lt;br /&gt;
und sie stehen auch sauber in der Reihe.&lt;br /&gt;
&lt;br /&gt;
=== Erweiterungsplatine ===&lt;br /&gt;
&lt;br /&gt;
Seit Januar 2010 gibt es auch eine Erweiterungsplatine &lt;br /&gt;
&lt;br /&gt;
[http://www.pollin.de/shop/dt/Nzg4OTgxOTk-/Bausaetze/Diverse/Bausatz_Add_on_fuer_AVR_NET_IO.html Add-on für AVR-NET-IO-Board Best.Nr. 810 112]&lt;br /&gt;
&lt;br /&gt;
Diese Platine erweitert das NET-IO um:&lt;br /&gt;
&lt;br /&gt;
* SD-Karten-Slot über SPI&lt;br /&gt;
* Display über PCF 8574&lt;br /&gt;
* Infrarot-Empfang&lt;br /&gt;
* [[RFM12]] Funkmodul (nicht im Lieferumfang enthalten)&lt;br /&gt;
&lt;br /&gt;
Eine Aufstellung bekannter Fehler findet sich weiter unten [[#Bekannte Fehler|Bekannte Fehler - Erweiterungplatine]] &lt;br /&gt;
&lt;br /&gt;
Erste Erfahrungsberichte im Forum http://www.mikrocontroller.net/topic/161354&lt;br /&gt;
&lt;br /&gt;
=== Hardware-Umbauten &amp;amp; -Verbesserungen ===&lt;br /&gt;
&lt;br /&gt;
* Kühlkörper auf dem 7805 - (Vorsicht: Der LM317T ist rückseitig spannungsführend. Den Kühlkörper also keinesfalls an beide Spannungsregler anschließen!)&lt;br /&gt;
* MAX232 nach anfänglicher Konfiguration nicht bestücken um Strom zu sparen oder um zwei weitere I/O-Pins zu gewinnen&lt;br /&gt;
* 10µF-Elkos für MAX232N (C14-C17) durch 1µF ersetzen. &amp;lt;s&amp;gt;Eine 10µF-Version für den MAX232 gibt es nicht&amp;lt;/s&amp;gt;. Die 10µF-Elkos können auch Ursache einer nicht funktionierenden RS232 sein.&lt;br /&gt;
** Laut Spezifikation sind auch mehr als 1µF erlaubt. Selbst Atmel verwendet beim STK500 10µF. Dies führt keinesfalls dazu, dass die RS232 nicht mehr funktioniert.&lt;br /&gt;
* Die IC-Fassungen aus &amp;quot;Pollins Resterampe&amp;quot; durch Fassungen mit gedrehten Kontakten ersetzen. &lt;br /&gt;
* &#039;&#039;Netz&#039;&#039; LED nicht bestücken oder größere Widerstände einlöten um Strom zu sparen (R3)&lt;br /&gt;
* Vorwiderstände der Ethernet-LEDs größer machen (z.&amp;amp;nbsp;B. verdoppeln) um Strom zu sparen (R6,R7)&lt;br /&gt;
* Linear-Spannungsregler ersetzen&lt;br /&gt;
* Kondensator an AREF-Pin des ATmega32 (ATmega32 Datenblatt) (100nF gegen Masse)&lt;br /&gt;
* Kondensator an den RESET-Pin des ATmega32 ([http://www.atmel.com/dyn/resources/prod_documents/doc2521.pdf Atmel Application Note AVR042: AVR Hardware Design Considerations]) Wenn man diese Quelle genauer liest, ist das aber eher unnötig. - Kondensator bei selbstbau-ISP empfehlenswert.&lt;br /&gt;
* Umbau auf 3,3 V:&lt;br /&gt;
** Ersatz der Spannungsregler durch einen einzigen 3,3 V Regler&lt;br /&gt;
** Anpassen (verkleinern) des LED-Vorwiderstands R3 für 3,3 Volt Betrieb&lt;br /&gt;
** Reduktion der Taktfrequenz (Austausch von Q2) auf den bei 3,3V erlaubten Bereich des ATmega32 ( ATmega32(L)  3.3V /8.0 Mhz Takt )&lt;br /&gt;
** Ersatz des MAX232 durch einen MAX3232&lt;br /&gt;
[[Bild:POWER.JPG|thumb|400px|5V Stromversorgung über USB Kabel, ohne 5 V Spannungsregler und Gleichrichterdioden, Vorsicht: kein Verpolungsschutz!  ]]&lt;br /&gt;
* ATmega32 vom ENC28J60 takten (OSC2)&lt;br /&gt;
* Betrieb mit Gleichspannung:&lt;br /&gt;
** Dioden D2 und D5 durch Drahtbrücken ersetzen, D1 und D4 nicht bestücken (komplette Entfernung des Brückengleichrichters, beinhaltet Verlust des Verpolungsschutzes)&lt;br /&gt;
** Diode D2 bestücken, D5 durch Drahtbrücke ersetzen, D1 und D4 nicht bestücken (Brückengleichrichter durch Verpolungsschutze ersetzen)&lt;br /&gt;
*** ??? Ist dies nicht kontraproduktiv? Bei mir wurde durch D2-Bestückung die Eingangsspannung von ca. 5,2 V am LM317T auf ca. 4,6 V gedrückt, so dass am ENC28J60 nur ca. 2,6 V ankamen (außerhalb der lt. Datenblatt &amp;quot;Operating voltage range of 3.14V to 3.45V&amp;quot;). Man müsste also ein geregeltes Netzteil mit ca. 5,5 V anschließen um 5 und 3,3 V zu erzielen. Dann lieber den Verpolungsschutz durch andere Maßnahmen sicherstellen.&lt;br /&gt;
** Beim Betrieb von USB beachten, dass USB-Spezifikation keinesfalls 5V garantiert, sondern Spannung bis runter 4.4V erlaubt und dann u.U. durch den LM317 nicht mehr genügend Spannung am ENC anliegt. Das äußert sich so, dass zwar der Atmega einwandfrei funktioniert, die Ethernet-Kommunikation aber nicht oder nur sehr sporadisch.&lt;br /&gt;
* Betrieb mit Steckernetzteil&lt;br /&gt;
** Wenn man ein energieeffizientes Stecker-Schaltnetzteil mit 5V, 1A direkt an J6 kontaktiert, kann man sich die o.g. Um- und Ausbauten sparen. Kein Spannungsregler wird mehr heiß, kein Kühlkörper wird benötigt, das Board arbeitet absolut stabil. &lt;br /&gt;
* Ersatz des ATmega32 durch einen ATmega644 oder ATmega1284p mit mehr FLASH-Speicher.&lt;br /&gt;
** Der ATmega644 und auch der ATMega1284p sind nicht mit der Pollin-Firmware kompatibel&lt;br /&gt;
* 100nF über alle drei IC Störunterdrückung zusätzlich bestücken&lt;br /&gt;
&lt;br /&gt;
== Inbetriebnahme der Originalsoftware ==&lt;br /&gt;
=== Einleitung ===&lt;br /&gt;
&lt;br /&gt;
Die bei Auslieferung (Stand September 2008) in den ATmega32 gebrannte Firmware stellt sich manchmal recht zickig an. Es scheint dann die Netzwerk-Schnittstelle, ggf. auch  die serielle Schnittstelle, nicht zu funktionieren. Falls es Probleme geben sollte, sollte man erst einmal ein Firmwareupdate versuchen. Dies geschieht über die serielle Schnittstelle mittels des Programmes NetServer (aktuelle Version 1.03, Februar 2010), die dem Bausatz beiliegt. &lt;br /&gt;
&lt;br /&gt;
Falls die serielle Schnittstelle ebenfalls nicht zugänglich ist, kann mit den im folgenden beschriebenen Schritten die Inbetriebnahme der Software möglich sein. Dazu benötigt man:&lt;br /&gt;
&lt;br /&gt;
* Einen Windows-PC mit Ethernet-Schnittstelle und RS232-Schnittstelle (ein Prolific RS232-USB Konverter funktioniert)&lt;br /&gt;
* Entweder&lt;br /&gt;
**zwei normale (&#039;&#039;straight through&#039;&#039;) Ethernet-Kabel und einen Ethernet Switch/Hub, oder&lt;br /&gt;
**ein gekreuztes(&#039;&#039;cross over&#039;&#039;) Ethernet-Kabel&lt;br /&gt;
* Einen AVR Programmer (Hardware und Software). Zum Beispiel einen [[AVR Dragon]] oder [[STK500]] mit [[AVR Studio]] oder das [[Pollin ATMEL Evaluations-Board]] und [[avrdude]].&lt;br /&gt;
* Die [http://www.pollin.de/shop/ds/MTQ5OTgxOTk-.html Pollin NetServer Software], Version 1.03 (oder neuer)&lt;br /&gt;
&lt;br /&gt;
=== Gelieferten ATmega32 richtig einstellen ===&lt;br /&gt;
[[image:fuse_bits_avr_studio.jpg|thumb|right|250px|Einstellungen der Fuse-Bits mittels AVR Studio 4]]&lt;br /&gt;
Die Fuses der gelieferten ATmega32s scheinen nicht immer mit den im Handbuch auf Seite 12 als erforderlich angegebenen Fuse-Einstellungen übereinzustimmen.&lt;br /&gt;
&lt;br /&gt;
Dies kann man mittels eines Programmers ändern. LFuse = 0xBF, HFuse = 0xD2. Das genaue Vorgehen hängt dabei vom verwendeten Programmer ab. Bei der Gelegenheit kann man ebenfalls eine Sicherheitskopie des ursprünglichen Flash-Inhalts und des EEPROMs anfertigen. Das EEPROM scheint die MAC-Adresse des Ethernet-Ports zu enthalten.&lt;br /&gt;
&lt;br /&gt;
Entgegen der Spezifikation im Handbuch von Pollin sollten die &#039;&#039;&#039;HFuses auf 0xC2&#039;&#039;&#039; gesetzt werden, d. h. CKOPT-Fuse programmiert (dies ist in der Software Version 1.03 bereits vollzogen). Das sorgt für einen stabilen Betrieb des AVR-Oszillators im &amp;quot;full rail-to-rail swing&amp;quot;-Mode bei 16 MHz. Atmel garantiert ansonsten nur stabilen Betrieb bis 8 MHz. Siehe ATmega32-Datenblatt, Kapitel 8.4, Crystal Oscillator.&lt;br /&gt;
{{Absatz}}&lt;br /&gt;
&lt;br /&gt;
==== Funktionsfähige Konfiguration - AVR-Prog ====&lt;br /&gt;
&lt;br /&gt;
[[Bild:Avrprog.png|thumb|right|250px]]&lt;br /&gt;
Benutzer von AVR-Prog können die nachfolgenden Einstellungen für die Lock- und Fuse-Bits verwenden. Hierbei handelt es sich um die ausgelesenen Einstellungen eines funktionsfähigen Controllers. Allerdings sollte, laut Handbuch des AVR-NET-IO-Boards, das Fuse-Bit EESAVE eigentlich gesetzt sein. &lt;br /&gt;
&lt;br /&gt;
Alternativ kann auch per avrdude die Einstellung getroffen werden:&lt;br /&gt;
 avrdude -c stk500v2 -pm32 -U lfuse:w:0xBF:m&lt;br /&gt;
und &lt;br /&gt;
 avrdude -c stk500v2 -pm32 -U hfuse:w:0xC2:m&lt;br /&gt;
&lt;br /&gt;
Anschließend muß noch der Bootloader und die Firmware aktualisiert werden (siehe Handbuch AVR-NET-IO-Board Seite 12 Punkt 3).&lt;br /&gt;
&lt;br /&gt;
=== PC Konfiguration ===&lt;br /&gt;
&lt;br /&gt;
==== PC normalerweise nicht im 192.168.0.0/24 Subnetz ====&lt;br /&gt;
&lt;br /&gt;
Betreibt man den PC nicht im 192.168.0.0/24 Subnetz, muss er wie folgt umkonfiguriert werden, oder die IP Adresse des Boards wird entsprechend angepasst. ( Siehe Handbuch Seite 14ff. Das ist meist sinnvoller und auch einfacher. ) &lt;br /&gt;
&lt;br /&gt;
Den PC vom normalen Netzwerk abstecken[1]. Zur Umkonfiguration dazu bei Windows XP in der Systemsteuerung &#039;&#039;Netzwerkverbindungen&#039;&#039; aufrufen und die lokale &#039;&#039;LAN-Verbindung&#039;&#039; markieren. Dann in der rechten Leiste &#039;&#039;Einstellungen dieser Verbindung ändern&#039;&#039; aufrufen. &lt;br /&gt;
&lt;br /&gt;
Es erscheint der Dialog &#039;&#039;Eigenschaften von &amp;lt;Verbindungsname&amp;gt;&#039;&#039;. In der Liste im Dialog zu &#039;&#039;Internetprotokoll (TCP/IP)&#039;&#039; gehen. Ein Doppelklick auf den Eintrag öffnet den &#039;&#039;Eigenschaften von Internetprotokoll (TCP/IP)&#039;&#039; Dialog.&lt;br /&gt;
&lt;br /&gt;
In diesem Dialog &#039;&#039;Folgende IP-Adresse verwenden:&#039;&#039; auswählen und zum Beispiel&lt;br /&gt;
&lt;br /&gt;
IP-Adresse: &#039;&#039;&#039;192.168.0.100&#039;&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Subnetzmaske: &#039;&#039;&#039;255.255.255.0&#039;&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Standardgateway: &#039;&#039;&#039;192.168.0.1&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
eingeben. &lt;br /&gt;
&lt;br /&gt;
Anmerkung von bitman:&lt;br /&gt;
[1] Dies ist spätestens ab Windows XP nicht mehr notwendig, wenn das Netz 192.168.0.0/24 noch frei ist. Dann kann man einfach den Client &#039;&#039;zusätzlich&#039;&#039; in diesem Netzwerk zusätzlich einbinden über Einstellungen/Netzwerkverbindungen/Lanverbindung/Eigenschaften/TCP-IP/Eigenschaften/Erweitert/IP-Adresse hinzufügen. Es werden dann eben mehrere IP-Adressen an den NIC gebunden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Alle geöffneten Dialoge nacheinander mit OK schließen.&lt;br /&gt;
&lt;br /&gt;
Alternativ bietet sich das Umprogrammieren des Boards über die serielle Schnittstelle an. Die Werte für IP-Adresse, Netzmaske und Standard-Gateway werden mit den dokumentierten SETxx-Befehlen geändert, das Board neu gestartet und ans vorhandene Netzwerk gesteckt.&lt;br /&gt;
&lt;br /&gt;
Im EEPROM sind folgende Werte vorprogrammiert:&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
3EE - 3F3 MAC-ADRESSE&amp;lt;br&amp;gt;&lt;br /&gt;
3F4 - 3F7 GATEWAY&amp;lt;br&amp;gt;&lt;br /&gt;
3F8 - 3FB NETMASK&amp;lt;br&amp;gt;&lt;br /&gt;
3FC - 3FF IP-ADRESSE&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== PC bereits im 192.168.0.0/24 Subnetz ====&lt;br /&gt;
&lt;br /&gt;
In diesem Fall muss man prüfen, ob die IP-Adresse 192.168.0.90 bereits im Subnetz verwendet wird. Ist dies der Fall, muss das verwendete Gerät mit dieser IP vorübergehend aus dem Subnetz entfernt werden. Es sei denn, dabei handelt es sich um den PC. In diesem Fall muss er wie zuvor umkonfiguriert werden. Ansonsten kann der unverändert im Netz verbleiben.&lt;br /&gt;
&lt;br /&gt;
Dem AVR-NET-IO gibt man eine neue, zuvor unbenutzte Adresse (siehe unten). Dann kann das abgekoppelte Gerät wieder angeschlossen werden, beziehungsweise der PC zurückkonfiguriert werden.&lt;br /&gt;
&lt;br /&gt;
=== AVR-NET-IO anschließen ===&lt;br /&gt;
&lt;br /&gt;
Musste man den PC umkonfigurieren, so werden jetzt nur der PC und der AVR-NET-IO über Ethernet miteinander verbunden. Je nach Ethernet-Kabel benötigt man dazu einen Switch/Hub oder nicht.&lt;br /&gt;
&lt;br /&gt;
Musste man den PC nicht umkonfigurieren, so kann man den AVR-NET-IO wie einen normalen Rechner an das vorhandenen Netz anschließen.&lt;br /&gt;
&lt;br /&gt;
Zusätzlich schließt man die serielle Schnittstelle des AVR-NET-IO an den PC an.&lt;br /&gt;
&lt;br /&gt;
=== Firmware 1.03 einspielen ===&lt;br /&gt;
&lt;br /&gt;
Laut Handbuch sollte der AVR-NET-IO jetzt über Ethernet funktionieren. Ebenso sollte er über die serielle Schnittstelle und ein Terminalprogramm konfigurierbar sein. Beides ist offensichtlich im Auslieferungszustand selten der Fall.&lt;br /&gt;
&lt;br /&gt;
Auch wenn sich Pollins NetServer Software nicht mit dem AVR-NET-IO verbinden lässt, so ist sie jedoch in der Lage eine neue Firmware 1.03 einzuspielen. Das Vorgehen ist im Handbuch auf Seite 12 beschrieben. NetServer präsentiert dabei ein paar einfache Anweisungen denen man folgen sollte.&lt;br /&gt;
&lt;br /&gt;
Wenn sich nach dem scheinbar erfolgreichem Einspielen der Firmware, später nichts tut, so sollte die Firmware mit gesetztem &amp;quot;FailSafe&amp;quot; in der mitgelieferten NetServer-Software nochmals Eingespielt werden.&lt;br /&gt;
&lt;br /&gt;
=== Abschluss ===&lt;br /&gt;
&lt;br /&gt;
Jetzt sollte sich die NetServer Software mit dem AVR-NET-IO über Ethernet verbinden lassen. Dies macht es wiederum möglich, den AVR-NET-IO mit einer anderen IP-Adresse zu versehen. Will man den AVR-NET-IO in einem anderen Subnetz betreiben kann man dies jetzt einstellen.&lt;br /&gt;
&lt;br /&gt;
Nachdem man die IP-Adresse neu eingestellt hat, muss man den PC zurückkonfigurieren und kann dann sowohl den AVR-NET-IO und den PC zusammen betreiben.&lt;br /&gt;
&lt;br /&gt;
== Funktionsumfang der Originalsoftware ==&lt;br /&gt;
Die Originalsoftware ist sehr einfach gestrickt. Im AVR Net-IO läuft ein Programm, welches am Port 50290 eine Textschnittstelle bereit stellt. Diese Schnittstelle kann sowohl über die RS232 als auch über Ethernet angesprochen werden kann. Mit diesem Programm ist es möglich, alle Eingänge sowie alle Ausgänge anzusprechen, als auch die Konfiguration der Netzwerkeinstellungen zu verändern. Die Karte versteht dann folgende Befehle:&lt;br /&gt;
* SETPORT&lt;br /&gt;
Einen digitalen Ausgang auf 0 oder 1 schalten&lt;br /&gt;
* GETPORT&lt;br /&gt;
Den Status eines digital Ausgangs/Eingangs abfragen&lt;br /&gt;
* GETSTATUS&lt;br /&gt;
Den Status aller digital Ausgänge abfragen&lt;br /&gt;
* GETADC&lt;br /&gt;
Den Messwert eines analogen Eingangs ermitteln&lt;br /&gt;
* SETIP&lt;br /&gt;
Die IP-Adresse des Boards ändern&lt;br /&gt;
* GETIP&lt;br /&gt;
Die eingestellte IP-Adresse abfragen&lt;br /&gt;
* SETMASK&lt;br /&gt;
Die Netzwerkmaske verändern&lt;br /&gt;
* GETMASK&lt;br /&gt;
Die eingestelle Netzwerkmaske abfragen&lt;br /&gt;
* SETGW&lt;br /&gt;
Das Netzwerk-Gateway verändern &lt;br /&gt;
* GETGW&lt;br /&gt;
Das eingestellte Netzwerk-Gateway abfragen&lt;br /&gt;
* INITLCD&lt;br /&gt;
Ein angeschlossenes LCD initialisieren&lt;br /&gt;
* WRITELCD&lt;br /&gt;
Einen Text am LCD ausgeben&lt;br /&gt;
* CLEARLCD&lt;br /&gt;
Ein angeschlossenes LCD löschen&lt;br /&gt;
* VERSION&lt;br /&gt;
Die Versionsnummer des Programms ausgeben&lt;br /&gt;
&lt;br /&gt;
Dazu gibt es ein auf Java basierendes Programm, welches alternativ zu einem Terminalprogramm benutzt werden kann. Es zeigt den Status der Portpins an und diese lassen sich auch mit der Maus verändern. Die Messwerte der 4 analogen Eingänge werden ständig angezeigt, wobei es möglich ist, durch einstellbare Faktoren die internen Werte gleich in sinnvolle Einheiten umrechnen zu lassen. Diese Messwerte können auch in eine Datei geloggt werden.&lt;br /&gt;
Neben der Möglichkeit, alle Kommandos auch händisch einzugeben, wird das Java-Programm auch benötigt, um einen Firmware-Update der Net-IO Platine durchzuführen.&lt;br /&gt;
Alles in allem ist dieses Frontend aber mehr als Testumgebung anzusehen, um damit die Hardware in Betrieb zu nehmen. Für einen sinnvollen Dauereinsatz ist das Programm deutlich zu einfach und unflexibel gestrickt. Auch kann die grafische Aufbereitung der Anzeige- und Kontrollelemente nicht befriedigen.&lt;br /&gt;
&lt;br /&gt;
== Bekannte Fehler ==&lt;br /&gt;
=== AVR-NET-IO ===&lt;br /&gt;
&lt;br /&gt;
Siehe auch [[#Hardware-Umbauten_.26_-Verbesserungen|Hardware-Umbauten und Verbesserungen]]&amp;lt;br&amp;gt;&lt;br /&gt;
Käufer berichten von fehlenden Bauteilen im Bausatz (Wannenstecker, Widerstände, Kondensatoren, Induktivitäten). Für Reklamationen: [https://www.pollin.de/shop/kontakt_service/reklamation.html]&lt;br /&gt;
&lt;br /&gt;
* Die Stückliste auf Seite 4 in den Anleitung mit den Versionsangaben&lt;br /&gt;
** &#039;&#039;Stand 20.08.2008, kloiber, #1100, wpe&#039;&#039; (gedruckt im Bausatz)&lt;br /&gt;
** &#039;&#039;Stand 20.08.2008, cd, #all, wpe&#039;&#039; (auf der CD)&lt;br /&gt;
:ist falsch. Pollin legt dem Bausatz irgendwann ab September 2008 einen gedruckten Korrekturzettel bei. Die Online-Version der Anleitung ist korrigiert.&lt;br /&gt;
* Im Schaltplan auf Seite 7 in den Anleitungen mit den Versionen&lt;br /&gt;
** &#039;&#039;Stand 20.08.2008, kloiber, #1100, wpe&#039;&#039; (gedruckt im Bausatz)&lt;br /&gt;
** &#039;&#039;Stand 20.08.2008, cd, #all, wpe&#039;&#039; (auf der CD)&lt;br /&gt;
** &#039;&#039;Stand 03.09.2008, online, #all, wpe&#039;&#039; (Online)&lt;br /&gt;
:ist eine 25-polige SUB-D Buchse gezeichnet. Geliefert wird und in der Stückliste verzeichnet ist ein Stecker.&lt;br /&gt;
&lt;br /&gt;
* Die September 2008 ausgelieferte Firmware im ATmega32  funktioniert bei vielen nicht und muss erst upgedatet werden (siehe [[#Inbetriebnahme der Originalsoftware|Inbetriebnahme der Originalsoftware]])&lt;br /&gt;
&lt;br /&gt;
* Im Flash der gelieferten AVR ist anders als beschrieben nur der Bootloader enthalten, die eigentliche Firmware muss erst mit Hilfe der Updatefunktion geladen werden. Wenn zusätzlich auch die Fuses falsch gebrannt sind, dann funktioniert das Update nicht, auch wenn das PC Programm was anderes behauptet.&lt;br /&gt;
&lt;br /&gt;
* Die Fuse-Einstellungen des ausgelieferten ATmega32 entspricht nicht der Anleitung (siehe [[#Inbetriebnahme der Originalsoftware|Inbetriebnahme der Originalsoftware]])&lt;br /&gt;
&lt;br /&gt;
* Bausatz, gekauft am 27.10.08, Anleitungsversion 19.09.08, ohne Probleme oder erkennbare Fehler zusammengebaut und in Betrieb genommen.&lt;br /&gt;
&lt;br /&gt;
* Bausatz gekauft 29.09.2008, Pinbelegung des 25 poligen D-Sub &amp;quot;Anschlusses&amp;quot; stimmt nicht mit der Anleitung überein. Der Aufdruck auf der Platine ist falsch. Pin1 &amp;lt;-&amp;gt; Pin13, Pin2 &amp;lt;-&amp;gt; Pin12 usw. Setzt man den D-Sub Stecker ein, so sind dessen Pinnummern korrekt. Bei einem Bausatz gekauft 05/2013 ist dies ebenfalls noch der Fall.&lt;br /&gt;
&lt;br /&gt;
* 3 Bausätze Anf. Oktober 2008 gekauft, bei einem waren 2 LM317 dabei, dafür fehlte der 7805 - aus der Bastelkiste ersetzt. Alle haben jedoch auf Anhieb funktioniert&lt;br /&gt;
&lt;br /&gt;
* Bausatz gekauft Ende Januar 2009. Die Lock-Bits (u.a. für PonyProg2000) werden falsch beschrieben. Die in Klammern aufgeführten Werte stimmen bei einem Bit nicht. Die Texte &amp;quot;Programmiert/Unprogrammiert&amp;quot; hingegen schon. Bei den Bauteilen gab es 4 Kondensatoren mit der Aufschrift &amp;quot;220&amp;quot;, ich habe diese durch welche mit 22p ersetzt, da ich nicht sicher war ob wirklich 22p geliefert wurden. Dafür wurden statt einem zwei 7805 und statt einem mindestens vier LM317 mitgeliefert.&lt;br /&gt;
&lt;br /&gt;
* Bausatz geliefert 22.4.2009. Alles vollständig, zusammengebaut, läuft. Software-Version 1.03. Für den oben schon genannten Steckverbinder wurde eine Buchse geliefert. Allerdings stimmen die PIN-Nummern im Schaltplan nicht mit den PIN-Nummern auf der Buchse überein (sie sind gespiegelt), daher liefen die Test-LEDs zunächst nicht.&lt;br /&gt;
&lt;br /&gt;
* Bausatz geliefert 11.7.2009. Spannungsregler LM317T fehlt, grüne statt roter LED. Ein Kondensator 22pF zu viel. LM317T wurde auf Anfrage kostenlos nachgeliefert (27.7.). Inbetriebnahme problemlos.&lt;br /&gt;
&lt;br /&gt;
* Bausatz geliefert 24.7.2009. Ein Quarz 16MHz zu viel, ebenfalls grüne statt rote LED.&lt;br /&gt;
&lt;br /&gt;
* Bausatz geliefert 20.08.2009. Ein Kondensator 22pF zuviel und grüne statt rote LED.&lt;br /&gt;
&lt;br /&gt;
* Bausatz Juli &#039;09 gekauft, grüne statt rote LED&lt;br /&gt;
&lt;br /&gt;
* Bausatz 25.09.09 geliefert, grüne Betriebs-LED, ein ELKO zuviel, Fehler 1µF am MAX232 statt 100nF behoben, richtiger C wird mitgeliefert, Aufbau komplett nach Pollin Anleitung durchgeführt, auf Anhieb fehlerfrei!&lt;br /&gt;
&lt;br /&gt;
* Bausatz 17.10.09 geliefert, grüne Betriebs-LED, zwei 100nF Kondensatoren zu wenig. Aufbau und Inbetriebnahme problemlos.&lt;br /&gt;
&lt;br /&gt;
* Bausatz 21.10.09 gekauft, grüne Betriebs-LED. Aufbau problemlos, RS232 läuft nicht. LAN läuft&lt;br /&gt;
&lt;br /&gt;
* Bausatz Nov. 09 gekauft, grüne LED, alles o.k.&lt;br /&gt;
&lt;br /&gt;
* Bausatz Nov. 09 gekauft, grüne LED, ENC28J60, MAX232 und ATmega32 fehlen, Nachlieferung nach einer Woche&lt;br /&gt;
&lt;br /&gt;
* Bausatz Nov. 09 gekauft,Bauteile komplett.Verbindungsaufbau Seriell klappt erst nach mehreren Versuchen.Problem gelöst:Spannung an MAX und Mega zu niedrig&lt;br /&gt;
&lt;br /&gt;
* Bausatz Dez. 09 gekauft, grüne LED, 100µF Kondensator fehlt, alles o.k.&lt;br /&gt;
&lt;br /&gt;
* Bausatz August 09 gekauft, alle teile da nach Einstellen der fusebits lief alles perfekt&lt;br /&gt;
&lt;br /&gt;
* Bausatz Okt. 09 gekauft, ein 100nF Kondensator und 25MHz Quarz fehlten ... hab beim lokalen Elektronikhändler keinen 25Mhz Grundton Quarz sondern nur im 3. Oberton bekommen aber mit R2.2k parallel zum Quarz schwingt er in der Schaltung schön bei 25Mhz. Mit 1µF am MAX232 funktioniert jetzt auch die RS232.&lt;br /&gt;
&lt;br /&gt;
* 2x Bausatz Feb. 10 gekauft, bei beiden fehlten 7805, L1+L2 je 100µH sowie 4x falscher Wert Kondensator an Max232 vorhanden. Fehlende Bauteile nachgelötet und Funktion getestet. Hat alles einwandfrei funktioniert!!!&lt;br /&gt;
&lt;br /&gt;
* Bausatz März. 10 gekauft, RS232 Printbuchse fehlt, dafür 1x 10pol Wannenstecker zuviel. Grüne LED statt Rot. Funktioniert ansonsten einwandfrei.&lt;br /&gt;
&lt;br /&gt;
* Bausatz Jan. 10 gekauft, gelbe LED statt rot, C14...C17: 10µF, weder seriell noch via Ethernet Konnektivität. Nach Austausch von C14-C17 gegen 1µF, wenigstens serielle Kontaktaufnahme möglich, kein Ethernet auch nach Flash von 1.03 mit NetServer.&lt;br /&gt;
&lt;br /&gt;
* Bausatz Feb. 10 gekauft, Spannungsregler LM317T fehlte&lt;br /&gt;
&lt;br /&gt;
* Bausatz März 10 gekauft, gelbe statt rote LED geliefert, aber Aufbau und inbetriebnahme lt. Handbuch ohne Probleme&lt;br /&gt;
&lt;br /&gt;
* Bausatz März 10 gekauft und gelbe statt rote LED geliefert, funzt wunderbar gemäß Anleitung&lt;br /&gt;
&lt;br /&gt;
* Fertig gelötete Platine gekauft. µC war falsch im Sockel.&lt;br /&gt;
&lt;br /&gt;
* Bausatz April 10 gekauft und gelbe statt rote LED geliefert, ADM232LJN statt MAX232 - Funktion erst nach Ersetzung des ADM durch nen MAX&lt;br /&gt;
&lt;br /&gt;
* Bausatz April 10 gekauft und gelbe statt rote LED geliefert, ADM232LJN statt MAX232 - funktionierte sofort auch mit dem ADM232LJN.&lt;br /&gt;
&lt;br /&gt;
* Bausatz April 10 gekauft wurde mit grüner statt roter LED Ausgeliefert&lt;br /&gt;
&lt;br /&gt;
* Bausatz Juni 10 gekauft: wurde mit grüner statt roter Netz-LED ausgeliefert, 2x 22pF Kerko zuviel&lt;br /&gt;
&lt;br /&gt;
* Bausatz August 10 gekauft: komplett und sofort funktioniert&lt;br /&gt;
&lt;br /&gt;
* Bausatz Juli 10 gekauft: 2 Quarze mit 16 MHz geliefert, statt 1x 16MHz und   1x25MHz.&lt;br /&gt;
&lt;br /&gt;
* Bausatz September 10 gekauft: hat sofort funktioniert. 1x 3,3k und 1x 10k Widerstand zuviel. Statt 100nF Kondensatoren wurden 1µF geliefert -&amp;gt; Platzprobleme auf der Platine durch grössere Bauform. LED grün.&lt;br /&gt;
&lt;br /&gt;
* Bausatz Oktober  6 gekauft: alles funktioniert. LED grün statt rot.&lt;br /&gt;
&lt;br /&gt;
* Fertigmodul Oktober 10 gekauft: Auf Anhieb alles funktioniert!&lt;br /&gt;
&lt;br /&gt;
* Bausatz Oktober 10 gekauft: komplett und sofort funktioniert&lt;br /&gt;
&lt;br /&gt;
* Bausatz November 10 gekauft: komplett und sofort funktioniert (sogar mit der neusten Pollin Firmware 1.03 schon drauf) LED grün statt rot.&lt;br /&gt;
&lt;br /&gt;
* Bausatz November 10 gekauft. Nach Bezug neuer Feinst-Lötspitzen konnte ich ihn dann auch zusammenlöten. Es hat sofort alles funktioniert, obwohl ich nur 12V bzw. 9V Gleichspannung zur Verfügung hatte, und nicht sicher war, wieviel die Komponenten wirklich benötigen. Der Regler wird auch bei 9V Gleichspannungsversorgung noch sehr warm. Da muss auf jeden Fall ein Kühlkörper dran! Ich habe auch eine grüne LED bekommen, ist mir aber wurscht :-)&lt;br /&gt;
&lt;br /&gt;
* Bausatz Dezember 10 gekauft: komplett und funktionierte sofort. Firmware 1.03, grüne LED (Ein Quarz und ein IC-Sockel zu viel)&lt;br /&gt;
&lt;br /&gt;
* Bausatz Januar 2011 gekauft: nur genau die richtige Anzahl Teile dabei, Firmware 1.03, grüne LED, ging auf Anhieb&lt;br /&gt;
&lt;br /&gt;
* 2x Bausatz Januar 2011 gekauft: beide grüne LED, und 1x doppelter Satz Jumper/Stiftleiste, 22PF und Anschlussklemmen. Rest vollständig und beide haben sofort nach zusammenbau funktioniert.&lt;br /&gt;
&lt;br /&gt;
* Februar 2011: AVR-NET-IO: die Diode D5 fehlt, 10 µF gegen 1 µF für MAX232 getauscht, Flash im ATmega32 war programmiert, passende IP-Adr über serielle Schnittstelle eingestellt; ADD-ON: für R1 war 22Ω statt 0,2Ω beigelegt, durch richtigen ersetzt, Beschreibung der LED Bestückung mangelhaft / oe1smc&lt;br /&gt;
&lt;br /&gt;
* Februar 2011: AVR-NET-IO: 1 Diode zuviel, 2 Spulen fehlen, LED grün. Die fehlenden Spulen wurden durch welche aus der Bastelkiste ersetzt - funktioniert. Der 7805 bekam einen kleinen Kühlkörper spendiert.&lt;br /&gt;
&lt;br /&gt;
* Februar 2011: AVR-NET-IO: 2x 10k Widerstände fehlen. Dafür eine Diode zu viel.&lt;br /&gt;
&lt;br /&gt;
* Ende Februar 2011: Zwei Bausaetze an jeweils zwei Adressen, alles in Ordnung.&lt;br /&gt;
&lt;br /&gt;
* Ende März 2011: 2x 25 Mhz Quarz statt 1x16 u. 1x25 Mhz. LED fehlt. Bausatz funktioniert nach Tausch des Quarz den mir mein Freund oe9rsv aus seinem Fundus spendiert hat. Danke auch für die Hilfe beim Fehler suchen.&lt;br /&gt;
&lt;br /&gt;
* Mitte 2010 gekauft: 1x 100nF fehlt&lt;br /&gt;
&lt;br /&gt;
* Mitte Juni 2011: Beide Quarze fehlen und beide Spannungsregler fehlen, Pollin wollte, dass ich das ganze Paket zurückschicke für einen Austausch. Ein 51Ω zu viel. 16Mhz im Handel und 25Mhz vom alten Mobo ausgelötet. Läuft wunderbar.&lt;br /&gt;
&lt;br /&gt;
* Anfang Juni 2011: Beide Quarze fehlen und beide Spannungsregler fehlen, nach kurzer Mail an Pollin (leider ohne Antwort) wurden diese nach ca. 1 Woche in einem Brief nachgeliefert.&lt;br /&gt;
&lt;br /&gt;
* August 2011: alles 1a...&lt;br /&gt;
&lt;br /&gt;
* August 2011: Platine fehlte -&amp;gt; in Nachlieferung&lt;br /&gt;
&lt;br /&gt;
* 30 August 2011: alles 1a...&lt;br /&gt;
&lt;br /&gt;
* 06 Sep. 2011: alles 1a...&lt;br /&gt;
&lt;br /&gt;
* August 2011: 6 Stück bestellt, bei einem haben die 100nF Kondensatoren gefehlt, bei einem zwei LM317 statt 7805 und LM317. Angerufen, 3 Tage später Nachlieferung erhalten.&lt;br /&gt;
&lt;br /&gt;
* Nov. 2011: &#039;&#039;&#039;Net_IO&#039;&#039;&#039; vollständig. Einspielen der Firmware 1.03 war erforderlich. Bei &#039;&#039;&#039;Add-On&#039;&#039;&#039; immer noch falscher Q1 BC548 (NPN) in Stückliste und Lieferung. BC327-40 oder BC328-40 (PNP) nachgefordert. R11 und R24 mitgeliefert, entsprechend Beschreibung V1.1 von Pollin&#039;s Download. Beiliegende Beschreibung war älter, ohne diese Widerstände.&lt;br /&gt;
&lt;br /&gt;
* Ende Nov.2011, alle Teile dabei, Firmware war drauf, sofort funktioniert.&lt;br /&gt;
&lt;br /&gt;
* Anfang Dez.2011, komplett bestückte Platine gekauft. Auf 7805 Kühlkörper gebaut, da er nach 1 Minute schon ausgestiegen ist (LED hat das Pumpen angefangen). Firmware 1.03 musste noch aufgespielt werden danach funktioniert alles einwandfrei. In Betrieb mit 10V DC&lt;br /&gt;
&lt;br /&gt;
* Ende Dez.2011 2xNET-IO und 2xADD bestellt, 4 verschieden volle Kisten bekommen... WSL16 ist mit Verriegelung, geht nicht aufs Board, Jumper fehlen, Spannungsregler doppelt, Poti Löcher zu klein, lsb3 fehlt, SD-Slot hab ich jetzt 3, 100nF hab ich jetzt 4 übrig ... also immer noch lustig. HW-Stand immer noch 1.0 ( gab es überhaupt eine 1.1?)&lt;br /&gt;
&lt;br /&gt;
* Mitte Jan. 2012, 10pol. beide Wannenstecker nicht dabei, Firmware war drauf, sofort funktioniert. 1 LED zuviel. Unproblematische Nachlieferung bei Reklamation (wegen der beiden Wannenstecker kam ein PAKET!).&lt;br /&gt;
&lt;br /&gt;
* Ende Feb. 2012, Um die PHP-Scripte über öffentlichen Webserver zu betreiben muss mit SETGW die Gateway-Adresse des lokalen Routers eingetragen werden. Bei der NAT im Router sollte z.B. Port 8080 auf den internen Port 50290 umgeleitet werden, da manche Provider diesen Port für die Socket-Kommunikation nicht zulassen.&lt;br /&gt;
&lt;br /&gt;
* Juli 2012, Bausatz vollständig, Nach Aufbau sofort den 7805 mit einem kleinen Kühlkörper versehen, da er sonst thermisch überlastet wird! hat weder auf LAN noch RS232 reagiert, musste erst Update einspielen (Download Pollin), danach funktionierte alles einwandfrei!&lt;br /&gt;
&lt;br /&gt;
* Januar 2013, Bausatz vollständig, 7805 mit Kühlkörper versehen, nach Aufbau ohne Probleme funktioniert&lt;br /&gt;
&lt;br /&gt;
* Februar 2013, Bausatz komplett, Aufbau ohne Probleme, 7805 nur leicht warm, LAN funktioniert, RS232 noch ohne Funktion.&lt;br /&gt;
&lt;br /&gt;
* Oktober 2013, Bausatz komplett laut Stückliste, problemloser Aufbau, 7805 leicht warm am 10V DC. RS232 und LAN funktionierten auf Anhieb.&lt;br /&gt;
&lt;br /&gt;
* Januar 2014, Bausatz komplett, Aufbau ohne Probleme, Betrieb mit 9V DC, LAN funktioniert auf Anhieb, RS232 noch nicht getestet.&lt;br /&gt;
&lt;br /&gt;
* März 2014, Komplettgerät, von ca. 100 Versuchen gerade mal 2 erfolgreiche Zugänge. Weder LAN noch RS232 mit Putty funktionierten.&lt;br /&gt;
&lt;br /&gt;
* Dezember Bausatz komplett, Aufbau ohne Probleme und mit zusätzlichen Kondensatoren gesichert, Betrieb mit 9V DC, LAN funktioniert auf Anhieb, RS232  getestet.&lt;br /&gt;
&lt;br /&gt;
=== Erweiterungsplatine ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die nachfolgend genannten Änderungen sind in der Bauanleitung V1.1 mit Stand 07.12.2011 (Wichtig! Es gibt mehr als eine V1.1 ...) bereits berücksichtigt, R3 wird allerdings mit 3,6kΩ angegeben.&lt;br /&gt;
&lt;br /&gt;
Um bei einem Neuaufbau parallele Widerstände zu vermeiden, sollten folgende Änderungen auf dem Addon-Board gemacht werden:&lt;br /&gt;
*R2 1,5kΩ ersetzen mit 2kΩ&lt;br /&gt;
*R3 1,8K ersetzen mit 3,3kΩ&lt;br /&gt;
*R19 470kΩ ersetzen zu 470Ω&lt;br /&gt;
*Q1 BC548 ersetzen durch BC327 oder BC328 (Hauptsache PNP! und mehr als 100mA)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ACHTUNG&#039;&#039;&#039; beim Anschluß eines LC-Displays an J5 (über I&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;C, PCF 8574): Vcc/5V liegt an Pin 1, GND an Pin 2 von J5. Es gibt etliche Displays mit abweichender Belegung Pin 1 GND und Pin 2 Vcc!&lt;br /&gt;
&lt;br /&gt;
Auch beim Add-On gibt es fehlende oder falsche Bauteile im Bausatz und Fehler im Schaltplan und auf der Platine:&lt;br /&gt;
&lt;br /&gt;
*Stand Feb. 2011: R2 wird mit 2,2kΩ und R3 wird mit 3,6kΩ ausgeliefert. Somit werden die 3,3 V richtig erzeugt. R19 hat 470Ω. Der ISP-Anschluß ist nicht vollständig durchgeschleift, es besteht keine Verbindung der RESET-Leitung zwischen ISP und ISP1 (Abhilfe: Drahtbrücke einlöten, [http://www.mikrocontroller.net/topic/161354#1600385 Quelle]). &lt;br /&gt;
&lt;br /&gt;
*Stand Nov. 2011: bei mir ist die RESET-Leitung korrekt zw. ISP und ISP1 verbunden. Es gibt jetzt auch einen R24 (470Ohm) und R11 (1KOhm), der in der bei mir mitgelieferten Bauanleitung fehlt, in der zum Download (V1.1) angebotenen  aber drin steht. Es wird immer noch der falsche Q1 BC548C (NPN) mitgeliefert. Das Schaltsymbol für einen PNP ist richtig im Schaltplan gezeichnet.&lt;br /&gt;
&lt;br /&gt;
*Stand Dez. 2011: R24 (470Ω) kann mit 0Ω ersetzt und R11 (1kΩ) völlig weggelassen werden. Diese Widerstände bilden einen (eigentlich überflüssigen) Spannungsteiler in der MISO Leitung. Der Spannungsteiler hat allerdings auch eine Schutzfunktion, falls weitere Slaves am SPI-Bus hängen, die 5V-Pegel nutzen, z. B. ISP-Programmierer. (siehe [http://son.ffdf-clan.de/include.php?path=forumsthread&amp;amp;threadid=1167&amp;amp;postid=9203 1284p: Board, ich oder beide verwirrt?])&lt;br /&gt;
&lt;br /&gt;
*Sept&#039;12: Bausatz mit Stecker anstelle einer Buchse ausgeliefert, 5mm anstelle von 3mm LED&#039;s dafür aber 3 Poti zuviel.&lt;br /&gt;
&lt;br /&gt;
*Sept&#039;12: Ebenfalls Bausatz mit Sub-D-Stecker statt Buchse ausgeliefert, 5mm anstelle von 3mm LED&#039;s und 3 Potis zuviel.&lt;br /&gt;
&lt;br /&gt;
*Stand März 2013: Die Belegung der 25 pol. Sub-D-Buchse im Schaltplan der Anleitung V1.1 (und früher) ist falsch dargestellt. SCL und SDA des I&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;C-Busses liegen wie beim AVR-NET-IO Board auf Pin 2 bzw. 3 und nicht auf Pin 11 bzw. 12 der Buchse. Ein 1:1 verdrahtetes Kabel funktioniert.&lt;br /&gt;
&lt;br /&gt;
== Andere Software für den Client-PC ==&lt;br /&gt;
=== NetIOLib ===&lt;br /&gt;
&lt;br /&gt;
In C# geschriebene Bibliothek zur Ansteuerung der Platine im Orginalzustand. Inkl. Beispielsoftware und Quellcode (GNU GPL) &lt;br /&gt;
&lt;br /&gt;
Links gehen nicht:&lt;br /&gt;
DLL: [http://www.tware.org/downloads/NetIOLib_dll.zip Download-Link]&lt;br /&gt;
Source: [http://www.tware.org/downloads/NetIOLib_src.zip Download-Link]&lt;br /&gt;
&lt;br /&gt;
=== E2000-NET-IO-Multi-Control ===&lt;br /&gt;
Mit dem E2000-NET-IO-Multi-Control ist es möglich, die von dem E2000-NET-IO-Designer erstellten Projekte zu öffnen und die AVR-NET-IO&#039;s zu steuern. &lt;br /&gt;
&lt;br /&gt;
Die Anwendung liegt dem [http://www.mikrocontroller.net/articles/AVR_Net-IO_Bausatz_von_Pollin#E2000-NET-IO-Designer_.28Windows.5BXP.2F7.5D_.2F_Android.29 E2000-NET-IO-Designer] bei.&lt;br /&gt;
&lt;br /&gt;
=== ControlIO ===&lt;br /&gt;
Einfache Bibliothek zur Ansteuerung mit Originalfirmware.&lt;br /&gt;
http://www.mikrocontroller.net/topic/149695&lt;br /&gt;
&lt;br /&gt;
=== JAVA Lib ===&lt;br /&gt;
Einfache Java-Bibliothek zur Ansteuerung mit Originalfirmware.&lt;br /&gt;
http://son.ffdf-clan.de/?path=forumsthread&amp;amp;threadid=611&lt;br /&gt;
&lt;br /&gt;
=== PHP ===&lt;br /&gt;
PHP Klasse zur Ansteuerung mit der Originalfirmware. (Opensource Lizenz)&lt;br /&gt;
http://blog.coldtobi.de/1_coldtobis_blog/archive/298_pollin_net-io_php_library.html&lt;br /&gt;
&lt;br /&gt;
PHP Funktionen zum Ansteuern der Originalfirmware. (Free for All Lizenz)&lt;br /&gt;
http://defcon-cc.dyndns.org/wiki/index.php/Pollin_AVR-NetIO_PHP_Wrapper&lt;br /&gt;
&lt;br /&gt;
== Clients für Smartphones ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== AVR NET IO Control (Windows Phone 7.5,7.8,8.0) ===&lt;br /&gt;
&lt;br /&gt;
Freie App zur steuerung des AVR NET IO.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;App im Market: [http://www.windowsphone.com/de-de/store/app/avr-net-io-controll/030d107f-9a27-4a62-ac8f-cb74e79c0500 AVR NET IO Control]&#039;&#039;&#039;&lt;br /&gt;
=== App NetIO (Windows Mobile 6.5) ===&lt;br /&gt;
Frei verfügbare App für Windows Mobile zur Ansteuerung mit der Orginalsoftware. Das HTC HD2 wird damit zur Fernsteuerung für das AVR Net-IO Board.&lt;br /&gt;
http://www.heesch.net/netio.aspx&lt;br /&gt;
&lt;br /&gt;
=== NET-IO Control (Android) ===&lt;br /&gt;
Eine Application für das Android Betriebssystem zur Steuerung des AVR Net-IO Boards. Es ist möglich, alle Ausgänge zu steuern und alle Eingänge anzuzeigen. Die Analogen Eingänge können mit einem Berechnungsfaktor versehen werden. &#039;&#039;Geplant ist noch ein Offsetwert.&#039;&#039; Außerdem kann jedem analogen Wert eine Einheit zugeordnet werden. Die Ausgänge können in der neusten Version in einen Tastermodus gesetzt werden.&lt;br /&gt;
&lt;br /&gt;
[[Datei:NET-IO-Control.png|200px]] [[Datei:NET-IO-Control2.png|200px]] [[Datei:NET-IO-Control3.png|200px]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Trial-Version: [https://play.google.com/store/apps/details?id=de.android.AVR.NETIOControlTRAIL Google-Play]&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
(In dieser Probe Version können nur 1 Output und 2 Inputs gesteuert werden)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Vollversion: [https://play.google.com/store/apps/details?id=de.android.AVR.NETIOControl Google-Play]&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
(Kostet im Google-Play 3,00 €)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Weitere Informationen sind auf der Entwickler-Seite zu finden:  [http://elektronik2000.de/ Elektronik2000.de]&lt;br /&gt;
&lt;br /&gt;
=== E2000-NET-IO-Designer (Windows[XP/7] / Android) ===&lt;br /&gt;
[[Datei:E2000-NET-IO-Designer.png|400px|right]]&lt;br /&gt;
Mit dem E2000-NET-IO-Designer ist es möglich, eine grafische Oberfläche für die NET-IOs von Pollin zu erstellen. Dafür werden Knöpfe, Texte und Anzeigebilder zur Verfügung gestellt. Jedes dieser Element kann &amp;quot;Aufgaben&amp;quot; übernehmen um die NET-IOs zu steuern oder einen Status des NET-IO anzuzeigen. Weitere Icons können von dem Benutzer selbst in den entsprechenden Ordner gelegt werden und in die Oberfläche eingebunden werden. Es können mehrere Seiten designt werden die durch einen selbst positionierten Knopf erreichbar sind. Die Android Application arbeitet somit im Fullscreen-Modus. Des weiteren ist es möglich, mehrere NET-IO&#039;s in einem Projekt zu benutzen. Nach dem erstellen der grafischen Oberfläche mit dem E2000-NET-IO-Designer, kann mit der Android APP das Projekt einfach gedownloaded werden. Dafür baut die APP eine Verbindung zum E2000-NET-IO-Designer auf und läd alle benötigten Dateien herunter (Achtung: Firewall-Einstellungen beachten). Die designten Oberflächen können außerdem noch mit der E2000-NET-IO-Multi-Control.exe auf dem Computer ausgeführt werden. Dadurch ist es Möglich, seine NET-IOs vom PC aus zu steuern über eine selbst designte Oberfläche. &lt;br /&gt;
&lt;br /&gt;
Zum Ausführen des E2000-NET-IO-Designer muss .NET Framework 4.0 installiert sein und es muss eine Internetverbindung exisitieren.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Features:&#039;&#039;&#039;&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Grafische Oberfläche am PC erstellen&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Verwendung von eigenen Button- und Hintergrundbildern&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Designbare Anzeige von Digital- und Analogwerten&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Steuern von mehreren AVR-NET-IO Boards&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Unterstützung der E2000-NET-IO Firmware (mehere Boards gleichzeitig)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Designte Steuerungen können auf dem PC oder dem Handy ausgeführt werden (Android)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Schnelle Verbindung&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Einfache übertragung auf das Handy durch Projekt Download&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[http://www.elektronik2000.de/downloads.php?id=44 Download E2000-NET-IO-Designer]&lt;br /&gt;
&lt;br /&gt;
[http://www.elektronik2000.de/hilfe/E2000Netdesigneruebersicht.html Online Hilfe]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Weitere Informationen sind auf der Entwickler-Seite zu finden:  [http://elektronik2000.de/ Elektronik2000.de]&lt;br /&gt;
&lt;br /&gt;
=== NetIO ( iPhone &amp;amp; Android ) ===&lt;br /&gt;
&amp;lt;div style=&amp;quot;float: left; margin-right: 20px&amp;quot;&amp;gt;[[Datei:Netio_logo.png|70px]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Schöne universelle Fernbedienung für das Board (iOS / Android). Konfigurierbar über einen Browserbasierten Editor. &amp;lt;br&amp;gt;&lt;br /&gt;
Unterstützt TCP socket Verbindungen, kann http request absetzen und kann auch Webseiten einbinden (z.B. IP-Kameras). Kann mehrere &lt;br /&gt;
Boards gleichzeitig steuern! Einfach super schnell ins Projekt eingebaut... Es gibt Buttons (die auch als Taster konfiguriert werden können), Slider, Switches und einfache Labels. Dinge können geschaltet oder Daten ausgelesen und mit regex dargstellt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&#039;float: right&#039;&amp;gt;&lt;br /&gt;
[[Datei:Netio_TV.png|190px]]&lt;br /&gt;
[[Datei:Netio_iphone5.png|190px]]&lt;br /&gt;
[[Datei:NetIO_appflow.jpg|190px]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
AppStore Link: http://itunes.apple.com/app/netio/id464924297?mt=8 &amp;lt;br/&amp;gt;&lt;br /&gt;
Google Play Link: https://play.google.com/store/apps/details?id=com.luvago.netio &amp;lt;br/&amp;gt;&lt;br /&gt;
Webseite: http://netioapp.de &lt;br /&gt;
&lt;br /&gt;
Hinweis: &amp;lt;br&amp;gt; Man findet es unter &amp;quot;NetIO&amp;quot; im Store, im Icon selbst und in iTunes wird es als &amp;quot;Controller&amp;quot; angezeigt. &amp;lt;br&amp;gt;&lt;br /&gt;
Die eigene Konfiguration kann man mit dem [http://netioapp.com/editor/ Online Editor] vorher am PC erstellen.&lt;br /&gt;
Eine fertige [http://netioapp.com/editor/?config=pollin AVR-NET-IO Konfiguration] gibt es als funktionierendes Beispiel schon als Preset.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;div style=&#039;clear: both&#039;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== AVR Net IO (iPhone) ===&lt;br /&gt;
[[Datei:AVRNetIO-Screenshot1.png|160px|rechts]]&lt;br /&gt;
Update 15.12.2011: Die Neue Version 1.3 ist seit gestern im AppStore. Fehlerkorrekturen und ein robusteres Handling machen die App nun zur universellen AVR-Net-IO-Steuerung.&lt;br /&gt;
&lt;br /&gt;
Mit der [http://itunes.apple.com/de/app/avr-net-io/id460991760?mt=8 iPhone App AVR-Net-IO] kann das Board ferngesteuert werden. Die Fernsteuerung umfasst in der Version 1.1 folgende Funktionen:&amp;lt;br&amp;gt;&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;ADC-Werte zyklisch auslesen und darstellen&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Digital-Inputs zyklisch darstellen&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Digital-Outputs können über Buttons geschaltet werden. Die Werte der Digital-Outputs werden zuerst ausgelesen und zeigen den zuletzt gesetzten Wert an.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Terminal-Modus: Hier können beliebige AVR-Net-IO-Befehle eingegeben werden. Das Ergebnis wird 1:1 angezeigt, wie es vom Board kommt. Hilfreich für Tests bei Eigenentwicklungen und Konfigurationen.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Mehr Infos gibt&#039;s dazu direkt von den Entwicklern auf [http://www.facebook.com/pages/AVR-Net-IO/187799687958255?ref=nf AVR-net-IO Facebook-Page] oder direkt auf deren Homepage [http://www.ondics.de/apps/1001/ Homepage].&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Hinweis: MIt der aktuellen Version 1.1 gibt es noch bei manchen Boards Probleme beim auslesen und anzeigen der ADC- und Digital-Werte. Das Terminal funzt problemlos. Die Entwickler kümmern sich gerade drum und haben einen baldigen Update versprochen.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Andere Software statt der Originalsoftware von Pollin ==&lt;br /&gt;
&lt;br /&gt;
Die Umrüstung auf einen Webserver durch Austausch der Software (und ev. des ATmega32) bietet sich an. Kleiner Hinweis dabei: wenn zum Flashen ein ISP-Adapter verwendet wird, diesen unbedingt vor dem Start der neuen Software abziehen! Der ISP arbeitet nämlich über dieselbe SPI-Schnittstelle über die auch der ENC28J60 angesteuert wird. Ein eventuell noch angeschlossener, wenn auch passiver ISP-Adapter stört diese Kommunikation, d.h. das Programm an sich scheint zu laufen, aber die Ethernet-Schnittstelle funktioniert nicht.&lt;br /&gt;
&lt;br /&gt;
=== E2000 - Logik ===&lt;br /&gt;
&lt;br /&gt;
[[Datei:E2000-Logik-Bedienoberflaeche.jpg|500px|rechts]]&lt;br /&gt;
&lt;br /&gt;
Anwenderfreundliche Logik-Software von Elektronik2000.de zur Steuerung des AVR-NET-IO. Der ATMEGA32 wird durch einen ATMEGA644 ersetzt und mit der E2000-Firmware beschrieben. Nun ist es möglich in der E2000-Logik Software eine Logikschaltung zu erstellen und diese auf das NET-IO-Board zu übertragen. Dort wird diese Schaltung simuliert. Dies funktioniert komplett ohne einen Computer.&lt;br /&gt;
&lt;br /&gt;
Durch ein Erweiterungsboard von Elektronik2000.de ist es auch möglich, das Board ohne Internet laufen zu lassen eine RTC (RealTimeClock) übernimmt dabei die Uhrzeitgesteuerten Funktionen. Auf dieser Erweiterung ist auch ein EEPROM integriert, um Firmware-Updates über Netzwerk einzuspielen (in Zukunft). Diese Erweiterung bietet außerdem die Anbindung an das E2000-Bus-System, durch das es möglich ist das AVR-NET-IO-Board durch weitere Ein- und Ausgänge zu erweitern.&lt;br /&gt;
&lt;br /&gt;
Das Designen von Schaltaufgaben wird in diesem Programm grafisch dargestellt, durch das ein einfaches Anpassen seiner Logikschaltungen möglich ist.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Eine Steuerung des E2000-NET-IO ist möglich durch den Intregrieten Webserver, die PC-Software (E2000-NET-IO Control) oder der Androidsoftware. All diese Können gleichzeitig auf das E2000-NET-IO zugreifen und Funktionen ausführen. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Weitere Informationen gibt es auf der Entwicklerseite: [http://www.elektronik2000.de Elektronik2000.de]&lt;br /&gt;
&lt;br /&gt;
=== Bascom Version von Hütti ===&lt;br /&gt;
&lt;br /&gt;
(Quelle: http://bascom-forum.de/index.php/topic,1781.45.html )&lt;br /&gt;
dort am Ende der Seite.&lt;br /&gt;
&lt;br /&gt;
=== Ben&#039;s Bascom Quellcode ===&lt;br /&gt;
&lt;br /&gt;
(Quelle: http://members.home.nl/bzijlstra/software/examples/enc28j60.htm )&lt;br /&gt;
&lt;br /&gt;
Muss aber für Bascom 1.11.9.3 angepasst werden, siehe Code von Hütti !&lt;br /&gt;
&lt;br /&gt;
=== U. Radigs Webserver ===&lt;br /&gt;
&lt;br /&gt;
Angepasster Sourcecode von U.Radig: http://www.mikrocontroller.net/attachment/40027/Webserver_MEGA32.hex&lt;br /&gt;
oder selbst anpassen: &lt;br /&gt;
Ändere in der Datei ENC28J60.H:&lt;br /&gt;
 #define ENC28J60_PIN_CS    4&lt;br /&gt;
(Quelle: http://www.mikrocontroller.net/topic/109988#988386)&lt;br /&gt;
&lt;br /&gt;
Temporären Dateien (*.d, *,lst,*.o) vorher im Verzeichnis löschen &#039;&#039;make clean&#039;&#039;, damit neu compiliert wird.&lt;br /&gt;
&lt;br /&gt;
IP: 192.168.0.99&amp;lt;br&amp;gt;&lt;br /&gt;
User: admin&amp;lt;br&amp;gt;&lt;br /&gt;
Pass: uli1&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Den orginal SourceCode gibt&#039;s übrigens hier:http://www.ulrichradig.de/home/index.php/avr/eth_m32_ex&lt;br /&gt;
&lt;br /&gt;
Bei den Fuses BOOTRST ausschalten, da die Software keinen Bootloader enthält.&lt;br /&gt;
&lt;br /&gt;
IP: 192.168.1.90&amp;lt;br&amp;gt;&lt;br /&gt;
User: admin&amp;lt;br&amp;gt;&lt;br /&gt;
Pass: tim&amp;lt;br&amp;gt;&lt;br /&gt;
Test: http://beitz-online.dyndns.org&amp;lt;br&amp;gt;&lt;br /&gt;
Test: http://pieper-online.dyndns.org&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Weiterentwicklung des Radig-Codes von RoBue: &amp;lt;br&amp;gt;&lt;br /&gt;
- 1-Wire-Unterstützung (Anschlus an PORTA7) &amp;lt;br&amp;gt;&lt;br /&gt;
- PORTA0-3 digitaler Eingang (ein/aus) &amp;lt;br&amp;gt;&lt;br /&gt;
- PORTA4-6 analoger Eingang (0 - 1023) &amp;lt;br&amp;gt;&lt;br /&gt;
- LCD an PORTC &amp;lt;br&amp;gt;&lt;br /&gt;
- Schalten in Abhängigkeit von Temperatur und analogem Wert &amp;lt;br&amp;gt;&lt;br /&gt;
- (Teilweise) Administration über Weboberfläche &amp;lt;br&amp;gt;&lt;br /&gt;
- Erweiterung des cmd-Befehlsatzes für telnet/rs232 &amp;lt;br&amp;gt;&lt;br /&gt;
Gedacht ist der Einsatz des AVR-NET-IO-Bausatzes für Heizungs- oder Haussteuerung) &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Test: http://avrboard.eluhost.de/&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(Quelle:&amp;lt;br&amp;gt;&lt;br /&gt;
http://www.mikrocontroller.net/attachment/43307/AVR-NET-IO_RoBue_V1.3.zip&amp;lt;br&amp;gt;&lt;br /&gt;
http://www.mikrocontroller.net/attachment/44569/AVR-NET-IO_RoBue_V1.4.zip&amp;lt;br&amp;gt;&lt;br /&gt;
http://www.mikrocontroller.net/attachment/46720/AVR-NET-IO_RoBue_1.5-final_hoffentlich_.zip)&lt;br /&gt;
&lt;br /&gt;
Bei der Ver 1.5 sind die Ports PD2+3 fürs 4bit LCD (Ext.) vertauscht ! Gruß B.P&lt;br /&gt;
&lt;br /&gt;
=== Simon Ks Webserver (uip-Stack) ===&lt;br /&gt;
Angepasster Sourcecode von Simon K: http://www.mikrocontroller.net/attachment/39939/uWebSrv.zip&lt;br /&gt;
IP: 192.168.0.93:8080&amp;lt;br&amp;gt;&lt;br /&gt;
Um diesen Code mit einem Atmega1284P verwenden zu können, muss in der main.c in Zeile 38, &amp;quot;TIMSK&amp;quot; durch &amp;quot;TIMSK1&amp;quot; ersetzt werden.&lt;br /&gt;
Die Fusebits für den Atmega1284p ohne Bootloader sind:&lt;br /&gt;
lfuse=0xFF, hfuse=0xD9, efuse=0xFF&lt;br /&gt;
&lt;br /&gt;
=== Ethersex Server ===&lt;br /&gt;
&lt;br /&gt;
http://www.ethersex.de - Einfach für atmega32 compilieren und funktioniert.&lt;br /&gt;
&lt;br /&gt;
=== Etherrape Server ===&lt;br /&gt;
&lt;br /&gt;
http://www.lochraster.org/etherrape/ &lt;br /&gt;
&lt;br /&gt;
ist in jedem Fall hier auch zu erwähnen zumal es sich beim etherrape um das Ursprungsprojekt von ethersex handelt.&lt;br /&gt;
Es scheint aber bei der Weiterentwicklung wenig zu passieren.&lt;br /&gt;
Ausführliche Dokumentation findet sich unter http://wiki.lochraster.org/wiki/Etherrape&lt;br /&gt;
&lt;br /&gt;
=== Mini SRCP Server (kommerziell, Closed-Source)===&lt;br /&gt;
&lt;br /&gt;
Damit wird die Platine zu einer Modellbahnsteuerung, die&lt;br /&gt;
über das Netzwerkprotokoll SRCP mit verschiedenen Programmen&lt;br /&gt;
gesteuert werden kann.&lt;br /&gt;
&lt;br /&gt;
[http://www.7soft.de/de/mini_srcp_server/index.html Infoseite] zur Hardware&lt;br /&gt;
und das zugrundeliegende [http://www.der-moba.de/index.php/Digitalprojekt Digitalprojekt].&lt;br /&gt;
&lt;br /&gt;
=== Avr ArtNET-Node ===&lt;br /&gt;
&lt;br /&gt;
Hiermit kann die Platine zu einem Art-Net Node werden, mit dem sich ein DMX-Universe über Ethernet übertragen lässt. Basiert auf den Quellen von Ulrich Radig.&lt;br /&gt;
&lt;br /&gt;
Dokumentation: [http://www.dmxcontrol.de/wiki/Art-Net-Node_f%C3%BCr_25_Euro Art-Net-Node für 25 Euro]&lt;br /&gt;
&lt;br /&gt;
=== Webserver von G. Menke ===&lt;br /&gt;
&lt;br /&gt;
Ein Webserver (basierend auf den Sourcen von U. Radig), der so angepasst ist, dass alle Ein- und Ausgänge wie bei der originalen Pollin-Software genutzt werden können (8xDIGOUT, 4xDIGIN, 4xADIN). Der Webserver kann daher direkt auf das Net-IO geladen werden. Im ZIP-File sind ein ReadMe und alle C-Sourcen enthalten.&amp;lt;br&amp;gt;&amp;lt;i&amp;gt;Download&amp;lt;/i&amp;gt;:&lt;br /&gt;
[http://gm.stream-center.de/webserver/ Webserver mit passender IO]&lt;br /&gt;
&lt;br /&gt;
=== OpenMCP === &lt;br /&gt;
&#039;&#039;&#039;(Projekt scheint erloschen - Links all down - Jan. 2014)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Tolles Projekt, welches viele Features bietet und stabil läuft. Hervorzuheben ist die Übersichtlichkeit der Programmteile/Module und die vielleicht nicht ganz komplette Dokumentation. Man merkt, dass viel Arbeit und Liebe in diesem Projekt steckt. Herausgekommen ist dabei eine einfach zu handhabende Entwicklungsumgebung. Anfänger können, dank des gut durchdachten CGI-Systems, welches sich um alle wichtigen Sachen kümmert, leicht eigene CGI implementieren. Alle Ausgaben erfolgen nur mit printf über die Standardausgabe und werden automatisch richtig per Netzwerk übertragen, dadurch ist es auch für den Anfänger recht gut geeignet, da man sich nicht mit der Netzwerkprogrammierung auseinander setzen muss.&lt;br /&gt;
&lt;br /&gt;
Die Software belegt im Moment (Stand Juli 2010) ca. 55 Kb im Flash, so dass man das Board mit einem grösseren µC (z.B. ATMega644) aufrüsten muss.&lt;br /&gt;
&lt;br /&gt;
[http://wiki.neo-guerillaz.de Projekt und Doku]&lt;br /&gt;
&lt;br /&gt;
Der Autor stellt zwei über das Internet erreichbare Testboards bereit unter http://www.neo-guerillaz.de:81 und http://www.neo-guerillaz.de:82 die beide unter OpenMCP laufen, je auf einen AVR-NETIO mit einem ATmega644 und dem eigentlichen Board mit einem ATmega2561. Zusätzlich ist gerade eine Version für das myAVR in Arbeit die schon ordentlich Fortschritte macht.&lt;br /&gt;
&lt;br /&gt;
=== OpenMLP ===&lt;br /&gt;
Auf openMCP basierender Port nach [http://avr.myluna.de LunaAVR] (GPL). Umfangreiche Funktionalität und direkte Anpassung an die Sprache. Abgespeckte Version auch auf Atmega32 lauffähig. Die Original-Dokumentation kann zum Großteil hergenommen werden. Einige Zusatzfeatures. Leichte Konfiguration und guter Einstieg für Anfänger und zum Verständnis der Serverfunktionalität.&lt;br /&gt;
&lt;br /&gt;
[http://avr.myluna.de/doku.php?id=de:openmlp Artikelseite]&lt;br /&gt;
[http://forum.myluna.de/viewtopic.php?f=8&amp;amp;t=13 Forum]&lt;br /&gt;
&lt;br /&gt;
=== ENC28J60 I/O-Webserver von Thomas Heldt ===&lt;br /&gt;
&lt;br /&gt;
Ein Modul-Webserver (Softwarekompatibel zum Pollin Webserver), der durch div. Module erweitert werden kann, Software in Bascom basierend auf dem Code von Ben Zijlsta wurde erweitert und angepasst:&lt;br /&gt;
&lt;br /&gt;
[http://mikrocontroller.heldt.eu/index.php?page=enc28j60-io-webserver Projekt und Software]&lt;br /&gt;
&lt;br /&gt;
=== AVR-Netino ===&lt;br /&gt;
[http://code.google.com/p/avr-netino/ Projekt und Software]&lt;br /&gt;
&lt;br /&gt;
Arduino fürs Net-IO&lt;br /&gt;
&lt;br /&gt;
== Siehe auch ==&lt;br /&gt;
* Diskussion zu diesem Projekt: http://www.mikrocontroller.net/topic/109988&lt;br /&gt;
* [http://www.microchip.com/wwwproducts/Devices.aspx?dDocName=en022889 ENC28J60 Produktseite]&lt;br /&gt;
* [http://ww1.microchip.com/downloads/en/DeviceDoc/39662c.pdf ENC28J60 Datenblatt(pdf)]&lt;br /&gt;
* [http://son.ffdf-clan.de Forum für AVR-Net-IO]&lt;br /&gt;
* [http://avr.myluna.de/doku.php?id=de:openmlp LunaAVR openMLP ]&lt;br /&gt;
* [http://bascom-forum.de/index.php/topic,1781.0.html Bascom Forum ]&lt;br /&gt;
* [http://hobbyelektronik.org/w/index.php/AVR-NET-IO-Shield Shield für den NET-IO]&lt;br /&gt;
&lt;br /&gt;
[[Category:AVR-Boards]]&lt;br /&gt;
[[Category:Ethernet|P]]&lt;/div&gt;</summary>
		<author><name>Df2au</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=Wellenwiderstand&amp;diff=86722</id>
		<title>Wellenwiderstand</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=Wellenwiderstand&amp;diff=86722"/>
		<updated>2015-01-19T09:02:56Z</updated>

		<summary type="html">&lt;p&gt;Df2au: /* Eine schöne und verständliche Erklärung aus einem Forumsthread */ Pleonasmus, Typo&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Einleitung ==&lt;br /&gt;
&lt;br /&gt;
Schnelle Digitalschaltkreise bzw. hochfrequente Analogschaltungen stellen erhöhte Anforderungen an die Verbindungsleitungen zwischen ICs und Baugruppen. Wo ein langsamer CMOS-Baustein der 4000 Serie mit ein paar Megahertz (wobei die Flankensteilheit entscheidet - nicht die Frequenz) noch problemlos auf dem Steckbrett mit wilder Klingeldrahtverkabelung funktioniert, dort versagt ein moderner, schneller IC seinen Dienst. Ähnliches passiert auf geätzten Leiterplatten. Nicht nur die Packungsdichte der Gehäuse, auch die immer kürzer werdenden Schaltzeiten der Signale verlangen mehr und mehr einen durchdachten, hochfrequenzgerechten Aufbau mit zwei, vier oder mehr Lagen. Die Verbindungsleitungen, welche bei niedrigen Frequenzen praktisch nicht auffallen, sind plötzlich sichtbare Bauelemente, welche die zwei wichtigen Parameter Wellenwiderstand und Laufzeit aufweisen.&lt;br /&gt;
&lt;br /&gt;
== Wellenwiderstand ==&lt;br /&gt;
&lt;br /&gt;
[[bild:wellenwiderstand_ersatzschaltbild.png|thumb|right|372px|Modell eines elektrischen Leiters mit Widerständen, Kapazitäten und Induktivitäten]]&lt;br /&gt;
Eine elektrische Leitung muß bei hohen Frequenzen als ein Netzwerk aus folgenden Komponenten betrachtet werden:&lt;br /&gt;
&lt;br /&gt;
* Serienwiderstand R&amp;lt;sub&amp;gt;s&amp;lt;/sub&amp;gt;&lt;br /&gt;
* Parallelwiderstand R&amp;lt;sub&amp;gt;p&amp;lt;/sub&amp;gt;&lt;br /&gt;
* Serieninduktivität L&amp;lt;sub&amp;gt;s&amp;lt;/sub&amp;gt;&lt;br /&gt;
* Parallelkapazität C&amp;lt;sub&amp;gt;p&amp;lt;/sub&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Praktisch kann man sich das so vorstellen: Jeder elektrische Leiter hat einen [[Widerstand|ohmschen Widerstand]] Rs. Vorsicht! Das ist nicht der Wellenwiderstand! Ebenso hat jede elektrische Leitung einen Widerstand zwischen den Leitern, denn der Isolator ist nie ideal. Praktisch kann man den allerdings meist vernachlässigen, da er im Bereich von Gigaohm liegt.&lt;br /&gt;
&lt;br /&gt;
Die unvermeidlichen und ausschlaggebenden Parameter sind jedoch L&amp;lt;sub&amp;gt;s&amp;lt;/sub&amp;gt; und C&amp;lt;sub&amp;gt;p&amp;lt;/sub&amp;gt;. Jeder elektrische Leiter, welcher von einem Strom durchflossen wird, erzeugt ein Magnetfeld. Das ist gleichbedeutend mit der Induktivität L&amp;lt;sub&amp;gt;s&amp;lt;/sub&amp;gt;. Ebenso besteht zwischen zwei isolierten Leitern immer ein elektrisches Feld, wodurch der Kondensator C&amp;lt;sub&amp;gt;p&amp;lt;/sub&amp;gt; gebildet wird. L&amp;lt;sub&amp;gt;s&amp;lt;/sub&amp;gt; und C&amp;lt;sub&amp;gt;p&amp;lt;/sub&amp;gt; sind die entscheidenden Größen zur Bestimmung des Wellenwiderstandes. Je nach geometrischer Anordnung der Leiter kann man sie in gewissen Grenzen variieren (Koaxialkabel, Twisted Pair, Flachbandkabel etc.).&lt;br /&gt;
&lt;br /&gt;
Der Wellenwiderstand berechnet sich aus&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;Z_0= \sqrt{\frac{L_s}{C_p}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Er ist eine charkteristische Größe einer Leitung. Er ist unabhängig von der Länge der Leitung. &lt;br /&gt;
&lt;br /&gt;
Beispiele:&lt;br /&gt;
&lt;br /&gt;
* Koaxialkabel RG58 und RG174, 50Ω &lt;br /&gt;
* Koaxialkabel RG59, 75Ω;&lt;br /&gt;
* Twisted Pair CAT3/5/7 für Ethernet, 100Ω&lt;br /&gt;
* Flachbandkabel, 150Ω typ.&lt;br /&gt;
* Leiterbahnen auf Platinen mit 30...150Ω&lt;br /&gt;
&lt;br /&gt;
== Laufzeit ==&lt;br /&gt;
&lt;br /&gt;
Elektrische Signale haben eine sehr hohe, aber dennoch begrenzte Ausbreitungsgeschwindigkeit. In Luft bzw. im Vakuum breiten sich Funksignale mit Lichtgeschwindigkeit aus, das sind 300.000 km/s, oder 30cm/ns. Auf Leitungen breiten sich Signale langsamer aus, da das elektromagnetische Feld mit der Umgebung interagiert. Je nach Leitungstyp etwa mit 50..70% der Lichtgeschwindigkeit, sprich mit ca. 15..21 cm/ns.&lt;br /&gt;
&lt;br /&gt;
== Terminierung ==&lt;br /&gt;
&lt;br /&gt;
Wenn eine elektrische Leitung als lang betrachtet werden muß, dann treten Reflexionen auf. Diese sind unerwünscht und können von sporadischen Fehlern bis zum völligen Versagen einer Schaltung alles verursachen. Deshalb müssen solche Leitungen terminiert werden. Die Terminierung absorbiert die einlaufenden Signale und verhindert damit ungewollte Reflexionen. Eine Leitung wird mit einem ohmschen Widerstand terminiert, welcher den gleichen Wert wie der Wellenwiderstand aufweist. Die Terminierungswiderstände müssen möglichst am Ende der Leitung plaziert werden.&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Eine Leitung ist dann als elektrisch lang zu betrachten, wenn die einfache Laufzeit der Leitung größer als ca. 1/6 der minimalen Anstiegszeit der Signale ist.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
;Ein Beispiel:&lt;br /&gt;
&lt;br /&gt;
Ein [[AVR]] ist ein recht typischer, digitaler IC. Die minimale Anstiegszeit beträgt ca. 5ns. Nach obiger Formel darf die Laufzeit nur&lt;br /&gt;
: 1/6&amp;amp;nbsp;·&amp;amp;nbsp;5ns&amp;amp;nbsp;≈&amp;amp;nbsp;0,83ns&lt;br /&gt;
betragen. Bei einer Ausbreitungsgeschwindigkeit von 21cm/ns ergibt das eine maximal zulässige Leitungslänge von&lt;br /&gt;
: 21cm/ns&amp;amp;nbsp;·&amp;amp;nbsp;0,83ns&amp;amp;nbsp;≈&amp;amp;nbsp;17,5cm&lt;br /&gt;
Das heißt, bei einer Leitungslänge von bis zu 17,5cm &#039;&#039;und&#039;&#039; halbwegs sauberer Leitungsführung treten keine nennenswerten Reflexionen auf und eine Terminierung ist nicht notwendig. Darüber muss man aufpassen: spätestens bei dem doppelten bis dreifachen Wert ist eine Terminierung meist unverzichtbar.&lt;br /&gt;
&lt;br /&gt;
=== Serienterminierung ===&lt;br /&gt;
&lt;br /&gt;
[[bild:wellenwiderstand_serienterminierung.png|thumb|right|350px|Serienterminierung]]&lt;br /&gt;
Serienterminierung arbeitet bewußt mit Reflexionen. Von der Quelle wird ein Signal mit einem Innen&amp;amp;shy;widerstand gleich dem Wellen&amp;amp;shy;widerstand eingespeist. Dadurch ergibt sich ein Spannung&amp;amp;shy;steiler von 1:2, d.h. Das Signal hat kurzzeitig nur die halbe Amplitude. Damit läuft es bis zum Ende der Leitung, welches offen ist. Es wird zu 100% reflektiert. Dadurch entsteht der volle Spannungs&amp;amp;shy;pegel. Wenn die rücklaufende Reflexion die Quelle wieder erreicht wird sie vom Innen&amp;amp;shy;widerstand der Quelle, welcher gleich dem Wellen&amp;amp;shy;widerstand ist, absorbiert, es entsteht keine weitere Reflexion. Idealerweise sollte der externe Serien&amp;amp;shy;widerstand Rs plus der Innen&amp;amp;shy;widerstand des Ausgangs Ri gleich dem Wellen&amp;amp;shy;widerstand sein. CMOS-ICs haben Ausgangs&amp;amp;shy;widerstände zwischen 15..50Ω.&lt;br /&gt;
&lt;br /&gt;
Der Terminierungswiderstand muss in der Nähe des Ausgangs des treibenden Bausteins platziert werden -&amp;gt; Quellenterminierung.&lt;br /&gt;
&lt;br /&gt;
Datensignale können meist problemlos mit Serien&amp;amp;shy;terminierung betrieben werden. Taktsignale dürfen nur bei Punkt zu Punkt Verbindungen mit Serienterminierung betrieben werden (ein Sender und nur ein Empfänger). Anderenfalls kann es zu Fehlfunktionen kommen, da ein Takteingang, welcher in der Mitte der Leitung sitzt für ein paar Nanosekunden eine Spannung am Eingang anliegen hat die etwa VCC/2 entspricht. Das ist aber genau die Schaltschwelle von CMOS-ICs. Kleinste eingekoppelte Störungen können nun dafür sorgen, daß der Takteingang mehrere Flanken &amp;quot;sieht&amp;quot;, wo eigentlich nur eine sein sollte.&lt;br /&gt;
&lt;br /&gt;
=== Parallelterminierung ===&lt;br /&gt;
&lt;br /&gt;
[[bild:wellenwiderstand_parallelterminierung.png|thumb|right|350px|Parallelterminierung]]&lt;br /&gt;
Parallelterminierung absorbiert die ankommende Welle am Ende einer Leitung. Damit treten zu keinem Zeitpunkt Reflexionen auf. Nachteilig ist der Stromverbrauch bei HIGH-Pegel. Diese Terminierung ist nicht für 5 oder 3.3V CMOS geeignet. Parallelterminierung wird typisch bei Ethernet sowie beim RS485-Bus verwendet, dort sogar an beiden Enden. Es gibt diverse IO-Standards wie HSTL, SSTL etc., welche für schnelle ICs entwickelt wurden (DDR-RAM, DDR2-RAM), diese arbeiten mit Parallel- sowie Serien&amp;amp;shy;terminierung.&lt;br /&gt;
&lt;br /&gt;
[[bild:wellenwiderstand_vt-terminierung.png|thumb|right|350px|Terminierungsspannung]]&lt;br /&gt;
Den Stromverbrauch kann man halbieren, indem man mit einem speziellen Spannungsregler eine sog. &#039;&#039;Terminierungs&amp;amp;shy;spannung&#039;&#039; generiert (z.&amp;amp;nbsp;B. bei SCSI). Dieser Spannungsregler muss sowohl Strom liefern können (source) als auch Strom aufnehmen können (sink). Allerdings ist auch hier der Strom&amp;amp;shy;verbrauch noch recht beachtlich, jedoch hat man mit etwas stärkeren Bustreibern eine Chance, auch mit 5/3.3V CMOS eine Terminierung treiben zu können.&lt;br /&gt;
&lt;br /&gt;
Der Terminierungswiderstand muss in der Nähe des Eingangs des empfangenden Bausteins platziert werden -&amp;gt; Senkenterminierung.&lt;br /&gt;
&lt;br /&gt;
{{Absatz}}&lt;br /&gt;
&lt;br /&gt;
[[bild:wellenwiderstand_theveninterminierung.png|thumb|right|350px|Thevenin-Terminierung]]&lt;br /&gt;
&lt;br /&gt;
Ohne Terminierungsspannung kommt man mit der sog. &#039;&#039;Thevenin-Terminierung&#039;&#039; aus. Dabei wird der Terminierungs&amp;amp;shy;widerstand durch zwei doppelt so große Widerstände ersetzt. Aus Sicht des Kabels sind diese beiden Widerstände &#039;&#039;parallel&#039;&#039; geschaltet! Wichtig ist der zusätzliche Kondensator an VCC und GND, er stellt einen hochfrequenten Kurzschluß dar und ist wichtig für die Funktion dieser speziellen Terminierung. Er muss wie ein [[Kondensator#Entkoppelkondensator | Entkoppelkondensator]] bei einem IC betrachtet und dementsprechend nah platziert werden.&lt;br /&gt;
&lt;br /&gt;
Daher auch der Name: &#039;&#039;Thevenin Equivalent&#039;&#039; ist im Englischen die Bezeichung für eine Ersatzschaltung mit anderem Aufbau aber im Endeffekt gleichen Eigenschaften. Hier spart man auch die Hälfte des Stroms ein, allerdings fliesst jetzt auch bei LOW ein Strom durch die Terminierung. Der Stromverbrauch bzw. die Treiberbelastung ist identisch zur Nutzung einer Terminierungsspannung.&lt;br /&gt;
&lt;br /&gt;
{{Absatz}}&lt;br /&gt;
&lt;br /&gt;
=== AC-Terminierung ===&lt;br /&gt;
&lt;br /&gt;
[[bild:wellenwiderstand_ac-terminierung.png|thumb|rigt|350px|AC-Terminierung]]&lt;br /&gt;
Um den Stromverbrauch allgemein zu senken kann AC-Terminierung eingesetzt werden. &lt;br /&gt;
&lt;br /&gt;
Dazu wird ein Kondensator in Reihe zum Terminierungs&amp;amp;shy;widerstand geschaltet. Damit fliesst nur für eine kurze Zeit ein Strom, wenn der Pegel wechselt. Nachteilig ist die bisweilen kritische Dimensionierung des Kondensators. Er darf nicht zu klein sein, damit die Spannung nicht zu schnell steigt und somit der Terminierungs&amp;amp;shy;widerstand nicht voll wirksam ist. Andererseits darf er nicht zu groß sein, damit der Umlade&amp;amp;shy;vorgang vor dem nächsten Flanken&amp;amp;shy;wechsel abgeschlossen ist (Taktfrequenz). Hier muß man ggf. experimentieren und &#039;&#039;richtig&#039;&#039; messen. Typische Werte liegen zwischen 100pF und 10nF.&lt;br /&gt;
&lt;br /&gt;
Für Takte und Signale mit konstantem Mittelwert ([[Manchester]]kodierung, 8B10B Kodierung) kann man den Kondensator sehr groß wählen (100nF Keramik + großen Elko). Dann lädt sich der Kondensator über mehrere hundert Takte auf den Mittelwert der Spannung auf und hält diese. Damit wirkt er wie eine Spannungsquelle für die Terminierungs&amp;amp;shy;spannung.&lt;br /&gt;
&lt;br /&gt;
Der Vorteil ist der eingesparte Spannungsregler, der Stromverbrauch ist identisch mit der Parallel&amp;amp;shy;terminierung mit Terminierungsspannng. Als grobe Orientierung sollte die Zeitkonstante aus Terminierungs&amp;amp;shy;widerstand mal Kondensator ca. 1000 mal größer sein als die Periodendauer des Taktes bzw. die Bitdauer das Datenstroms sein:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;R_T \cdot C_T \;\gtrapprox\; 1000 \cdot T_\text{CLK}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Takt- und Datensignale ==&lt;br /&gt;
&lt;br /&gt;
Bei Datensignalen ist es meist durchaus akzeptabel, wenn ein erhöhtes Maß an Überschwingern und Reflexionen auftreten. Auf synchronen [[Bus]]systemem werden die Daten mittels eines Taktes abgetastet. Nur zu diesem Zeitpunkt müssen die Daten sauber anliegen, ein wenig davor (Setup Time) und ein wenig danach (Hold time). Ganz anders bei Takten, asynchronen Resets und Interruptsignalen. Auf diese reagiert ein digitaler IC &#039;&#039;&#039;sofort&#039;&#039;&#039; und sehr schnell. Durch Reflexionen kann es zu &amp;quot;Zacken&amp;quot; auf Taktflanken kommen, welche ein langsamer IC ignoriert aber ein schneller darauf reagiert und zwei Taktflanken &amp;quot;sieht&amp;quot;, wo eigentlich nur eine ist. Hier muss man aufpassen. Diese Signale sollten&lt;br /&gt;
&lt;br /&gt;
* sehr solide layoutet werden&lt;br /&gt;
* etwas Abstand zu allen anderen Signalen bekommen&lt;br /&gt;
* ggf. sauber terminiert werden&lt;br /&gt;
&lt;br /&gt;
Dann gibt es auch keine Probleme mit instabilen Datenübertragungen etc.&lt;br /&gt;
&lt;br /&gt;
== Leitungsführung und Layout ==&lt;br /&gt;
&lt;br /&gt;
Der Zusatz &amp;quot;und halbwegs saubere Leitungsführung&amp;quot; ist eine entscheidende Komponente bei der Verteilung schneller Signale! Irgendwelche wilde Klingeldrahtorgien oder lieblos auf die Platine geschmissene Leitungen zählen nicht dazu. Im Idealfall sind die Leitungen mit einer Impedanz von 50 oder 75Ω layoutet, bei differentiellen Signalen auch 100Ω (Ethernet, LVDS etc.). Dazu muß eine bestimmte Geometrie der Leiterbahn eingehalten werden, im wesentlichen bestimmt durch Breite und Abstand zur Referenzfläche (GND oder VCC). Die Stichworte für eine Suche im Internet lauten Microstrip und Stripline. Bei zwei- oder vierlagigen Platinen werden die Leitungen mit 50/75&amp;amp;Omega; ziemlich breit, deshalb kann man sich dort dem Ideal nur sehr grob nähern. Dennoch sollte man es vor allem für Takte versuchen und möglichst die Leitung über einer Referenzfläche führen. Das grundlegende Prinzip lautet:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Die Fläche der Leiterschleife zwischen Signal und Massefläche muß minimiert werden.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Man muß immer daran denken. Strom fließt immer im Kreis, deshalb heißt es ja auch Stromkreis. Der Stromkreis beginnt am Versorgungspin des ICs, welcher das Signal generiert, läuft über den Ausgang und die Signalleitung zum Eingang des Empfängers bzw. der dort platzierten Terminierung, dort nach Masse und über die Masse zurück zum Sender-IC. Die Rückleitung über Masse ist genauso wichtig wie die Hinleitung des Signals! Eine wild geschlungene Masseleitung macht das beste Layout zunichte. Optimal sind komplette Masseflächen, doch die sind meist nur bei Platinen mit vier oder mehr Lagen machbar. Bei hochfrequenten Analogschaltungen gönnt man sich den &amp;quot;Luxus&amp;quot; auch bei zweilagigen, weil man sonst in Teufels Küche kommt. Bei schnellen Digitalschaltungen auf zweilagigen Platinen muß man Kompromisse eingehen. Aber auch hier gilt die alte Weisheit, daß die Masse möglichst sternförmig verteilt werden sollte. Entgegen der weit verbreiteten Meinung spielen 90° Winkel keine große Rolle, auch nicht weit in den den Bereich von 1 GHz! Siehe [[#Links | Abschnitt Links]].&lt;br /&gt;
&lt;br /&gt;
Wenn Kabel als Verbindung zwischen ICs verwendet werden, sollte man auch hier Sorgfalt walten lassen.&lt;br /&gt;
&lt;br /&gt;
* Idealerweise sollte man bei Flachbandkabeln jede 2. Ader auf Masse legen und auf BEIDEN Seiten der Verbindung am Stecker mit der Masse der Platine verbunden werden.&lt;br /&gt;
* Meist reicht es, jede 4.  bis 10. Ader auf Masse zu legen, wobei man Takte direkt neben die Masse legen sollte.&lt;br /&gt;
* Bei Steuerkabeln (verdrillt oder auch nicht) gilt ähnliches.&lt;br /&gt;
&lt;br /&gt;
== Zusammenfassung ==&lt;br /&gt;
&lt;br /&gt;
* Entscheidend für das Entstehen von Reflexionen ist &#039;&#039;&#039;NICHT&#039;&#039;&#039; die Taktfrequenz sondern die Anstiegszeit der Signale. Eine Schaltung mit schnellen ICs wird auch bei niedrigen Taktfrequenzen sehr schnell schalten, auch wenn das nicht unbedingt notwendig wäre.&lt;br /&gt;
* Mit Reflexionen muß man rechnen, wenn die einfache Laufzeit der Leitung grösser als ca. 1/6 der minimalen Anstiegszeit der Signale ist.&lt;br /&gt;
* Serienterminierung ist für Takte nur bei Punkt-zu-Punkt-Verbindungen sicher nutzbar.&lt;br /&gt;
* Parallelterminierung ist für 5/3,3V CMOS ungeeignet (Stromverbrauch).&lt;br /&gt;
* Auch mit Terminierung ist bei schnellen Signalen eine halbwegs saubere Leitungsführung notwendig.&lt;br /&gt;
* Man sollte nach Möglichkeit immer die langsamsten Logikbausteine verwenden, um Probleme mit Reflexionen zu minimieren (Wozu braucht man 1ns Anstiegszeit bei 5 MHz Takt?).&lt;br /&gt;
* Ausgänge sollten möglichst identische Ausgangswiderstände für LOW und HIGH haben (wie z.&amp;amp;nbsp;B. die HC-Familie), sonst wird eine Serienterminierung schwierig bis unmöglich (wie. z.&amp;amp;nbsp;B. die ABT-Familie); siehe [http://www.ti.com/litv/pdf/szza008 &amp;quot;Input and Output Characteristics of Digital Integrated Circuits&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
== Eine schöne und verständliche Erklärung aus einem Forumsthread ==&lt;br /&gt;
&lt;br /&gt;
→ [http://www.mikrocontroller.net/topic/238751 Forum: &#039;&#039;Was ist der Wellenwiderstand?&#039;&#039;]&lt;br /&gt;
# Bei einer kurzen Leitung (kürzer als ein Viertel der Wellenenlänge)&lt;br /&gt;
#* Bei einer Leitung ohne Last (Re = ∞) wirkt die Leitung wegen ihrer verteilten Kapazität (Kapazitätsbelag) kapazitiv.&lt;br /&gt;
#* Bei einer Leitung mit Kurzschluss am Ende (Re = 0) wirkt die Leitung wegen ihrer verteilten Induktivität (Induktivitätsbelag) induktiv.&lt;br /&gt;
#* Irgendwo dazwischen gibt es einen Wert, wo Induktivität und Kapazität sich gerade kompensieren: Das ist der Wellenwiderstand. Er ermöglicht eine kapazitäts- und induktivitätsfreie Übertragung.&lt;br /&gt;
# Eine Leitung gibt an einen Lastwiderstand volle Leistung nur bei einem bestimmten Strom/Spannungsverhältnis ab. Wenn der Lastwiderstand ein anderes Strom/Spannungsverhältnis erzwingt, wird ein Teil des Stroms oder der Spannung in die Leitung reflektiert. Der Widerstand, bei dem z.B. Impulse reflexionsfrei übergeben werden, ist der Wellenwiderstand.&lt;br /&gt;
# Durch die Geometrie einer Leitung werden Kapazitätsbelag und/oder Induktivitätsbelag verändert. Aus dem Verhältnis Kapazität/Induktivität lässt sich ein Widerstand errechnen, dies ist der Wellenwiderstand.&lt;br /&gt;
&lt;br /&gt;
== Wellenwiderstand messen ==&lt;br /&gt;
&lt;br /&gt;
Siehe hier: http://www.mikrocontroller.net/topic/106235&lt;br /&gt;
&lt;br /&gt;
== 90° Ecken in Leiterbahnen ==&lt;br /&gt;
&lt;br /&gt;
Das Thema wird seit Jahrzehnten diskutiert, real gemessen haben die Wenigsten. Hier die kurze Zusammenfassung aus zwei guten Quellen.&lt;br /&gt;
&lt;br /&gt;
[http://www.ultracad.com/articles/90deg.pdf Messung] von Ultraboard&lt;br /&gt;
*sieben Leiterzüge mit 20,3cm Länge, 0,25mm Breite, Microstrip mit 50 Ohm; verschiedene Winkel&lt;br /&gt;
*Messung mit TDR und 17ps Anstiegszeit, ~2,8mm Pulslänge auf der Leitung, etwa 10fache Leiterbahnbreite &lt;br /&gt;
*Auf keiner Leitung konnten Effekte nachgewiesen werden!&lt;br /&gt;
*Eine Messung der Abstrahlung mittels Antenne bis 1,3 GHz zeigte auch keine sichtbaren Unterschiede jenseits der Messungenauigkeit&lt;br /&gt;
&lt;br /&gt;
[http://www.theamphour.com/the-amp-hour-77-winsome-waveform-wizardry/ Interview] mit [http://www.signalintegrity.com/hj.htm Dr. Howard Johnson],  HF-Guru&lt;br /&gt;
* Die Legende kommt aus dem Bereich der Mikrowellen, wo die Theorie und Praxis in den 1960er Jahren sehr umfangreich erarbeitet wurde&lt;br /&gt;
* Direkte Übertragung vom Mikrowellengebiet 1-100GHz auf schnelle Digitalsignale (100MHz-10GHz) ist direkt nicht möglich, weil die Parameter anders sind&lt;br /&gt;
* Typische Leiterbahnbreiten für Digitalsignale sind 0,25mm und weniger, eine 90 Grad Ecke fügt ca. 0,02pF hinzu, typische Frequenz 1GHz bei Signalamplituden von 400mV und mehr (PECL, LVDS), hoher Störabstand (Digitalsignale), der Effekt ist kaum nachweisbar&lt;br /&gt;
* Typische Leiterbahnbreite für Mikrowellentechnik ist 3mm, Kapazitätszuwachs liegt bei ca. 0,2pF, Frequenzen von 10 GHz und mehr, Signalamplituden im Millivoltbereich mit engen Toleranzen über eine lange, analoge Verstärkerkette (+/-0,5dB über 10 Stufen)&lt;br /&gt;
&lt;br /&gt;
Fazit. Die Winkel spielen unter 1 GHz keine Rolle, darüberhinaus nur sehr wenig. VIAs spielen bei 1GHz und mehr eine Rolle. 10fach wichtiger ist jedoch immer eine solide Bezugsfläche unter der HF-Leitung!&lt;br /&gt;
&lt;br /&gt;
== Siehe auch ==&lt;br /&gt;
&lt;br /&gt;
* [http://www.mikrocontroller.net/topic/181484?goto=1752540#1752540 Forumsbeitrag]: Warum HF-Leitungen abrunden?&lt;br /&gt;
* [http://www.mikrocontroller.net/topic/299855?goto=new#3220070 Forumsbeitrag:] Skurriles Problem mit BS170 Mosfets; erfolgreiche Anwendung einer Thevenin-Terminierung für einen [[SPI]]-[[Bus]] mit langen Kabeln&lt;br /&gt;
* [http://www.mikrocontroller.net/topic/299855?page=1#3216635 Forumsbeitrag]: Einfacher Treiber für Parallelterminierung.&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
* [http://de.wikipedia.org/wiki/Wellenimpedanz Wellenwiderstand bei Wikipedia]&lt;br /&gt;
* [http://www.signalintegrity.com www.signalintegrity.com], Die Bibel der hochfrequenten Digitalsignale&lt;br /&gt;
* [http://www.onsemi.com/pub/Collateral/AND8020-D.PDF AppNote von ON Semiconductor: Termination of ECL Logic Devices] (ausführlicher als der Artikel)&lt;br /&gt;
* [http://www.ti.com/litv/pdf/szza008 &amp;quot;Input and Output Characteristics of Digital Integrated Circuits&amp;quot;]&lt;br /&gt;
* http://www.forelec.ch/fichiers/HS-PCB-1.PDF (Sehr gutes Dokument zum Thema)&lt;br /&gt;
* [http://wiki.fed.de/fed-wiki/images/3/3f/Impedanzarten_-_Lagenaufbauten.pdf Striplines/Microstrip schnell berechnet] (PDF)&lt;br /&gt;
* [http://www1.sphere.ne.jp/i-lab/ilab/tool/cpw_e.htm Online Calculator]&lt;br /&gt;
* [http://www.hp.woodshot.com/appcad/version302/setup.exe Noch ein Offline Calculator]&lt;br /&gt;
* Linksammlung [http://www.circuitsage.com/tline.html Transmission Line Design and Analysis]&lt;br /&gt;
* [http://www.epanorama.net/circuits/tdr.html TDR Circuit], ein einfaches Time Domain Reflektometer zum selber bauen&lt;br /&gt;
*[http://www.theamphour.com/the-amp-hour-77-winsome-waveform-wizardry/ The Amp Hour #77 — Winsome Waveform Wizardry], Podcast mit Dr. Howard Johnson, HF-Guru (Ab 01:15:00 kommt die Stelle zum Thema 90° Leiterbahnen)&lt;br /&gt;
* [http://www.ultracad.com/articles/90deg.pdf Messung] von verschiedenen Winkeln von Leiterbahnen mit 17ps TDR, keinerlei Unterschiede!&lt;br /&gt;
* [http://www.afug-info.de/Tipps-Tricks/Impedanz-messen/ Impedanzen einfach und praktisch messen]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Grundlagen]]&lt;br /&gt;
[[Kategorie:Bauteile]]&lt;br /&gt;
[[Kategorie:Datenübertragung]]&lt;/div&gt;</summary>
		<author><name>Df2au</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=Entprellung&amp;diff=85272</id>
		<title>Entprellung</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=Entprellung&amp;diff=85272"/>
		<updated>2014-10-16T08:03:36Z</updated>

		<summary type="html">&lt;p&gt;Df2au: /* Funktionsweise */ Typo&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Problembeschreibung ==&lt;br /&gt;
Mechanische [[Schalter]] wie [[Drehgeber]] neigen beim Ein- und Ausschalten zum sogenannten &#039;&#039;&#039;Prellen&#039;&#039;&#039;, d.h sie schalten schnell mehrfach aus und ein, verursacht durch mechanische Vibrationen des Schaltkontaktes, sofern sie nicht dagegen geschützt sind. Vereinfacht dargestellt, sieht eine von einem Schalter oder Taster geschaltete Spannung beim Schalten wie folgt aus:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Entprellen.png]]&lt;br /&gt;
&lt;br /&gt;
Für die Vermeidung bzw. Auswertung dieses unsauberen Signals gibt es verschiedene Ansätze:&lt;br /&gt;
&lt;br /&gt;
== Hardwareentprellung ==&lt;br /&gt;
&lt;br /&gt;
===Prellfreie Schalter===&lt;br /&gt;
&lt;br /&gt;
Für Spezialanwendungen hält die elektromechanische Industrie verschiedene Sonderkonstruktionen bereit, die saubere Schaltzustände nach Aussen generieren, indem sie entweder eine mechanische Dämpfung in Form eines selbsthemmenden Federmechanismus oder eine integrierte elektronische Signalverzögerung benutzen.&lt;br /&gt;
&lt;br /&gt;
Solche Systeme sind jedoch teuer und werden meist nur im Leistungsbereich eingesetzt.&lt;br /&gt;
&lt;br /&gt;
===Wechselschalter===&lt;br /&gt;
&lt;br /&gt;
Für die Entprellung von Wechselschaltern (engl. Double Throw Switch) kann ein klassisches RS-[[Flipflop]] genutzt werden. Bei dieser Variante werden neben zwei NAND-Gattern nur noch zwei Pull-Up Widerstände benötigt.&lt;br /&gt;
&lt;br /&gt;
[[Bild:NAND_debouncer.png|thumb|left|350px|&#039;&#039;&#039;Taster entprellen mit NAND-RS-Flipflop&#039;&#039;&#039;]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br clear=&amp;quot;all&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In der gezeigten Schalterstellung liegt an der Position /S der Pegel 0 an. Damit ist das Flipflop gesetzt und der Ausgang auf dem Pegel 1. Schließt der Schalter zwischen den Kontakten 2 und 3, liegt an der Postion /R der Pegel 0 an. Dies bedeutet, dass der Ausgang des Flipflops auf den Pegel 0 geht. Sobald der Schalter von einem zum anderen Kontakt wechselt, beginnt er in der Regel zu prellen. Während des Prellens wechselt der Schalter zwischen den beiden Zuständen &amp;quot;Schalter berührt Kontakt&amp;quot; und &amp;quot;Schalter ist frei in der Luft&amp;quot;. Der Ausgang des Flipflops bleibt in dieser Prellzeit aber stabil, da der Schalter während des Prellens nie den gegenüberliegenden Kontakt berührt und das RS-Flipflop seinen Zustand allein halten kann. Die Prellzeit ist stark vom Schaltertyp abhängig und liegt zwischen 0,1 und 10ms. Die Dimensionierung der Widerstände ist relativ unkritisch. Als Richtwert können hier 100kOhm verwendet werden.&lt;br /&gt;
&lt;br /&gt;
====Wechselschalter ohne Flip-Flop====&lt;br /&gt;
&lt;br /&gt;
Wenn man mal gerade kein Flip-Flop zur Hand hat, kann man sich auch mit dieser Schaltung behelfen.&lt;br /&gt;
&lt;br /&gt;
[[Bild:WechselEntprellC.PNG|thumb|left|350px|&#039;&#039;&#039;Wechsler entprellen mit Kondensator&#039;&#039;&#039;]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br clear=&amp;quot;all&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zur Funktionsweise:&lt;br /&gt;
Beim Umschalten wird der Kondensator immer sofort umgeladen.&lt;br /&gt;
Während der Kontakt prellt, befindet er sich in der Luft und hat keinerlei Verbindung. Während dieser Zeit übernimmt der Kondensator das halten des Pegels.&lt;br /&gt;
&lt;br /&gt;
Dimensionierung:&lt;br /&gt;
Ist der entprellte Taster an ein IC Angeschlossen, ist der &#039;&#039;Input Leakage Current&#039;&#039; der ausschlaggebende Strom. Falls weitere Ströme fließen sind diese mit zu berücksichtigen. Bei einem Mikrocontroller von Atmel sind 1µA typisch.&lt;br /&gt;
Es gilt:&lt;br /&gt;
:&amp;lt;math&amp;gt;\frac{dU}{dt} = \frac{I}{C}&amp;lt;/math&amp;gt;&lt;br /&gt;
Da eine Prellung ca. 10ms dauert und die Spannung in dieser Zeit beispielsweise um maximal 0,5V fallen soll kommt man auf folgende Kapazität:&lt;br /&gt;
:&amp;lt;math&amp;gt; C = \frac{I \cdot dt}{dU} = \frac{1\mu A \cdot 10ms}{0,5V} = 20nF &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Um Stromspitzen zu verringern kann ein Widerstand mit eingefügt werden. Eine Zeitkonstante von 1µs bis 1ms scheint sinnvoll. Also 500 Ohm bis 500kOhm sind nutzbar, wobei bei niedrigem Widerstand die Stromspitzen höher sind, und bei 500kOhm der Pinstrom störend wird.&lt;br /&gt;
&lt;br /&gt;
===Einfacher Taster===&lt;br /&gt;
&lt;br /&gt;
Auch wenn das RS-Flipflop sehr effektiv ist, wird diese Variante der Entprellung nur selten angewendet. Grund dafür ist, dass in Schaltungen häufiger einfache Taster eingesetzt werden. Diese sind oft kleiner und preisgünstiger. Um einfache Taster (engl. Single Throw Switch) zu entprellen, kann ein einfacher RC-Tiefpass eingesetzt werden. Hierbei wird ein Kondensator über einen Widerstand je nach Schalterstellung auf- oder entladen. Das RC-Glied bildet einen Tiefpass, sodass die Spannung über den Kondensator nicht von einen Pegel auf den anderen springen kann.&lt;br /&gt;
&lt;br /&gt;
[[Bild:RC_debouncer.png|thumb|left|300px|Taster entprellen mit RC-Entpreller]]&lt;br /&gt;
&lt;br /&gt;
[[Datei:Entprellen1a.png|thumb|350px| Entstehender Spannungsverlauf]]&lt;br /&gt;
{{Absatz}}&lt;br /&gt;
&lt;br /&gt;
Wenn der Schalter geöffnet ist, lädt sich der Kondensator langsam über die beiden Widerstände R&amp;lt;sub&amp;gt;1&amp;lt;/sub&amp;gt; und R&amp;lt;sub&amp;gt;2&amp;lt;/sub&amp;gt; auf V&amp;lt;sub&amp;gt;cc&amp;lt;/sub&amp;gt; auf. Beim Erreichen der Umschaltschwelle springt der Ausgang auf den Pegel 0. Wird der Schalter geschlossen, entlädt sich der Kondensator langsam über den Widerstand R&amp;lt;sub&amp;gt;2&amp;lt;/sub&amp;gt;. Demnach ändert sich der Ausgang des Inverters auf den Pegel 1. Während der Taster prellt, kann sich die Spannung über dem Kondensator nicht sprunghaft ändern, da das Auf- und Entladen eher langsam über die Widerstände erfolgt. Außerdem sind die Schaltschwellen für den Übergang LOW-&amp;gt;HIGH und HIGH-&amp;gt;LOW stark verschieden (Hysterese, siehe Artikel [[Schmitt-Trigger]]). Bei richtiger Dimensionierung der Bauelemente wird somit der Ausgang des Inverters prellfrei.&lt;br /&gt;
&lt;br /&gt;
Zu beachten ist, dass der Inverter &#039;&#039;&#039;unbedingt&#039;&#039;&#039; einer mit [[Schmitt-Trigger]]-Eingängen sein muss, weil bei Standard-Logikeingängen im Bereich von üblicherweise 0,8V - 2,0V der Ausgang nicht definiert ist. Als Inverter kann zum Beispiel der 74HC14 oder der CD40106 (pinkompatibel) eingesetzt werden. Alternativ kann auch ein CD4093 eingesetzt werden. Bei dem CD4093 handelt es sich um NAND-Gatter mit Schmitt-Trigger-Eingängen. Um aus einem NAND-Gatter einen Inverter zu machen, müssen einfach nur die beiden Eingänge verbunden werden oder ein Eingang fest auf HIGH gelegt werden.&lt;br /&gt;
&lt;br /&gt;
Für eine geeignete Dimensionierung muss man etwas mit den Standardformeln für einen Kondensator jonglieren. Die Spannung über den Kondensator beim Entladen berechnet sich nach:&lt;br /&gt;
:&amp;lt;math&amp;gt;U_C(t) = U_0 \cdot e^{\frac{-t}{R_2 C_1}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Damit der Ausgang des Inverters stabil ist, muss die Spannung über den Kondensator und damit die Spannung am Eingang des Inverters über der Spannung bleiben, bei welcher der Inverter umschaltet. Diese Schwellwertspannung ist genau die zeitabhängige Spannung über den Kondensator.&lt;br /&gt;
:&amp;lt;math&amp;gt;U_C(t)\!\ = U_{th}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Durch Umstellen der Formel ergibt sich nun:&lt;br /&gt;
:&amp;lt;math&amp;gt;R_2=\frac{-t}{C_1 \cdot ln\left(\frac{U_{th}}{U_0} \right)}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein Taster prellt üblicherweise etwa 10ms. Zur Sicherheit kann bei der Berechnung des Widerstandes eine Prellzeit von 20ms angenommen werden. U_0 ist die Betriebsspannung also Vcc. Die Schwellwertspannung muss aus dem Datenblatt des eingesetzten Schmitt-Triggers abgelesen werden. Beim 74HC14 beträgt der gesuchte Wert 2,0V. Nimmt man für den Kondensator 1µF und beträgt die  Betriebsspannung 5V, ergibt sich für den Widerstand ein Wert von etwa 22kOhm.&lt;br /&gt;
&lt;br /&gt;
Wird der Schalter geöffnet, lädt sich der Kondensator nach folgender Formel auf:&lt;br /&gt;
:&amp;lt;math&amp;gt;U_C(t) = U_0 \cdot \left( 1-e^{\frac{-t}{(R_1+R_2)\cdot C_1}} \right)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit U_th=U_C ergibt das Umstellen nach (R_1+R_2):&lt;br /&gt;
:&amp;lt;math&amp;gt;R_1+R_2 = \frac{-t}{C_1 \cdot ln\left(1-\frac{U_{th}}{U_0} \right)} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für die Schwellspannung lässt sich aus dem Datenblatt ein Wert von 2,3V ablesen. Mit diesem Wert und den Annahmen von oben ergibt sich für R_1+R_2 ein Wert von 32kOhm. Somit ergibt sich für R_1 ein Wert von etwa 10kOhm.&lt;br /&gt;
&lt;br /&gt;
Anmerkung: Beim 74LS14 von Hitachi z.&amp;amp;nbsp;B. sind die oberen und unteren Schaltschwellwerte unterschiedlich. Es muss darauf geachtet werden, dass U_{th} beim Entladen die untere Schwelle und U_{th} beim Laden die obere Schwelle einnimmt.&lt;br /&gt;
&lt;br /&gt;
== Softwareentprellung ==&lt;br /&gt;
&lt;br /&gt;
In den Zeiten der elektronischen Auswertung von Tastern und Schaltern ist das softwaretechnische Entprellen oft billiger, als die Benutzung eines teuren Schalters. Daher werden heute z.B. auch Computertastaturen nicht mehr mit prellarmen Tasten oder Entprellkondensatoren ausgestattet.&lt;br /&gt;
&lt;br /&gt;
Bei Verwendung des in den meisten Geräten ohnehin vorhandenen Mikrocontrollers z.B., kann man sich die zusätzliche Hardware sparen, da die Entprellung in Software praktisch genauso gut funktioniert. Dabei ist nur zu beachten, dass zusätzliche Rechenleistung und je nach Umsetzung auch einige Hardwareressourcen (z.B. Timer) benötigt werden.&lt;br /&gt;
&lt;br /&gt;
=== Flankenerkennung ===&lt;br /&gt;
Bei einem Taster gibt es insgesamt 4 theoretische Zustände:&lt;br /&gt;
&lt;br /&gt;
* 1. war nicht gedrückt und ist nicht gedrückt&lt;br /&gt;
* 2. war nicht gedrückt und ist gedrückt (steigende Flanke)&lt;br /&gt;
* 3. war gedrückt und ist immer noch gedrückt&lt;br /&gt;
* 4. war gedrückt und ist nicht mehr gedrückt (fallende Flanke)&lt;br /&gt;
&lt;br /&gt;
Diese einzelnen Zustände lassen sich jetzt bequem abfragen/durchlaufen. Die Entprellung geschieht dabei durch die ganze Laufzeit des Programms. Die Taster werden hierbei als Active-Low angeschlossen, um die internen Pull-Ups zu nutzen.&lt;br /&gt;
&lt;br /&gt;
Diese Routine gibt für den Zustand &amp;quot;steigende Flanke&amp;quot; den Wert &amp;quot;1&amp;quot; zurück, sonst &amp;quot;0&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define TASTERPORT PINC&lt;br /&gt;
#define TASTERBIT PINC1&lt;br /&gt;
&lt;br /&gt;
char taster(void)&lt;br /&gt;
{&lt;br /&gt;
    static unsigned char zustand;&lt;br /&gt;
    char rw = 0;&lt;br /&gt;
&lt;br /&gt;
    if(zustand == 0 &amp;amp;&amp;amp; !(TASTERPORT &amp;amp; (1&amp;lt;&amp;lt;TASTERBIT)))   //Taster wird gedrueckt (steigende Flanke)&lt;br /&gt;
    {&lt;br /&gt;
        zustand = 1;&lt;br /&gt;
        rw = 1;&lt;br /&gt;
    }&lt;br /&gt;
    else if (zustand == 1 &amp;amp;&amp;amp; !(TASTERPORT &amp;amp; (1&amp;lt;&amp;lt;TASTERBIT)))   //Taster wird gehalten&lt;br /&gt;
    {&lt;br /&gt;
         zustand = 2;&lt;br /&gt;
         rw = 0;&lt;br /&gt;
    }&lt;br /&gt;
    else if (zustand == 2 &amp;amp;&amp;amp; (TASTERPORT &amp;amp; (1&amp;lt;&amp;lt;TASTERBIT)))   //Taster wird losgelassen (fallende Flanke)&lt;br /&gt;
    {&lt;br /&gt;
        zustand = 3;&lt;br /&gt;
        rw = 0;&lt;br /&gt;
    }&lt;br /&gt;
    else if (zustand == 3 &amp;amp;&amp;amp; (TASTERPORT &amp;amp; (1&amp;lt;&amp;lt;TASTERBIT)))   //Taster losgelassen&lt;br /&gt;
    {&lt;br /&gt;
        zustand = 0;&lt;br /&gt;
        rw = 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return rw;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Eine Erweiterung, damit beliebig lange das Halten einer Taste erkannt wird kann man ganz einfach so implementieren:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
    // zustand kann entweder zum ersten mal als gehalten detektiert werden oder aber jedes weitere mal&lt;br /&gt;
    else if (((zustand == 1) || (zustand == 2)) &amp;amp;&amp;amp; !(TASTERPORT &amp;amp; (1&amp;lt;&amp;lt;TASTERBIT)))   //Taster wird gehalten&lt;br /&gt;
    {&lt;br /&gt;
         zustand = 2;&lt;br /&gt;
         rw = 0;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Warteschleifen-Verfahren ===&lt;br /&gt;
&lt;br /&gt;
Soll nun mit einem Mikrocontroller gezählt werden, wie oft ein Kontakt oder ein Relais geschaltet wird, muss das Prellen des Kontaktes exakt berücksichtigt - und von einem gewollten Mehrfachschalten abgegrenzt werden, da sonst  möglicherweise Fehlimpulse gezählt- oder andererseits echte Schaltvorgänge übersprungen werden. Dies muss beim Schreiben des Programms hinsichtlich des Abtastens des Kontaktes unbedingt Rechnung getragen werden.&lt;br /&gt;
&lt;br /&gt;
Beim folgenden einfachen Beispiel für eine Entprellung ist zu beachten, dass der AVR im Falle eines Tastendrucks 200ms wartet, also brach liegt. Bei zeitkritischen Anwendungen sollte man ein anderes Verfahren nutzen (z.&amp;amp;nbsp;B. Abfrage der Tastenzustände in einer Timer-Interrupt-Service-Routine).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&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);   // Maximalwert des Parameters an _delay_ms &lt;br /&gt;
        _delay_ms(50);   // beachten, vgl. Dokumentation der avr-libc&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))&lt;br /&gt;
    {&lt;br /&gt;
        /* Falls Taster an PIN PB0 gedrueckt     */&lt;br /&gt;
        /* LED an Port PD7 an- bzw. ausschalten: */&lt;br /&gt;
        PORTD = PORTD ^ ( 1 &amp;lt;&amp;lt; PD7 );&lt;br /&gt;
    }&lt;br /&gt;
    ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die obige Routine hat leider mehrere Nachteile:&lt;br /&gt;
* sie detektiert nur das Loslassen (unergonomisch)&lt;br /&gt;
* sie verzögert die Mainloop immer um 100ms bei gedrückter Taste&lt;br /&gt;
* sie verliert Tastendrücke, je mehr die Mainloop zu tun hat.&lt;br /&gt;
&lt;br /&gt;
Eine ähnlich einfach zu benutzende Routine, aber ohne all diese Nachteile findet sich im Forenthread&lt;br /&gt;
[http://www.mikrocontroller.net/topic/164194#new Entprellung für Anfänger]&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;DEBOUNCE&#039;&#039; Befehl in dem BASIC-Dialekt BASCOM für AVR ist ebenfalls nach dem Warteschleifen-Verfahren programmiert. Die Wartezeit beträgt standardmäßig 25 ms, kann aber vom Anwender überschrieben werden. Vgl.  [http://avrhelp.mcselec.com/bascom-avr.html?DEBOUNCE BASCOM Online-Manual zu DEBOUNCE].&lt;br /&gt;
&lt;br /&gt;
Eine C-Implementierung für eine Tastenabfrage mit Warteschleife ist im Artikel [[AVR-GCC-Tutorial#IO-Register_als_Parameter_und_Variablen|AVR-GCC-Tutorial: IO-Register als Parameter und Variablen]] angeben.&lt;br /&gt;
&lt;br /&gt;
Der Nachteil dieses Verfahrens ist, dass der Controller durch die Warteschleife blockiert wird. Günstiger ist die Implementierung mit einem Timer-Interrupt.&lt;br /&gt;
&lt;br /&gt;
==== Warteschleifenvariante mit Maske und Pointer (nach Christian Riggenbach) ====&lt;br /&gt;
&lt;br /&gt;
Hier eine weitere Funktion, um Taster zu entprellen: Durch den zusätzlichen Code kann eine Entprellzeit von durchschnittlich 1-3ms (mindestens 8*150µs = 1ms) erreicht werden. Grundsätzlich prüft die Funktion den Pegel der Pins auf einem bestimmten Port. Wenn die/der Pegel 8 Mal konstant war, wird die Schleife verlassen. Diese Funktion kann sehr gut eingesetzt werden, um in einer Endlosschleife Taster anzufragen, da sie, wie erwähnt, eine kurze Wartezeit hat.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void entprellung( volatile uint8_t *port, uint8_t maske ) {&lt;br /&gt;
  uint8_t   port_puffer;&lt;br /&gt;
  uint8_t   entprellungs_puffer;&lt;br /&gt;
&lt;br /&gt;
  for( entprellungs_puffer=0 ; entprellungs_puffer!=0xff ; ) {&lt;br /&gt;
    entprellungs_puffer&amp;lt;&amp;lt;=1;&lt;br /&gt;
    port_puffer = *port;&lt;br /&gt;
    _delay_us(150);&lt;br /&gt;
    if( (*port &amp;amp; maske) == (port_puffer &amp;amp; maske) )&lt;br /&gt;
      entprellungs_puffer |= 0x01;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Die Funktion wird wie folgt aufgerufen:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
  // Bugfix 20100414&lt;br /&gt;
  // http://www.nongnu.org/avr-libc/user-manual/FAQ.html#faq_port_pass&lt;br /&gt;
  entprellung( &amp;amp;PINB, (1&amp;lt;&amp;lt;PINB2) ); // ggf. Prellen abwarten &lt;br /&gt;
  if( PINB &amp;amp; (1&amp;lt;&amp;lt;PINB2) )           // dann stabilen Wert einlesen&lt;br /&gt;
  {&lt;br /&gt;
    // mach was&lt;br /&gt;
  }&lt;br /&gt;
  else&lt;br /&gt;
  {&lt;br /&gt;
    // mach was anderes&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Als Maske kann ein beliebiger Wert übergeben werden. Sie verhindert, dass nichtverwendete Taster die Entprellzeit negativ beeinflussen.&lt;br /&gt;
&lt;br /&gt;
==== Debounce-Makro von Peter Dannegger ====&lt;br /&gt;
&lt;br /&gt;
Peter Dannegger hat in [http://www.mikrocontroller.net/topic/164194#1566921 &amp;quot;Entprellen für Anfänger&amp;quot;] folgende vereinfachtes Entprellverfahren beschrieben. Das Makro arbeitet in der Originalversion mit &#039;&#039;active low&#039;&#039; geschalteten Tastern, kann aber einfach für  &#039;&#039;active high&#039;&#039; geschaltete Taster angepasst werden ([[Pollin Funk-AVR-Evaluationsboard#Tasty Reloaded|Tasty Reloaded]]). &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/************************************************************************/&lt;br /&gt;
/*                                                                      */&lt;br /&gt;
/*                      Not so powerful Debouncing Example              */&lt;br /&gt;
/*                      No Interrupt needed                             */&lt;br /&gt;
/*                                                                      */&lt;br /&gt;
/*              Author: Peter Dannegger                                 */&lt;br /&gt;
/*                                                                      */&lt;br /&gt;
/************************************************************************/&lt;br /&gt;
// Target: ATtiny13&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#define F_CPU 9.6e6&lt;br /&gt;
#include &amp;lt;util/delay.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
#define debounce( port, pin )                                         \&lt;br /&gt;
({                                                                    \&lt;br /&gt;
  static uint8_t flag = 0;     /* new variable on every macro usage */  \&lt;br /&gt;
  uint8_t i = 0;                                                      \&lt;br /&gt;
                                                                      \&lt;br /&gt;
  if( flag ){                  /* check for key release: */           \&lt;br /&gt;
    for(;;){                   /* loop ... */                         \&lt;br /&gt;
      if( !(port &amp;amp; 1&amp;lt;&amp;lt;pin) ){  /* ... until key pressed or ... */     \&lt;br /&gt;
        i = 0;                 /* 0 = bounce */                       \&lt;br /&gt;
        break;                                                        \&lt;br /&gt;
      }                                                               \&lt;br /&gt;
      _delay_us( 98 );         /* * 256 = 25ms */                     \&lt;br /&gt;
      if( --i == 0 ){          /* ... until key &amp;gt;25ms released */     \&lt;br /&gt;
        flag = 0;              /* clear press flag */                 \&lt;br /&gt;
        i = 0;                 /* 0 = key release debounced */        \&lt;br /&gt;
        break;                                                        \&lt;br /&gt;
      }                                                               \&lt;br /&gt;
    }                                                                 \&lt;br /&gt;
  }else{                       /* else check for key press: */        \&lt;br /&gt;
    for(;;){                   /* loop ... */                         \&lt;br /&gt;
      if( (port &amp;amp; 1&amp;lt;&amp;lt;pin) ){   /* ... until key released or ... */    \&lt;br /&gt;
        i = 0;                 /* 0 = bounce */                       \&lt;br /&gt;
        break;                                                        \&lt;br /&gt;
      }                                                               \&lt;br /&gt;
      _delay_us( 98 );         /* * 256 = 25ms */                     \&lt;br /&gt;
      if( --i == 0 ){          /* ... until key &amp;gt;25ms pressed */      \&lt;br /&gt;
        flag = 1;              /* set press flag */                   \&lt;br /&gt;
        i = 1;                 /* 1 = key press debounced */          \&lt;br /&gt;
        break;                                                        \&lt;br /&gt;
      }                                                               \&lt;br /&gt;
    }                                                                 \&lt;br /&gt;
  }                                                                   \&lt;br /&gt;
  i;                           /* return value of Macro */            \&lt;br /&gt;
})&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
   Testapplication&lt;br /&gt;
 */&lt;br /&gt;
int main(void)&lt;br /&gt;
{&lt;br /&gt;
  DDRB  &amp;amp;= ~(1&amp;lt;&amp;lt;PB0);&lt;br /&gt;
  PORTB |=   1&amp;lt;&amp;lt;PB0;&lt;br /&gt;
  DDRB  |=   1&amp;lt;&amp;lt;PB2;&lt;br /&gt;
  DDRB  &amp;amp;= ~(1&amp;lt;&amp;lt;PB1);&lt;br /&gt;
  PORTB |=   1&amp;lt;&amp;lt;PB1;&lt;br /&gt;
  DDRB  |=   1&amp;lt;&amp;lt;PB3;&lt;br /&gt;
  for(;;){&lt;br /&gt;
    if( debounce( PINB, PB1 ) )&lt;br /&gt;
      PORTB ^= 1&amp;lt;&amp;lt;PB2;&lt;br /&gt;
    if( debounce( PINB, PB0 ) )&lt;br /&gt;
      PORTB ^= 1&amp;lt;&amp;lt;PB3;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn das Makro für die gleiche Taste (Pin) an mehreren Stellen aufgerufen werden soll, muss eine Funktion angelegt werden, damit beide Aufrufe an die gleiche Zustandsvariable &#039;&#039;flag&#039;&#039; auswerten [http://www.mikrocontroller.net/topic/195914#1918727]:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Hilfsfunktion&lt;br /&gt;
uint8_t debounce_C1( void )&lt;br /&gt;
{&lt;br /&gt;
  return debounce(PINC, PC1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Beispielanwendung&lt;br /&gt;
int main(void)&lt;br /&gt;
{&lt;br /&gt;
  DDRB  |=   1&amp;lt;&amp;lt;PB2;&lt;br /&gt;
  DDRB  |=   1&amp;lt;&amp;lt;PB3;&lt;br /&gt;
  DDRC  &amp;amp;= ~(1&amp;lt;&amp;lt;PC1);&lt;br /&gt;
  PORTC |=   1&amp;lt;&amp;lt;PC1; // Pullup für Taster&lt;br /&gt;
&lt;br /&gt;
  for(;;){&lt;br /&gt;
    if( debounce_C1() )  // nicht: debounce(PINC, PC1)&lt;br /&gt;
      PORTB ^= 1&amp;lt;&amp;lt;PB2;&lt;br /&gt;
    if( debounce_C1() )  // nicht: debounce(PINC, PC1)&lt;br /&gt;
      PORTB ^= 1&amp;lt;&amp;lt;PB3;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Timer-Verfahren (nach Peter Dannegger) ===&lt;br /&gt;
&lt;br /&gt;
==== Grundroutine (AVR Assembler) ====&lt;br /&gt;
&lt;br /&gt;
Siehe dazu: [http://www.mikrocontroller.net/forum/read-4-20435.html#new Forum] &lt;br /&gt;
&lt;br /&gt;
Vorteile&lt;br /&gt;
* besonders kurzer Code&lt;br /&gt;
* schnell&lt;br /&gt;
&lt;br /&gt;
Außerdem können 8 Tasten (aktiv low) gleichzeitig bearbeitet werden, es dürfen also&lt;br /&gt;
alle exakt zur selben Zeit gedrückt werden. Andere Routinen können z.&amp;amp;nbsp;B. nur eine Taste verarbeiten, d.h. die zuerst oder zuletzt gedrückte gewinnt, oder es kommt Unsinn heraus.&lt;br /&gt;
&lt;br /&gt;
Die eigentliche Einlese- und Entprellroutine ist nur 8 Instruktionen&lt;br /&gt;
kurz. Der entprellte Tastenzustand ist im Register &#039;&#039;key_state&#039;&#039;. Mit nur 2 weiteren Instruktionen wird dann der Wechsel von &#039;&#039;Taste offen&#039;&#039; zu&lt;br /&gt;
&#039;&#039;Taste gedrückt&#039;&#039; erkannt und im Register &#039;&#039;key_press&#039;&#039; abgelegt. Im Beispielcode werden dann damit 8 LEDs ein- und ausgeschaltet. Jede Taste entspricht einem Bit in den Registern, d.h. die Verarbeitung erfolgt bitweise mit logischen Operationen. Zum Verständnis empfiehlt es sich daher, die Logikgleichungen mit Gattern für ein Bit = eine Taste aufzumalen. Die Register kann man sich als Flipflops denken, die mit der Entprellzeit als Takt arbeiten. D.h. man kann das auch so z.&amp;amp;nbsp;B. in einem GAL22V10 realisieren.&lt;br /&gt;
&lt;br /&gt;
Als Kommentar sind neben den einzelnen Instruktionen alle 8 möglichen&lt;br /&gt;
Kombinationen der 3 Signale dargestellt.&lt;br /&gt;
&lt;br /&gt;
Beispielcode für AVR (Assembler):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;avrasm&amp;quot;&amp;gt; &lt;br /&gt;
.nolist&lt;br /&gt;
.include &amp;quot;c:\avr\inc\1200def.inc&amp;quot;&lt;br /&gt;
.list&lt;br /&gt;
.def  save_sreg         = r0&lt;br /&gt;
.def  iwr0              = r1&lt;br /&gt;
.def  iwr1              = r2&lt;br /&gt;
&lt;br /&gt;
.def  key_old           = r3&lt;br /&gt;
.def  key_state         = r4&lt;br /&gt;
.def  key_press         = r5&lt;br /&gt;
&lt;br /&gt;
.def  leds              = r16&lt;br /&gt;
.def  wr0               = r17&lt;br /&gt;
&lt;br /&gt;
.equ  key_port          = pind&lt;br /&gt;
.equ  led_port          = portb&lt;br /&gt;
&lt;br /&gt;
      rjmp   init&lt;br /&gt;
.org OVF0addr		;timer interrupt 24ms&lt;br /&gt;
      in     save_sreg, SREG&lt;br /&gt;
get8key:                               ;/old      state     iwr1      iwr0&lt;br /&gt;
      mov    iwr0, key_old             ;00110011  10101010            00110011&lt;br /&gt;
      in     key_old, key_port         ;11110000&lt;br /&gt;
      eor    iwr0, key_old             ;                              11000011&lt;br /&gt;
      com    key_old                   ;00001111&lt;br /&gt;
      mov    iwr1, key_state           ;                    10101010&lt;br /&gt;
      or     key_state, iwr0           ;          11101011&lt;br /&gt;
      and    iwr0, key_old             ;                              00000011&lt;br /&gt;
      eor    key_state, iwr0           ;          11101000&lt;br /&gt;
      and    iwr1, iwr0                ;                    00000010&lt;br /&gt;
      or     key_press, iwr1           ;store key press detect&lt;br /&gt;
;&lt;br /&gt;
;			insert other timer functions here&lt;br /&gt;
;&lt;br /&gt;
      out    SREG, save_sreg&lt;br /&gt;
      reti&lt;br /&gt;
;-------------------------------------------------------------------------&lt;br /&gt;
init:&lt;br /&gt;
      ldi    wr0, 0xFF&lt;br /&gt;
      out    ddrb, wr0&lt;br /&gt;
      ldi    wr0, 1&amp;lt;&amp;lt;CS02 | 1&amp;lt;&amp;lt;CS00    ;divide by 1024 * 256&lt;br /&gt;
      out    TCCR0, wr0&lt;br /&gt;
      ldi    wr0, 1&amp;lt;&amp;lt;TOIE0             ;enable timer interrupt&lt;br /&gt;
      out    TIMSK, wr0&lt;br /&gt;
&lt;br /&gt;
      clr    key_old&lt;br /&gt;
      clr    key_state&lt;br /&gt;
      clr    key_press&lt;br /&gt;
      ldi    leds, 0xFF&lt;br /&gt;
main: cli&lt;br /&gt;
      eor    leds, key_press           ;toggle LEDs&lt;br /&gt;
      clr    key_press                 ;clear, if key press action done&lt;br /&gt;
      sei&lt;br /&gt;
      out    led_port, leds&lt;br /&gt;
      rjmp   main&lt;br /&gt;
;-------------------------------------------------------------&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Komfortroutine (C für AVR) ====&lt;br /&gt;
&lt;br /&gt;
Siehe dazu: [http://www.mikrocontroller.net/forum/read-4-310276.html Forum]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Anmerkung&#039;&#039;&#039; Wenn statt active-low (Ruhezustand High) active-high (Ruhezustand Low) verwendet wird muss eine Zeile geändert werden siehe:&lt;br /&gt;
[http://www.mikrocontroller.net/forum/read-4-310276.html gesamter Beitrag im Forum], &lt;br /&gt;
[http://www.mikrocontroller.net/topic/48465#606555 Stelle 1 im Beitrag], ([http://www.mikrocontroller.net/topic/48465#2306398 Stelle 2 im Beitrag] muss *nicht* geändert werden, da hier die Polarität gar keinen Einfluß hat).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Anmerkung 2&#039;&#039;&#039; Zur Initialisierung siehe [http://www.mikrocontroller.net/topic/48465#3572793 Forum]&lt;br /&gt;
&lt;br /&gt;
Funktionsprinzip wie oben plus zusätzliche Features:  &lt;br /&gt;
* Kann Tasten sparen durch unterschiedliche Aktionen bei kurzem oder langem Drücken&lt;br /&gt;
* Wiederholfunktion, z.&amp;amp;nbsp;B. für die Eingabe von Werten&lt;br /&gt;
&lt;br /&gt;
Das Programm ist für avr-gcc/avr-libc geschrieben, kann aber mit ein paar Anpassungen auch mit anderen Compilern und Mikrocontrollern verwendet werden. Eine Portierung für den AT91SAM7 findet man [http://www.google.com/codesearch?q=show:ac2viP-2E2Y:pzkOO5QRsoc:RPICuprYy-A&amp;amp;sa=N&amp;amp;cd=1&amp;amp;ct=rc&amp;amp;cs_p=svn://mikrocontroller.net/mp3dec/trunk&amp;amp;cs_f=keys.c#a0 hier] (aus dem Projekt [[ARM MP3/AAC Player]]).&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/************************************************************************/&lt;br /&gt;
/*                                                                      */&lt;br /&gt;
/*                      Debouncing 8 Keys                               */&lt;br /&gt;
/*                      Sampling 4 Times                                */&lt;br /&gt;
/*                      With Repeat Function                            */&lt;br /&gt;
/*                                                                      */&lt;br /&gt;
/*              Author: Peter Dannegger                                 */&lt;br /&gt;
/*                      danni@specs.de                                  */&lt;br /&gt;
/*                                                                      */&lt;br /&gt;
/************************************************************************/&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/interrupt.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#ifndef F_CPU&lt;br /&gt;
#define F_CPU           1000000                   // processor clock frequency&lt;br /&gt;
#warning kein F_CPU definiert&lt;br /&gt;
#endif&lt;br /&gt;
 &lt;br /&gt;
#define KEY_DDR         DDRB&lt;br /&gt;
#define KEY_PORT        PORTB&lt;br /&gt;
#define KEY_PIN         PINB&lt;br /&gt;
#define KEY0            0&lt;br /&gt;
#define KEY1            1&lt;br /&gt;
#define KEY2            2&lt;br /&gt;
#define ALL_KEYS        (1&amp;lt;&amp;lt;KEY0 | 1&amp;lt;&amp;lt;KEY1 | 1&amp;lt;&amp;lt;KEY2)&lt;br /&gt;
 &lt;br /&gt;
#define REPEAT_MASK     (1&amp;lt;&amp;lt;KEY1 | 1&amp;lt;&amp;lt;KEY2)       // repeat: key1, key2&lt;br /&gt;
#define REPEAT_START    50                        // after 500ms&lt;br /&gt;
#define REPEAT_NEXT     20                        // every 200ms&lt;br /&gt;
&lt;br /&gt;
#define LED_DDR         DDRA&lt;br /&gt;
#define LED_PORT        PORTA&lt;br /&gt;
#define LED0            0&lt;br /&gt;
#define LED1            1&lt;br /&gt;
#define LED2            2&lt;br /&gt;
 &lt;br /&gt;
volatile uint8_t key_state;                                // debounced and inverted key state:&lt;br /&gt;
                                                  // bit = 1: key pressed&lt;br /&gt;
volatile uint8_t key_press;                                // key press detect&lt;br /&gt;
 &lt;br /&gt;
volatile uint8_t key_rpt;                                  // key long press and repeat&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
ISR( TIMER0_OVF_vect )                            // every 10ms&lt;br /&gt;
{&lt;br /&gt;
  static uint8_t ct0, ct1, rpt;&lt;br /&gt;
  uint8_t i;&lt;br /&gt;
 &lt;br /&gt;
  TCNT0 = (uint8_t)(int16_t)-(F_CPU / 1024 * 10e-3 + 0.5);  // preload for 10ms&lt;br /&gt;
 &lt;br /&gt;
  i = key_state ^ ~KEY_PIN;                       // key changed ?&lt;br /&gt;
  ct0 = ~( ct0 &amp;amp; i );                             // reset or count ct0&lt;br /&gt;
  ct1 = ct0 ^ (ct1 &amp;amp; i);                          // reset or count ct1&lt;br /&gt;
  i &amp;amp;= ct0 &amp;amp; ct1;                                 // count until roll over ?&lt;br /&gt;
  key_state ^= i;                                 // then toggle debounced state&lt;br /&gt;
  key_press |= key_state &amp;amp; i;                     // 0-&amp;gt;1: key press detect&lt;br /&gt;
 &lt;br /&gt;
  if( (key_state &amp;amp; REPEAT_MASK) == 0 )            // check repeat function&lt;br /&gt;
     rpt = REPEAT_START;                          // start delay&lt;br /&gt;
  if( --rpt == 0 ){&lt;br /&gt;
    rpt = REPEAT_NEXT;                            // repeat delay&lt;br /&gt;
    key_rpt |= key_state &amp;amp; REPEAT_MASK;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
///////////////////////////////////////////////////////////////////&lt;br /&gt;
//&lt;br /&gt;
// check if a key has been pressed. Each pressed key is reported&lt;br /&gt;
// only once&lt;br /&gt;
//&lt;br /&gt;
uint8_t get_key_press( uint8_t key_mask )&lt;br /&gt;
{&lt;br /&gt;
  cli();                                          // read and clear atomic !&lt;br /&gt;
  key_mask &amp;amp;= key_press;                          // read key(s)&lt;br /&gt;
  key_press ^= key_mask;                          // clear key(s)&lt;br /&gt;
  sei();&lt;br /&gt;
  return key_mask;&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
///////////////////////////////////////////////////////////////////&lt;br /&gt;
//&lt;br /&gt;
// check if a key has been pressed long enough such that the&lt;br /&gt;
// key repeat functionality kicks in. After a small setup delay&lt;br /&gt;
// the key is reported being pressed in subsequent calls&lt;br /&gt;
// to this function. This simulates the user repeatedly&lt;br /&gt;
// pressing and releasing the key.&lt;br /&gt;
//&lt;br /&gt;
uint8_t get_key_rpt( uint8_t key_mask )&lt;br /&gt;
{&lt;br /&gt;
  cli();                                          // read and clear atomic !&lt;br /&gt;
  key_mask &amp;amp;= key_rpt;                            // read key(s)&lt;br /&gt;
  key_rpt ^= key_mask;                            // clear key(s)&lt;br /&gt;
  sei();&lt;br /&gt;
  return key_mask;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
///////////////////////////////////////////////////////////////////&lt;br /&gt;
//&lt;br /&gt;
// check if a key is pressed right now&lt;br /&gt;
//&lt;br /&gt;
uint8_t get_key_state( uint8_t key_mask )&lt;br /&gt;
&lt;br /&gt;
{&lt;br /&gt;
  key_mask &amp;amp;= key_state;&lt;br /&gt;
  return key_mask;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
///////////////////////////////////////////////////////////////////&lt;br /&gt;
//&lt;br /&gt;
uint8_t get_key_short( uint8_t key_mask )&lt;br /&gt;
{&lt;br /&gt;
  cli();                                          // read key state and key press atomic !&lt;br /&gt;
  return get_key_press( ~key_state &amp;amp; key_mask );&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
///////////////////////////////////////////////////////////////////&lt;br /&gt;
//&lt;br /&gt;
uint8_t get_key_long( uint8_t key_mask )&lt;br /&gt;
{&lt;br /&gt;
  return get_key_press( get_key_rpt( key_mask ));&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
int main( void )&lt;br /&gt;
{&lt;br /&gt;
  LED_PORT = 0xFF;&lt;br /&gt;
  LED_DDR = 0xFF;                     &lt;br /&gt;
&lt;br /&gt;
  // Configure debouncing routines&lt;br /&gt;
  KEY_DDR &amp;amp;= ~ALL_KEYS;                // configure key port for input&lt;br /&gt;
  KEY_PORT |= ALL_KEYS;                // and turn on pull up resistors&lt;br /&gt;
&lt;br /&gt;
  TCCR0 = (1&amp;lt;&amp;lt;CS02)|(1&amp;lt;&amp;lt;CS00);         // divide by 1024&lt;br /&gt;
  TCNT0 = (uint8_t)(int16_t)-(F_CPU / 1024 * 10e-3 + 0.5);  // preload for 10ms&lt;br /&gt;
  TIMSK |= 1&amp;lt;&amp;lt;TOIE0;                   // enable timer interrupt&lt;br /&gt;
&lt;br /&gt;
  sei();&lt;br /&gt;
&lt;br /&gt;
  while(1){&lt;br /&gt;
    if( get_key_short( 1&amp;lt;&amp;lt;KEY1 ))&lt;br /&gt;
      LED_PORT ^= 1&amp;lt;&amp;lt;LED1;&lt;br /&gt;
 &lt;br /&gt;
    if( get_key_long( 1&amp;lt;&amp;lt;KEY1 ))&lt;br /&gt;
      LED_PORT ^= 1&amp;lt;&amp;lt;LED2;&lt;br /&gt;
 &lt;br /&gt;
    // single press and repeat&lt;br /&gt;
 &lt;br /&gt;
    if( get_key_press( 1&amp;lt;&amp;lt;KEY2 ) || get_key_rpt( 1&amp;lt;&amp;lt;KEY2 )){&lt;br /&gt;
      uint8_t i = LED_PORT;&lt;br /&gt;
 &lt;br /&gt;
      i = (i &amp;amp; 0x07) | ((i &amp;lt;&amp;lt; 1) &amp;amp; 0xF0);&lt;br /&gt;
      if( i &amp;lt; 0xF0 )&lt;br /&gt;
        i |= 0x08;&lt;br /&gt;
      LED_PORT = i;      &lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das single-press-und-repeat-Beispiel geht nicht in jeder Beschaltung; folgendes Beispiel sollte universeller sein (einzelne LED an/aus):&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// single press and repeat&lt;br /&gt;
if( get_key_press( 1&amp;lt;&amp;lt;KEY2 ) || get_key_rpt( 1&amp;lt;&amp;lt;KEY2 ))&lt;br /&gt;
    LED_PORT ^=0x08;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===== Funktionsweise =====&lt;br /&gt;
Der Code basiert auf 8 parallelen vertikalen Zählern, die über die Variablen ct0 und ct1 aufgebaut werden&lt;br /&gt;
&lt;br /&gt;
[[Bild:VertCount.png|framed|center|&#039;&#039;&#039;8 vertikale Zähler in 2 8-Bit Variablen&#039;&#039;&#039;]]&lt;br /&gt;
&lt;br /&gt;
wobei jeweils ein Bit in ct0 mit dem gleichwertigen Bit in ct1 zusammengenommen einen 2-Bit-Zähler bildet.&lt;br /&gt;
Der Code der sich um die 8 Zähler kümmert, ist so geschrieben, daß er alle 8 Zähler gemeinsam parallel behandelt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
  i = key_state ^ ~KEY_PIN;                       // key changed ?&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
i enthält an dieser Stelle für jede Taste, die sich im Vergleich mit dem vorhergehenden entprellten Zustand (keystate) verändert hat, ein 1 Bit.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
  ct0 = ~( ct0 &amp;amp; i );                             // reset or count ct0&lt;br /&gt;
  ct1 = ct0 ^ (ct1 &amp;amp; i);                          // reset or count ct1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Diese beiden Anweisungen erniedrigen den 2-Bit Zähler ct0/ct1 für jedes Bit um 1, welches in i gesetzt ist. Liegt an der entsprechenden Stelle in i ein 0 Bit vor (keine Änderung des Zustands), so wird der Zähler ct0/ct1 für dieses Bit auf 1 gesetzt.&lt;br /&gt;
Der Grundzustand des Zählers ist als ct0 == 1 und ct1 == 1 (Wert 3). Der Zähler zählt daher mit jedem ISR Aufruf, bei dem die Taste im Vergleich zu keystate als verändert erkannt wurde&lt;br /&gt;
&lt;br /&gt;
   ct1   ct0&lt;br /&gt;
     1    1   // 3&lt;br /&gt;
     1    0   // 2&lt;br /&gt;
     0    1   // 1&lt;br /&gt;
     0    0   // 0&lt;br /&gt;
     1    1   // 3&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
  i &amp;amp;= ct0 &amp;amp; ct1;                                 // count until roll over ?&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
in i bleibt nur dort ein 1-Bit erhalten, wo sowohl in ct1 als auch in ct0 ein 1 Bit vorgefunden wird, der betreffende Zähler also bis 3 zählen konnte. Durch die zusätzliche Verundung mit i wird der Fall abgefangen, dass ein konstanter Zählerwert von 3 in i ein 1 Bit hinterlässt. Im Endergebnis bedeutet dass, dass nur ein Zählerwechsel von 0 auf 3 zu einem 1 Bit an der betreffenden Stelle in i führt, aber auch nur dann, wenn in i an dieser Bitposition ebenfalls ein 1 Bit war (welches wiederrum deswegen auf 1 war, weil an diesem Eingabeport eine Veränderung zum letzten bekannten entprellten Zustand festgestellt wurde). alles zusammengenommen heißt das, dass ein Tastendruck dann erkannt wird, wenn die Taste 4 mal hintereinander in einem anderen Zustand vorgefunden wurde als dem zuletzt bekannten entprellten Tastenzustand.&lt;br /&gt;
&lt;br /&gt;
An dieser Stelle ist i daher ein Vektor von 8 Bits, von denen jedes einzelne der Bits darüber Auskunft gibt, ob die entsprechende Taste mehrmals hintereinander im selben Zustand angetroffen wurde, der nicht mit dem zuletzt bekannten Tastenzustand übereinstimmt. Ist das der Fall, dann wird eine entsprechende Veränderung des Tastenzustands in key_state registriert&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
  key_state ^= i;                                 // then toggle debounced state&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
und wenn sich in key_state das entsprechende Bit von 0 auf 1 verändert hat, wird dieses Ereignis als &#039;Taste wurde niedergedrückt&#039; gewertet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
  key_press |= key_state &amp;amp; i;                     // 0-&amp;gt;1: key press detect&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Damit ist der Tasteneingang entprellt. Und zwar sowohl beim Drücken einer Taste als auch beim Loslassen (damit Tastenpreller beim Loslassen nicht mit dem Niederdrücken einer Taste verwechselt werden). Der weitere Code beschäftigt sich dann nur noch damit, diesen entprellten Tastenzustand weiter zu verarbeiten.&lt;br /&gt;
&lt;br /&gt;
Der Codeteil sieht durch die Verwendung der vielen bitweisen Operationen relativ komplex aus. Behält man aber im Hinterkopf, dass einige der bitweisen wie ein &#039;paralles If&#039; gleichzeitig auf allen 8 Bits eingesetzt werden, dann vereinfacht sich vieles. Ein&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
    key_press |= key_state &amp;amp; i;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
ist nichts anderes als ein&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
    // teste ob Bit 0 sowohl in key_state als auch in i gesetzt ist&lt;br /&gt;
    // und setze Bit 0 in key_press, wenn das der Fall ist&lt;br /&gt;
    if( ( key_state &amp;amp; ( 1 &amp;lt;&amp;lt; 0 ) ) &amp;amp;&amp;amp;&lt;br /&gt;
        ( i &amp;amp; ( 1 &amp;lt;&amp;lt; 0 ) )&lt;br /&gt;
       key_press |= ( 1 &amp;lt;&amp;lt; 0 );&lt;br /&gt;
&lt;br /&gt;
    // Bit 1&lt;br /&gt;
    if( ( key_state &amp;amp; ( 1 &amp;lt;&amp;lt; 1 ) ) &amp;amp;&amp;amp;&lt;br /&gt;
        ( i &amp;amp; ( 1 &amp;lt;&amp;lt; 1 ) )&lt;br /&gt;
       key_press |= ( 1 &amp;lt;&amp;lt; 1 );&lt;br /&gt;
&lt;br /&gt;
    // Bit 2&lt;br /&gt;
    if( ( key_state &amp;amp; ( 1 &amp;lt;&amp;lt; 2 ) ) &amp;amp;&amp;amp;&lt;br /&gt;
        ( i &amp;amp; ( 1 &amp;lt;&amp;lt; 2 ) )&lt;br /&gt;
       key_press |= ( 1 &amp;lt;&amp;lt; 2 );&lt;br /&gt;
&lt;br /&gt;
    ...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
nur als wesentlich kompaktere Operation ausgeführt und für alle 8 Bits gleichzeitig.&lt;br /&gt;
Die Kürze und Effizienz dieser paar Codezeilen ergibt sich aus dem Umstand, dass jedes Bit in den Variablen für eine Taste steht und alle 8 (maximal möglichen) Tasten gleichzeitig die Operationen durchlaufen.&lt;br /&gt;
&lt;br /&gt;
===== Reduziert auf lediglich 1 Taste =====&lt;br /&gt;
Diskussionen im Forum zeigen immer wieder, dass viele eine Abneigung gegen diesen Code haben, weil er ihnen sehr kompliziert vorkommt.&lt;br /&gt;
&lt;br /&gt;
Der Code ist nicht leicht zu analysieren und er zieht alle Register dessen, was möglich ist, um sowohl Laufzeit als auch Speicherverbrauch einzusparen. Oft hört man auch das Argument: Ich benötige ja nur eine Entprellung für 1 Taste, gibt es da nichts Einfacheres?&lt;br /&gt;
&lt;br /&gt;
Hier ist die &#039;Langform&#039; des Codes, so wie man das für lediglich 1 Taste schreiben würde, wenn man exakt dasselbe Entprellverfahren einsetzen würde. Man sieht: Da ist keine Hexerei dabei: In key_state wird der letzte bekannte entprellte Zustand der Taste gehalten. Der Pin-Eingang wird mit diesem Zustand verglichen und wenn sich die beiden unterscheiden, dann wird ein Zähler heruntergezählt. Produziert dieses herunterzählen einen Unterlauf des Zählers, dann gilt die Taste als entprellt und wenn dann auch noch die Taste gerade gedrückt ist, dann wird dieses in key_press entsprechend vermerkt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
uint8_t key_state;&lt;br /&gt;
uint8_t key_counter;&lt;br /&gt;
volatile uint8_t key_press;&lt;br /&gt;
&lt;br /&gt;
ISR( ... Overflow ... )&lt;br /&gt;
{&lt;br /&gt;
  uint8_t input = KEY_PIN &amp;amp; ( 1 &amp;lt;&amp;lt; KEY0 );&lt;br /&gt;
&lt;br /&gt;
  if( input != key_state ) {&lt;br /&gt;
    key_counter--;&lt;br /&gt;
    if( key_counter == 0xFF ) {&lt;br /&gt;
      key_counter = 3;&lt;br /&gt;
      key_state = input;&lt;br /&gt;
      if( input )&lt;br /&gt;
        key_press = TRUE;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  else&lt;br /&gt;
    key_counter = 3;&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
uint8_t get_key_press()&lt;br /&gt;
{&lt;br /&gt;
  uint8_t result;&lt;br /&gt;
&lt;br /&gt;
  cli();&lt;br /&gt;
  result = key_press;&lt;br /&gt;
  key_press = FALSE;&lt;br /&gt;
  sei();&lt;br /&gt;
&lt;br /&gt;
  return result;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der vollständige Entprellcode, wie weiter oben gelistet, besticht jetzt aber darin, dass er compiliert kleiner ist als diese anschaulichere Variante für lediglich 1 Taste. Und das bei gleichzeitig erhöhter Funktionalität. Denn zb. ein Autorepeat ist in diesem Code noch gar nicht eingebaut. Und spätestens wenn man dann eine 2.te Taste entprellen möchte, dann ist auch der SRAM-Speicherverbrauch dieser Langform höher als der des Originals für 8 Tasten. Daraus folgt: Selbst für lediglich 1 Taste ist die Originalroutine die bessere Wahl.&lt;br /&gt;
&lt;br /&gt;
Und wegen der Komplexität mal eine Frage: Sind Sie selbst in der Lage eine entsprechend effiziente sqrt() Funktion zu schreiben, wie die, die sie in der Standard-C-Bibliothek vorfinden? Nein? Dann dürften Sie eigentlich Ihrer Argumentation nach die Bibliotheksfunktion sqrt() nicht verwenden, sondern müssten sich statt dessen selbst eine Wurzel-Funktion schreiben.&lt;br /&gt;
&lt;br /&gt;
=== Selbstsättigender Filter (nach Jürgen Schuhmacher) ===&lt;br /&gt;
Durch die Nutzung der diskreten Signalanalyse in Software kann die Funktionalität einer einfachen Entprellung mit einem Widerstand, einem Kondensator und einem Schmitttrigger wie in Hardware nachgebildet werden, indem ein abstrakter IIR-Filter benutzt wird, der eine Kondensatorladekurve emuliert. Mit der Vorschrift Y(t) = k Y(t-1) + Input wird ein einfaches Filter erzeugt, dass dem Eingangswert träge folgt. Bei Überschreiten eines bestimmten Wertes erfolgt mit einer einfachen Abfrage das Schalten des Ausgangssignals.&lt;br /&gt;
&lt;br /&gt;
Für Assembler und VHDL bei FPGAs eignet sich aufgrund der leicht zu implementierenden binären Operationen folgende Darstellung mit einer Auflösung des Filterwertspeichers von nur 8 bit: Wert_Neu = Wert_Alt - Wert_Alt/16 + 16*(Taste = True). Der Filterwert bildet dann den gedämpften Verlauf des Eingangs (flankenverschliffen) ab und kann Prellen bis nahe an den Grenzbereich zum schnellen Tasten unterdrücken. Der Ausgangswert ist dann einfach das höchstwertige Bit des Filterwertes.&lt;br /&gt;
&lt;br /&gt;
[[Datei:Entprellung mit IIR-Filter.gif]]&lt;br /&gt;
&lt;br /&gt;
Dazu muss das Signal des Tasters idealerweise um den Faktor 10-20 schneller abgetastet werden, als die höchste gewünschte Tippgeschwindigkeit vorgibt. Noch schneller abzutasten ist möglich, führt aber zu mehr Bedarf an Bits beim Filter. Die Schmittriggerfunktion kann dadurch gebildet werden, dass eine 1 am Ausgang bei z.B. Überschreiten einer 55% Grenze und eine 0 bei Unterschreitung der 45%-Grenze ausgeben wird. Im Zwischenbereich wird der alte Wert gehalten.&lt;br /&gt;
&lt;br /&gt;
=== Einfacher Mittelwertfilter (nach Lothar Miller) ===&lt;br /&gt;
Für digitale Schaltungen oder PLDs empfiehlt sich ein FIR-Filter mit aneinandergereihten FlipFlops. Man schiebt das Eingangssignal in eine FlipFlop-Kette und schaltet oberhalb der Mitte um:&lt;br /&gt;
&lt;br /&gt;
SignalInput -&amp;gt; FF1 -&amp;gt; FF2 -&amp;gt; FF3 -&amp;gt; FF4 -&amp;gt; FF5 -&amp;gt; FF6 -&amp;gt; FF7 -&amp;gt; FF8&lt;br /&gt;
&lt;br /&gt;
Wenn alle FFs = 1 (Summe der FFs=8) dann SignalOutput = 1&amp;lt;br /&amp;gt;&lt;br /&gt;
Wenn alle FFs = 0 (Summe der FFs=0) dann SignalOutput = 0&lt;br /&gt;
&lt;br /&gt;
Dieses Verfahren kann sehr einfach in Logik abgebildet werden, weil für die Berechnung des Ausgangs nur ein NOR bz. ein AND Gatter nötig ist.&lt;br /&gt;
&lt;br /&gt;
== Gegenüberstellung der Verfahren ==&lt;br /&gt;
* HW - &amp;quot;entprellte Schalter&amp;quot;: Sehr teuer, grosse Bauform, verschleissbelastet, geringe Haltbarkeit&lt;br /&gt;
* HW - &amp;quot;Umschalter&amp;quot; : benötigt aufwändigeren Schalter, benötigt Elektronik&lt;br /&gt;
* HW - &amp;quot;Umschalter ohne FF&amp;quot; : benötigt aufwändigeren Schalter und kleiner Kondensator&lt;br /&gt;
* HW - &amp;quot;Kondensatorentprellung&amp;quot; : benötigt etwas mehr Platz, kommt mit schlechten Schaltern zurecht&lt;br /&gt;
&lt;br /&gt;
* SW - Flankenverfahren:&lt;br /&gt;
* SW - Warteschleife: Durch die Warteschleifen eine nicht zu vernachlässigende Verzögerung im Code. Speziell wenn mehrere Tasten zu überwachen sind, nicht unproblematisch&lt;br /&gt;
* SW - Timer: Universalfunktionalität, die durch geringen Speicherverbrauch, geringen Rechenzeitverbrauch und gute Funktion besticht. Der &#039;Verbrauch&#039; eines Timers sieht auf den ersten Blick schlimmer aus, als er ist, denn in den meisten Programmen hat man sowieso einen Basistimer für die Zeitsteuerung des Programms im Einsatz, der für die Tastenentprellung mitbenutzt werden kann.&lt;br /&gt;
* SW - Filter: sehr geringer Platzbedarf in FPGAs, relativ gute Wirkung&lt;br /&gt;
* SW - Filter 2: sehr geringer Platzbedarf, gute Wirkung&lt;br /&gt;
&lt;br /&gt;
== Links zum Thema ==&lt;br /&gt;
&lt;br /&gt;
* [http://www.edn.com/design/analog/4324067/Contact-debouncing-algorithm-emulates-Schmitt-trigger Contact-debouncing algorithm (Artikel)],  [http://www.edn.com/file/13370-70705di.pdf als PDF]&lt;br /&gt;
* [[AVR-Tutorial: Tasten]]&lt;br /&gt;
* [[AVR-GCC-Tutorial#.28Tasten-.29Entprellung|AVR-GCC-Tutorial Tastenentprellung]]&lt;br /&gt;
* [http://www.mikrocontroller.net/forum/read-4-20435.html Beitrag im Forum, AVR Assembler]&lt;br /&gt;
* [http://www.ganssle.com/debouncing.pdf A guide to debouncing (engl.), praktische Erläuterungen zum Entprellen in Soft- und Hardware]&lt;br /&gt;
* [http://www.pololu.com/docs/0J16/all Understanding Destructive LC Voltage Spikes]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:AVR]]&lt;br /&gt;
[[Kategorie:Signalverarbeitung]]&lt;/div&gt;</summary>
		<author><name>Df2au</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=AVR-GCC-Tutorial&amp;diff=83315</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=83315"/>
		<updated>2014-06-11T15:43:01Z</updated>

		<summary type="html">&lt;p&gt;Df2au: /* __flash, progmem und Portierbarkeit */ Typo&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Dieses Tutorial soll den Einstieg in die Programmierung von Atmel [[AVR]]-Mikrocontrollern in der Programmiersprache [[C]] mit dem freien C-Compiler [[avr-gcc]] aus der [http://gcc.gnu.org/ GNU Compiler Collection] (GCC) erleichtern.&lt;br /&gt;
&lt;br /&gt;
Vorausgesetzt werden Grundkenntnisse der Programmiersprache C. Diese Kenntnisse kann man sich online erarbeiten, z. B. mit dem [http://www.schellong.de/c.htm C Tutorial von Helmut Schellong] ([[C|Liste von C-Tutorials]]). Nicht erforderlich sind Vorkenntnisse in der Programmierung von Mikrocontrollern.&lt;br /&gt;
&lt;br /&gt;
= Vorwort =&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. Beim Paket [[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 ständig weiterentwickelt. Einige Unterschiede, die sich im Verlauf der Entwicklung ergeben haben, werden hier und im Artikel [[AVR-GCC-Tutorial/Alte Quellen|Alte Quellen]] zwar angesprochen, Anfängern und Umsteigern sei jedoch empfohlen, eine aktuelle Versionen zu nutzen.&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 [[Media:AVR-GCC-Tutorial.pdf|PDF-Form]] erhältlich (nicht immer auf aktuellem Stand).&lt;br /&gt;
&lt;br /&gt;
== Weiterführende Kapitel ==&lt;br /&gt;
&lt;br /&gt;
Um dieses riesige Tutorial etwas überschaubarer zu gestalten, wurden einige Kapitel ausgelagert, die nicht unmittelbar mit den Grundlagen von avr-gcc in Verbindung stehen. All diese Seiten gehören zur [[:Kategorie:avr-gcc Tutorial]].&lt;br /&gt;
&lt;br /&gt;
;UART: → Hauptartikel: &#039;&#039;[[AVR-GCC-Tutorial/Der UART|Der UART]]&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
;ADC: → Hauptartikel: &#039;&#039;[[AVR-GCC-Tutorial/Analoge Ein- und Ausgabe|Analoge Ein- und Ausgabe (ADC)]]&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
;Timer: → Hauptartikel: &#039;&#039;[[AVR-GCC-Tutorial/Die Timer und Zähler des AVR|Die Timer und Zähler des AVR]]&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
;LCD: → Hauptartikel: &#039;&#039;[[AVR-GCC-Tutorial/LCD-Ansteuerung|LCD-Ansteuerung]]&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
;Watchdog: → Hauptartikel: &#039;&#039;[[AVR-GCC-Tutorial/Der Watchdog|Der Watchdog]]&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
;Assembler: → Hauptartikel: &#039;&#039;[[AVR-GCC-Tutorial/Assembler und Inline-Assembler|Assembler und Inline-Assembler]]&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
;alte Quellen anpassen: → Hauptartikel: &#039;&#039;[[AVR-GCC-Tutorial/Alte Quellen|Alte Quellen anpassen]]&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
;Makefiles: → Hauptartikel: &#039;&#039;[[AVR-GCC-Tutorial/Exkurs Makefiles|Exkurs Makefiles]]&#039;&#039; sowie als Alternative für sehr kleine Projekte → Hauptartikel: &#039;&#039;[[C ohne Makefile]]&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
= Benötigte Werkzeuge =&lt;br /&gt;
&lt;br /&gt;
Um eigene Programme für AVRs mittels einer AVR-Toolchain zu erstellen wird folgende Hard- und Software benötigt:&lt;br /&gt;
&lt;br /&gt;
* Eine AVR-Toolchain bestehend aus avr-gcc, den avr-Binutils (Assembler, Linker, etc) und einer Standard-C Bibliothek.  Üblich ist die AVR-LibC, die auch quasi in allen avr-gcc Distributionen enthalten ist.&lt;br /&gt;
&lt;br /&gt;
Hardware wird keine benötigt – bis auf einen PC natürlich, auf dem der Compiler ablaufen kann.  Selbst ohne AVR-Hardware kann man also bereits C-Programme für AVRs schreiben, compiliern und sich das Look-an-Feel von avr-gcc sowie von IDEs wie [[Atmel Studio]], Eclipse oder leichtgewichtigeren Entwicklungsumbgebungen anschauen. Selbst das Debuggen und Simulieren ist mithilfe entsprechender Tools wie Debugge und Simulator in gewissen Grenzen möglich.&lt;br /&gt;
&lt;br /&gt;
Um Programme für AVRs mittels einer AVR-Toolchain 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.&amp;lt;ref&amp;gt;Für eine Liste der unterstützten COntroller siehe die Dokumentation des Compilers oder [http://www.nongnu.org/avr-libc/user-manual/index.html#supported_devices AVR-Libc: Supported Devices].&amp;lt;/ref&amp;gt; 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. &lt;br /&gt;
&lt;br /&gt;
:Brauchbare Testplattformen sind auch das [[STK500]] und der [[AVR Butterfly]] von Atmel. Weitere Infos findet man in den Artikeln [[AVR#Starterkits|AVR Starterkits]] und [[AVR-Tutorial: Equipment]].&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]].&lt;br /&gt;
&lt;br /&gt;
* Wer unter Windows und Linux gleichermassen entwickeln will, der sollte sich die [http://www.eclipse.org/ IDE Eclipse for C/C++ Developers] und das [http://avr-eclipse.sourceforge.net/wiki/index.php/The_AVR_Eclipse_Plugin AVR-Eclipse Plugin] ansehen. Beide sind unter Windows und Linux einfach zu installieren, siehe auch [[AVR Eclipse]]. Ebenfalls unter Linux und Windows verfügbar ist die Entwicklungsumgebung [http://www.codeblocks.org/ Code::Blocks]&amp;lt;ref&amp;gt;Aktuelle, stabile Versionen sind als Nightly Builds regelmäßig im [http://forums.codeblocks.org/ Forum] verfügbar.&amp;lt;/ref&amp;gt;. Innerhalb dieser Entwicklungsumgebung können ohne die Installation zusätzlicher Plugins &amp;quot;AVR-Projekte&amp;quot; angelegt werden. Für Linux gibt es auch noch das [http://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=25220 KontrollerLab].&lt;br /&gt;
&lt;br /&gt;
= Was tun, wenn&#039;s nicht klappt? =&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/gcc 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 Beispielprogramme 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.tty1.net/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 drei 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 (ohne Anspruch auf Vollständigkeit): [http://www.eclipse.org/ Eclipse for C/C++ Developers] (d.h. inkl. CDT) und das [http://avr-eclipse.sourceforge.net/wiki/index.php/The_AVR_Eclipse_Plugin AVR-Eclipse Plugin] (für diverse Plattformen, u.a. Linux und MS Windows, IDE und Plugin kostenlos), [http://sourceforge.net/projects/kontrollerlab KontrollerLab] (Linux/KDE, kostenlos). [http://www.atmanecl.com/EnglishSite/SoftwareEnglish.htm AtmanAvr] (MS Windows, relativ günstig), KamAVR (MS-Windows, kostenlos, wird augenscheinlich nicht mehr weiterentwickelt), [http://www.amctools.com/vmlab.htm VMLab] (MS Windows, 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;
* Das Generieren des Programms ohne IDE und ohne Makefile. In diesem Fall muss die Quellcodedatei durch eine vorgefertigte Kommandofolge an den Compiler übergeben werden. Der Artikel [[C ohne Makefile]] zeigt, wie das funktioniert. Diese Vorgehensweise empfiehlt sich jedoch nur für kleine Programme, die nicht auf verschiedene Quellcodedateien verteilt sind.&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. Artikel [[AVR-GCC-Tutorial/Exkurs_Makefiles|AVR-GCC-Tutorial/Exkurs: Makefiles]], typisch: -Os) nicht einstellt und die mathematische Bibliothek der avr-libc (libm.a, Linker-Option -lm) nicht einbindet. (Hinweis: Bei Version 4.16 wird beides bereits gesetzt). 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;
Ein kurzes Wort zur Hardware: Bei diesem Programm werden alle Pins von PORTB auf Ausgang gesetzt, und einige davon werden auf HIGH andere auf LOW gesetzt. Das kann je nach angeschlossener Hardware an diesen Pins kritisch sein. Am ungefährlichsten ist es, wenn nichts an den Pins angeschlossen ist und man die Funktion des Programmes durch eine Spannungsmessung mit einem Multimeter kontrolliert. Die Spannung wird dabei zwischen GND-Pin und den einzelnen Pins von PORTB gemessen.&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;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Alle Zeichen zwischen Schrägstrich-Stern &lt;br /&gt;
   und Stern-Schrägstrich sind 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) {                // (5)&lt;br /&gt;
     /* &amp;quot;leere&amp;quot; Schleife*/   // (6)&lt;br /&gt;
   }                         // (7)&lt;br /&gt;
&lt;br /&gt;
   /* wird nie erreicht */&lt;br /&gt;
   return 0;                 // (8)&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# In dieser Zeile wird eine sogenannte Header-Datei eingebunden. In &amp;lt;code&amp;gt;avr/io.h&amp;lt;/code&amp;gt; sind die Registernamen definiert, die im späteren Verlauf genutzt werden. Auch unter Windows wird ein&amp;amp;nbsp;&amp;lt;code&amp;gt;/&amp;lt;/code&amp;gt; zur Kennzeichnung von Unterverzeichnissen in Include-Dateinamen verwendet und kein&amp;amp;nbsp;&amp;lt;code&amp;gt;\&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Hier beginnt das eigentliche Programm. Jedes C-Programm beginnt mit den Anweisungen in der Funktion &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Die Anschlüsse eines AVR (Pins) 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 Datenrichtungsregister den entsprechenden Anschluss auf Ausgang schalten, werden mit DDRB=0xff alle Anschlüsse des Ports B als Ausgänge eingestellt.&lt;br /&gt;
# 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). Es ist sinnvoll, sich möglichst frühzeitig eine alternative Schreibweise beizubringen, die wegen der leichteren Überprüfbarkeit und Portierbarkeit oft im weiteren Tutorial und in Forenbeiträgen benutzt wird. Die Zuordnung sieht in diesem Fall so aus, Näheres dazu im Artikel [[Bitmanipulation]]:&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;PORTB = (1&amp;lt;&amp;lt;PB1) | (1&amp;lt;&amp;lt;PB0);&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
# ist der Beginn der sogenannte &#039;&#039;Hauptschleife&#039;&#039; (main-loop). Dies ist eine Endlosschleife, welche kontinuierlich wiederkehrende Befehle enthält.&lt;br /&gt;
# In diesem Beispiel ist die Hauptschleife leer. Der Controller durchläuft die Schleife immer wieder, ohne dass etwas passiert. 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 kehrt das Programm aus &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; zurück, alle Interrupts werden deaktiviert und eine Endlosschleife betreten.&lt;br /&gt;
# Ende der Hauptschleife und Sprung zur passenden, öffnenden Klammer, also zu 5.&lt;br /&gt;
# ist das Programmende. Die Zeile ist nur aus Gründen der C-Kompatibilität enthalten: &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;int main(void)&amp;lt;/syntaxhighlight&amp;gt; besagt, dass die Funktion einen int-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 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 &amp;lt;code&amp;gt;Makefile&amp;lt;/code&amp;gt; (ohne Endung) im selben Verzeichnis, in dem auch die Datei &amp;lt;code&amp;gt;main.c&amp;lt;/code&amp;gt; mit dem Programmcode abgelegt ist. Detailliertere Erklärungen zur Funktion von Makefiles finden sich im Artikel [[AVR-GCC-Tutorial/Exkurs_Makefiles|Exkurs: Makefiles]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
D:\beispiel&amp;gt;dir&lt;br /&gt;
&lt;br /&gt;
 Verzeichnis von D:\beispiel&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 &amp;lt;code&amp;gt;main.hex&amp;lt;/code&amp;gt;, in welcher der Code für den AVR enthalten ist. &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
D:\beispiel&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;
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;
&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&amp;lt;ref&amp;gt;z.&amp;amp;nbsp;B. [[Pony-Prog_Tutorial|Ponyprog]], yapp, AVRStudio&amp;lt;/ref&amp;gt;, 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;
= Ganzzahlige Datentypen (Integer) =&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 &amp;lt;code&amp;gt;stdint.h&amp;lt;/code&amp;gt; definiert, die folgendermaßen eingebunden werden kann:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;#include &amp;lt;stdint.h&amp;gt;&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{| {{Tabelle}}&lt;br /&gt;
|+ &#039;&#039;&#039;int-Typen aus &amp;lt;code&amp;gt;stdint.h&amp;lt;/code&amp;gt; (C99)&#039;&#039;&#039;&amp;lt;br/&amp;gt;&amp;amp;nbsp;&lt;br /&gt;
|- bgcolor=&amp;quot;#d0d0ff&amp;quot;&lt;br /&gt;
!colspan=&amp;quot;5&amp;quot;| Vorzeichenbehaftete int-Typen&lt;br /&gt;
|- bgcolor=&amp;quot;#e8e8ff&amp;quot;&lt;br /&gt;
! Typname || Bit-Breite ||colspan=&amp;quot;2&amp;quot;| Wertebereich&lt;br /&gt;
|align=&amp;quot;center| &#039;&#039;&#039;C-Entsprechung&#039;&#039;&#039; (avr-gcc)&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;int8_t&amp;lt;/code&amp;gt; ||align=&amp;quot;right&amp;quot;| 8 || −128 ⋯ 127 || −2&amp;lt;sup&amp;gt;7&amp;lt;/sup&amp;gt; ⋯ 2&amp;lt;sup&amp;gt;7&amp;lt;/sup&amp;gt;−1 || &amp;lt;code&amp;gt;signed char&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;int16_t&amp;lt;/code&amp;gt; ||align=&amp;quot;right&amp;quot;| 16 || −32768 ⋯ 32767 || −2&amp;lt;sup&amp;gt;15&amp;lt;/sup&amp;gt; ⋯ 2&amp;lt;sup&amp;gt;15&amp;lt;/sup&amp;gt;−1 || &amp;lt;code&amp;gt;signed short&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;signed int&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;int32_t&amp;lt;/code&amp;gt; ||align=&amp;quot;right&amp;quot;| 32 || −2147483648 ⋯ 2147483647 || −2&amp;lt;sup&amp;gt;31&amp;lt;/sup&amp;gt; ⋯ 2&amp;lt;sup&amp;gt;31&amp;lt;/sup&amp;gt;−1 || &amp;lt;code&amp;gt;signed long&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;int64_t&amp;lt;/code&amp;gt; ||align=&amp;quot;right&amp;quot;| 64 || −9223372036854775808 ⋯ 9223372036854775807 || −2&amp;lt;sup&amp;gt;63&amp;lt;/sup&amp;gt; ⋯ 2&amp;lt;sup&amp;gt;63&amp;lt;/sup&amp;gt;−1 || &amp;lt;code&amp;gt;signed long long&amp;lt;/code&amp;gt;&lt;br /&gt;
|- bgcolor=&amp;quot;#d0d0ff&amp;quot;&lt;br /&gt;
!colspan=&amp;quot;5&amp;quot;| Vorzeichenlose int-Typen&lt;br /&gt;
|- bgcolor=&amp;quot;#e8e8ff&amp;quot;&lt;br /&gt;
! Typname || Bit-Breite ||colspan=&amp;quot;2&amp;quot;| Wertebereich&lt;br /&gt;
|align=&amp;quot;center| &#039;&#039;&#039;C-Entsprechung&#039;&#039;&#039; (avr-gcc)&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;uint8_t&amp;lt;/code&amp;gt; ||align=&amp;quot;right&amp;quot;| 8 || 0 ⋯ 255 || 0 ⋯ 2&amp;lt;sup&amp;gt;8&amp;lt;/sup&amp;gt;−1 || &amp;lt;code&amp;gt;unsigned char&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;uint16_t&amp;lt;/code&amp;gt; ||align=&amp;quot;right&amp;quot;| 16 || 0 ⋯ 65535 || 0 ⋯ 2&amp;lt;sup&amp;gt;16&amp;lt;/sup&amp;gt;−1 || &amp;lt;code&amp;gt;unsigned short&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;unsigned int&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;uint32_t&amp;lt;/code&amp;gt; ||align=&amp;quot;right&amp;quot;| 32 || 0 ⋯ 4294967295 || 0 ⋯ 2&amp;lt;sup&amp;gt;32&amp;lt;/sup&amp;gt;−1 || &amp;lt;code&amp;gt;unsigned long&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;uint64_t&amp;lt;/code&amp;gt; ||align=&amp;quot;right&amp;quot;| 64 || 0 ⋯ 18446744073709551615 || 0 ⋯ 2&amp;lt;sup&amp;gt;64&amp;lt;/sup&amp;gt;−1 || &amp;lt;code&amp;gt;unsigned long long&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Neben den Typen gibt es auch Makros für die Bereichsgrenzen wie &amp;lt;code&amp;gt;INT8_MIN&amp;lt;/code&amp;gt; oder &amp;lt;code&amp;gt;UINT16_MAX&amp;lt;/code&amp;gt;. Siehe dazu auch: [http://www.nongnu.org/avr-libc/user-manual/group__avr__stdint.html Dokumentation der avr-libc: Standard Integer Types].&lt;br /&gt;
&lt;br /&gt;
= Grundsätzlicher Programmaufbau eines µ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;
[[Image:Sequentielle Programme.gif|left]]&lt;br /&gt;
Bei dieser Programmiertechnik wird eine Endlosschleife programmiert, welche im&lt;br /&gt;
Wesentlichen immer den gleichen Aufbau hat. Es wird hier nach dem sogenannten EVA-Prinzip gehandelt. EVA steht für &amp;quot;Eingabe, Verarbeitung, Ausgabe&amp;quot;.&lt;br /&gt;
{{Absatz}}&lt;br /&gt;
&lt;br /&gt;
== Interruptgesteuerter Programmablauf ==&lt;br /&gt;
&lt;br /&gt;
[[Image:Interrupt Programme.gif|left]]&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;
{{Absatz}}&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 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;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&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.&amp;amp;nbsp;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;syntaxhighlight lang=&amp;quot;c&amp;quot;&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;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Beispiele in den folgenden Abschnitten demonstrieren den Zugriff auf Register anhand der Register für I/O-Ports (PORTx, DDRx, PINx), die Vorgehensweise ist jedoch für alle Register (z.&amp;amp;nbsp;B. die des UART, ADC, SPI) analog.&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.&amp;lt;ref&amp;gt;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, outp() ist nicht mehr erforderlich.&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&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;
    /* 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;
    // 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;
    while (1);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&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. Mehr zu der Schreibweise mit &amp;quot;|&amp;quot; und &amp;quot;&amp;lt;&amp;lt;&amp;quot; findet man unter [[Bitmanipulation]].&lt;br /&gt;
&lt;br /&gt;
Der gcc C-Compiler unterstützt ab Version 4.3.0 Konstanten im Binärformat, z.&amp;amp;nbsp;B. DDRB&amp;amp;nbsp;=&amp;amp;nbsp;0b00011111. Diese Schreibweise ist jedoch nur in GNU-C verfügbar und nicht in ISO-C definiert. Man sollte sie daher 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;syntaxhighlight lang=&amp;quot;c&amp;quot;&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;/syntaxhighlight&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;syntaxhighlight lang=&amp;quot;c&amp;quot;&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;/syntaxhighlight&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;syntaxhighlight lang=&amp;quot;c&amp;quot;&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;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bei bestimmten AVR Registern mit Bits, die durch Beschreiben mit einer logischen 1 gelöscht werden, muss eine absolute Zuweisung benutzt werden. Ein ODER löscht in diesen Registern ALLE gesetzten Bits!&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
TIFR2 = (1&amp;lt;&amp;lt;OCF2A); // Nur Bit OCF2A löschen&lt;br /&gt;
&amp;lt;/syntaxhighlight&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;syntaxhighlight lang=&amp;quot;c&amp;quot;&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;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Abfrage der 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;syntaxhighlight lang=&amp;quot;c&amp;quot;&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 (bitweise 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;
  test1();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Funktion aufrufen, wenn Bit 0 und/oder Bit 2 gesetzt ist. (Bit 0 und 2 also Wert 5) &lt;br /&gt;
// (Bedenke: Bit 0 hat Wert 1, Bit 1 hat Wert 2 und Bit 2 hat Wert 4)&lt;br /&gt;
if ( PINA &amp;amp; 0x05 ) {&lt;br /&gt;
  test1();  // Vergleich &amp;lt;&amp;gt; 0 (wahr), also mindestens eines der Bits gesetzt&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 Bit 0&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 not-Operator&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;/syntaxhighlight&amp;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;syntaxhighlight lang=&amp;quot;c&amp;quot;&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;/syntaxhighlight&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;syntaxhighlight lang=&amp;quot;c&amp;quot;&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;/syntaxhighlight&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;
== 16-Bit Register (ADC, ICR1, OCR1x, 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; (Low-Byte) und &amp;quot;H&amp;quot; (High-Byte) 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 Register kann dann direkt zugegriffen werden. Dies ist zum Beispiel der Fall für Register wie ADC oder TCNT1.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
    uint16_t foo;&lt;br /&gt;
&lt;br /&gt;
    /* setzt die Wort-Variable foo auf den Wert der letzten AD-Wandlung */&lt;br /&gt;
    foo = ADC; &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bei anderen Registern, wie zum Beispiel Baudraten-Register, liegen High- und Low-Teil nicht direkt nebeneinander im SFR-Bereich, so dass ein 16-Bit Zugriff nicht möglich ist und der Zugriff zusammengebastelt werden muss:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&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;
...&lt;br /&gt;
   uint16_t baud = F_CPU / (UART_BAUD_RATE * 16L) -1;&lt;br /&gt;
&lt;br /&gt;
   UBRRH = (uint8_t) (baud &amp;gt;&amp;gt; 8);&lt;br /&gt;
   UBRRL = (uint8_t) baud;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bei einigen AVR-Typen wie ATmega8 oder ATmega16 teilen sich UBRRH und UCSRC die gleiche Speicher-Adresse. Damit der AVR trotzdem zwischen den beiden Registern unterscheiden kann, bestimmt das Bit7 (URSEL), welches Register tatsächlich beschrieben werden soll. &#039;&#039;1000 0011&#039;&#039; (0x83) adressiert demnach UCSRC und übergibt den Wert &#039;&#039;3&#039;&#039;. Und &#039;&#039;0000 0011&#039;&#039; (0x3) adressiert UBRRH und übergibt ebenfalls den Wert &#039;&#039;3&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
Speziell bei den 16-Bit-Timern und auch beim ADC ist es bei allen Zugriffen auf Datenregister erforderlich, dass diese Daten synchronisiert sind. Wenn z.&amp;amp;nbsp;B. bei einem 16-Bit-Timer das High-Byte des Zählregisters gelesen wurde und vor dem Lesezugriff auf das Low-Byte ein Überlauf des Low-Bytes stattfindet, erhält man einen völlig unsinnigen Wert. Auch die Compare-Register müssen synchron geschrieben werden, da es ansonsten zu unerwünschten Compare-Ereignissen kommen kann. &lt;br /&gt;
&lt;br /&gt;
Beim ADC besteht das Problem darin, dass zwischen den Zugriffen auf die beiden Teilregister eine Wandlung beendet werden kann und der ADC ein neues Ergebnis in ADCL und ADCH schreiben will, wodurch High- und Low-Byte nicht zusammenpassen.&lt;br /&gt;
&lt;br /&gt;
Um diese Datenmüllproduktion zu verhindern, gibt es in beiden Fällen eine Synchronisation, die jeweils durch den Zugriff auf das Low-Byte ausgelöst wird:&lt;br /&gt;
* Bei den Timer-Registern (das gilt für alle TCNT-, OCR- und ICR-Register bei den 16-Bit-Timern) wird bei einem &#039;&#039;Lesezugriff&#039;&#039; auf das Low-Byte automatisch das High-Byte in ein temporäres Register, das ansonsten nach außen nicht sichtbar ist, geschoben. Greift man nun &#039;&#039;anschließend&#039;&#039; auf das High-Byte zu, dann wird eben dieses temporäre Register gelesen.&lt;br /&gt;
* Bei einem &#039;&#039;Schreibzugriff&#039;&#039; auf eines der genannten Register wird das High-Byte in besagtem temporären Register zwischengespeichert und erst beim Schreiben des Low-Bytes werden &#039;&#039;beide&#039;&#039; gleichzeitig in das eigentliche Register übernommen.&lt;br /&gt;
&lt;br /&gt;
Das bedeutet für die Reihenfolge:&lt;br /&gt;
* Lesezugriff: Erst Low-Byte, dann High-Byte&lt;br /&gt;
* Schreibzugriff: Erst High-Byte, dann Low-Byte&lt;br /&gt;
&lt;br /&gt;
Des weiteren ist zu beachten, dass es für all diese 16-Bit-Register nur ein einziges temporäres Register gibt, so dass das Auftreten eines Interrupts, in dessen Handler ein solches Register manipuliert wird, bei einem durch ihn unterbrochenen Zugriff i.d.R. zu Datenmüll führt. 16-Bit-Zugriffe sind generell nicht atomar! Wenn mit Interrupts gearbeitet wird, kann es erforderlich sein, vor einem solchen Zugriff auf ein 16-Bit-Register die Interrupt-Bearbeitung zu deaktivieren.&lt;br /&gt;
&lt;br /&gt;
Beim ADC-Datenregister ADCH/ADCL ist die Synchronisierung anders gelöst. Hier wird beim Lesezugriff (ADCH/ADCL sind logischerweise read-only) auf das Low-Byte ADCL beide Teilregister für Zugriffe seitens des ADC so lange gesperrt, bis das High-Byte ADCH ausgelesen wurde. Dadurch kann der ADC nach einem Zugriff auf ADCL keinen neuen Wert in ADCH/ADCL ablegen, bis ADCH gelesen wurde. Ergebnisse von Wandlungen, die zwischen einem Zugriff auf ADCL und ADCH beendet werden, gehen verloren!&lt;br /&gt;
&lt;br /&gt;
Nach einem Zugriff auf ADCL muss grundsätzlich ADCH gelesen werden!&lt;br /&gt;
&lt;br /&gt;
In beiden Fällen – also sowohl bei den Timern als auch beim ADC – werden vom C-Compiler 16-Bit Pseudo-Register zur Verfügung gestellt (z.&amp;amp;nbsp;B. TCNT1H/TCNT1L → TCNT1, ADCH/ADCL → ADC bzw. ADCW), bei deren Verwendung der Compiler automatisch die richtige Zugriffsreihenfolge regelt. In C-Programmen sollten grundsätzlich diese 16-Bit-Register verwendet werden! Sollte trotzdem ein Zugriff auf ein Teilregister erforderlich sein, sind obige Angaben zu berücksichtigen.&lt;br /&gt;
&lt;br /&gt;
Es ist darauf zu achten, dass auch ein Zugriff auf die 16-Bit-Register vom Compiler in zwei 8-Bit-Zugriffe aufgeteilt wird und dementsprechend genauso nicht-atomar ist wie die Einzelzugriffe. Auch hier gilt, dass u.U. die Interrupt-Bearbeitung gesperrt werden muss, um Datenmüll zu vermeiden.&lt;br /&gt;
&lt;br /&gt;
Beim ADC gibt es für den Fall, dass eine Auflösung von 8 Bit ausreicht, die Möglichkeit, das Ergebnis &amp;quot;linksbündig&amp;quot; in ADCH/ADCL auszurichten, so dass die relevanten 8 MSB in ADCH stehen. In diesem Fall muss bzw. sollte nur ADCH ausgelesen werden.&lt;br /&gt;
&lt;br /&gt;
ADC und ADCW sind unterschiedliche Bezeichner für das selbe Registerpaar. Üblicherweise kann man in C-Programmen ADC verwenden, was analog zu den anderen 16-Bit-Registern benannt ist. ADCW (ADC Word) existiert nur deshalb, weil die Headerdateien auch für Assembler vorgesehen sind und es bereits einen Assembler-Befehl namens &#039;&#039;adc&#039;&#039; gibt. &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;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;lt;util/delay.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
uint8_t key_pressed (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;
  /* 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;
void foo (void)&lt;br /&gt;
{&lt;br /&gt;
   uint8_t i = key_pressed (&amp;amp;PINB, PB1);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&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;
Siehe auch: [http://www.nongnu.org/avr-libc/user-manual/FAQ.html#faq_port_pass avr-libc FAQ: &amp;quot;How do I pass an IO port as a parameter to a function?&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
= Zugriff auf IO-Ports =&lt;br /&gt;
&lt;br /&gt;
Jeder AVR implementiert eine unterschiedliche Menge an GPIO-Registern&lt;br /&gt;
(GPIO - General Purpose Input/Output). Diese Register dienen dazu:&lt;br /&gt;
* einzustellen welche der Anschlüsse (&amp;quot;Beinchen&amp;quot;) des Controllers als Ein- oder Ausgänge dienen&lt;br /&gt;
* bei Ausgängen deren Zustand festzulegen&lt;br /&gt;
* bei Eingängen deren Zustand zu erfassen&lt;br /&gt;
&lt;br /&gt;
Mittels GPIO werden digitale Zustände gesetzt und erfasst, d.h. die Spannung an einem Ausgang wird ein- oder ausgeschaltet und an einem Eingang wird erfasst, ob die anliegende Spannung über oder unter einem bestimmten Schwellwert liegt. Im Datenblatt Abschnitt Electrical Characteristics/DC Characteristics finden sich die Spannungswerte (V_OL, V_OH für Ausgänge, V_IL, V_IH für Eingänge).&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;
Die physischen Ein- und Ausgänge werden bei AVR-Controllern zu logischen Ports gruppiert.&lt;br /&gt;
&lt;br /&gt;
Alle Ports werden über Register gesteuert. Dazu sind jedem Port 3 Register zugeordnet:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
! DDRx&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;
! PINx&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;
! PORTx&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;
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;syntaxhighlight lang=&amp;quot;c&amp;quot;&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;
int main()&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;
  // direkte Zuweisung - standardkonform */&lt;br /&gt;
  DDRB = 0x1F;    /* &lt;br /&gt;
&lt;br /&gt;
  // übersichtliche Alternative - Binärschreibweise, aber kein ISO-C&lt;br /&gt;
  DDRB = 0b00011111;&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;
&amp;lt;/syntaxhighlight&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;syntaxhighlight lang=&amp;quot;c&amp;quot;&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;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Vordefinierte Bitnummern für I/O-Register ==&lt;br /&gt;
&lt;br /&gt;
Die Bitnummern (z.&amp;amp;nbsp;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;syntaxhighlight lang=&amp;quot;c&amp;quot;&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;/syntaxhighlight&amp;gt;&lt;br /&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;syntaxhighlight lang=&amp;quot;c&amp;quot;&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;
&lt;br /&gt;
    // übersichtliche Alternative - Binärschreibweise&lt;br /&gt;
    PORTB = 0b00000100;    /* direkte Zuweisung - übersichtlich */&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&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;syntaxhighlight lang=&amp;quot;c&amp;quot;&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;/syntaxhighlight&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;syntaxhighlight lang=&amp;quot;c&amp;quot;&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;/syntaxhighlight&amp;gt;&lt;br /&gt;
Siehe auch [[Bitmanipulation]]&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 war:&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.&amp;amp;nbsp;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;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align:center&amp;quot;&lt;br /&gt;
|+ &#039;&#039;&#039;Spannungstabelle&#039;&#039;&#039; &amp;lt;br /&amp;gt; &amp;lt;small&amp;gt;(ca. Grenzwerte)&amp;lt;/small&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
! Low || High&lt;br /&gt;
|-&lt;br /&gt;
! bei 5 V&lt;br /&gt;
| 1 V || 3,5 V&lt;br /&gt;
|-&lt;br /&gt;
! bei 3,3 V&lt;br /&gt;
| 0,66 V || 2,31 V&lt;br /&gt;
|-&lt;br /&gt;
! bei 1,8 V&lt;br /&gt;
| 0,36 V || 1,26 V&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die Abfrage der Zustände der Portpins erfolgt direkt über den Registernamen.&lt;br /&gt;
&lt;br /&gt;
{{Warnung|Dabei ist wichtig, zur Abfrage der Eingänge &#039;&#039;nicht&#039;&#039; etwa Portregister &#039;&#039;&#039;PORTx&#039;&#039;&#039; zu verwenden, sondern Eingangsregister &#039;&#039;&#039;PINx&#039;&#039;&#039;. Ansonsten liest man nicht den Zustand der Eingänge, sondern den Status der internen Pull-Up-Widerstände. Die Abfrage der Pinzustände über PORTx statt PINx ist ein häufiger Fehler beim AVR-&amp;quot;Erstkontakt&amp;quot;.}}&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;syntaxhighlight lang=&amp;quot;c&amp;quot;&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;/syntaxhighlight&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;syntaxhighlight lang=&amp;quot;c&amp;quot;&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;/syntaxhighlight&amp;gt;&lt;br /&gt;
Siehe auch [[Bitmanipulation#Bits_prüfen]]&lt;br /&gt;
&lt;br /&gt;
=== Interne Pull-Up Widerstände ===&lt;br /&gt;
&lt;br /&gt;
Portpins für Ein- und Ausgänge (GPIO) eines AVR verfügen über zuschaltbare interne Pull-Up Widerstände (nominal mehrere 10kOhm, z.&amp;amp;nbsp;B. ATmega16 20-50kOhm). Diese können in vielen Fällen statt externer Widerstände genutzt werden.&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;syntaxhighlight lang=&amp;quot;c&amp;quot;&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;PC7);  /* 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;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Taster und Schalter ===&lt;br /&gt;
&lt;br /&gt;
Der Anschluss mechanischer Kontakte an den Mikrocontroller, ist zwischen zwei unterschiedliche Methoden zu unterscheiden: &#039;&#039;Active Low&#039;&#039; und &#039;&#039;Active High&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;gallery widths=&amp;quot;300&amp;quot; heights=&amp;quot;300&amp;quot; caption=&amp;quot;Anschluss mechanischer Kontakte an einen µC&amp;quot;&amp;gt;&lt;br /&gt;
Image:Active Low.gif|&#039;&#039;&#039;Active Low:&#039;&#039;&#039; Bei dieser Methode wird der Kontakt zwischen den Eingangspin des Controllers und Masse geschaltet. Damit bei offenem Schalter der Controller kein undefiniertes Signal bekommt, wird zwischen die Versorgungsspannung und den Eingangspin ein sogenannter &#039;&#039;&#039;Pull-Up&#039;&#039;&#039; Widerstand geschaltet. Dieser dient dazu, den Pegel bei geöffnetem Schalter auf logisch 1 zu ziehen.&lt;br /&gt;
Image:Active High.gif|&#039;&#039;&#039;Active High:&#039;&#039;&#039; Hier wird der Kontakt zwischen die Versorgungsspannung und den Eingangspin geschaltet. Damit bei offener Schalterstellung kein undefiniertes Signal am Controller ansteht, wird zwischen den Eingangspin und die Masse ein &#039;&#039;&#039;Pull-Down&#039;&#039;&#039; Widerstand geschaltet. Dieser dient dazu, den Pegel bei geöffneter Schalterstellung auf logisch 0 zu halten. &lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Widerstandswert von Pull-Up- und Pull-Down-Widerständen 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. Die AVRs verfügen an den meisten Pins über zuschaltbare interne Pull-Up Widerstände (vgl. Abschnitt [[AVR-GCC-Tutorial#Interne Pull-Up Widerstände|Interne Pull-Up Widerstände]]), welche insbesondere wie hier bei Tastern und ähnlichen Bauteilen (z.&amp;amp;nbsp;B. Drehgebern) statt externer Bauteile verwendet werden können. Interne Pull-Down-Widerstand sind nicht verfügbar und müssen daher in Form zusätzlicher Bauteile in die Schaltung eingefügt werden.&lt;br /&gt;
&lt;br /&gt;
==== Taster entprellen ====&lt;br /&gt;
&lt;br /&gt;
Siehe: &#039;&#039;[[Entprellung#Warteschleifen-Verfahren|Entprellung: Warteschleifen-Verfahren]]&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. Außerdem 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 (abgesehen von möglicherweise auftretenden Interrupts, falls welche aktiviert sind). Die Wartefunktion blockiert den Programmablauf. Möchte man einerseits warten, um z.&amp;amp;nbsp;B. eine LED blinken zu lassen und gleichzeitig andere Aktionen ausführen z.&amp;amp;nbsp;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;
Eine weitere Einschränkung liegt darin, daß sie möglicherweise länger warten, als erwartet, nämlich in dem Fall, daß Interrupts auftreten und die _delay...()-Funktion unterbrechen. Genau genommen warten diese nämlich nicht eine bestimmte Zeit, sondern verbrauchen eine bestimmte Anzahl von Prozessortakten. Die wiederum ist so bemessen, daß ohne Unterbrechung durch Interrupts die gewünschte Wartezeit erreicht wird.&lt;br /&gt;
Wird das Warten aber durch eine oder mehrere ISR unterbrochen, die zusammen 1% Prozessorzeit verbrauchen, dann dauert das Warten etwa 1% länger. Bei 50% Last durch die ISR dauert das Warten doppelt solange wie gewünscht, bei 90% zehnmal solange...&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 bis 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,4µs 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;syntaxhighlight lang=&amp;quot;c&amp;quot;&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.&amp;amp;nbsp;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;
{&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;
    {                &lt;br /&gt;
        PORTB ^= ( 1 &amp;lt;&amp;lt; PB0 );  // Toggle PB0 z.&amp;amp;nbsp;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;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== avr-libc Versionen ab 1.7 ==&lt;br /&gt;
&lt;br /&gt;
_delay_ms() kann mit einem Argument bis 6553,5 ms (= 6,5535 Sekunden) benutzt werden. Es ist nicht möglich, eine Variable als Argument zu übergeben. 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;syntaxhighlight lang=&amp;quot;c&amp;quot;&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;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Trick zur Übergabe einer Variablen an _delay_ms():&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.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;&lt;br /&gt;
&lt;br /&gt;
void sleep ( uint8_t ms )&lt;br /&gt;
{&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;
    int x = 0;                  // Variable als Wartezeit erstellen&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;
        sleep(x); &lt;br /&gt;
        x++;       &lt;br /&gt;
    }&lt;br /&gt;
    return 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die _delay_ms() und die _delay_us aus &#039;&#039;&#039;avr-libc 1.7.0&#039;&#039;&#039; sind fehlerhaft. _delay_ms () läuft 4x schneller als erwartet. Abhilfe ist eine korrigierte Includedatei: [http://www.mikrocontroller.net/topic/196738#1943039]&lt;br /&gt;
&lt;br /&gt;
= Programmieren mit Interrupts =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;float:right; margin:2em;&amp;quot;&amp;gt;&lt;br /&gt;
[[Image:Interrupt Programme.gif]]&lt;br /&gt;
&amp;lt;/div&amp;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;
Tritt ein Interrupt auf, unterbricht (engl. interrupts) der Controller die Verarbeitung des Hauptprogramms und verzweigt zu einer Interruptroutine. Das Hauptprogramm wird also beim Eintreffen eines Interrupts unterbrochen, die Interruptroutine ausgeführt und danach erst wieder das Hauptprogramm an der Unterbrechungsstelle fortgesetzt (vgl. die Abbildung).&lt;br /&gt;
&lt;br /&gt;
Um Interrupts verarbeiten zu können, ist folgendes zu beachten:&lt;br /&gt;
&lt;br /&gt;
* Für jede aktivierte Interruptquelle ist eine Funktion zu programmieren, in der die beim Auftreten des jeweiligen Interrupts erforderlichen Verarbeitungsschritte enthalten sind. Für diese Funktion existieren verschiedene Bezeichnungen. Üblich sind die englischen Begriffe Interrupt-Handler oder Interrupt-Service-Routinen (ISR), man findet aber auch die Bezeichnungen Interruptverarbeitungs- oder -behandlungsroutine oder auch kurz Interruptroutine. Zum Beispiel wird üblicherweise in der ISR zur Verarbeitung des Empfangsinterrupts eines UARTs (UART-RX Interrupt) das empfangene Zeichen in einen Zwischenspeicher (FIFO-Buffer) kopiert, dessen Inhalt später von anderen Programmteilen geleert wird. Sofern der Zwischenspeicher ausreichend groß ist, geht also kein Zeichen verloren, auch wenn im Hauptprogramm zeitintensive Operationen durchgeführt werden.&lt;br /&gt;
* Die benötigten Interrupts sind in den jeweiligen Funktionsbausteinen einzuschalten. Dies erfolgt über das jeweilige Aktivierungsbit (Interrupt Enable) in einem der Hardwareregister (z.B. RX(Complete)Interrupt Enable eines UARTs)&lt;br /&gt;
* Sämtliche Interrupts werden über einen weiteren globalen Schalter aktiviert und deaktiviert. Zur Verarbeitung der Interrupts ist dieser Schalter zu aktivieren (sei(), siehe unten).&lt;br /&gt;
 &lt;br /&gt;
Alle Punkte sind zu beachten. Fehlt z.B. die globale Aktivierung, werden Interruptroutinen auch dann nicht aufgerufen, wenn sie im Funktionsbaustein eingeschaltet sind und eine Behandlungsroutine verhanden ist.&lt;br /&gt;
&lt;br /&gt;
Siehe auch&lt;br /&gt;
&lt;br /&gt;
* [http://www.mikrocontroller.net/forum/read-1-235092.html#new Ausführlicher Thread im Forum]&lt;br /&gt;
* Artikel [[Interrupt]]&lt;br /&gt;
* Artikel [[Multitasking]]&lt;br /&gt;
{{Clear}}&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 sollten 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 Microcontroller-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 zusammenhängen.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&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;a&#039;&#039;&#039;sk&#039;&#039;&#039; Register.&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align:center&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
! Bit &lt;br /&gt;
| 7 || 6|| 5 || 4 || 3 || 2 || 1 || 0&lt;br /&gt;
|- &lt;br /&gt;
! Name&lt;br /&gt;
| &#039;&#039;&#039;INT1&#039;&#039;&#039; || &#039;&#039;&#039;INT0&#039;&#039;&#039; || &#039;&#039;&#039;-&#039;&#039;&#039; || &#039;&#039;&#039;-&#039;&#039;&#039; || &#039;&#039;&#039;-&#039;&#039;&#039; || &#039;&#039;&#039;-&#039;&#039;&#039; || &#039;&#039;&#039;-&#039;&#039;&#039; || &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
! R/W&lt;br /&gt;
| R/W || R/W || R || R || R || R || R || R&lt;br /&gt;
|- &lt;br /&gt;
! Initialwert&lt;br /&gt;
| 0 || 0 || 0 || 0 || 0 || 0 || 0 || 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;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align:center&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
! Bit&lt;br /&gt;
| 7 || 6 || 5 || 4 || 3 || 2 || 1 || 0&lt;br /&gt;
|- &lt;br /&gt;
! Name&lt;br /&gt;
| &#039;&#039;&#039;INTF1&#039;&#039;&#039; || &#039;&#039;&#039;INTF0&#039;&#039;&#039; || &#039;&#039;&#039;-&#039;&#039;&#039; || &#039;&#039;&#039;-&#039;&#039;&#039; || &#039;&#039;&#039;-&#039;&#039;&#039; || &#039;&#039;&#039;-&#039;&#039;&#039; || &#039;&#039;&#039;-&#039;&#039;&#039; || &#039;&#039;&#039;-&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
! R/W&lt;br /&gt;
| R/W || R/W || R || R || R || R || R || R&lt;br /&gt;
|- &lt;br /&gt;
! Initialwert&lt;br /&gt;
| 0 || 0 || 0 || 0 || 0 || 0 || 0 || 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-Bedingung, entsprechend der Konfiguration, als eingetreten 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-Bedingung, entsprechend der Konfiguration, als eingetreten 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 MCU-Funktionen.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align:center&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
! Bit&lt;br /&gt;
| 7 || 6 || 5 || 4 || 3 || 2 || 1 || 0&lt;br /&gt;
|- &lt;br /&gt;
! Name&lt;br /&gt;
| &#039;&#039;&#039;-&#039;&#039;&#039;|| &#039;&#039;&#039;-&#039;&#039;&#039;|| &#039;&#039;&#039;SE&#039;&#039;&#039;|| &#039;&#039;&#039;SM&#039;&#039;&#039;|| &#039;&#039;&#039;ISC11&#039;&#039;&#039;|| &#039;&#039;&#039;ISC10&#039;&#039;&#039;|| &#039;&#039;&#039;ISC01&#039;&#039;&#039;|| &#039;&#039;&#039;ISC00&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
! R/W&lt;br /&gt;
| R || R || R/W || R/W || R/W || R/W || R/W || R/W&lt;br /&gt;
|- &lt;br /&gt;
! Initialwert&lt;br /&gt;
| 0 || 0 || 0 || 0 || 0 || 0 || 0 || 0&lt;br /&gt;
&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 über den 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;
&lt;br /&gt;
:{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
! ISC11 || ISC10 || Bedeutung&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| Low Level an &#039;&#039;&#039;INT1&#039;&#039;&#039; erzeugt einen Interrupt.&lt;br /&gt;
&lt;br /&gt;
Der Interrupt wird getriggert, solange der Pin auf 0 bleibt.&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;
&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;
:{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
! ISC01 || ISC00 || Bedeutung&lt;br /&gt;
|- &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| Low Level an &#039;&#039;&#039;INT0&#039;&#039;&#039; erzeugt einen Interrupt.&lt;br /&gt;
&lt;br /&gt;
Der Interrupt wird getriggert, solange der Pin auf 0 bleibt.&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;
&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, wird dringend davon abgeraten. 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 avr-gcc ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- &#039;&#039;Anmerkung eines Nutzers: Ich habe mir das Thema hier angearbeitet und hatte am Anfang starke Probleme: Jeder Interrupt muss nochmals einzeln aktiviert werden. Es reicht nicht nur per &#039;&#039;sei()&#039;&#039; die Interrupts global zu aktiveren.&#039;&#039; - mthomas: Hoffentlich duch die modifizerte Einleitung etwas offensichtlicher erläutert. Ansonsten bitte per Eintrag auf die Diskussionseite nochmals melden) --&amp;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;syntaxhighlight lang=&amp;quot;c&amp;quot;&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;/syntaxhighlight&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;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
    sei();&lt;br /&gt;
&amp;lt;/syntaxhighlight&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;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
    cli();&lt;br /&gt;
&amp;lt;/syntaxhighlight&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 Interrupts 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;syntaxhighlight lang=&amp;quot;c&amp;quot;&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;/syntaxhighlight&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;
Nachdem nun die Interrupts aktiviert sind, braucht es selbstverständlich noch den auszuführenden Code, der ablaufen soll, wenn ein Interrupt eintrifft.&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
Zu den aktivierten Interrupts ist eine Funktion zu programmieren, deren Code aufgerufen wird, wenn der betreffende Interrupt auftritt (Interrupt-Handler, Interrupt-Service-Routine). Dazu existiert die Definition (ein Makro) &#039;&#039;&#039;ISR&#039;&#039;&#039;.&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;. SIGNAL sollte nicht mehr genutzt werden, zur Portierung von SIGNAL nach ISR siehe den [[AVR-GCC-Tutorial#Anhang|Anhang]].)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&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;/syntaxhighlight&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;syntaxhighlight lang=&amp;quot;c&amp;quot;&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;/syntaxhighlight&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;syntaxhighlight lang=&amp;quot;c&amp;quot;&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;/syntaxhighlight&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;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/interrupt.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ISR(XXX,ISR_NOBLOCK) /* veraltet: INTERRUPT(SIG_OVERFLOW0) */&lt;br /&gt;
{&lt;br /&gt;
    /* Interrupt-Code */&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hierbei steht XXX für den oben beschriebenen Namen des Vektors (also z.&amp;amp;nbsp;B. &#039;&#039;TIMER0_OVF_vect&#039;&#039;). Der Unterschied im Vergleich zu einer herkömmlichen ISR ist, dass hier beim Aufrufen der Funktion das &#039;&#039;&#039;Global Enable Interrupt&#039;&#039;&#039; Bit durch Einfügen einer SEI-Anweisung direkt wieder gesetzt und somit alle Interrupts zugelassen werden &amp;amp;ndash; auch XXX-Interrupts. &lt;br /&gt;
&lt;br /&gt;
Bei unsachgemässer Handhabung kann dies zu erheblichen Problemen durch Rekursion wie einem Stack-Overflow oder anderen unerwarteten Effekten führen und sollte wirklich nur dann eingesetzt werden, wenn man sich sicher ist, das Ganze auch im Griff zu haben.&lt;br /&gt;
&lt;br /&gt;
Insbesondere sollte möglichst am ISR-Anfang die auslösende IRQ-Quelle deaktiviert und erst am Ende der ISR wieder aktiviert werden. Robuster als die Verwendung einer NOBLOCK-ISR ist daher folgender ISR-Aufbau:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/interrupt.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ISR (XXX) &lt;br /&gt;
{&lt;br /&gt;
    // Implementiere die ISR ohne zunaechst weitere IRQs zuzulassen&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;&amp;lt;Deaktiviere die XXX-IRQ&amp;gt;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    // Erlaube alle Interrupts (ausser XXX)&lt;br /&gt;
    sei();&lt;br /&gt;
&lt;br /&gt;
    //... Code ...&lt;br /&gt;
&lt;br /&gt;
    // IRQs global deaktivieren um die XXX-IRQ wieder gefahrlos &lt;br /&gt;
    // aktivieren zu koennen&lt;br /&gt;
    cli();&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;&amp;lt;Aktiviere die XXX-IRQ&amp;gt;&amp;gt;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Auf diese Weise kann sich die XXX-IRQ nicht selbst unterbrechen, was zu einer Art Endlosschleife führen würde.&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 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;syntaxhighlight lang=&amp;quot;c&amp;quot;&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.&amp;amp;nbsp;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;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wird innerhalb einer ISR mehrfach auf eine mit volatile deklarierte Variable zugegriffen, wirkt sich dies ungünstig auf die Verarbeitungsgeschwindigkeit aus, da bei jedem Zugriff mit dem Speicherinhalt abgeglichen wird. Da bei AVR-Controllern &#039;&#039;innerhalb&#039;&#039; einer ISR keine Unterbrechungen zu erwarten sind, bietet es sich an, einen Zwischenspeicher in Form einer lokalen Variable zu verwenden, deren Inhalt zu Beginn und am Ende mit dem der volatile Variable synchronisiert wird. Lokale Variable werden bei eingeschalteter Optimierung mit hoher Wahrscheinlichkeit in Prozessorregistern verwaltet und der Zugriff darauf ist daher nur mit wenigen internen Operationen verbunden. Die ISR aus dem vorherigen Beispiel lässt sich so optimieren:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
ISR(TIMER1_COMPA_vect)&lt;br /&gt;
{&lt;br /&gt;
   uint8_t tmp_kc;&lt;br /&gt;
&lt;br /&gt;
   tmp_kc = gKeyCounter; // Uebernahme in lokale Arbeitsvariable&lt;br /&gt;
&lt;br /&gt;
   if ( !(KEY_PIN &amp;amp; (1&amp;lt;&amp;lt;KEY_PINNO)) ) {&lt;br /&gt;
      if (tmp_kc &amp;lt; CNTREPEAT) {&lt;br /&gt;
         tmp_kc++;&lt;br /&gt;
      }&lt;br /&gt;
   }&lt;br /&gt;
   else {&lt;br /&gt;
      tmp_kc = 0;&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
   gKeyCounter = tmp_kc; // Zurueckschreiben&lt;br /&gt;
}&lt;br /&gt;
//...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Vergleich die Disassemblies (Ausschnitte der &amp;quot;lss-Dateien&amp;quot;, compiliert für ATmega162) im Anschluss. Man erkennt den viermaligen Zugriff auf die Speicheraddresse von &#039;&#039;gKeyCounter&#039;&#039; (hier 0x032A) in der ISR ohne &amp;quot;Cache&amp;quot;-Variable und den zweimaligen Zugriff in der Variante mit Zwischenspeicher. Im Beispiel ist der Vorteil gering, bei komplexeren Routinen kann die Zwischenspeicherung in lokalen Variablen jedoch zu deutlicheren Verbesserungen führen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ISR(TIMER1_COMPA_vect)&lt;br /&gt;
{&lt;br /&gt;
     86a:	1f 92       	push	r1&lt;br /&gt;
     86c:	0f 92       	push	r0&lt;br /&gt;
     86e:	0f b6       	in	r0, 0x3f	; 63&lt;br /&gt;
     870:	0f 92       	push	r0&lt;br /&gt;
     872:	11 24       	eor	r1, r1&lt;br /&gt;
     874:	8f 93       	push	r24&lt;br /&gt;
    if ( !(KEY_PIN &amp;amp; (1&amp;lt;&amp;lt;KEY_PINNO)) ) {&lt;br /&gt;
     876:	ca 99       	sbic	0x19, 2	; 25&lt;br /&gt;
     878:	0a c0       	rjmp	.+20     	; 0x88e &amp;lt;__vector_13+0x24&amp;gt;&lt;br /&gt;
      if (gKeyCounter &amp;lt; CNTREPEAT) gKeyCounter++;&lt;br /&gt;
     87a:	80 91 2a 03 	lds	r24, 0x032A&lt;br /&gt;
     87e:	88 3c       	cpi	r24, 0xC8	; 200 &lt;br /&gt;
     880:	40 f4       	brcc	.+16     	; 0x892 &amp;lt;__vector_13+0x28&amp;gt;&lt;br /&gt;
     882:	80 91 2a 03 	lds	r24, 0x032A&lt;br /&gt;
     886:	8f 5f       	subi	r24, 0xFF	; 255&lt;br /&gt;
     888:	80 93 2a 03 	sts	0x032A, r24&lt;br /&gt;
     88c:	02 c0       	rjmp	.+4      	; 0x892 &amp;lt;__vector_13+0x28&amp;gt;&lt;br /&gt;
   }&lt;br /&gt;
   else {&lt;br /&gt;
      gKeyCounter = 0;&lt;br /&gt;
     88e:	10 92 2a 03 	sts	0x032A, r1&lt;br /&gt;
     892:	8f 91       	pop	r24&lt;br /&gt;
     894:	0f 90       	pop	r0&lt;br /&gt;
     896:	0f be       	out	0x3f, r0	; 63&lt;br /&gt;
     898:	0f 90       	pop	r0&lt;br /&gt;
     89a:	1f 90       	pop	r1&lt;br /&gt;
     89c:	18 95       	reti&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ISR(TIMER1_COMPA_vect)&lt;br /&gt;
{&lt;br /&gt;
     86a:	1f 92       	push	r1&lt;br /&gt;
     86c:	0f 92       	push	r0&lt;br /&gt;
     86e:	0f b6       	in	r0, 0x3f	; 63&lt;br /&gt;
     870:	0f 92       	push	r0&lt;br /&gt;
     872:	11 24       	eor	r1, r1&lt;br /&gt;
     874:	8f 93       	push	r24&lt;br /&gt;
   uint8_t tmp_kc;&lt;br /&gt;
 &lt;br /&gt;
   tmp_kc = gKeyCounter;&lt;br /&gt;
     876:	80 91 2a 03 	lds	r24, 0x032A&lt;br /&gt;
 &lt;br /&gt;
   if ( !(KEY_PIN &amp;amp; (1&amp;lt;&amp;lt;KEY_PINNO)) ) {&lt;br /&gt;
     87a:	ca 9b       	sbis	0x19, 2	; 25&lt;br /&gt;
     87c:	02 c0       	rjmp	.+4      	; 0x882 &amp;lt;__vector_13+0x18&amp;gt;&lt;br /&gt;
     87e:	80 e0       	ldi	r24, 0x00	; 0&lt;br /&gt;
     880:	03 c0       	rjmp	.+6      	; 0x888 &amp;lt;__vector_13+0x1e&amp;gt;&lt;br /&gt;
      if (tmp_kc &amp;lt; CNTREPEAT) {&lt;br /&gt;
     882:	88 3c       	cpi	r24, 0xC8	; 200&lt;br /&gt;
     884:	08 f4       	brcc	.+2      	; 0x888 &amp;lt;__vector_13+0x1e&amp;gt;&lt;br /&gt;
         tmp_kc++;&lt;br /&gt;
     886:	8f 5f       	subi	r24, 0xFF	; 255&lt;br /&gt;
      }&lt;br /&gt;
   }&lt;br /&gt;
   else {&lt;br /&gt;
      tmp_kc = 0;&lt;br /&gt;
   }&lt;br /&gt;
 &lt;br /&gt;
   gKeyCounter = tmp_kc;&lt;br /&gt;
     888:	80 93 2a 03 	sts	0x032A, r24&lt;br /&gt;
     88c:	8f 91       	pop	r24&lt;br /&gt;
     88e:	0f 90       	pop	r0&lt;br /&gt;
     890:	0f be       	out	0x3f, r0	; 63&lt;br /&gt;
     892:	0f 90       	pop	r0&lt;br /&gt;
     894:	1f 90       	pop	r1&lt;br /&gt;
     896:	18 95       	reti&lt;br /&gt;
&amp;lt;/pre&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;syntaxhighlight lang=&amp;quot;c&amp;quot;&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;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Falls der Pointer volatile ist (zweiter Fall im Beispiel), ist zu beachten, dass der Wert des Pointers, also eine Speicheradresse, intern in mehr als einem Byte verwaltet wird. Lese- und Schreibzugriffe im Hauptprogramm (außerhalb von Interrupt-Routinen) sind daher so zu implementieren, dass alle Teilbytes der Adresse konsistent bleiben, vgl. dazu den folgenden Abschnitt.&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;syntaxhighlight lang=&amp;quot;c&amp;quot;&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();  // Interrupts 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;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die avr-libc bietet ab Version 1.6.0(?) einige Hilfsfunktionen/Makros, mit der im Beispiel oben gezeigten Funktionalität, die zusätzlich auch sogenannte [http://en.wikipedia.org/wiki/Memory_barrier memory barriers] beinhalten. Diese stehen nach #include &amp;lt;util/atomic.h&amp;gt; zur Verfügung.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
#include &amp;lt;util/atomic.h&amp;gt;&lt;br /&gt;
//...&lt;br /&gt;
&lt;br /&gt;
    // analog zu cli, Zugriff, sei:&lt;br /&gt;
    ATOMIC_BLOCK(ATOMIC_FORCEON) {&lt;br /&gt;
        tmpCnt = gMyCounter16Bit;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
// oder:&lt;br /&gt;
&lt;br /&gt;
    // analog zu Sicherung des SREG, cli, Zugriff und Zurückschreiben des SREG:&lt;br /&gt;
    ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {&lt;br /&gt;
        tmpCnt = gMyCounter16Bit;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
//...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* siehe auch [http://www.nongnu.org/avr-libc/user-manual/group__util__atomic.html Dokumentation der avr-libc zu atomic.h]&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;syntaxhighlight lang=&amp;quot;c&amp;quot;&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;/syntaxhighlight&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 Unterbrechungen 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 Unterbrechungen. Eine Interrupt-Routine könnte nach dem Laden des Ausgangszustands in den Zwischenspeicher (hier Register 24) den Wert des Registers ändern, z.&amp;amp;nbsp;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 auf &#039;&#039;&#039;1&#039;&#039;&#039;, PORTA ist danach 0b0000000&#039;&#039;&#039;1&#039;&#039;&#039;. 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-&#039;&#039;&#039;ODER&#039;&#039;&#039;-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;
== Interruptflags löschen ==&lt;br /&gt;
&lt;br /&gt;
Beim Löschen von Interruptflags haben AVRs eine Besonderheit, die auch im Datenblatt beschrieben ist: Es wird zum Löschen eine 1 in das betreffende Bit geschrieben. &lt;br /&gt;
&lt;br /&gt;
Hinweis: Dazu &#039;&#039;&#039;nicht&#039;&#039;&#039; übliche bitweise VerODERung nehmen, sondern eine direkte Zuweisung machen ([http://www.mikrocontroller.net/topic/171148#1640133 Erklärung]).&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 [[Sleep Mode |&#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;
;set_sleep_mode (uint8_t mode): Setzt den Schlafmodus, der bei Aufruf von sleep() aktiviert wird. In sleep.h sind einige Konstanten definiert (z.&amp;amp;nbsp;B. SLEEP_MODE_PWR_DOWN). Die definierten Modi werden jedoch nicht alle von sämtlichten AVR-Controllern unterstützt.&lt;br /&gt;
;sleep_enable(): Aktiviert den gesetzten Schlafmodus, versetzt den Controller aber noch nicht in den Schlafmodus&lt;br /&gt;
;sleep_cpu(): Versetzt den Controller in den Schlafmodus .sleep_cpu wird im Prinzip durch die Assembler-Anweisung &#039;&#039;sleep&#039;&#039; ersetzt.&lt;br /&gt;
;sleep_disable(): Deaktiviert den gesetzten Schlafmodus&lt;br /&gt;
;sleep_mode(): 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;syntaxhighlight lang=&amp;quot;c&amp;quot;&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;/syntaxhighlight&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;syntaxhighlight lang=&amp;quot;c&amp;quot;&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;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Sleep Modi ==&lt;br /&gt;
Zu beachten ist, dass unterschiedliche Prozessoren aus der AVR Familie unterschiedliche Sleep-Modi unterstützen oder nicht unterstützen. Auskunft über die tatsächlichen Gegebenheiten gibt, wie immer, das zum Prozessor gehörende Datenblatt. Die unterschiedlichen Modi unterscheiden sich dadurch, welche Bereiche des Prozessors abgeschaltet werden. Damit korrespondiert unmittelbar welche Möglichkeiten es gibt, den Prozessor aus den jeweiligen Sleep Modus wieder aufzuwecken.&lt;br /&gt;
&lt;br /&gt;
;Idle Mode (SLEEP_MODE_IDLE): Die CPU kann durch SPI, USART, Analog Comperator, ADC, TWI, Timer, Watchdog und irgendeinen anderen Interrupt wieder aufgeweckt werden.&lt;br /&gt;
&lt;br /&gt;
;ADC Noise Reduction Mode (SLEEP_MODE_ADC): In diesem Modus liegt das Hauptaugenmerk darauf, die CPU soweit stillzulegen, dass der ADC möglichst keine Störungen aus dem inneren der CPU auffangen kann. Aufwachen aus diesem Modus kann ausgelöst werden durch den ADC, externe Interrupts, TWI, Timer und Watchdog.&lt;br /&gt;
&lt;br /&gt;
;Power-Down Mode (SLEEP_MODE_PWR_DOWN): In diesem Modus wird ein externer Oszillator (Quarz, Quarzoszillator) gestoppt. Geweckt werden kann die CPU durch einen externen Level Interrupt, TWI, Watchdog, Brown-Out-Reset&lt;br /&gt;
&lt;br /&gt;
;Power-Save-Mode (SLEEP_MODE_PWR_SAVE): Power-Save ist identisch zu Power-Down mit einer Ausnahme: Ist der Timer 2 auf die Verwendung eines externen Taktes konfiguriert, so läuft dieser Timer auch im Power-Save weiter und kann die CPU mit einem Interrupt aufwecken.&lt;br /&gt;
&lt;br /&gt;
;Standby-Mode (SLEEP_MODE_STANDBY, SLEEP_MODE_EXT_STANDBY): Voraussetzung für den Standby-Modus ist die Verwendung eines Quarzes oder eines Quarzoszillators (also einer externen Taktquelle). Ansonsten ist dieser Modus identisch zum Power-Down Modus. Vorteil dieses Modus ist eine kürzere Aufwachzeit.&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/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;
= Zeiger =&lt;br /&gt;
Zeiger (engl. &#039;&#039;Pointer&#039;&#039;) sind Variablen, die die Adresse von Daten oder Funktionen enthalten und belegen 16 Bits. Die Größe hängt mit dem adressierbaren Speicherbereich zusammen und der GCC reserviert dann den entsprechenden Platz.&lt;br /&gt;
Ggf. ist es also günstiger, Indizes auf Arrays (Listen) zu verwenden, so dass der GCC für die Zeigerarithmetik den erforderlichen RAM nur temporär benötigt.&lt;br /&gt;
&lt;br /&gt;
Siehe auch: [[Zeiger]]&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.&amp;amp;nbsp;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;
Siehe auch:&lt;br /&gt;
* [[Binäre Daten zum Programm hinzufügen]]&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;alloziert&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;syntaxhighlight lang=&amp;quot;c&amp;quot;&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;/syntaxhighlight&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 erst ab Version 4.7 &amp;quot;transparent&amp;quot; möglich. Um Daten aus dem Flash zu lesen, muss die AVR-Instruktion LPM (&#039;&#039;load from program memory&#039;&#039;) erzeugt erzeugt werden, bei Controllern mit mehr als 64kiB Flash auch ELMP.  Zum Erzeugen dieser Instruktionen gibt es die im folgenden dargestellten zwei Wege.&lt;br /&gt;
&lt;br /&gt;
=== progmem und pgm_read_xxx ===&lt;br /&gt;
&lt;br /&gt;
→ [http://nongnu.org/avr-libc/user-manual/group__avr__pgmspace.html avr-libc: Doku zu avr/pgmspace.h]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;progmem&amp;lt;/tt&amp;gt; ist ein AVR-spezifisches GCC-Attribut, mit dem eine Variablendeklaration im &#039;&#039;static storage&#039;&#039;&amp;lt;ref&amp;gt;Variablen der Speicherklasse &#039;&#039;static storage&#039;&#039; haben eine unbegrenzte Lebensdauer.  Beispiel für solche Variablen sind globale Variablen, aber auch static-Variablen innerhalb einer Funktion gehören dazu.  Beispiele für Variablen, die nicht &#039;&#039;static storage&#039;&#039; sind: auto-Variablen (&amp;quot;normale&amp;quot; lokale Variablen), register-Variablen, durch malloc geschaffene Objekte, etc.&amp;lt;/ref&amp;gt; markiert werden kann:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
const int value __attribute__((progmem)) = 1;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Effekt ist, dass die so markierte Variable nicht im RAM sondern im Flash angelegt wird.  Wird durch &amp;quot;normalen&amp;quot; C-Code auf solch eine Variable zugegriffen, wird jedoch aus dem RAM gelesen und nicht aus dem Flash!&lt;br /&gt;
&lt;br /&gt;
Zum Lesen aus dem Flash stellt die avr-libc daher zahlreiche Makros zur Verfügung.  Zudem wird das Makro &amp;lt;tt&amp;gt;PROGMEM&amp;lt;/tt&amp;gt; definiert, das etwas Tipparbeit spart:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/pgmspace.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
const int value PROGMEM = 1;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;progmem&amp;lt;/tt&amp;gt; funktioniert im Wesentlichen wie ein Section-Attribut, das die Daten in der Section &amp;lt;tt&amp;gt;.progmem.data&amp;lt;/tt&amp;gt; ablegt.  Im Gegensatz zum Section-Attribut werden jedoch noch weitere Prüfungen unternommen, ab avr-gcc 4.6 etwa muss die entsprechende Variable &amp;lt;tt&amp;gt;const&amp;lt;/tt&amp;gt; sein.&lt;br /&gt;
&lt;br /&gt;
==== Integer und float ====&lt;br /&gt;
&lt;br /&gt;
Zum Lesen von Skalaren stellt die avr-libc folgende Makros zu Verfügung, die jeweils ein Argument erhalten: Die 16-Bit Adresse des zu lesenden Wertes&amp;lt;ref&amp;gt;Damit ist der mögliche Speicherbereich für Flash-Konstanten auf 64kiB begrenzt. Einige pgmspace-Funktionen ermöglichen den Lesezugriff auf den gesamten Flash-Speicher, intern via Assembler-Anweisung ELPM. Die Initialisierungswerte des Speicherinhalts jenseits der 64kiB-Marke müssen dann jedoch auf anderem Weg angelegt werden, d.h. nicht per PROGMEM. Evtl. eigene Section und Linker-Optionen. Alt und nicht ganz korrekt: Die avr-libc pgmspace-Funktionen unterstützen nur die unteren 64kiB Flash bei Controllern mit mehr als 64kiB.&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:{| {{Tabelle}}&lt;br /&gt;
|+ Übersicht der &amp;lt;tt&amp;gt;pgm_read&amp;lt;/tt&amp;gt; Funktionen aus&amp;lt;br/&amp;gt;dem Header &amp;lt;tt&amp;gt;avr/pgmspace.h&amp;lt;/tt&amp;gt; der avr-libc&lt;br /&gt;
|-&lt;br /&gt;
! Gelesener Wert || &amp;lt;tt&amp;gt;pgm_read_xxx&amp;lt;/tt&amp;gt; || Anzahl Bytes&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;uint8_t&amp;lt;/tt&amp;gt; || &amp;lt;tt&amp;gt;pgm_read_byte&amp;lt;/tt&amp;gt; || 1&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;uint16_t&amp;lt;/tt&amp;gt; || &amp;lt;tt&amp;gt;pgm_read_word&amp;lt;/tt&amp;gt; || 2&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;uint32_t&amp;lt;/tt&amp;gt; || &amp;lt;tt&amp;gt;pgm_read_dword&amp;lt;/tt&amp;gt; || 4&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;float&amp;lt;/tt&amp;gt; || &amp;lt;tt&amp;gt;pgm_read_float&amp;lt;/tt&amp;gt;&amp;lt;ref&amp;gt;ab avr-libc 1.7.0&amp;lt;/ref&amp;gt; || 4&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Soll ein Zeiger gelesen werden, so verwendet man &amp;lt;tt&amp;gt;pgm_read_word&amp;lt;/tt&amp;gt; und castet das Ergebnis zum gewünschten Zeiger-Typ.&lt;br /&gt;
&lt;br /&gt;
;Beispiele:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/pgmspace.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/* Byte */&lt;br /&gt;
const uint8_t aByte PROGMEM = 123;&lt;br /&gt;
&lt;br /&gt;
/* int-Array */&lt;br /&gt;
const int anArray[] PROGMEM = { 18, 3 ,70 };&lt;br /&gt;
&lt;br /&gt;
void foo (void)&lt;br /&gt;
{&lt;br /&gt;
  /* Zeiger */&lt;br /&gt;
  static const uint8_t* const aPointer PROGMEM = &amp;amp;aByte;&lt;br /&gt;
&lt;br /&gt;
  uint8_t a        = pgm_read_byte (&amp;amp;aByte);&lt;br /&gt;
  int a2           = (int) pgm_read_word (&amp;amp;anArray[2]);&lt;br /&gt;
  const uint8_t* p = (const uint8_t*) pgm_read_word (&amp;amp;aPointer);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Blöcke ====&lt;br /&gt;
&lt;br /&gt;
In den Flash-Funktionen der avr-libc sind keine der pgm_read_xxxx Nomenklatur folgenden Funktionen, die Speicherblöcke auslesen oder vergleichen. Die enstprechende Funktionen sind Varianten von &amp;lt;tt&amp;gt;memcpy&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;memcmp&amp;lt;/tt&amp;gt; und heißt &amp;lt;tt&amp;gt;memcpy_P&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;memcmp_P&amp;lt;/tt&amp;gt;, usw.  Für weitere Funktionen und deren Prototypen siehe die Dokumentation der avr-libc.&lt;br /&gt;
&lt;br /&gt;
==== Strings ====&lt;br /&gt;
&lt;br /&gt;
Strings sind in C nichts anderes als eine Abfolge von Zeichen und einem &amp;lt;tt&amp;gt;&#039;\0&#039;&amp;lt;/tt&amp;gt; als Stringende. Der prinzipielle Weg ist daher identisch zum  Lesen von Bytes, wobei auf die [[FAQ#Wie funktioniert String-Verarbeitung in C?|Besonderheiten von Strings]] wie 0-Terminierung geachtet werden muss.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/pgmspace.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
size_t my_string_length (const char* addr)&lt;br /&gt;
{&lt;br /&gt;
    size_t length = 0;&lt;br /&gt;
&lt;br /&gt;
    while (pgm_read_byte (addr++))&lt;br /&gt;
    {&lt;br /&gt;
        len++;&lt;br /&gt;
    }&lt;br /&gt;
    return length;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zur Unterstützung des Programmierers steht das Repertoire der str-Funktionen auch in jeweils eine Variante zur Verfügung, die mit dem Flash-Speicher arbeiten kann. Die Funktionsnamen tragen den Suffix &amp;lt;tt&amp;gt;_P&amp;lt;/tt&amp;gt;. Darüber hinaus gibt es das Makro &amp;lt;tt&amp;gt;PSTR&amp;lt;/tt&amp;gt;, das ein String-Literal im Flash-Speicher ablegt und die Adresse des Strings liefert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/pgmspace.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/* Liefert true zurück, wenn string_im_ram gleich &amp;quot;Hallo Welt&amp;quot; ist. */&lt;br /&gt;
int foo (const char* string_im_ram)&lt;br /&gt;
{&lt;br /&gt;
    return strcmp_P (string_im_ram, PSTR (&amp;quot;Hallo Welt&amp;quot;));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zu beachten ist, dass &amp;lt;tt&amp;gt;PSTR&amp;lt;/tt&amp;gt; nur innerhalb von Funktionen verwendet werden kann.&lt;br /&gt;
&lt;br /&gt;
; Array aus Strings:&lt;br /&gt;
&lt;br /&gt;
Arrays aus Strings im Flash-Speicher werden in zwei Schritten angelegt:&lt;br /&gt;
&lt;br /&gt;
# Zuerst die einzelnen Elemente des Arrays und&lt;br /&gt;
# im Anschluss ein Array, in dem die Startaddressen der Strings abgelegt werden.&lt;br /&gt;
&lt;br /&gt;
Zum Auslesen wird zuerst die Adresse des gewünschten Elements aus dem Array im Flash-Speicher gelesen, die im Anschluss dazu genutzt wird, um auf das Element (den String) selbst zuzugreifen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/pgmspace.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
static const char str1[] PROGMEM = &amp;quot;Hund&amp;quot;;&lt;br /&gt;
static const char str2[] PROGMEM = &amp;quot;Katze&amp;quot;;&lt;br /&gt;
static const char str3[] PROGMEM = &amp;quot;Maus&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
const char * const array[] PROGMEM = &lt;br /&gt;
{&lt;br /&gt;
   str1, str2, str3&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
// Liest den i-ten String von array[] und kopiert ihn ins RAM nach buf[]&lt;br /&gt;
void read_string (char* buf, size_t i)&lt;br /&gt;
{&lt;br /&gt;
    // Lese die Adresse des i-ten Strings aus array[]&lt;br /&gt;
    const char *parray = (const char*) pgm_read_word (&amp;amp;array[i]);&lt;br /&gt;
&lt;br /&gt;
    // Kopiere den Inhalt der Zeichenkette vom Flash ins RAM&lt;br /&gt;
    strcpy_P (buf, parray);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Eine weitere Möglichkeit ist, die Strings in einem 2-dimensionalen char-Array abzulegen anstatt deren Adresse in einem 1-dimensionalen Adress-Array zu speichern.&lt;br /&gt;
&lt;br /&gt;
Vorteil ist, dass der Code einfacher wird.  Nachteil ist, dass bei unterschiedlich langen Strings Speicherplatz verschwendet wird, weil sich die Array-Dimension and der Länge des längsten Strings orientieret.  Bei in etwa gleich langen Strings kann es aber sogar Speicherplatz sparen, denn es die Adressen der einzelnen Strings müssen nicht abgespeichert werden.&amp;lt;ref&amp;gt;In unserem Hund-Katze-Maus Beispiel belegt die erste Variante 22 Bytes Daten und 18 Bytes Code, die zweite Variante mit 2-dimensionalem Array belegt 18 Bytes Daten und 20 Bytes Code. Gemessen wurde mit avr-gcc 4.8 -Os für ATmega8.&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/pgmspace.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
// Die &amp;quot;6&amp;quot; ist 1 plus die Länge des längsten Strings (&amp;quot;Katze&amp;quot;)&lt;br /&gt;
const char array[][6] PROGMEM = &lt;br /&gt;
{&lt;br /&gt;
   &amp;quot;Hund&amp;quot;, &amp;quot;Katze&amp;quot;, &amp;quot;Maus&amp;quot;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
// Liest den i-ten String von array[] und kopiert ihn ins RAM nach buf[]&lt;br /&gt;
void read_string (char* buf, size_t i)&lt;br /&gt;
{&lt;br /&gt;
    // Kopiere den Inhalt der i-ten Zeichenkette vom Flash ins RAM&lt;br /&gt;
    strcpy_P (buf, array[i]);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Siehe dazu auch die avr-libc FAQ: [http://www.nongnu.org/avr-libc/user-manual/FAQ.html#faq_rom_array How do I put an array of strings completely in ROM?]&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 kompliziert 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 sieht keine unterschiedlichen Adressräume vor.&lt;br /&gt;
&lt;br /&gt;
Hat man zum Beispiel eine Funktion string_an_uart (const char* s) und übergibt an diese Funktion die Adresse einer Zeichenkette, dann weiß die Funktion nicht, ob die Adresse in den Flash-Speicher oder das RAM zeigt. Weder aus dem Pointer-Wert, also dem Zahlenwert, noch aus dem &amp;quot;const&amp;quot; kann auf den Ort der Ablage geschlossen werden.&lt;br /&gt;
&lt;br /&gt;
Einige AVR-Compiler bilden die Harvard-Architektur ab, indem sie in einen Pointer nicht nur die Adresse speichern, sondern auch den Ablageort wie &#039;&#039;Flash&#039;&#039; oder &#039;&#039;RAM&#039;&#039;. In einem Aufruf einer Funktion wird dann bei Pointer-Parametern neben der Adresse auch der Speicherbereich, auf den der Pointer zeigt, übergeben.&lt;br /&gt;
&lt;br /&gt;
Dies hat jedoch auch Nachteile, denn bei jedem Zugriff über einen Zeiger muss zur &#039;&#039;Laufzeit&#039;&#039; entschieden werden, wie der Zugriff auszuführen ist und entsprechend länglicher und langsamer wird der erzeugte Code.&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] Abschnitte Modules/Program Space String Utilities und Abschnitt Modules/Bootloader Support Utilities&lt;br /&gt;
&lt;br /&gt;
==== Variablenzugriff &amp;gt;64kB ====&lt;br /&gt;
&lt;br /&gt;
Die Zeiger beim avr-gcc sind nur 16 Bit breit, können somit also nur 64kiB Datenspeicher adressieren. Als Funktionspointer können sie beim AVR bis zu 128 kiB Programmspeicher adressieren, weil FUnktionsadressen immer gerade sind. Für den Datenzugriff jenseits von 64kiB stellt die AVR-Libc die Funktionen &amp;lt;tt&amp;gt;pgm_read_xxx_far&amp;lt;/tt&amp;gt; zur Verfügung. Diese Funktionen erwarten einen 32-Bit Pointer auf die Daten. Unverständlicherweise gibt es aber in der AVR-Libc keine Funktion, um diesen 32-Bit Pointer zu erhalten. Hier schafft ein eigenes Makro Abhilfe:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&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;
&lt;br /&gt;
//====================================================================&lt;br /&gt;
// Macro to access strings defined in PROGMEM above 64kB&lt;br /&gt;
//--------------------------------------------------------------------&lt;br /&gt;
#define FAR(var)                     \&lt;br /&gt;
({ uint_farptr_t tmp;                \&lt;br /&gt;
   __asm__ (                         \&lt;br /&gt;
       &amp;quot;ldi    %A0, lo8(%1)&amp;quot;  &amp;quot;\n\t&amp;quot; \&lt;br /&gt;
       &amp;quot;ldi    %B0, hi8(%1)&amp;quot;  &amp;quot;\n\t&amp;quot; \&lt;br /&gt;
       &amp;quot;ldi    %C0, hh8(%1)&amp;quot;         \&lt;br /&gt;
       : &amp;quot;=d&amp;quot; (tmp)                  \&lt;br /&gt;
       : &amp;quot;i&amp;quot;  (&amp;amp;(var)));             \&lt;br /&gt;
   tmp;                              \&lt;br /&gt;
})&lt;br /&gt;
//-------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
//===================================================================&lt;br /&gt;
// Define a section above 64kiB (FAR_SECTION)&lt;br /&gt;
// and add the required linker argument below&lt;br /&gt;
// -Wl,--section-start=.far_section=0x10000&lt;br /&gt;
//--------------------------------------------------------------------&lt;br /&gt;
#define FAR_SECTION   __attribute__((__section__(&amp;quot;.far_section&amp;quot;)))&lt;br /&gt;
//--------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
//====================================================================&lt;br /&gt;
// Just a Sample&lt;br /&gt;
//--------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
char MyString[] FAR_SECTION = &amp;quot;Hier liegt mein FAR-Teststring!&amp;quot;;&lt;br /&gt;
char MyBmp64[]  FAR_SECTION = {0xAA,0xBB,0xCC,0xDD,0xEE,0xFF,0x00};&lt;br /&gt;
&lt;br /&gt;
int main(void)&lt;br /&gt;
{&lt;br /&gt;
  char MyChar;&lt;br /&gt;
  DDRC = 0xFF;&lt;br /&gt;
  do&lt;br /&gt;
  {&lt;br /&gt;
    MyChar = pgm_read_byte_far(FAR(MyBmp64));&lt;br /&gt;
    PORTC  = MyChar;&lt;br /&gt;
  }&lt;br /&gt;
  while(MyChar);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
D.h. man muss&lt;br /&gt;
* Das Makro FAR im Quellcode einfügen&lt;br /&gt;
* Die Definition der neuen Sektion FAR_SECTION einfügen&lt;br /&gt;
* Die Variablen mit dieser Sektion kennzeichnen&lt;br /&gt;
* Dem Linker mittels Kommandozeilenoption diese Sektion mitteilen&lt;br /&gt;
&lt;br /&gt;
Der Zugriff auf diese Variablen kann nur mittels direkter Pointerarithmetik erfolgen, eine Indizierung von Arrays mit variablem Index ist nicht möglich.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
int n=3;&lt;br /&gt;
MyChar = pgm_read_byte_far(FAR(MyBmp64)+n);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== __flash und Embedded-C ===&lt;br /&gt;
&lt;br /&gt;
Ab Version 4.7 unterstützt avr-gcc &#039;&#039;Adress-Spaces&#039;&#039; gemäß dem Embedded-C Dokument ISO/IEC TR18037.  Der geläufigste Adress-Space ist &amp;lt;tt&amp;gt;__flash&amp;lt;/tt&amp;gt;, der im Gegensatz zu &amp;lt;tt&amp;gt;progmem&amp;lt;/tt&amp;gt; kein GCC-Attribut ist, sondern ein Qualifier und damit ähnlich verwendet wird wie &amp;lt;tt&amp;gt;const&amp;lt;/tt&amp;gt; oder &amp;lt;tt&amp;gt;volatile&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
GCC kennt keine eigene Option zum Aktivieren von Embedded-C, es wird als GNU-C Erweiterung behandelt. Daher müssen C-Module, die Address-Spaces verwenden, mit &amp;lt;tt&amp;gt;-std=gnu99&amp;lt;/tt&amp;gt; compiliert werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static const __flash int value = 10;&lt;br /&gt;
&lt;br /&gt;
int get_value (void)&lt;br /&gt;
{&lt;br /&gt;
  return value;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Im Gegensatz zu &amp;lt;tt&amp;gt;progmem&amp;lt;/tt&amp;gt; sind keine speziellen Bibliotheksfunktionen oder -makros für den Zugriff mehr notwendig: Der Code zum Lesen der Variable ist &amp;quot;normales&amp;quot; C.&lt;br /&gt;
# Die Variable wird im richtigen Speicherbereich (Flash) angelegt.&lt;br /&gt;
# &amp;lt;tt&amp;gt;__flash&amp;lt;/tt&amp;gt; ist nur zusammen mit read-only Objekten oder Zeigern, d.h. nur zusammen mit &amp;lt;tt&amp;gt;const&amp;lt;/tt&amp;gt;, erlaubt.&lt;br /&gt;
# Zugriffe wie im obigen Beispiel können (weg)optimiert werden.  Das Beispiel entspricht einem &amp;quot;&amp;lt;tt&amp;gt;return 10&amp;lt;/tt&amp;gt;&amp;quot;.  Es besteht keine Notwendigkeit, für &amp;lt;tt&amp;gt;value&amp;lt;/tt&amp;gt; überhaupt Flash-Speicher zu reservieren.&lt;br /&gt;
&lt;br /&gt;
Auch Zeiger-Indirektionen sind problemlos möglich.  Zu beachten ist, dass &amp;lt;tt&amp;gt;__flash&amp;lt;/tt&amp;gt; auf der richtigen Seite des &amp;quot;&amp;lt;tt&amp;gt;*&amp;lt;/tt&amp;gt;&amp;quot; in der Zeigerdeklaration bzw. -definition steht:&lt;br /&gt;
* &#039;&#039;&#039;Rechts vom &amp;lt;tt&amp;gt;*&amp;lt;/tt&amp;gt;:&#039;&#039;&#039; Der Zeiger selbst liegt im Flash&lt;br /&gt;
* &#039;&#039;&#039;Links vom &amp;lt;tt&amp;gt;*&amp;lt;/tt&amp;gt;:&#039;&#039;&#039; Der Zeiger enthält eine Flash-Adresse&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// val ist eine Variable im Flash&lt;br /&gt;
const __flash int val = 42;&lt;br /&gt;
&lt;br /&gt;
// pval liegt auch im Flash und enthält die Adresse von val&lt;br /&gt;
const __flash int* const __flash pval = &amp;amp;val;&lt;br /&gt;
&lt;br /&gt;
char get_val (void)&lt;br /&gt;
{&lt;br /&gt;
  // liest den Wert von val über die in pval abgelegte Adresse&lt;br /&gt;
  return *pval;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Blöcke ====&lt;br /&gt;
&lt;br /&gt;
Um Speicherbereiche vom Flash in den RAM zu kopieren, gibt es zwei Möglichkeiten: Zum einen können wie bei &amp;lt;tt&amp;gt;progmem&amp;lt;/tt&amp;gt; beschreiben die Funktionen der avr-libc wie &amp;lt;tt&amp;gt;memcpy_P&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;memcmp_P&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;movmem_P&amp;lt;/tt&amp;gt;, etc. verwendet werden:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/pgmspace.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
// Eine Datenstruktur&lt;br /&gt;
typedef struct&lt;br /&gt;
{&lt;br /&gt;
    int id;&lt;br /&gt;
    char buf[10];&lt;br /&gt;
} data_t;&lt;br /&gt;
&lt;br /&gt;
extern void uart_send (const void*, size_t);&lt;br /&gt;
&lt;br /&gt;
void send_data (const __flash data_t *pdata)&lt;br /&gt;
{&lt;br /&gt;
    // buf wird auf dem Stack angelegt&lt;br /&gt;
    data_t buf;&lt;br /&gt;
    &lt;br /&gt;
    // Kopiere Daten vom Flash nach buf ins RAM&lt;br /&gt;
    memcpy_P (&amp;amp;buf, pdata, sizeof (data_t));&lt;br /&gt;
 &lt;br /&gt;
    // Sende die Daten in buf&lt;br /&gt;
    uart_send (&amp;amp;buf, sizeof (data_t));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum anderen kann eine Struktur auch über direktes Kopieren ins RAM geladen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
// Eine Datenstruktur&lt;br /&gt;
typedef struct&lt;br /&gt;
{&lt;br /&gt;
    int id;&lt;br /&gt;
    char buf[10];&lt;br /&gt;
} data_t;&lt;br /&gt;
&lt;br /&gt;
extern void uart_send (const void*, size_t);&lt;br /&gt;
&lt;br /&gt;
void send_data (const __flash data_t *pdata)&lt;br /&gt;
{&lt;br /&gt;
    // Kopiere Daten ins RAM.  buf wird auf dem Stack angelegt&lt;br /&gt;
    const data_t buf = *pdata;&lt;br /&gt;
    &lt;br /&gt;
    // Verwendet die Daten in buf&lt;br /&gt;
    uart_send (&amp;amp;buf, sizeof (data_t));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Strings ====&lt;br /&gt;
&lt;br /&gt;
Natürlich können auch Strings im Flash abgelegt werden und auch mit Funktionen wie &amp;lt;tt&amp;gt;strcpy_P&amp;lt;/tt&amp;gt; aus der avr-libc verarbeitet werden.  Zudem ist es möglich, Flash-Zeiger mit der Adresse eines String-Literals zu initialisieren:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/pgmspace.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#define FSTR(X) ((const __flash char[]) { X } )&lt;br /&gt;
&lt;br /&gt;
const __flash char * const __flash array[] = &lt;br /&gt;
{&lt;br /&gt;
    FSTR (&amp;quot;Hund&amp;quot;), FSTR (&amp;quot;Katze&amp;quot;), FSTR (&amp;quot;Maus&amp;quot;)&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
size_t get_len (uint8_t tier)&lt;br /&gt;
{&lt;br /&gt;
    return strlen_P (array[tier]);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Leider sieht der Embedded-C Draft nicht vor, String-Literale direkt in einem anderen Adress-Space als &#039;&#039;generic&#039;&#039; anzulegen, so dass hier der Umweg über &amp;lt;tt&amp;gt;FSTR&amp;lt;/tt&amp;gt; genommen werden muss.  Dieses Konstrukt ist nur ausserhalb von Funktionen möglich und kann daher nicht als Ersatz für &amp;lt;tt&amp;gt;PSTR&amp;lt;/tt&amp;gt; aus der avr-libc dienen.&lt;br /&gt;
&lt;br /&gt;
Soll &amp;lt;tt&amp;gt;array&amp;lt;/tt&amp;gt; ein 2-dimensonales Array sein anstatt ein 1-dimensionales Array von Zeigern, dann geht das ohne große Verrenkungen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Die 6 ergibt sich aus 1 plus der Länge des längsten Strings &amp;quot;Katze&amp;quot;&lt;br /&gt;
const __flash char array[][6] = &lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;Hund&amp;quot;, &amp;quot;Katze&amp;quot;, &amp;quot;Maus&amp;quot;&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Weiters besteht die Möglichkeit, &amp;lt;tt&amp;gt;array&amp;lt;/tt&amp;gt; analog anzulegen, wie man es mit &amp;lt;tt&amp;gt;PROGMEM&amp;lt;/tt&amp;gt; machen würde:  Jeder String wird explizit angelegt und seine Adresse bei der Initialisierung von &amp;lt;tt&amp;gt;array&amp;lt;/tt&amp;gt; verwendet.  Dies entspricht dem ersten Beispiel eines 1-dimensionalen Zeigerarrays:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static const __flash char strHund[]  = &amp;quot;Hund&amp;quot;;&lt;br /&gt;
static const __flash char strKatze[] = &amp;quot;Katze&amp;quot;;&lt;br /&gt;
static const __flash char strMaus[]  = &amp;quot;Maus&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
const __flash char * const __flash array[] = &lt;br /&gt;
{&lt;br /&gt;
    strHund, strKatze, strMaus&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Casts ====&lt;br /&gt;
&lt;br /&gt;
Embedded C fordert, dass zwei Adress-Spaces entweder disjunkt sind – d.h. sie enthalten keine gemeinsamen Adressen – oder aber ein Space komplett im anderen enthalten ist, also eine Teilmengen-Beziehung besteht.  Die Adress-Spaces von avr-gcc sind so implementiert, dass jeder Space Teilmenge jedes anderes ist.  Zwar haben Spaces wie RAM und Flash physikalisch keinen Speicherbereich gemein, allerdings ermöglicht diese Implementierung das Casten von Zeigern zu unterschiedlichen Adress-Spaces&amp;lt;ref&amp;gt;Im Gegensatz zu einem Attribute wie &amp;lt;tt&amp;gt;progmem&amp;lt;/tt&amp;gt; ist ein (Adress Space) Qualifier Teil des Zeiger-Typs.&amp;lt;/ref&amp;gt;:  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;stdbool.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
char read_char (const char *address, bool data_in_flash)&lt;br /&gt;
{&lt;br /&gt;
    if (data_in_flash)&lt;br /&gt;
        return *(const __flash char*) address;&lt;br /&gt;
    else&lt;br /&gt;
        return *address;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Cast selbst erzeugt keinen zusätzlichen Code, da eine RAM-Adresse und eine Flash-Adresse die gleiche Binärdarstellung haben.  Allerdings wird über den nach &amp;lt;tt&amp;gt;__flash&amp;lt;/tt&amp;gt; gecasteten Zeiger anders zugegriffen, nämlich per LPM.&lt;br /&gt;
&lt;br /&gt;
==== Jenseits von __flash ====&lt;br /&gt;
&lt;br /&gt;
Ausser &amp;lt;tt&amp;gt;__flash&amp;lt;/tt&amp;gt; gibt es auch folgende Address-Spaces:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tt&amp;gt;__flash&amp;lt;/tt&amp;gt;&#039;&#039;N&#039;&#039;, &#039;&#039;N&#039;&#039; = 1..5, sind fünf weitere Spaces, die analog zu &amp;lt;tt&amp;gt;__flash&amp;lt;/tt&amp;gt; funktionieren und deren Zeiger ebenfalls 16 Bit breit sind.  avr-gcc erwartet, dass die zugehörigen Daten, welche in die Section &amp;lt;tt&amp;gt;.progmem&amp;lt;/tt&amp;gt;&#039;&#039;N&#039;&#039;&amp;lt;tt&amp;gt;.data&amp;lt;/tt&amp;gt; abgelegt werden, so lokatiert sind, dass das high-Byte der Adresse (Bits 16..23) gerade &#039;&#039;N&#039;&#039; ist.  Dies wird in Binutils noch nicht unterstützt&amp;lt;ref&amp;gt;[http://sourceware.org/PR14406 Binutils PR14406]: Support .progmem&amp;lt;N&amp;gt;.data sections to work with GCC&#039;s [http://gcc.gnu.org/PR49868 PR49868].&amp;lt;/ref&amp;gt; (Stand Binutils 2.23) Die Unterstützung kann durch ein eigenes Linker-Skript erhalten werden, dass diese Sections wie vom Compiler erwartet lokatiert.&lt;br /&gt;
* Address-Space &amp;lt;tt&amp;gt;__memx&amp;lt;/tt&amp;gt; implementiert 3-Byte Zeiger und unterstützt Lesen über 64KiB-Segmentgrenzen hinweg.  Das MSB (Bit 23) gibt dabei an, ob der Zeiger eine Flash-Adresse enthält (Bit23 = 0) oder eine RAM-Adresse (Bit23 = 1), was folgenden Code erlaubt:&lt;br /&gt;
&amp;lt;!-- Bitte die Tabelle belassen, damit der Code richtig eingerückt wird! --&amp;gt;&lt;br /&gt;
:{|&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
const __memx int a_flash = 42;&lt;br /&gt;
const        int a_ram   = 100;&lt;br /&gt;
&lt;br /&gt;
static int get_a (const __memx int* pa)&lt;br /&gt;
{&lt;br /&gt;
    return *pa;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int main (void)&lt;br /&gt;
{&lt;br /&gt;
    return get_a (&amp;amp;a_flash) + get_a (&amp;amp;a_ram);&lt;br /&gt;
}&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
|}Dies bedeutet, dass erst zur &#039;&#039;Laufzeit&#039;&#039; entschieden werden kann, ob aus dem RAM oder aus dem Flash gelesen werden soll, was &amp;lt;tt&amp;gt;__memx&amp;lt;/tt&amp;gt; im Vergleich zu den anderen Address-Spaces langsamer macht. Ausserdem ist zu beachten, dass &amp;lt;tt&amp;gt;__memx&amp;lt;/tt&amp;gt;-Zeiger zwar 24-Bit Zeiger sind, die zugrundeliegende Adress-Arithmetik jedoch gemäß dem C-Standard erfolgt, also als 16-Bit Arithmetik.&lt;br /&gt;
&lt;br /&gt;
=== __flash, progmem und Portierbarkeit ===&lt;br /&gt;
&lt;br /&gt;
Da ab er aktuellen Compilerversion 4.7 sowohl &amp;lt;tt&amp;gt;__flash&amp;lt;/tt&amp;gt; als auch &amp;lt;tt&amp;gt;PROGMEM&amp;lt;/tt&amp;gt; und die &amp;lt;tt&amp;gt;pgm_read&amp;lt;/tt&amp;gt;-Funktionen zur Verfügung stehen, ergibt sich die Frage, welche Variante &amp;quot;besser&amp;quot; ist und wie zwischen ihnen hin- und her zu portieren ist.&lt;br /&gt;
&lt;br /&gt;
Zunächst sei erwähnt, dass &amp;lt;tt&amp;gt;__flash&amp;lt;/tt&amp;gt; kein Ersatz für &amp;lt;tt&amp;gt;PROGMEM&amp;lt;/tt&amp;gt; ist, sondern lediglich eine Alternative dazu.  Das &amp;quot;alte&amp;quot; progmem wird weiterhin mir gleicher Semantik unterstützt, so dass alter Code ohne Änderungen mit den neueren Compilerversionen übersetzbar bleibt.&lt;br /&gt;
&lt;br /&gt;
Von der Codegüte her dürften sich keine großen Unterschiede ergeben.  Es ist nicht zu erwarten, dass die eine oder die andere Variante wesentlich besseren oder schlechteren Code erzeugt — von einer Ausnahme abgesehen:  Der Wert beim Zugriff ist zur Compilezeit bekannt und kann daher eliminiert werden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static const __flash char x[] = { &#039;A&#039;, &#039;V&#039;, &#039;R&#039; };&lt;br /&gt;
&lt;br /&gt;
char foo (void)&lt;br /&gt;
{&lt;br /&gt;
    return x[2];&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Dies wird übersetzt wie &amp;quot;&amp;lt;tt&amp;gt;return &#039;R&#039;;&amp;lt;/tt&amp;gt;&amp;quot;, und das Array &amp;lt;tt&amp;gt;x[]&amp;lt;/tt&amp;gt; kann komplett wegoptimiert werden und entfallen.&lt;br /&gt;
&lt;br /&gt;
==== progmem → __flash ====&lt;br /&gt;
&lt;br /&gt;
Portierung in diese Richtung bedeutet, alten Code anzupassen.  Zwingend ist die Portierung nicht, da &amp;lt;tt&amp;gt;progmem&amp;lt;/tt&amp;gt; weiterhin unterstützt wird.&lt;br /&gt;
Allerdings ist eine Quelle mit &amp;lt;tt&amp;gt;__flash&amp;lt;/tt&amp;gt; besser lesbar, denn der Code wird von den &amp;lt;tt&amp;gt;pgm_read&amp;lt;/tt&amp;gt;-Funktionen befreit, die vor allem bei Mehrfach-Indirektion den Code ziemlich verunstalten und unleserlich machen können.&lt;br /&gt;
Weiterer Vorteil von &amp;lt;tt&amp;gt;_flash&amp;lt;/tt&amp;gt; ist, daß eine striktere Typprüfung erfolgen kann.&lt;br /&gt;
&lt;br /&gt;
Eine Portierung wird man in zwei Schritten vornehmen:&lt;br /&gt;
&lt;br /&gt;
;1. Definitionen von Flash-Variablen werden angepasst:&lt;br /&gt;
&lt;br /&gt;
Vorher:&lt;br /&gt;
:{|&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/pgmspace.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
static const char hund[]  PROGMEM = &amp;quot;Hund&amp;quot;;&lt;br /&gt;
static const char katze[] PROGMEM = &amp;quot;Katze&amp;quot;;&lt;br /&gt;
static const char maus[]  PROGMEM = &amp;quot;Maus&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
const char * const tier[] PROGMEM = &lt;br /&gt;
{&lt;br /&gt;
   hund, katze, maus&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Nachher:&lt;br /&gt;
:{|&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static const __flash char hund[]  = &amp;quot;Hund&amp;quot;;&lt;br /&gt;
static const __flash char katze[] = &amp;quot;Katze&amp;quot;;&lt;br /&gt;
static const __flash char maus[]  = &amp;quot;Maus&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
const __flash char * const __flash tier[] = &lt;br /&gt;
{&lt;br /&gt;
   hund, katze, maus&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Der Header &amp;lt;tt&amp;gt;avr/pgmspace.h&amp;lt;/tt&amp;gt; wird nicht mehr benötigt.  Im Gegensatz zu &amp;lt;tt&amp;gt;progmem&amp;lt;/tt&amp;gt; müssen Qualifier immer links von der definierten Variablen stehen; bei Attributen wie &amp;lt;tt&amp;gt;progmem&amp;lt;/tt&amp;gt; ist das mehr oder weniger egal.&lt;br /&gt;
&lt;br /&gt;
Nachdem diese Anpassung erfolgreich abgeschlossen ist, folgt Schritt&lt;br /&gt;
&lt;br /&gt;
; 2. Der Code wird von &amp;lt;tt&amp;gt;pgm_reg&amp;lt;/tt&amp;gt;-Aufrufen bereinigt:&lt;br /&gt;
&lt;br /&gt;
Vorher:&lt;br /&gt;
:{|&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/pgmspace.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
extern const char *tier[];&lt;br /&gt;
 &lt;br /&gt;
char first_letter (uint8_t i)&lt;br /&gt;
{&lt;br /&gt;
    const char* ptier = (const char*) pgm_read_word (&amp;amp;tier[i]);&lt;br /&gt;
    return (char) pgm_read_byte (&amp;amp;ptier[0]);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Nachher:&lt;br /&gt;
:{|&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
extern const __flash char * const __flash tier[];&lt;br /&gt;
 &lt;br /&gt;
char first_letter (uint8_t i)&lt;br /&gt;
{&lt;br /&gt;
    return tier[i][0];&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== __flash → progmem ====&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 vom Anwendungsprogramm beschrieben werden. Dies ist nur möglich, wenn die Schreibfunktion in einem besonderen Speicherbereich, der Boot-Section des Programmspeichers/Flash, abgelegt ist.&lt;br /&gt;
&lt;br /&gt;
Bei einigen kleinen 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;
Siehe auch: &lt;br /&gt;
* Forumsbeitrag [http://www.mikrocontroller.net/topic/163632#1561622 Daten in Programmspeicher speichern]&lt;br /&gt;
&lt;br /&gt;
== EEPROM ==&lt;br /&gt;
&lt;br /&gt;
Möchte man Werte aus einem Programm heraus so speichern, dass sie auch nach dem Abschalten der Versorgungsspannung noch vorhanden sind und nach dem Wiederherstellen der Versorgungsspannung bei erneutem Programmstart wieder zur Verfügung stehen, dann benutzt man das EEPROM.&lt;br /&gt;
&lt;br /&gt;
Schreib- und Lesezugriffe auf den EEPROM-Speicher erfolgen über die im Modul eeprom.h der avr-libc definierten Funktionen. Mit diesen Funktionen können einzelne Bytes, Datenworte (16bit), Fließkommawerte (32-Bit, single-precision, float) und Datenblöcke geschrieben und gelesen werden. &lt;br /&gt;
&lt;br /&gt;
Diese Funktionen kümmern sich auch um diverse Details, die bei der Benutzung des EEPROMS normalerweise notwendig sind:&lt;br /&gt;
* EEPROM Operationen sind im Vergleich relativ langsam. Man muss daher darauf achten, dass eine vorhergehende Operation abgeschlossen ist, ehe die nächste Operation mit dem EEPROM gestartet wird. Die in der avr-libc implementierten Funktionen aus eeprom.h berücksichtigten dies. Soll beim Aufruf einer EEPROM-Funktion sicher gestellt werden, dass diese nicht intern in einer Warteschleife auf den Abschluss der vorherigen Operation wartet, kann vorher per eeprom_is_ready testen, ob der Zugriff auf den EEPROM-Speicher sofort möglich ist.&lt;br /&gt;
* Es ist darauf zu achten, dass die EEPROM Funktionen nicht durch einen Interrupt unterbrochen werden können. Einige Phasen des Zugriffs sind zeitkritisch und müssen in einer definierten Anzahl Takte durchgeführt werden. Durch einen unterbrechenden Interrupt würde diese Restriktion nicht mehr eingehalten. Auch dieses Detail wird von den avr-libc Funktionen berücksichtigt, so dass man sich als C Programmierer nicht darum kümmern muss. 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;
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. Dies gilt für jede einzelne Zelle. &lt;br /&gt;
&lt;br /&gt;
Bei geschickter Programmierung (z.&amp;amp;nbsp;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 gesamten EEPROM-Speicher, erreichen. Auf jeden Fall sollte man aber eine Abschätzung über die zu erwartende Lebensdauer des EEPROM durchführen. Wird ein Wert im EEPROM im Durchschnitt nur einmal pro Woche verändert, wird die garantierte Anzahl der Schreibzyklen innerhalb der voraussichtlichen Verwendungszeit des Controllers wahrscheinlich nicht erreicht. In diesem Fall lohnt es sich daher nicht, erweiterte Programmfunktionen zu implementieren, mit denen die Anzahl der Schreibzugriffe minimiert wird. &lt;br /&gt;
&lt;br /&gt;
Eine weitere Möglichkeit Schreibzyklen einzusparen besteht darin, dass geprüft wird, ob im EEPROM bereits der zu speichernde Wert enthalten ist und nur veränderte Werte zu schreiben. In aktuelleren Versionen der avr-libc sind bereits Funktionen enthalten, die solche Prüfungen enthalten (eeprom_update_*).&lt;br /&gt;
&lt;br /&gt;
Lesezugriffe können beliebig oft durchgeführt werden. Sie unterliegen keinen Einschränkungen in Bezug auf deren Anzahl. &lt;br /&gt;
&lt;br /&gt;
=== EEMEM ===&lt;br /&gt;
Um eine Variable im EEPROM anzulegen, stellt die avr-libc das Makro EEMEM zur Verfügung:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/eeprom.h&amp;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-Array */&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;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die grundsätzliche Vorgehensweise ist identisch zur Verwendung von PROGMEM. Auch hier erzeugt man sich spezielle attributierte Variablen (EEMEM erledigt das), die vom Compiler/Linker nicht wie normale Variablen behandelt werden. Compiler/Linker kümmern sich zwar darum, dass diesen Variablen eine Adresse zugewiesen wird, diese Adresse ist dann aber die Adresse der &#039;Variablen&#039; im EEPROM. Um die dort gespeicherten Werte zu lesen bzw. zu schreiben, übergibt man diese Adresse an spezielle Funktionen, die die entsprechenden Werte aus dem EEPROM holen bzw. das EEPROM neu beschreiben.&lt;br /&gt;
&lt;br /&gt;
Die mittels EEMEM erzeugten &#039;Variablen&#039; sind also mehr als Platzhalter zu verstehen, denn als echte Variablen. Es geht nur darum, im C Programm symbolische Namen zur Verfügung zu haben, anstatt mit echten EEPROM Adressen hantieren zu müssen - etwas das grundsätzlich aber auch genauso gut möglich ist. Nur muss man sich in diesem Fall dann selbst darum kümmern, dass mehrere &#039;Variablen&#039; ohne Überschneidung im EEPROM angeordnet werden.&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;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define EEPROM_DEF 0xFF&lt;br /&gt;
&lt;br /&gt;
void eeprom_example (void)&lt;br /&gt;
{&lt;br /&gt;
    uint8_t myByte;&lt;br /&gt;
&lt;br /&gt;
    // myByte lesen (Wert = 123)&lt;br /&gt;
    myByte = eeprom_read_byte (&amp;amp;eeFooByte);&lt;br /&gt;
&lt;br /&gt;
    // der Wert 99 wird im EEPROM an die Adresse der&lt;br /&gt;
    // Variablen eeFooByte geschrieben&lt;br /&gt;
    myByte = 99;&lt;br /&gt;
    eeprom_write_byte(&amp;amp;eeFooByte, myByte); // schreiben&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;
    // Beispiel fuer eeprom_update_byte: die EEPROM-Zelle wird nur&lt;br /&gt;
    // dann beschrieben, wenn deren Inhalt sich vom Parameterwert&lt;br /&gt;
    // unterscheidet. In diesem Beispiel erfolgt also kein Schreib-&lt;br /&gt;
    // zugriff, da die Werte gleich sind.&lt;br /&gt;
    eeprom_update_byte(&amp;amp;eeFooByte, myByte);&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;
    uint8_t fooByteDefault = 222;&lt;br /&gt;
    if ((myByte = eeprom_read_byte (&amp;amp;eeFooByte)) == EEPROM_DEF)&lt;br /&gt;
    {&lt;br /&gt;
        myByte = fooByteDefault;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&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;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
    // lesen&lt;br /&gt;
    uint16_t myWord = eeprom_read_word (&amp;amp;eeFooWord);&lt;br /&gt;
&lt;br /&gt;
    // schreiben&lt;br /&gt;
    eeprom_write_word (&amp;amp;eeFooWord, 2222);&lt;br /&gt;
&amp;lt;/syntaxhighlight&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 &amp;lt;code&amp;gt;eeprom_read_block()&amp;lt;/code&amp;gt; bzw. &amp;lt;code&amp;gt;eeprom_write_block()&amp;lt;/code&amp;gt;. Die Funktionen erwarten drei Parameter: die Adresse der Quell- bzw. Zieldaten im RAM, die EEPROM-Addresse und die Länge des Datenblocks in Bytes als &amp;lt;code&amp;gt;size_t&amp;lt;/code&amp;gt;.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
uint8_t  myByteBuffer[3];&lt;br /&gt;
uint16_t myWordBuffer[4];&lt;br /&gt;
&lt;br /&gt;
void eeprom_block_example (void)&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 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 16-Bit Array */&lt;br /&gt;
    eeprom_read_block (myWordBuffer, eeFooWordArray1, sizeof(myWordBuffer));&lt;br /&gt;
&lt;br /&gt;
    /* Datenblock in EEPROM schreiben */&lt;br /&gt;
    eeprom_write_block (myByteBuffer, eeFooByteArray1, sizeof(myByteBuffer));&lt;br /&gt;
    eeprom_write_block (myWordBuffer, eeFooWordArray1, sizeof(myWordBuffer));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Fließkommawerte lesen/schreiben ===&lt;br /&gt;
&lt;br /&gt;
In der avr-libc stehen auch EEPROM-Funktionen für Variablen des Typs float (Fließkommazahlen mit &amp;quot;einfacher&amp;quot; Genauigkeit) zur Verfügung.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/eeprom.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
float eeFloat EEMEM = 12.34f;&lt;br /&gt;
&lt;br /&gt;
float void eeprom_float_example(float value)&lt;br /&gt;
{&lt;br /&gt;
   /* float in EEPROM schreiben */&lt;br /&gt;
   eeprom_write_float(&amp;amp;eeFloat, value);&lt;br /&gt;
&lt;br /&gt;
   /* float aus EEPROM lesen */&lt;br /&gt;
   return  eeprom_read_float(&amp;amp;eeFloat);&lt;br /&gt;
}&amp;lt;/syntaxhighlight&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 Variablendeklarationen abgeleitete EEPROM-Inhalt in eine Datei geschrieben werden. Die übliche Dateiendung ist .eep, Daten im Intel Hex-Format. Damit können Standardwerte für den EEPROM-Inhalt im Quellcode definiert werden. &lt;br /&gt;
&lt;br /&gt;
Makefiles nach WinAVR/MFile-Vorlage enthalten bereits die notwendigen Einstellungen, siehe dazu die Erläuterungen im [[AVR-GCC-Tutorial/Exkurs Makefiles|Exkurs Makefiles]].&lt;br /&gt;
&lt;br /&gt;
Der Inhalt der eep-Datei muss ebenfalls zum Mikrocontroller übertragen werden, 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&amp;lt;ref&amp;gt;vgl. Datenblatt Abschnitt Fuse Bits&amp;lt;/ref&amp;gt; nicht die korrekten Werte:&lt;br /&gt;
; EESAVE = 0 (programmed): Die Daten im EEPROM bleiben erhalten. Werden sie nicht neu geschrieben, so enthält das EEPROM evtl. Daten, die nicht mehr zum Programm passen.&lt;br /&gt;
; EESAVE = 1 (unprogrammed): Beim Programmieren werden die Daten im EEPROM gelöscht, also auf 0xff gesetzt.&lt;br /&gt;
&lt;br /&gt;
Als Sicherung kann man im Programm nochmals die Standardwerte vorhalten, beim Lesen auf 0xFF prüfen und gegebenenfalls einen Standardwert nutzen.&lt;br /&gt;
&lt;br /&gt;
=== Direkter Zugriff auf EEPROM-Adressen ===&lt;br /&gt;
&lt;br /&gt;
Will man direkt auf bestimmte EEPROM Adressen zugreifen, dann sind folgende Funktionen hilfreich, um sich die Typecasts zu ersparen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/eeprom.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
// Byte aus dem EEPROM lesen&lt;br /&gt;
uint8_t EEPReadByte(uint16_t addr)&lt;br /&gt;
{&lt;br /&gt;
  return eeprom_read_byte((uint8_t *)addr);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Byte in das EEPROM schreiben&lt;br /&gt;
void EEPWriteByte(uint16_t addr, uint8_t val)&lt;br /&gt;
{&lt;br /&gt;
  eeprom_write_byte((uint8_t *)addr, val);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
oder als Makro:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define   EEPReadByte(addr)         eeprom_read_byte((uint8_t *)addr)     &lt;br /&gt;
#define   EEPWriteByte(addr, val)   eeprom_write_byte((uint8_t *)addr, val)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Verwendung:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
EEPWriteByte(0x20, 128);   // Byte an die Adresse 0x20 schreiben&lt;br /&gt;
...&lt;br /&gt;
Val=EEPReadByte(0x20);     // EEPROM-Wert von Adresse 0x20 lesen&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== EEPROM Register ===&lt;br /&gt;
Um das EEPROM anzusteuern, sind drei Register von Bedeutung:&lt;br /&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;
;EEDR: Hier werden die Daten eingetragen, die geschrieben werden sollen, bzw. es enthält die gelesenen Daten.&lt;br /&gt;
;EECR: Ist das Kontrollregister für das EEPROM&lt;br /&gt;
&lt;br /&gt;
Das EECR steuert den Zugriff auf das EEPROM und ist wie folgt aufgebaut:&lt;br /&gt;
&lt;br /&gt;
:{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align:center&amp;quot;&lt;br /&gt;
|+ &#039;&#039;&#039;Aufbau des EECR-Registers&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
!Bit&lt;br /&gt;
| 7 || 6 || 5 || 4 || 3 || 2 || 1 || 0&lt;br /&gt;
|-&lt;br /&gt;
! Name&lt;br /&gt;
| - || - || - ||- || EERIE || EEMWE || EEWE || EERE&lt;br /&gt;
|-&lt;br /&gt;
! Read/Write&lt;br /&gt;
| R || R || R || R || R/W || R/W || R/W || R/W&lt;br /&gt;
|-&lt;br /&gt;
!Init Value&lt;br /&gt;
| 0 || 0 || 0 || 0 || 0 || 0 || 0 || 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Bedeutung der Bits&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
;Bit 4-7: nicht belegt&lt;br /&gt;
&lt;br /&gt;
;Bit 3 (EERIE): &#039;&#039;EEPROM Ready Interrupt Enable&#039;&#039;: 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.&lt;br /&gt;
&lt;br /&gt;
;Bit 2 EEMWE): &#039;&#039;EEPROM Master Write Enable&#039;&#039;: Dieses Bit bestimmt, dass, 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. 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.&lt;br /&gt;
&lt;br /&gt;
;Bit 1 (EEWE): &#039;&#039;EEPROM Write Enable&#039;&#039;: 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. Ein Schreibvorgang sieht typischerweise wie folgt aus:&lt;br /&gt;
:# EEPROM-Bereitschaft abwarten (EEWE=0) &lt;br /&gt;
:# Adresse übergeben an EEAR&lt;br /&gt;
:# Daten übergeben an EEDR&lt;br /&gt;
:# Schreibvorgang auslösen in EECR mit Bit EEMWE=1 und EEWE=1&lt;br /&gt;
:# (Optional) Warten, bis Schreibvorgang abgeschlossen ist&lt;br /&gt;
&lt;br /&gt;
;Bit 0 EERE: &#039;&#039;EEPROM Read Enable&#039;&#039;: 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- und Schreibbefehle wieder bereit. Ein typischer Lesevorgang kann wie folgt aufgebaut sein:&lt;br /&gt;
:# Bereitschaft zum Lesen prüfen (EEWE=0)&lt;br /&gt;
:# Adresse übergeben an EEAR&lt;br /&gt;
:# Lesezyklus auslösen mit EERE = 1&lt;br /&gt;
:# Warten, bis Lesevorgang abgeschlossen EERE = 0&lt;br /&gt;
:# Daten abholen aus EEDR&lt;br /&gt;
&lt;br /&gt;
= Die Nutzung von sprintf und printf =&lt;br /&gt;
&lt;br /&gt;
Um komfortabel, d.h. formatiert, Ausgaben auf ein Display oder die serielle Schnittstelle zu tätigen, bieten sich &#039;&#039;&#039;sprintf&#039;&#039;&#039; oder &#039;&#039;&#039;printf&#039;&#039;&#039; an. Alle *printf-Varianten sind jedoch ziemlich speicherintensiv und der Einsatz in einem Mikrocontroller mit knappem Speicher muss sorgsam abgewogen werden.&lt;br /&gt;
&lt;br /&gt;
Bei &#039;&#039;&#039;sprintf&#039;&#039;&#039; wird die Ausgabe zunächst in einem Puffer vorbereitet und anschließend mit einfachen Funktionen zeichenweise ausgegeben. Es liegt in der Verantwortung des Programmierers, genügend Platz im Puffer für die erwarteten Zeichen bereitzuhalten.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&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;
// 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;
// Ausgabe eines unsigned Integerwertes&lt;br /&gt;
void uart_puti( uint16_t value )&lt;br /&gt;
{&lt;br /&gt;
    uint8_t puffer[20];&lt;br /&gt;
&lt;br /&gt;
    sprintf( puffer, &amp;quot;Zählerstand: %u&amp;quot;, value );&lt;br /&gt;
    uart_puts( puffer );&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;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Eine weitere elegante Möglichkeit besteht darin, den STREAM stdout (Standardausgabe) auf eine eigene Ausgabefunktion umzuleiten. Dazu wird dem Ausgabemechanismus der C-Bibliothek eine neue Ausgabefunktion bekannt gemacht, deren Aufgabe es ist, ein einzelnes Zeichen auszugeben. Wohin die Ausgabe dann tatsächlich stattfindet, ist Sache der Ausgabefunktion. Im Beispiel unten wird auf UART ausgegeben. Alle anderen, höheren Funktionen wie z.&amp;amp;nbsp;B. &#039;&#039;&#039;printf&#039;&#039;&#039;, greifen letztendlich auf diese primitive Ausgabefunktion zurück. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&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;
&lt;br /&gt;
// a. Deklaration der primitiven Ausgabefunktion&lt;br /&gt;
int uart_putchar(char c, FILE *stream);&lt;br /&gt;
&lt;br /&gt;
// b. Umleiten der Standardausgabe stdout (Teil 1)&lt;br /&gt;
static FILE mystdout = FDEV_SETUP_STREAM( uart_putchar, NULL, _FDEV_SETUP_WRITE );&lt;br /&gt;
&lt;br /&gt;
// c. Definition der Ausgabefunktion&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;
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 main(void)&lt;br /&gt;
{&lt;br /&gt;
    int16_t antwort = 42;&lt;br /&gt;
    uart_init();&lt;br /&gt;
&lt;br /&gt;
    // b. Umleiten der Standardausgabe stdout (Teil 2)&lt;br /&gt;
    stdout = &amp;amp;mystdout;&lt;br /&gt;
&lt;br /&gt;
    // Anwendung&lt;br /&gt;
    printf( &amp;quot;Die Antwort ist %d.\n&amp;quot;, antwort );&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;/syntaxhighlight&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;
= Anmerkungen =&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= TODO =&lt;br /&gt;
* Aktualisierung Register- und Bitbeschreibungen an aktuelle AVR&lt;br /&gt;
* &amp;quot;naked&amp;quot;-Funktionen&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:avr-gcc Tutorial| ]]&lt;/div&gt;</summary>
		<author><name>Df2au</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=AVR-Tutorial:_Servo&amp;diff=83046</id>
		<title>AVR-Tutorial: Servo</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=AVR-Tutorial:_Servo&amp;diff=83046"/>
		<updated>2014-05-18T07:34:53Z</updated>

		<summary type="html">&lt;p&gt;Df2au: Typo&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Die Seite ist noch im Entstehen und, bis sie einigermaßen vollständig ist, noch kein Teil des Tutorials&lt;br /&gt;
&lt;br /&gt;
= Vorbemerkung =&lt;br /&gt;
Dieses Tutorial überschneidet sich inhaltlich mit dem Artikel [[Modellbauservo_Ansteuerung]]. Wir beschreiben hier die grundsätzliche Vorgehensweise zur Ansteuerung von Servos und geben ein Beispiel in Assembler, während der genannte Artikel ein in C formuliertes Beispiel zur Ansteuerung mehrerer Servos liefert.&lt;br /&gt;
&lt;br /&gt;
= Allgemeines über Servos =&lt;br /&gt;
&lt;br /&gt;
= Stromversorgung =&lt;br /&gt;
Werden Servos an einem µC betrieben, so ist es am Besten, sie aus einer eigenen Stromquelle (Akku) zu betreiben. Manche Servos erzeugen kleine Störungen auf der Versorgungsspannung, die einen µC durchaus zum Abstürzen bringen können. Muss man Servos gemeinsam mit einem µC von derselben Stromquelle betreiben, so sollte man sich gleich darauf einrichten, diesen Störimpulsen mit Kondensatoren zu Leibe rücken zu müssen. Unter Umständen ist hier auch eine Mischung aus kleinen, schnellen Kondensatoren (100nF) und etwas größeren, aber dafür auch langsameren Kondensatoren (einige µF) notwendig.&lt;br /&gt;
&lt;br /&gt;
Die eindeutig beste Option ist es aber, die Servos strommäßig vom µC zu entkoppeln und ihnen ihre eigene Stromquelle zu geben. Servos sind nicht besonders heikel. Auch im Modellbau müssen sie mit unterschiedlichen Spannungen zurechtkommen, bedingt durch die dort übliche Versorgung aus Akkus, die im Laufe der Betriebszeit des Modells natürlich durch die Entladung ihre Voltzahl immer weiter reduzieren. Im Modellbau werden Akkus mit 4 oder 5 Zellen verwendet, sodass Servos mit Spannungen von ca. 4V bis hinauf zu ca. 6V zurecht kommen müssen, wobei randvolle Akkus diese 6V schon auch mal überschreiten können. Bei sinkenden Spannungslage verlieren Servos naturgemäß etwas an Kraft bzw. werden in ihrer Stellgeschwindigkeit unter Umständen langsamer.&lt;br /&gt;
&lt;br /&gt;
Die Servos werden dann nur mit ihrer Masseleitung und natürlich mit ihrer Impulsleitung mit dem µC verbunden.&lt;br /&gt;
&lt;br /&gt;
= Das Servo-Impulstelegram =&lt;br /&gt;
Das Signal, das an den Servo geschickt wird, hat eine Länge von ungefähr 20ms. Diese 20ms sind nicht besonders kritisch und sind ein Überbleibsel von der Technik mit der mehrere Kanäle über die Funkstrecke einer Fernsteuerung übertragen werden. Für das Servo wichtig ist die Impulsdauer in der ersten Phase eines Servosignals. Nominell ist dieser Impuls zwischen 1ms und 2ms lang. Wobei das jeweils die Endstellungen des Servos sind, an denen es noch nicht mechanisch begrenzt wird. Eine Pulslänge von 1.5ms wäre dann Servomittelstellung. Für die Positionsauswertung des Servos haben die 20ms Wiederholdauer keine besondere Bedeutung, sieht man einmal davon ab, dass ein Servo bei kürzeren Zeiten entsprechend öfter Positionsimpulse bekommt und daher auch öfter die Position gegebenenfalls korrigiert, was möglicherweise in einem etwas höheren Stromverbrauch resultiert.&lt;br /&gt;
&lt;br /&gt;
Umgekehrt lässt sich definitiv Strom sparen, indem die Pulse ganz ausgesetzt werden: Der Servo bleibt in der Position, in der er sich gerade befindet - korrigiert sich aber auch nicht mehr. Kommen die Impulse selten, also z.B. alle 50ms, läuft der Servo langsamer in seine Zielposition (praktische Erfahrungen, vermutlich nirgends spezifiziert). Dieses Verhalten lässt sich nutzen, um die manchmal unerwünschten ruckartigen Bewegungen eines Servos abzumildern.&lt;br /&gt;
&lt;br /&gt;
[[Bild:Servo.gif|framed|center| Servo Impulsdiagramm]]&lt;br /&gt;
&lt;br /&gt;
Den meisten Servos macht es nichts aus, wenn die Länge des Servoprotokolls anstelle von 20ms auf zb 10ms verkürzt wird. Bei der Generierung des Servosignals muss man daher den 20ms keine besondere Beachtung schenken. Eine kleine Pause nach dem eigentlichen Positionssignal reicht in den meisten Fällen aus und es spielt keine allzugroße Rolle, wie lange diese Pause tatsächlich ist. Generiert man das Imulsdiagramm zb. mit einem Timer, so orientiert man sich daher daran, dass man den 1.0 - 2.0ms Puls gut generieren kann und nicht an den 20ms.&lt;br /&gt;
&lt;br /&gt;
Reale Servos haben allerdings in den Endstellungen noch Reserven, so dass man bei vielen Servos auch Pulslängen von 0.9 bis 2.1 oder sogar noch kleinere/größere Werte benutzen kann. Allerdings sollte man hier etwas Vorsicht walten lassen. Wenn das Servo unbelastet in einer der Endstellungen deutlich zu &#039;knurren&#039; anfängt, dann hat man es übertrieben. Das Servo ist an seinen mechanischen Endanschlag gefahren worden und auf Dauer wird das der Motor bzw. das Getriebe nicht aushalten.&lt;br /&gt;
&lt;br /&gt;
= Programmierung =&lt;br /&gt;
== einfache Servoansteuerung mittels Warteschleifen ==&lt;br /&gt;
&lt;br /&gt;
Im folgenden Programm wurden einfache Warteschleifen auf die im Tutorial übliche Taktfrequen von 4Mhz angepasst, so dass sich die typischen Servo-Pulsdauern ergeben. Ein am Port D, beliebiger Pin angeschlossenes Servo dreht damit ständig vor und zurück. Die Servoposition kann durch laden eines Wertes im Bereich 1 bis ca 160 in das Register r18 und anschliessendem Aufruf von servoPuls in einen Puls für ein Servo umgewandelt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;avrasm&amp;quot;&amp;gt; &lt;br /&gt;
.include &amp;quot;m8def.inc&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
.equ XTAL = 4000000&lt;br /&gt;
 &lt;br /&gt;
         rjmp    init&lt;br /&gt;
&lt;br /&gt;
init:&lt;br /&gt;
          ldi      r16, HIGH(RAMEND)     ; Stackpointer initialisieren&lt;br /&gt;
          out      SPH, r16&lt;br /&gt;
          ldi      r16, LOW(RAMEND)&lt;br /&gt;
          out      SPL, r16&lt;br /&gt;
&lt;br /&gt;
          ldi r16, 0xFF&lt;br /&gt;
          out DDRD, r16&lt;br /&gt;
&lt;br /&gt;
loop:     ldi  r18, 0&lt;br /&gt;
           &lt;br /&gt;
loop1:    inc r18&lt;br /&gt;
          cpi r18, 160&lt;br /&gt;
          breq loop2&lt;br /&gt;
&lt;br /&gt;
          rcall servoPuls&lt;br /&gt;
&lt;br /&gt;
          rjmp loop1&lt;br /&gt;
&lt;br /&gt;
loop2:    dec r18&lt;br /&gt;
          cpi r18, 0&lt;br /&gt;
          breq loop1&lt;br /&gt;
&lt;br /&gt;
          rcall servoPuls&lt;br /&gt;
&lt;br /&gt;
          rjmp loop2&lt;br /&gt;
&lt;br /&gt;
servoPuls:&lt;br /&gt;
          push r18&lt;br /&gt;
          ldi r16, 0xFF         ; Ausgabepin auf 1&lt;br /&gt;
          out PORTD, r16&lt;br /&gt;
          &lt;br /&gt;
          rcall wait_puls        ; die Wartezeit abwarten&lt;br /&gt;
&lt;br /&gt;
          ldi r16, 0x00         ; Ausgabepin wieder auf 0&lt;br /&gt;
          out PORTD, r16&lt;br /&gt;
&lt;br /&gt;
          rcall wait_pause       ; und die Pause hinten nach abwarten&lt;br /&gt;
          pop r18&lt;br /&gt;
          ret&lt;br /&gt;
;&lt;br /&gt;
wait_pause:&lt;br /&gt;
          ldi r19, 15&lt;br /&gt;
w_paus_1: rcall wait_1ms&lt;br /&gt;
          dec r19&lt;br /&gt;
          brne w_paus_1&lt;br /&gt;
          ret&lt;br /&gt;
;&lt;br /&gt;
wait_1ms: ldi r18, 10           ; 1 Millisekunde warten&lt;br /&gt;
w_loop2:  ldi r17, 132          ; Es muessen bei 4 Mhz 4000 Zyklen verbraten werden&lt;br /&gt;
w_loop1:  dec r17               ; die innerste Schleife umfasst 3 Takte und wird 132&lt;br /&gt;
          brne w_loop1          ; mal abgearbeitet: 132 * 3 = 396 Takte&lt;br /&gt;
          dec r18               ; dazu noch 4 Takte für die äussere Schleife = 400&lt;br /&gt;
          brne w_loop2          ; 10 Wiederholungen: 4000 Takte&lt;br /&gt;
          ret                   ; der ret ist nicht eingerechnet&lt;br /&gt;
;&lt;br /&gt;
; r18 muss mit der Anzahl der Widerholungen belegt werden&lt;br /&gt;
; vernünftige Werte laufen von 1 bis ca 160&lt;br /&gt;
wait_puls:&lt;br /&gt;
w_loop4:  ldi r17, 10           ; die variable Zeit abwarten&lt;br /&gt;
w_loop3:  dec r17&lt;br /&gt;
          brne w_loop3&lt;br /&gt;
          dec r18&lt;br /&gt;
          brne w_loop4&lt;br /&gt;
&lt;br /&gt;
          rcall wait_1ms         ; und noch 1 Millisekunde drauflegen&lt;br /&gt;
          ret&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wie meistens gilt auch hier: Warteschleifen sind in der Programmierung nicht erwünscht. Der Prozessor kann in diesen Warteschleifen nichts anderes machen. Etwas ausgeklügeltere Programme, bei denen mehrere Dinge gleichzeitig gemacht werden sollen, sind damit nicht vernünftig realisierbar.&lt;br /&gt;
Daher sollte die Methode mittels Warteschleifen nur dann benutzt werden, wenn dies nicht benötigt wird, wie zb einem simplen Servotester, bei dem man die Servoposition zb durch Auslesen eines Potis mit dem ADC festlegt.&lt;br /&gt;
&lt;br /&gt;
Ausserdem ist die Berechnung der Warteschleifen auf eine bestimmte Taktfrequenz unangenehm und fehleranfällig :-)&lt;br /&gt;
&lt;br /&gt;
== einfache Servoansteuerung mittels Timer ==&lt;br /&gt;
&lt;br /&gt;
=== Ansteuerung mit dem 16-Bit Timer 1 ===&lt;br /&gt;
Im Prinzip programmiert man sich hier eine Software-PWM. Beginnt der Timer bei 0 zu zählen (nach Overflow Interrupt oder Compare Match Interrupt im CTC-Modus (Clear Timer on Compare)), so setzt man den gewünschten Ausgangspin auf 1. Ein Compare Match Register wird so mit einem berechneten Wert versorgt, daß es nach der gewünschten Pulszeit einen Interrupt auslöst. In der zugehörigen Interrupt Routine wird der Pin dann wieder auf 0 gesetzt.&lt;br /&gt;
&lt;br /&gt;
Auch hier wieder: Der Vorteiler des Timers wird so eingestellt, dass man die Pulszeit gut mit dem Compare Match erreichen kann, die nachfolgende Pause, bis der Timer dann seinen Overflow hat (oder den CTC Clear macht) ist von untergeordneter Bedeutung. Man nimmt was vom Zählbereich des Timers übrig bleibt. Beispiel:&lt;br /&gt;
* F_CPU = 16 MHz&lt;br /&gt;
* Vorteiler = 8&lt;br /&gt;
* 16 Bit Registerbreite = Overflow nach 2^16 Zyklen&lt;br /&gt;
* CTC-Modus *aus*, steigende Flanke durch Overflow-Interrupt erzeugen&lt;br /&gt;
* Overflow-Interrupt: 16 MHz / 2^16 / 8 = 30,52 Hz, 32,8 ms, Ausgangspin auf 1 setzen&lt;br /&gt;
* Servostellung links .. rechts = Pulsbreite 1 .. 2 ms = 1 s / 16000000 * 8 * OCR1; OCR1 = 2000 .. 4000&lt;br /&gt;
* Output-Compare-Match-Interrupt: Ausgangspin auf 0 setzen&lt;br /&gt;
&lt;br /&gt;
Alternativ zum Overflow-Interrupt könnte, um eine Gesamtpulsbreite von exakt 20 ms zu erreichen, z.B. im Output-Compare-Match-Interrupt (sofern nur einer pro Timer verfügbar ist) im Wechsel&lt;br /&gt;
* der Ausgangspin auf 1 und OCR1 auf 1000 .. 2000 gesetzt sowie das CTC-Bit gelöscht werden&lt;br /&gt;
* der Ausgangspin auf 0 und OCR1 auf 40000 gesetzt sowie das CTC-Bit gesetzt werden&lt;br /&gt;
Neuere ATmegas verfügen über zwei Output-Compare-Register (Suffix &#039;&#039;A&#039;&#039; und &#039;&#039;B&#039;&#039;) ebenso wie zwei OCR-Interrupt-Vektoren pro Timer, wobei das CTC-Bit nur bei einem Match mit dem Output-Compare-Register &#039;&#039;A&#039;&#039; wirkt. Damit können für die Pulserzeugung zwei getrennte Interrupt-Handler angelegt werden, und ein Umbelegen von OCR und CTC-Bit entfällt.&lt;br /&gt;
&lt;br /&gt;
=== Ansteuerung mit dem 8-Bit Timer 2 ===&lt;br /&gt;
&lt;br /&gt;
Mit einem 8 Bit Timer ist es gar nicht so einfach, sowohl die Zeiten für den Servopuls als auch die für die Pause danach unter einen Hut zu bringen. Abhilfe schafft ein Trick.&lt;br /&gt;
&lt;br /&gt;
Der Timer wird so eingestellt, dass sich der Servopuls gut erzeugen lässt. Dazu wird der Timer in den CTC Modus gestellt und das zugehörige Vergleichsregister so eingestellt, dass sich die entsprechenden Interrupts zeitlich so ergeben, wie es für einen Puls benötigt wird. In einem Aufruf des Interrupts wird der Ausgangspin für das Servo auf 1 gestellt, im nächsten wird er wieder auf 0 gestellt. Die kleine Pause bis zum nächsten Servoimpuls wird so erzeugt, dass eine gewisse Anzahl an Interrupt Aufrufen einfach nichts gemacht wird. Ähnlich wie bei einer PWM wird also auch hier wieder ein Zähler installiert, der die Anzahl der Interrupt Aufrufe mitzählt und immer wieder auf 0 zurückgestellt wird.&lt;br /&gt;
&lt;br /&gt;
Die eigentliche Servoposition steht im Register OCR2. Rein rechnerisch beträgt ihr Wertebereich:&lt;br /&gt;
&lt;br /&gt;
1ms      4000000 / 64 / 1000     OCR2 =  62.5&lt;br /&gt;
&lt;br /&gt;
2ms      4000000 / 64 /  500     OCR2 = 125&lt;br /&gt;
&lt;br /&gt;
mit einer Mittelstellung von ( 62.5 + 125 ) / 2 = 93.75&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;avrasm&amp;quot;&amp;gt; &lt;br /&gt;
.include &amp;quot;m16def.inc&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
.equ XTAL = 4000000&lt;br /&gt;
 &lt;br /&gt;
          rjmp    init&lt;br /&gt;
&lt;br /&gt;
.org OC2addr&lt;br /&gt;
          rjmp    Compare_vect&lt;br /&gt;
&lt;br /&gt;
init: &lt;br /&gt;
          ldi      r16, HIGH(RAMEND)     ; Stackpointer initialisieren&lt;br /&gt;
          out      SPH, r16&lt;br /&gt;
          ldi      r16, LOW(RAMEND)&lt;br /&gt;
          out      SPL, r16&lt;br /&gt;
&lt;br /&gt;
          ldi  r16, 0x80&lt;br /&gt;
          out  DDRB, r16                ; Servo Ausgangspin -&amp;gt; Output&lt;br /&gt;
&lt;br /&gt;
          ldi  r17, 0                   ; Software-Zähler&lt;br /&gt;
            &lt;br /&gt;
          ldi  r16, 120&lt;br /&gt;
          out  OCR2, r16                ; OCR2 ist der Servowert&lt;br /&gt;
&lt;br /&gt;
          ldi  r16, 1&amp;lt;&amp;lt;OCIE2&lt;br /&gt;
          out  TIMSK, r16&lt;br /&gt;
&lt;br /&gt;
          ldi  r16, (1&amp;lt;&amp;lt;WGM21) | (1&amp;lt;&amp;lt;CS22) ; CTC, Prescaler: 64&lt;br /&gt;
          out  TCCR2, r16&lt;br /&gt;
&lt;br /&gt;
          sei&lt;br /&gt;
&lt;br /&gt;
main:&lt;br /&gt;
          rjmp main&lt;br /&gt;
&lt;br /&gt;
Compare_vect:&lt;br /&gt;
          in   r18, SREG&lt;br /&gt;
          inc  r17&lt;br /&gt;
          cpi  r17, 1&lt;br /&gt;
          breq PulsOn&lt;br /&gt;
          cpi  r17, 2&lt;br /&gt;
          breq PulsOff&lt;br /&gt;
          cpi  r17, 10&lt;br /&gt;
          brne return&lt;br /&gt;
          ldi  r17, 0&lt;br /&gt;
return:   out  SREG, r18&lt;br /&gt;
          reti&lt;br /&gt;
&lt;br /&gt;
PulsOn:   sbi  PORTB, 0&lt;br /&gt;
          rjmp return&lt;br /&gt;
&lt;br /&gt;
PulsOff:  cbi  PORTB, 0&lt;br /&gt;
          rjmp return&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Ansteuerung mehrerer Servos mittels Timer ==&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
{{Navigation_zurückhochvor|&lt;br /&gt;
zurücktext=7-Segment-Anzeige|&lt;br /&gt;
zurücklink=AVR-Tutorial: 7-Segment-Anzeige|&lt;br /&gt;
hochtext=Inhaltsverzeichnis|&lt;br /&gt;
hochlink=AVR-Tutorial|&lt;br /&gt;
vortext=Watchdog|&lt;br /&gt;
vorlink=AVR-Tutorial: Watchdog}}&lt;br /&gt;
&lt;br /&gt;
[[Category:AVR-Tutorial|Servo]]&lt;br /&gt;
[[Category:Servos]]&lt;/div&gt;</summary>
		<author><name>Df2au</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=Sonnenfolger_/_Heliostat&amp;diff=82467</id>
		<title>Sonnenfolger / Heliostat</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=Sonnenfolger_/_Heliostat&amp;diff=82467"/>
		<updated>2014-04-02T16:38:27Z</updated>

		<summary type="html">&lt;p&gt;Df2au: /* Heliostat Software */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Einleitung ==&lt;br /&gt;
===Allgemeines===&lt;br /&gt;
Ursache für den Tageslauf der Sonne ist die Rotation der Erde um sich selbst. Die Höhen-Änderung der Sonnenbahn resultiert aus dem jährlichen Umlauf der Erde (Erdbahn) um die Sonne in Kombination mit der im Weltall annähernd fixen Richtung der gegen die Erdbahn geneigten Erdachse (Schiefe der Ekliptik). (Quelle Wikipedia)&lt;br /&gt;
&lt;br /&gt;
Würde man die Sonne an jedem Tag des Jahres immer genau um 12:00 Uhr Mittags (DCF77 Uhr) fotografieren und die Fotos alle übereinander legen, erhielte man die Analemma-Figur mit zusätzlichen Sprüngen von einer Stunde Ende März und Ende Oktober. Dass heißt, eine Sonnenuhr geht bis zu 15 Minuten zuzüglich Sommerzeitverschiebung falsch, da die Sonne mal rechts und mal links von der Position steht, die man vereinfacht erwarten würde.&lt;br /&gt;
&lt;br /&gt;
[[Bild:Analemma_pattern_in_the_sky.jpg|400px]]&lt;br /&gt;
&lt;br /&gt;
(Foto Quelle Wikipedia)&lt;br /&gt;
&lt;br /&gt;
Wie alle sicherlich beobachtet haben, ändert sich je nach Jahreszeit und nach dem Breitengrad der Aufstellung der Solaranlage die Sonnenhöhe (Höhenwinkel, Azimuth) &lt;br /&gt;
&lt;br /&gt;
Weiterhin leben wir in einer recht großen Zeitzone vom östlichsten Zipfel von Norwegen bis nach Spanien. Daher kann die Sonne um 12:00 Uhr nicht überall genau im Süden stehen. Je nach Längengrad der Aufstellung der Solaranlage ändert sich die Himmelsrichtung für die Stellung der Sonne in der Mittagszeit. Hinzu kommt die Sommer- Winterzeitumstellung.&lt;br /&gt;
&lt;br /&gt;
===Lösungsansätze===&lt;br /&gt;
Durch eine Nachführung wird entweder eine Solarzelle genau zur Sonne ausgerichtet oder ein Spiegel lenkt das Sonnenlicht auf einen Zielpunkt. Der Spiegel muss dann auf der Winkelhalbierenden zwischen Sonnenstand und dem Ziel stehen.&lt;br /&gt;
&lt;br /&gt;
Es kann generell zwischen analogen Lösungen mit Messung der Helligkeit ohne Inteligenz,  Messung der Helligkeit mit Mikrocontrollerauswertung und Uhrzeitnachführungen mit Berechung der Sonnenposition unterscheiden. Die Berechnung der Sonnenposition ist durch die oben beschriebene Problematik recht aufwendig, hat aber den Vorteil, dass keine Optik sauber gehalten werden muss.&lt;br /&gt;
&lt;br /&gt;
==einachsige Nachführung==&lt;br /&gt;
Zur Nachführung einer Solarzelle oder thermischen Solarpanels kann auf die Nachführung in der vertikalen Achse verzichtet werden. Man spart Mechanik, verliert aber Leistungsausbeute.&lt;br /&gt;
&lt;br /&gt;
===Analog===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Bild:Lichtfolger_analog.png|400px]]&lt;br /&gt;
&lt;br /&gt;
hier eine der vielen analogen Lichtfolgerschaltungen. An den Ausgängen wird eine H-Brücke als Motortreiber und ein Getriebemotor angeschlossen.&lt;br /&gt;
&lt;br /&gt;
In der Schaltung befinden sich zwei Spannungsteiler. Zu einen die&lt;br /&gt;
Reihenschaltung aus den beiden LDR´s. Werden beide gleichmäßig&lt;br /&gt;
beleuchtet, teilt sich die Spannung gleichmäßig auf.&lt;br /&gt;
Die Spannung Vcc teilt sich an der Reihenschaltung der Widerstände in&lt;br /&gt;
drei Teile auf:&lt;br /&gt;
Spannung U1 über Poti R1 und R3, Spannung U2 über Poti R2 und die&lt;br /&gt;
Spannung U3 über R4.&lt;br /&gt;
&lt;br /&gt;
Die Spannung U2 ist die Hysterese bei der sich beide Ausgänge auf 0 V&lt;br /&gt;
Potential befinden.&lt;br /&gt;
Die Spannungen U1 und Vcc-U3 sind die Schaltpunkte.&lt;br /&gt;
&lt;br /&gt;
Google nach: Fensterkomparator&lt;br /&gt;
&lt;br /&gt;
===Mikrocontroller===&lt;br /&gt;
&lt;br /&gt;
[[Bild:Lichtfolger_Tiny.png|400px]]&lt;br /&gt;
&lt;br /&gt;
Ähnliche Signalbildung, aber Auswertung durch einen Tiny. Hier kann die Hysterese und Schaltverzögerungen per Software eingestellt werden.&lt;br /&gt;
&lt;br /&gt;
==zweiachsige Nachführung==&lt;br /&gt;
Nach einer Weile an Überlegung habe ich mich für die Lösung mit DCF 77 Uhr, Berechnung des Sonnenstandes und Schrittmotoren entschieden.&lt;br /&gt;
&lt;br /&gt;
===Hardware===&lt;br /&gt;
&lt;br /&gt;
[[Bild:Base_Board_L317_alles.png|400px]]&lt;br /&gt;
&lt;br /&gt;
Beim Anschluss der ISP Schnittstelle bin ich etwas vom &amp;quot;Kanda-Standard&amp;quot; abgewichen und nur Pin10 des Wannensteckers für Masse benutzt. Dadurch waren die Pins 8,6,4 noch für das LCD frei. Zum Programmieren benutze ich einen Adapter, der diese Pins isoliert, um einen Kurzschluss zu vermeiden. Der Vorteil, ich habe nur einen Stecker für das LCD und zur Programmierung.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Download Hardware:  [[Media:Heliostep Hardware.zip‎|download zip-File]]&lt;br /&gt;
&lt;br /&gt;
===Software===&lt;br /&gt;
Der Programmteil DCF77 Empfang ist von Ulrich Rading, die Sonnenstandsberechnung von Clueso hier aus dem Forum, die LCD Anzeige ist ebenfalls aus dem Forum.&lt;br /&gt;
Da möchte ich mich nicht mit falschen Federn schmücken. Aber es blieben noch genügend Herausfordeungen zum Testen und Probieren.&lt;br /&gt;
&lt;br /&gt;
* http://www.mikrocontroller.net/forum/codesammlung?filter=sonne*&lt;br /&gt;
* http://www.mikrocontroller.net/topic/111783&lt;br /&gt;
* http://www.mikrocontroller.net/topic/121049&lt;br /&gt;
&lt;br /&gt;
====Motortest Software====&lt;br /&gt;
Download Software zum Motortest:  [[Media:Heliostep 05 Motor Test.zip‎|download zip-File]]&lt;br /&gt;
&lt;br /&gt;
Fährt die Schrittmotre zuerst in die Homeposition. Fährt dann die Steppermotore bei Tastendruck jeweils 2000 Schritte vorwärts, bzw wieder zurück in die Homeposition.&lt;br /&gt;
&lt;br /&gt;
====Heliostat Software====&lt;br /&gt;
Download Software zur Steuerung:  [[Media:Heliostep_15.zip‎|download zip-File]]&lt;br /&gt;
&lt;br /&gt;
Wartet auf DCF Empfang, fährt den Heliostat in die Homeposition Down und Ost, berechnet die Sonnenposition alle Minute und fährt den Spiegel entsprechend der Berechnung.&lt;br /&gt;
&lt;br /&gt;
Während der Wartezeit auf den ersten gültigen DCF77 Empfang wird das Trägersignal als blinkende 1 oder 0 im Sekundentakt auf den LCD angezeigt. Dies eignet sich gut zur Ausrichtung der DCF Antenne.&lt;br /&gt;
&lt;br /&gt;
Nach dem ersten gültigen Empfang wird nochmals 20 Sekunden auf das Signal Sommer- oder Winterzeit gewartet.&lt;br /&gt;
Mit diesem Signal und der aktuellen Uhrzeit wird die UTC Zeit berechnet (MEZ - 1h, oder MESZ - 2h). Die aktuelle Zeit in UTC wird auf dem LCD in der ersten Zeile angezeigt.&lt;br /&gt;
&lt;br /&gt;
Mit der UTC Zeit und dem Standort des Heliostaten wird die Position der Sonne in Radiant berechnet. Die Elevation und der Azimut multipliziert mit jeweils einem Faktor ergeben die Anzahl der Schritte die der jeweilige Schrittmotor fahren muss. Die beiden Faktoren werden in der zweiten Zeile auf den LCD angezeigt.&lt;br /&gt;
&lt;br /&gt;
===Video Mechanik===&lt;br /&gt;
Hier noch ein kleiner Videofilm von der Mechanik:&lt;br /&gt;
&lt;br /&gt;
http://www.youtube.com/watch?v=s7gXmlWX7Ro&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
* http://de.wikipedia.org/wiki/Sonnenstand&lt;br /&gt;
* http://de.wikipedia.org/wiki/Heliostat&lt;br /&gt;
* Programm &amp;quot;Orbitron&amp;quot; http://www.stoff.pl/&lt;br /&gt;
* [http://people.ece.cornell.edu/land/courses/ece4760/FinalProjects/s2009/nw59_yt322/nw59_yt322/index.html Heliostat Skylight] (ECE 476 Final Project by Yinan Tang and Nana Wu)&lt;br /&gt;
* http://de.wikipedia.org/wiki/Windlast&lt;br /&gt;
&lt;br /&gt;
[[Category:AVR-Projekte]]&lt;br /&gt;
[[Kategorie:DCF77]]&lt;/div&gt;</summary>
		<author><name>Df2au</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=4000_Stellen_von_Pi_mit_ATtiny2313&amp;diff=82034</id>
		<title>4000 Stellen von Pi mit ATtiny2313</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=4000_Stellen_von_Pi_mit_ATtiny2313&amp;diff=82034"/>
		<updated>2014-03-12T18:02:00Z</updated>

		<summary type="html">&lt;p&gt;Df2au: Typos&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Bild:attiny2313.jpg|thumb|right|ATtiny2313 im [[IC-Gehäuseformen|DIL]]-Gehäuse]]&lt;br /&gt;
Als neulich im Foren nach einem&lt;br /&gt;
: &#039;&#039;&amp;quot;rechenintensiven Beispielprogramm für den kleinen ATtiny2313 in C oder ASM&amp;quot;&#039;&#039;&amp;lt;ref&amp;gt;[http://www.mikrocontroller.net/topic/248373 Forum: AVR Atiny2313: &#039;&#039;&amp;quot;Suche rechenintensivs Beispielprogramm für ATtiny2313&amp;quot;&#039;&#039;]&amp;lt;/ref&amp;gt;&lt;br /&gt;
gesucht wurde und als Vorschlag ein&lt;br /&gt;
: &#039;&#039;&amp;quot;Pi auf 1000 Stellen&amp;quot;&#039;&#039;&amp;lt;ref&amp;gt;[http://www.mikrocontroller.net/topic/248373#2544249 Forum: AVR Atiny2313: &#039;&#039;&amp;quot;Pi auf 1000 Stellen&amp;quot;&#039;&#039;]&amp;lt;/ref&amp;gt;&lt;br /&gt;
kam, wolle ich es genauer wissen. Auch wenn der Vorschlag eher als Scherz aufzufassen ist — sind C-Compiler inzwischen so gut, daß damit π auf tausende Stellen berechnet werden kann? Bei einem Assembler-Programm hätte ich da keine Bedenken; aber C?&lt;br /&gt;
&lt;br /&gt;
Der [[AVR]] ATtiny2313 ist bekanntlich ein 8-Bit [[Mikrocontroller]] mit 2048 Bytes an Programmspeicher und 128 Bytes RAM. Die Aufgabe erfordert also eine spezielle Herangehensweise, denn nicht alle zu berechnenden Stellen sind gleichzeitig im RAM des µC speicherbar: bereits berechnete Stellen sollen ausgegeben werden und an der Ausgabe-Schnittstelle sollen Ziffernweise die Nachkommastellen von π heraus purzeln.&lt;br /&gt;
&lt;br /&gt;
== Die Formel ==&lt;br /&gt;
&lt;br /&gt;
Das theoretisch-algorithmische Rüstzeug dafür ist lange bekannt und das Web ist voll davon: Eine 1995 von Simon Plouffe gefundene Reihendarstellung&amp;lt;ref&amp;gt;Für einen Beweis siehe [http://www.pi314.net/eng/plouffe.php The World of π: Proof: Formula BBP].&amp;lt;/ref&amp;gt; für&amp;amp;nbsp;π:&lt;br /&gt;
:&amp;lt;math&amp;gt;&lt;br /&gt;
\pi=\sum_{k=0}^\infty \frac1{16^k}&lt;br /&gt;
\left(\frac4{8k+1}-\frac2{8k+4}-\frac{1}{8k+5}-\frac1{8k+6}\right)&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
Die Anwendung der Darstellung besteht dabei nicht in stupidem Auswerten bis zur gewünschten Genauigkeit, sondern es wird die n-te Nachkommastelle von π damit bestimmt &#039;&#039;ohne&#039;&#039; vorherige oder nachfolgende Ziffern der Darstellung zu bestimmen.&lt;br /&gt;
Der einzige Wehrmutstropfen ist, daß die Darstellung zur Basis&amp;amp;nbsp;16 erhalten wird und nicht wie gewohnt zur Basis&amp;amp;nbsp;10 — aber immerhin liefert die Formel &#039;&#039;überhaupt&#039;&#039; erst einen Weg, um die Berechnung auf einer kleinen Hardware mit 2k Programmspeicher ausführen zu können.&lt;br /&gt;
Auch dieser Weg ist hinreichend oft im Internet erklärt — je nach Seite mehr oder weniger gut. Eine gute Erklärung findet sich etwa in der Wikipedia&amp;lt;ref&amp;gt;[http://fr.wikipedia.org/wiki/Formule_BBP#Exploitation_de_la_formule_pour_calculer_les_chiffres_apr.C3.A8s_la_virgule_de_.CF.80 Wikipédia: Formule BBP]: Exploitation de la formule pour calculer les chiffres après la virgule de π&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die ganze Aufgabe besteht also nur noch darin, den Algorithmus hinzuschreiben und zu compilieren — und zu hoffen, daß das erzeugte Programm in den kleinen Programmspeicher eines ATtiny hineinpasst.&lt;br /&gt;
&lt;br /&gt;
Gerade der letzte Punkt ist nicht selbstverständlich, denn die Anwendung der obigen Formel verlangt den Einsatz von Fließkomma-Arithmetik. Zwar ist auch eine&lt;br /&gt;
Implementierung mittels Festkomma-Zahlen möglich, aber ich wollte mit den Bordmitteln der C-Sprache auskommen: Ohne Inline-Assembler Hacks, ohne umständliches Hin-und-Herwandeln und Skalieren, ohne Implementierung eigener Divisionroutinen, etc.  Das Programm kann somit als Stresstest für die Tools verstanden werden.&lt;br /&gt;
&lt;br /&gt;
Als Sprache wählte ich C99 und als Compiler avr-gcc&amp;lt;ref&amp;gt;[http://gcc.gnu.org/ GCC]: The GNU Compiler Collection&amp;lt;/ref&amp;gt; 4.7 oder neuer, so daß ein Executable erzeugen wird, das in die 2k Programmspeicher eines ATtiny2313 hineinpasst.&lt;br /&gt;
&lt;br /&gt;
== Der Quelltext: C99 == &lt;br /&gt;
&lt;br /&gt;
Zur Implementierung ist hier nicht viel zu sagen; die Quellen sind ausführlich kommentiert. Nur noch einige Anmerkungen:&lt;br /&gt;
* Die Quellen sind so allgemein gehalten, daß das Programm auch für einen PC übersetzt und dort gestartet werden kann.&lt;br /&gt;
* Wird für AVR übersetzt, erfolgt die Ausgabe der berechneten Ziffern auf der UART-Schnittstelle. Für Compiler- und Linker-Optionen siehe die Quellkommentare.&lt;br /&gt;
* Bei einer Taktfrequenz von 20 MHz dauert die Berechnung der ersten 1000 hex-Ziffern etwa 3–4 Minuten. Verdoppelt man die Anzahl der Ziffern, ist die 4-fache Rechenzeit zu erwarten.&lt;br /&gt;
* Der Algorithmus liefert brauchbare Resultate für die ersten 4096 Nachkommastellen von&amp;amp;nbsp;π. Danach reichten die verwendeten 16-Bit int für ganze Zahlen nicht mehr aus, und für 32-Bit Zahlen ist der Speicher zu klein.&lt;br /&gt;
* Der Algorithmus berechnet wie gesagt Nachkommastellen der Hexadezimaldarstellung von π. 4000 hex-Nachkommastellen entsprechen übrigens ca. 4800 Dezimalstellen: log 16 / log 10 ≈ 6/5.&lt;br /&gt;
* Die Ausgabe lässt sich etwa vergleichen mit &amp;quot;First 8366 Hex Digits of PI&amp;quot;&amp;lt;ref&amp;gt;[http://www.herongyang.com/Cryptography/Blowfish-First-8366-Hex-Digits-of-PI.html www.herongyang.com]: First 8366 Hex Digits of π&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/* pi.c: Compute the first 4000 hexadecimal digits of pi&lt;br /&gt;
         on an AVR ATtiny2313 microcontroller. */&lt;br /&gt;
/*&lt;br /&gt;
    Language: C99&lt;br /&gt;
    Compiler: An AVR toolchain based on avr-gcc 4.7 and AVR-Libc if you like&lt;br /&gt;
              to compile for AVR ATtiny2313, or a C99-compliant compiler if&lt;br /&gt;
              you like to run this program on a PC.&lt;br /&gt;
              &lt;br /&gt;
    Hardware: AVR ATtiny2313 which is an 8-bit microcontroller with&lt;br /&gt;
              128 Bytes of RAM and 2048 Bytes of program memory.&lt;br /&gt;
              http://www.atmel.com/Images/doc2543.pdf  (Manual,  PDF, 4 MB)&lt;br /&gt;
              http://www.atmel.com/Images/doc2543S.pdf (Summary, PDF, 500 kB)&lt;br /&gt;
              &lt;br /&gt;
    Compile:  You need a reasonably optimizing compiler and floating point&lt;br /&gt;
              implementation, or otherwise the program won&#039;t fit into the&lt;br /&gt;
              tiny silicon.  Notice that the code below is *vanilla* C with&lt;br /&gt;
              IEEE-754 floating point arithmetic and without assembler or&lt;br /&gt;
              fixed point hacks.  &lt;br /&gt;
              &lt;br /&gt;
              The program in generic enough to run on a PC.  If you use GCC,&lt;br /&gt;
              just compile with the following command line and run pi.exe&lt;br /&gt;
            &lt;br /&gt;
                  gcc pi.c -o pi.exe -std=c99 -O2 -lm&lt;br /&gt;
        &lt;br /&gt;
              The only compiler that produces code small enough for the&lt;br /&gt;
              AVR ATtiny2313 hardware is avr-gcc 4.7 together with AVR-Libc.&lt;br /&gt;
&lt;br /&gt;
                 avr-gcc pi.c -o pi.elf $(CFLAGS) $(OPT) $(DEFS) $(LDFLAGS)&lt;br /&gt;
    &lt;br /&gt;
              with the following abbreviations for convenience:&lt;br /&gt;
    &lt;br /&gt;
              CFLAGS  = -std=c99 -mmcu=attiny2313&lt;br /&gt;
              OPT     = -Os -mcall-prologues -fno-split-wide-types&lt;br /&gt;
                        -fno-caller-saves -fno-tree-loop-optimize &lt;br /&gt;
              LDFLAGS = -Wl,--relax -Wl,--gc-sections -lm&lt;br /&gt;
              DEFS    = -DF_CPU=22118400 -DBAUDRATE=115200 -DHOST_WINDOWS&lt;br /&gt;
    &lt;br /&gt;
              For documentation of GCC see http://gcc.gnu.org/onlinedocs&lt;br /&gt;
&lt;br /&gt;
              DEFS represents the UART setup.  In my circuit I use a&lt;br /&gt;
              22.1184 MHz quartz which is a bit of overclocking but is so&lt;br /&gt;
              comfortable with baud rates.  Depending on your configuration,&lt;br /&gt;
              you will use other values for F_CPU and BAUDRATE, see below.&lt;br /&gt;
    &lt;br /&gt;
    The first 1000 digits of pi take about 3 Minutes at 22 MHz.&lt;br /&gt;
    For 4000 digits, multiply this time by 16.&lt;br /&gt;
&lt;br /&gt;
    The time to get the first n digits of pi with this method is roughly&lt;br /&gt;
&lt;br /&gt;
        T(n) = K * n^2&lt;br /&gt;
&lt;br /&gt;
    so that, given the time for the computation of n digits, you can easily&lt;br /&gt;
    compute K and estimate how long the computation will take for other&lt;br /&gt;
    values of n.  K will depend on the clock speed you use, for example.&lt;br /&gt;
    &lt;br /&gt;
    Some software metrics for the AVR binary compiled as above:&lt;br /&gt;
    &lt;br /&gt;
    Program Size:  Less than 2000 of 2048 bytes&lt;br /&gt;
&lt;br /&gt;
    RAM Usage:&lt;br /&gt;
        Static storage     :    0 bytes&lt;br /&gt;
        Static stack usage : ~ 50 bytes&lt;br /&gt;
        Dynamic            :    0 bytes&lt;br /&gt;
        Total              : 40% of 128 bytes&lt;br /&gt;
&lt;br /&gt;
    Coding Style: Stroustrup&lt;br /&gt;
    Indentation:  4 Space&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
#include &amp;lt;math.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
// Factor out some platform/compiler dependencies&lt;br /&gt;
&lt;br /&gt;
#if defined (__AVR__) &amp;amp;&amp;amp; defined (__GNUC__)&lt;br /&gt;
&lt;br /&gt;
// Running on AVR&lt;br /&gt;
#   include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#   include &amp;lt;avr/wdt.h&amp;gt;&lt;br /&gt;
#   define cput(C) uart_putc(C)&lt;br /&gt;
static void uart_init (void);&lt;br /&gt;
static void uart_putc (const char);&lt;br /&gt;
&lt;br /&gt;
#else // ! avr-gcc&lt;br /&gt;
&lt;br /&gt;
// Running on PC&lt;br /&gt;
#   include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#   define wdt_reset() (void) 0&lt;br /&gt;
#   define uart_init() (void) 0&lt;br /&gt;
static void cput (char c) &lt;br /&gt;
{&lt;br /&gt;
    fputc (c, stdout);&lt;br /&gt;
    fflush (stdout);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#endif // avr-gcc&lt;br /&gt;
&lt;br /&gt;
// return a * b mod n&lt;br /&gt;
//   &lt;br /&gt;
// 0 &amp;lt;= a &amp;lt; n &lt;br /&gt;
// 0 &amp;lt;= b &amp;lt; n&lt;br /&gt;
//&lt;br /&gt;
// This is a school-book implementation of multiplication.&lt;br /&gt;
//&lt;br /&gt;
// First, ATtiny2313 has no hardware multiplyer or divider, anyway.&lt;br /&gt;
// We have to cope with 2048 bytes of program memory and&lt;br /&gt;
// thus avoid dragging in library routines if possible.&lt;br /&gt;
//&lt;br /&gt;
// Second, this implementation widens the range of valid moduli from&lt;br /&gt;
// \sqrt{1+UINT_MAX} to (1+UINT_MAX)/2.  Or vice versa, it allows us&lt;br /&gt;
// to use a smaller type for the modulus -- 16 bits in the AVR case.&lt;br /&gt;
&lt;br /&gt;
static unsigned mod_mul (unsigned a, unsigned b, unsigned n)&lt;br /&gt;
{&lt;br /&gt;
    unsigned ab = 0;&lt;br /&gt;
    &lt;br /&gt;
    while (1)&lt;br /&gt;
    {&lt;br /&gt;
        if (a % 2 == 1)&lt;br /&gt;
        {&lt;br /&gt;
            ab += b;&lt;br /&gt;
            if (ab &amp;gt;= n)&lt;br /&gt;
                ab -= n;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        a = a / 2;&lt;br /&gt;
        if (a == 0)&lt;br /&gt;
            return ab;&lt;br /&gt;
            &lt;br /&gt;
        b = b * 2;&lt;br /&gt;
        if (b &amp;gt;= n)&lt;br /&gt;
            b -= n;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Return 16^k mod n&lt;br /&gt;
//&lt;br /&gt;
// Exponentiation with the same approach as above except&lt;br /&gt;
// that we binary-expand the exponent instead of a factor.&lt;br /&gt;
&lt;br /&gt;
static unsigned mod_pow16 (unsigned k, unsigned n)&lt;br /&gt;
{&lt;br /&gt;
    unsigned p = 1;&lt;br /&gt;
    unsigned _16 = 16;&lt;br /&gt;
    &lt;br /&gt;
    if (n == 1)&lt;br /&gt;
        return 0;&lt;br /&gt;
        &lt;br /&gt;
    while (_16 &amp;gt;= n)&lt;br /&gt;
        _16 -= n;&lt;br /&gt;
    &lt;br /&gt;
    while (1)&lt;br /&gt;
    {&lt;br /&gt;
        if (k % 2 == 1)&lt;br /&gt;
            p = mod_mul (_16, p, n);&lt;br /&gt;
            &lt;br /&gt;
        k = k / 2;&lt;br /&gt;
        if (k == 0)&lt;br /&gt;
            break;&lt;br /&gt;
            &lt;br /&gt;
        _16 = mod_mul (_16, _16, n);&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    return p;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Helper for the function below.&lt;br /&gt;
&lt;br /&gt;
static float tame (float s)&lt;br /&gt;
{&lt;br /&gt;
    int8_t si = (int8_t) lrintf (s);&lt;br /&gt;
    &lt;br /&gt;
    if (si &amp;lt;= -2 || si &amp;gt;= 2)&lt;br /&gt;
        s -= si;&lt;br /&gt;
    &lt;br /&gt;
    return s;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// The finite part mod 1 of sigma_j, i.e. partial sum where the exponent&lt;br /&gt;
// of 16 is &amp;gt;= 0.  By &amp;quot;mod 1&amp;quot; we always mean &amp;quot;up to some integer&amp;quot;,&lt;br /&gt;
// i.e. the result needs not to be normalized to [0,1).&lt;br /&gt;
&lt;br /&gt;
static float sigma_a (unsigned n, uint8_t j)&lt;br /&gt;
{&lt;br /&gt;
    float s = 0.0f;&lt;br /&gt;
    &lt;br /&gt;
    for (unsigned k = n-1; k+1 != 0; k--)&lt;br /&gt;
    {&lt;br /&gt;
        unsigned j_8k = j + 8*k;&lt;br /&gt;
        &lt;br /&gt;
        s += mod_pow16 (n-k, j_8k) / (float) j_8k;&lt;br /&gt;
&lt;br /&gt;
        // Cut down the sum and don&#039;t let it grow too big.&lt;br /&gt;
        // The bigger the number grows the less precision is&lt;br /&gt;
        // left for the fractional part we are interested in.&lt;br /&gt;
        &lt;br /&gt;
        s = tame (s);&lt;br /&gt;
        &lt;br /&gt;
        wdt_reset();&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    return s;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#define MARGIN 10&lt;br /&gt;
&lt;br /&gt;
static float sigma_b (unsigned n, uint8_t j)&lt;br /&gt;
{&lt;br /&gt;
    float s = 0;&lt;br /&gt;
    float _16 = 1.0f;&lt;br /&gt;
   &lt;br /&gt;
    for (unsigned k = n; k &amp;lt;= n + MARGIN; k++)&lt;br /&gt;
    {&lt;br /&gt;
        s += _16 / (8*k + j);&lt;br /&gt;
        _16 /= 16;&lt;br /&gt;
        &lt;br /&gt;
        wdt_reset();&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    return s;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Compute an approximation of 16^n * sigma(j)  mod 1&lt;br /&gt;
// where&lt;br /&gt;
//&lt;br /&gt;
// sigma_j = \sum_0^oo  1 / (16^k * (8k + j))&lt;br /&gt;
//&lt;br /&gt;
// The sum is split into two parts:&lt;br /&gt;
// sigma_a is the finite sum up to n.&lt;br /&gt;
// sigma_b is the finite sum from n+1 to oo&lt;br /&gt;
// and approximated by a sum from n+1 to n+MARGIN&lt;br /&gt;
&lt;br /&gt;
float sigma (unsigned n, uint8_t j)&lt;br /&gt;
{&lt;br /&gt;
    return sigma_a (n, j) + sigma_b (n, j);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Compute  pi * 16^n  up to some integer&lt;br /&gt;
// using a Bailey-Borwein-Plouffe formula for pi: &lt;br /&gt;
//&lt;br /&gt;
//     pi = 4*sigma_1 - 2*sigma_4 - sigma_5 - sigma_6&lt;br /&gt;
//&lt;br /&gt;
// with the definition of sigma_j from above.  All this&lt;br /&gt;
// is explained very nicely in the French wikipedia at&lt;br /&gt;
// http://fr.wikipedia.org/wiki/Formule_BBP&lt;br /&gt;
// &lt;br /&gt;
// For a proof define the power series&lt;br /&gt;
//&lt;br /&gt;
//     sigma_j (x) = \sum x^{8k} / (8k + j)&lt;br /&gt;
//&lt;br /&gt;
// write the sum as integral and evaluate it at&lt;br /&gt;
// x = sqrt(1/2), see http://www.pi314.net/eng/plouffe.php&lt;br /&gt;
&lt;br /&gt;
float pi_n (unsigned n)&lt;br /&gt;
{&lt;br /&gt;
    float s = 0.0;&lt;br /&gt;
&lt;br /&gt;
    for (uint8_t i = 0; i &amp;lt; 4; i++)&lt;br /&gt;
    {&lt;br /&gt;
        // j[i] = 1, 4, 5, 6&lt;br /&gt;
        uint8_t j = i ? i + 3 : 1;&lt;br /&gt;
&lt;br /&gt;
        // c[i] = 4, -2, -1, -1&lt;br /&gt;
        int8_t c = -1;&lt;br /&gt;
        if (i == 0) c = 4;&lt;br /&gt;
        if (i == 1) c = -2;&lt;br /&gt;
        &lt;br /&gt;
        s += c * sigma (n, j);&lt;br /&gt;
    }&lt;br /&gt;
        &lt;br /&gt;
    return s;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// We computed pi_n = 16^n * pi  mod 1&lt;br /&gt;
// Get the first fractional hexadecimal digit by multiplying&lt;br /&gt;
// with 16 and extracting digit 0 of the result.  Voila!&lt;br /&gt;
&lt;br /&gt;
static uint8_t pi_dig16 (unsigned n)&lt;br /&gt;
{&lt;br /&gt;
    return 15 &amp;amp; lrintf (floorf (16 * pi_n (n)));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Map 0 &amp;lt;= n &amp;lt; 16 to its hexadecimal ASCII digit&lt;br /&gt;
// &#039;0&#039;, &#039;1&#039;, ... &#039;F&#039;&lt;br /&gt;
&lt;br /&gt;
static uint8_t hexdigit (uint8_t n)&lt;br /&gt;
{&lt;br /&gt;
    n += &#039;0&#039;;&lt;br /&gt;
    return n &amp;gt; &#039;9&#039; ? n + &#039;A&#039;-&#039;0&#039;-10 : n;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int main (void)&lt;br /&gt;
{&lt;br /&gt;
    uart_init();&lt;br /&gt;
&lt;br /&gt;
    cput (&#039;\n&#039;);&lt;br /&gt;
    cput (&#039;3&#039;);&lt;br /&gt;
    cput (&#039;.&#039;);&lt;br /&gt;
    &lt;br /&gt;
    // As explained above, 16-bit integers limitate us to moduli &amp;lt;= 2^15.&lt;br /&gt;
    // The biggest modulus for n is 8n+6 so that for n &amp;gt;= 4096 we expect&lt;br /&gt;
    // garbage from the implementation if 16-bit integers are used like&lt;br /&gt;
    // with avr-gcc.  In fact, we get garbage for n &amp;gt; 4100.&lt;br /&gt;
    // It&#039;s not exacly 4095 because of the denominators in sigma_a that&lt;br /&gt;
    // delay the garbage for some values of n.&lt;br /&gt;
    &lt;br /&gt;
    // Easy going 4000 hex-digits of pi.&lt;br /&gt;
&lt;br /&gt;
    for (unsigned n = 0; n &amp;lt; 4000; n++)&lt;br /&gt;
    {&lt;br /&gt;
        // Print a line break after every 64 digits.  That way the output&lt;br /&gt;
        // can easily be compared with, e.g. the hexadecimal representation&lt;br /&gt;
        // of pi from blowfish listed in &amp;quot;First 8366 Hex Digits of PI&amp;quot; from&lt;br /&gt;
        // http://www.herongyang.com/Cryptography/&lt;br /&gt;
&lt;br /&gt;
        if (n % 64 == 0)&lt;br /&gt;
            cput (&#039;\n&#039;);&lt;br /&gt;
        &lt;br /&gt;
        // Get the n+1-th hexadecimal digit of pi and&lt;br /&gt;
        // output it as ASCII character.&lt;br /&gt;
        &lt;br /&gt;
        cput (hexdigit (pi_dig16 (n)));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    cput (&#039;\n&#039;);&lt;br /&gt;
&lt;br /&gt;
    return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/************************************************************************/&lt;br /&gt;
// We are running on ATtiny2313 bare metal, of course.&lt;br /&gt;
// Provide some minimalist output routines that write to UART.&lt;br /&gt;
/************************************************************************/&lt;br /&gt;
&lt;br /&gt;
#ifdef __AVR__&lt;br /&gt;
&lt;br /&gt;
// !!! You must have set the fuses appropriately to run the    !!!&lt;br /&gt;
// !!! controller at desired F_CPU.  Defining F_CPU is needed  !!!&lt;br /&gt;
// !!! to get correct values to set up UART.                   !!!&lt;br /&gt;
// !!!                                                         !!!&lt;br /&gt;
// !!! DEFINING F_CPU WILL NOT CHANGE THE FREQUENCY!           !!!&lt;br /&gt;
&lt;br /&gt;
void uart_init (void)&lt;br /&gt;
{&lt;br /&gt;
    // Define F_CPU and BAUDRATE depending on your hardware setup.&lt;br /&gt;
    // For my setup, it&#039;s the followin defines in avr-gcc&#039;s command line:&lt;br /&gt;
    //    -DF_CPU=22118400 -DBAUDRATE=115200&lt;br /&gt;
&lt;br /&gt;
    unsigned ubrr = -.6 + F_CPU / (8L * BAUDRATE);&lt;br /&gt;
&lt;br /&gt;
    UBRRH = ubrr &amp;gt;&amp;gt; 8;&lt;br /&gt;
    UBRRL = ubrr;&lt;br /&gt;
&lt;br /&gt;
    // Enable UART Transmitter, data mode 8N1, asynchronous&lt;br /&gt;
&lt;br /&gt;
    UCSRA = (1 &amp;lt;&amp;lt; U2X) | (1 &amp;lt;&amp;lt; TXC);&lt;br /&gt;
    UCSRB = (1 &amp;lt;&amp;lt; TXEN);&lt;br /&gt;
    UCSRC = (1 &amp;lt;&amp;lt; UCSZ1) | (1 &amp;lt;&amp;lt; UCSZ0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/////////////////////////////////////////////////////////////////&lt;br /&gt;
&lt;br /&gt;
// Write one char to UART (non-buffered, blocking version)&lt;br /&gt;
&lt;br /&gt;
void uart_putc (char c)&lt;br /&gt;
{&lt;br /&gt;
    while (!(UCSRA &amp;amp; (1 &amp;lt;&amp;lt; UDRE)))&lt;br /&gt;
        wdt_reset();&lt;br /&gt;
    UDR = c;&lt;br /&gt;
&lt;br /&gt;
#ifdef HOST_WINDOWS&lt;br /&gt;
    if (c == &#039;\n&#039;)&lt;br /&gt;
        uart_putc (&#039;\r&#039;);&lt;br /&gt;
#endif // HOST_WINDOWS&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void exit (int x)&lt;br /&gt;
{&lt;br /&gt;
    (void) x;&lt;br /&gt;
&lt;br /&gt;
    while (1)&lt;br /&gt;
        wdt_reset();&lt;br /&gt;
}&lt;br /&gt;
#endif // __AVR__&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Weblinks ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:AVR-Projekte]]&lt;br /&gt;
[[Kategorie:AVR-Arithmetik]]&lt;br /&gt;
[[Kategorie:PC-Programmierung]]&lt;/div&gt;</summary>
		<author><name>Df2au</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=Hack-O-Copter&amp;diff=79691</id>
		<title>Hack-O-Copter</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=Hack-O-Copter&amp;diff=79691"/>
		<updated>2013-11-24T10:25:16Z</updated>

		<summary type="html">&lt;p&gt;Df2au: /* Funkfernbedienung */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Der Begriff &#039;&#039;&#039;Hack-O-Copter&#039;&#039;&#039; beschreibt einen Nachbau des Quadrocopters „Hubsan X4“, der er sich einfach „hacken“ lässt; die Original-Firmware kann also überschrieben und durch eigene ersetzt werden. Er wird für ca. 21€ verkauft, siehe Beitrag [http://www.mikrocontroller.net/topic/309185?page=single „Hackbarer(?) 21 EUR Quadcopter“.]&lt;br /&gt;
&lt;br /&gt;
Die Original-Firmware kann nicht ausgelesen werden, es muss also eine komplett neue Firmware erstellt werden.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Hinweis:&#039;&#039;&#039; Der Artikel enthält Infos bis zu [http://www.mikrocontroller.net/topic/309185?page=1#3356755 diesem Beitrag]. Weitere Inhalte aus dem Thread werden asap ergänzt.&lt;br /&gt;
&lt;br /&gt;
= Beschreibung des Quadrocopters =&lt;br /&gt;
* Abmessungen &#039;&#039;→ Infos ergänzen&#039;&#039;&lt;br /&gt;
* Gewicht &#039;&#039;→ Infos ergänzen&#039;&#039;&lt;br /&gt;
* Lieferumfang &#039;&#039;→ Infos ergänzen&#039;&#039;&lt;br /&gt;
* Reichweite &#039;&#039;→ Infos ergänzen&#039;&#039;&lt;br /&gt;
* Flugdauer und Ladezeit &#039;&#039;→ Infos ergänzen&#039;&#039;&lt;br /&gt;
* Funktionen &#039;&#039;→ Infos (3 Empfindlichkeiten, umdrehen, Rekalibrierung, ...) ergänzen&#039;&#039;&lt;br /&gt;
* Link zur Bedienungsanleitung&lt;br /&gt;
== Bedienung ==&lt;br /&gt;
Auf ebenen Untergrund legen, nach ein paar Sekunden blinken die LEDs er langsamer, dann den linken Steuerhebel einmal hoch und wieder runter fahren.&lt;br /&gt;
== Komponenten ==&lt;br /&gt;
Der Quadrocopter wird von vier kernlosen Gleichstrommotoren („Coreless DC“) angetrieben. Im Inneren des Gehäuses ist eine Platine. Ihre vergleichsweise modernen Hardware-Komponenten (Mikrocontroller, Sensoren, MOSFETs und Funkmodul) sind in den folgenden Kapiteln beschrieben.&lt;br /&gt;
=== Mikrocontroller ===&lt;br /&gt;
Der „Nuvoton Mini54ZAN“ ist ein Cortex-M0 MCU mit 16KiB Flash, 2KB SRAM und SWD.&lt;br /&gt;
&#039;&#039;→ Links zu Datenblättern ergänzen&#039;&#039;&lt;br /&gt;
=== Sensoren zur Flugstabilisierung ===&lt;br /&gt;
Für die Flugstabilisierung ist der Quadrocopter mit drei Gyroskopen und drei Beschleunigungssensoren ausgestattet. Diese sind alle zusammen im Intertialsensor „Invensense MPU-6050“ integriert.&lt;br /&gt;
&#039;&#039;→ Link zum Datenblatt&#039;&#039;&lt;br /&gt;
=== ESC ===&lt;br /&gt;
Die Ansteuerung der Gleichstrommotoren erfolgt über PWM und MOSFETs. Die verwendeten N-Kanal MOSFETs „G2310“ haben einen „Drain-Source On-Resistance“ von etwa 120mΩ.&lt;br /&gt;
&lt;br /&gt;
Siehe http://www.mikrocontroller.net/attachment/193854/G2310.pdf &lt;br /&gt;
=== Funk- Transceiver ===&lt;br /&gt;
Für die 2,4GHz Funkstrecke zur Fernsteuerung ist mit einem „Beken BK3423“ integriert. Die Vermutung, dass dieser voll kompatibel zum NRF24L01 ist, liegt nahe, da der NRF24L01 die Daten der Fernbedienung empfangen kann.&lt;br /&gt;
&lt;br /&gt;
[[Bild:HOC_Fernbedienung_Platine_Ausschnitt2.jpeg|200px]]&lt;br /&gt;
== Zubehör ==&lt;br /&gt;
=== Lade-Adapter ===&lt;br /&gt;
&lt;br /&gt;
Schaltplan des beiliegenden Ladeadapters:&lt;br /&gt;
&lt;br /&gt;
http://www.mikrocontroller.net/attachment/197005/ladeanzeige.png&lt;br /&gt;
&lt;br /&gt;
Auf der Platine vorgesehen sind weiter eine in Reihe zu R2 geschaltete Diode und ein Parallel zum Akku liegender Widerstand R5, welche allerdings nicht bestückt sind.&lt;br /&gt;
&lt;br /&gt;
Bei vollem Akku erlischt die LED&lt;br /&gt;
&lt;br /&gt;
=== Funkfernbedienung ===&lt;br /&gt;
Die Außenantenne ist nur „Verarsche“ ...&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;→ Infos ergänzen&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;→ Hinweis auf Idee: Neuen Sender entwickeln&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[Bild:HOC_Fernbedienung_Platine_B-Seite.jpeg|200px]]&lt;br /&gt;
[[Bild:HOC_Fernbedienung_Platine_Ausschnitt.jpeg|200px]]&lt;br /&gt;
[[Bild:HOC_Fernbedienung_Platine_total.jpeg|200px]]&lt;br /&gt;
[[Datei:HOC_Fernbedienung_Platine_Ausschnitt2.jpeg|200px]]&lt;br /&gt;
&lt;br /&gt;
==== Schaltbild der Fernbedienung ====&lt;br /&gt;
Das Schaltbild enthält alle funktionsrelevanten Bauteile. Es fehlen noch diverse Bauteilwerte. Auch der eine oder andere Stützkondensator fehlt eventuell.&lt;br /&gt;
&lt;br /&gt;
[[Medium:copter05.pdf]]&lt;br /&gt;
&lt;br /&gt;
==== Pinbelegung des Mikrocontrollers ====&lt;br /&gt;
&lt;br /&gt;
Pinbelegung für CPU N79E814&lt;br /&gt;
&lt;br /&gt;
 Pin    Name    Funktion&lt;br /&gt;
   1     P0.0   LCD, CS&lt;br /&gt;
   2     P1.7   LCD, CLK&lt;br /&gt;
   3     P1.6   LCD, DATA&lt;br /&gt;
   4     RST    Reset (10k - C)&lt;br /&gt;
   5     VSS    an Masse&lt;br /&gt;
   6     P3.1   RF-Modul, MOSI&lt;br /&gt;
   7     P3.0   RF-Modul, SCK&lt;br /&gt;
   8     P1.4   RF-Modul, MISO&lt;br /&gt;
   9     SDA    RF-Modul, CSN&lt;br /&gt;
  10     SCL    2K2 Pullup, unbestückter Schaltungsteil&lt;br /&gt;
  11     P1.1   LED via 1kOhm&lt;br /&gt;
  12     P1.0   Buzzer (via Transistor)&lt;br /&gt;
  13     AD6    über Widerstände an Batteriespannung vor Regler&lt;br /&gt;
  14     AD5    Auswertung Taster (Seite Yaw-Throttle)&lt;br /&gt;
  15     VDD    Versorgung&lt;br /&gt;
  16     AD4    Poti &amp;quot;Throttle&amp;quot;&lt;br /&gt;
  17     AD3    Poti &amp;quot;Yaw&amp;quot;&lt;br /&gt;
  18     AD2    Poti &amp;quot;Roll&amp;quot;, Dämpfung mit RC Glied&lt;br /&gt;
  19     AD1    Poti &amp;quot;Pitch&amp;quot;, Dämpfung mit RC Glied&lt;br /&gt;
  20     AD0    Auswertung Taster (Seite Pitch-Roll)&lt;br /&gt;
&lt;br /&gt;
==== Pinbelegung des Sendemoduls ====&lt;br /&gt;
[[Bild:HOC_Fernbedienung_Sendemodul.jpeg|200px]]&lt;br /&gt;
&lt;br /&gt;
 1 3.3V&lt;br /&gt;
 2 MOSI an PIN6  MCU&lt;br /&gt;
 3 SCK  an PIN7  MCU&lt;br /&gt;
 4 MISO an PIN8  MCU&lt;br /&gt;
 5 CE&lt;br /&gt;
 6 GND&lt;br /&gt;
 7 IRQ&lt;br /&gt;
 8 CSN  an PIN9  MCU&lt;br /&gt;
 9 RXEN&lt;br /&gt;
&lt;br /&gt;
==== Protokoll ====&lt;br /&gt;
&lt;br /&gt;
Es handelt sich um das V202 Protokoll.&lt;br /&gt;
&lt;br /&gt;
* Die Payload hat eine Länge von 16-Byte&lt;br /&gt;
* Das letzte Byte entspricht der Summe aller vorherigen Bytes (bzw. den unteren 8 Bit der Summe)&lt;br /&gt;
* Das Datenformat passt zu dem im GitRepo beschriebenen (https://github.com/hackocopter/Documentation/tree/master/RemoteControl)&lt;br /&gt;
* Das Datenformat passt zu der Implementierung des V202 Protokolls in der Deviation firmware (https://bitbucket.org/PhracturedBlue/deviation/src...)&lt;br /&gt;
&lt;br /&gt;
Zum Channel Hopping:&lt;br /&gt;
* jedes Packet wird zweimal versendet&lt;br /&gt;
* es immer 16-Channel durchgehoppt (dann gehts wieder von vorne los)&lt;br /&gt;
* auch das passt zur Implementierung in der Deviation firmware&lt;br /&gt;
&lt;br /&gt;
Siehe auch: http://www.mikrocontroller.net/topic/309185?goto=3410375#3410373&lt;br /&gt;
&lt;br /&gt;
=== Propeller ===&lt;br /&gt;
&#039;&#039;→ Infos ergänzen&#039;&#039;&lt;br /&gt;
== Schnittstellen ==&lt;br /&gt;
=== SWD-Port ===&lt;br /&gt;
Der SWD-Port ist über … herausgeführt. &#039;&#039;→ Infos ergänzen&#039;&#039;&lt;br /&gt;
=== Serielle Schnittstelle ===&lt;br /&gt;
Die Anschlüsse führen zu den RX und TX Pins des MCUs.&lt;br /&gt;
&#039;&#039;→ Infos ergänzen&#039;&#039;&lt;br /&gt;
=== PIN 9 ===&lt;br /&gt;
&#039;&#039;→ Infos ergänzen&#039;&#039;&lt;br /&gt;
=== I²C-Schnittstelle ===&lt;br /&gt;
&#039;&#039;→ Infos ergänzen&#039;&#039;&lt;br /&gt;
= Tipps und Tricks =&lt;br /&gt;
== Bezugsquellen und Kauf ==&lt;br /&gt;
=== Direktkauf aus China ===&lt;br /&gt;
&#039;&#039;→ Infos zu Aliexpress, ebay, Einfuhrumsatzsteuer und Käuferschutz ergänzen&#039;&#039;&lt;br /&gt;
=== Lieferanten aus Europa ===&lt;br /&gt;
&#039;&#039;→ Infos ergänzen&#039;&#039;&lt;br /&gt;
== Ersatzakkus ==&lt;br /&gt;
Der Original-Akku hat …mAh und wiegt …g. &#039;&#039;→ Infos ergänzen&#039;&#039;&lt;br /&gt;
(380mAh, ca. 2,31€, …g) &#039;&#039;→ Infos ergänzen&#039;&#039;&lt;br /&gt;
== Reduzierung der Unfallfolgen ==&lt;br /&gt;
&#039;&#039;→ Infos ergänzen&#039;&#039;&lt;br /&gt;
= Ideen für neue Funktionen =&lt;br /&gt;
== Bessere Flugstabilisierung mit bestehender Sensorik ==&lt;br /&gt;
== Neue Funktionen mit GPS-Sensor ==&lt;br /&gt;
[[Bild:HOC_GPS_Groessenvergleich.jpg|200px]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;→ Ideen ergänzen&#039;&#039;&lt;br /&gt;
== Neue Funktionen mit Luftdruck-Sensor ==&lt;br /&gt;
&#039;&#039;→ Ideen ergänzen&#039;&#039;&lt;br /&gt;
== Neue Funktionen mit Kamera ==&lt;br /&gt;
Alternativen: Keycam, Y3000, … &#039;&#039;→ Infos ergänzen&#039;&#039;&lt;br /&gt;
== Neue Funktionen mit Ultraschallsensor ==&lt;br /&gt;
&#039;&#039;→ Ideen ergänzen&#039;&#039;&lt;br /&gt;
== Neue Funktionen mit Infrarot-Entfernungssensor ==&lt;br /&gt;
[[Bild:HOC_IR-Entfernungsmesser-Testplatine.jpg|200px]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;→ Ideen ergänzen&#039;&#039;&lt;br /&gt;
== Neue Funktionen mit Bluetooth ==&lt;br /&gt;
&#039;&#039;→ Ideen ergänzen&#039;&#039;&lt;br /&gt;
== Erweiterung der Original-Fernbedienung ==&lt;br /&gt;
=== Funkmodul mit PA + LNA ===&lt;br /&gt;
&#039;&#039;→ Details ergänzen&#039;&#039;&lt;br /&gt;
=== Erweiterung um ein Display ===&lt;br /&gt;
[[Bild:HOC_Fernbedienung_mit_C0802-04.jpeg|200px]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;→ Details ergänzen&#039;&#039;&lt;br /&gt;
== Neue Funktionen mit alternativer Fernbedienung ==&lt;br /&gt;
&#039;&#039;→ Ideen ergänzen&#039;&#039;&lt;br /&gt;
= Programmierung neuer Firmware =&lt;br /&gt;
== Beschreibung der Toolkette ==&lt;br /&gt;
&#039;&#039;→ Details ergänzen&#039;&#039;&lt;br /&gt;
=== Notwendige Hardware und Software ===&lt;br /&gt;
&#039;&#039;→ Details ergänzen&#039;&#039;&lt;br /&gt;
=== Installation der Toolkette ===&lt;br /&gt;
&#039;&#039;→ Details ergänzen&#039;&#039;&lt;br /&gt;
=== ISP und ICD ===&lt;br /&gt;
== Beschreibung der Firmware-Varianten ==&lt;br /&gt;
=== „Blinky“ ===&lt;br /&gt;
&#039;&#039;→ Details ergänzen&#039;&#039;&lt;br /&gt;
= Weiterführende Links und Quellen =&lt;br /&gt;
* http://www.jann.cc/2013/10/13/tiny_hackable_quadcopter.html &#039;&#039;→ Details ergänzen&#039;&#039;&lt;br /&gt;
* Multiwii &#039;&#039;→ Details ergänzen&#039;&#039;&lt;br /&gt;
* Paparazzi (http://paparazzi.enac.fr/wiki/Main_Page) &#039;&#039;→ Details ergänzen&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Df2au</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=Datei:Copter05.pdf&amp;diff=79690</id>
		<title>Datei:Copter05.pdf</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=Datei:Copter05.pdf&amp;diff=79690"/>
		<updated>2013-11-24T10:20:20Z</updated>

		<summary type="html">&lt;p&gt;Df2au: Schaltbild der Fernbedienung des JD-385 Quadcopters&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Schaltbild der Fernbedienung des JD-385 Quadcopters&lt;/div&gt;</summary>
		<author><name>Df2au</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=Hack-O-Copter&amp;diff=79689</id>
		<title>Hack-O-Copter</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=Hack-O-Copter&amp;diff=79689"/>
		<updated>2013-11-24T10:10:36Z</updated>

		<summary type="html">&lt;p&gt;Df2au: /* Pinbelegung des Mikrocontrollers */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Der Begriff &#039;&#039;&#039;Hack-O-Copter&#039;&#039;&#039; beschreibt einen Nachbau des Quadrocopters „Hubsan X4“, der er sich einfach „hacken“ lässt; die Original-Firmware kann also überschrieben und durch eigene ersetzt werden. Er wird für ca. 21€ verkauft, siehe Beitrag [http://www.mikrocontroller.net/topic/309185?page=single „Hackbarer(?) 21 EUR Quadcopter“.]&lt;br /&gt;
&lt;br /&gt;
Die Original-Firmware kann nicht ausgelesen werden, es muss also eine komplett neue Firmware erstellt werden.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Hinweis:&#039;&#039;&#039; Der Artikel enthält Infos bis zu [http://www.mikrocontroller.net/topic/309185?page=1#3356755 diesem Beitrag]. Weitere Inhalte aus dem Thread werden asap ergänzt.&lt;br /&gt;
&lt;br /&gt;
= Beschreibung des Quadrocopters =&lt;br /&gt;
* Abmessungen &#039;&#039;→ Infos ergänzen&#039;&#039;&lt;br /&gt;
* Gewicht &#039;&#039;→ Infos ergänzen&#039;&#039;&lt;br /&gt;
* Lieferumfang &#039;&#039;→ Infos ergänzen&#039;&#039;&lt;br /&gt;
* Reichweite &#039;&#039;→ Infos ergänzen&#039;&#039;&lt;br /&gt;
* Flugdauer und Ladezeit &#039;&#039;→ Infos ergänzen&#039;&#039;&lt;br /&gt;
* Funktionen &#039;&#039;→ Infos (3 Empfindlichkeiten, umdrehen, Rekalibrierung, ...) ergänzen&#039;&#039;&lt;br /&gt;
* Link zur Bedienungsanleitung&lt;br /&gt;
== Bedienung ==&lt;br /&gt;
Auf ebenen Untergrund legen, nach ein paar Sekunden blinken die LEDs er langsamer, dann den linken Steuerhebel einmal hoch und wieder runter fahren.&lt;br /&gt;
== Komponenten ==&lt;br /&gt;
Der Quadrocopter wird von vier kernlosen Gleichstrommotoren („Coreless DC“) angetrieben. Im Inneren des Gehäuses ist eine Platine. Ihre vergleichsweise modernen Hardware-Komponenten (Mikrocontroller, Sensoren, MOSFETs und Funkmodul) sind in den folgenden Kapiteln beschrieben.&lt;br /&gt;
=== Mikrocontroller ===&lt;br /&gt;
Der „Nuvoton Mini54ZAN“ ist ein Cortex-M0 MCU mit 16KiB Flash, 2KB SRAM und SWD.&lt;br /&gt;
&#039;&#039;→ Links zu Datenblättern ergänzen&#039;&#039;&lt;br /&gt;
=== Sensoren zur Flugstabilisierung ===&lt;br /&gt;
Für die Flugstabilisierung ist der Quadrocopter mit drei Gyroskopen und drei Beschleunigungssensoren ausgestattet. Diese sind alle zusammen im Intertialsensor „Invensense MPU-6050“ integriert.&lt;br /&gt;
&#039;&#039;→ Link zum Datenblatt&#039;&#039;&lt;br /&gt;
=== ESC ===&lt;br /&gt;
Die Ansteuerung der Gleichstrommotoren erfolgt über PWM und MOSFETs. Die verwendeten N-Kanal MOSFETs „G2310“ haben einen „Drain-Source On-Resistance“ von etwa 120mΩ.&lt;br /&gt;
&lt;br /&gt;
Siehe http://www.mikrocontroller.net/attachment/193854/G2310.pdf &lt;br /&gt;
=== Funk- Transceiver ===&lt;br /&gt;
Für die 2,4GHz Funkstrecke zur Fernsteuerung ist mit einem „Beken BK3423“ integriert. Die Vermutung, dass dieser voll kompatibel zum NRF24L01 ist, liegt nahe, da der NRF24L01 die Daten der Fernbedienung empfangen kann.&lt;br /&gt;
&lt;br /&gt;
[[Bild:HOC_Fernbedienung_Platine_Ausschnitt2.jpeg|200px]]&lt;br /&gt;
== Zubehör ==&lt;br /&gt;
=== Lade-Adapter ===&lt;br /&gt;
&lt;br /&gt;
Schaltplan des beiliegenden Ladeadapters:&lt;br /&gt;
&lt;br /&gt;
http://www.mikrocontroller.net/attachment/197005/ladeanzeige.png&lt;br /&gt;
&lt;br /&gt;
Auf der Platine vorgesehen sind weiter eine in Reihe zu R2 geschaltete Diode und ein Parallel zum Akku liegender Widerstand R5, welche allerdings nicht bestückt sind.&lt;br /&gt;
&lt;br /&gt;
Bei vollem Akku erlischt die LED&lt;br /&gt;
&lt;br /&gt;
=== Funkfernbedienung ===&lt;br /&gt;
Die Außenantenne ist nur „Verarsche“ ...&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;→ Infos ergänzen&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;→ Hinweis auf Idee: Neuen Sender entwickeln&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[Bild:HOC_Fernbedienung_Platine_B-Seite.jpeg|200px]]&lt;br /&gt;
[[Bild:HOC_Fernbedienung_Platine_Ausschnitt.jpeg|200px]]&lt;br /&gt;
[[Bild:HOC_Fernbedienung_Platine_total.jpeg|200px]]&lt;br /&gt;
[[Datei:HOC_Fernbedienung_Platine_Ausschnitt2.jpeg|200px]]&lt;br /&gt;
&lt;br /&gt;
==== Pinbelegung des Mikrocontrollers ====&lt;br /&gt;
&lt;br /&gt;
Pinbelegung für CPU N79E814&lt;br /&gt;
&lt;br /&gt;
 Pin    Name    Funktion&lt;br /&gt;
   1     P0.0   LCD, CS&lt;br /&gt;
   2     P1.7   LCD, CLK&lt;br /&gt;
   3     P1.6   LCD, DATA&lt;br /&gt;
   4     RST    Reset (10k - C)&lt;br /&gt;
   5     VSS    an Masse&lt;br /&gt;
   6     P3.1   RF-Modul, MOSI&lt;br /&gt;
   7     P3.0   RF-Modul, SCK&lt;br /&gt;
   8     P1.4   RF-Modul, MISO&lt;br /&gt;
   9     SDA    RF-Modul, CSN&lt;br /&gt;
  10     SCL    2K2 Pullup, unbestückter Schaltungsteil&lt;br /&gt;
  11     P1.1   LED via 1kOhm&lt;br /&gt;
  12     P1.0   Buzzer (via Transistor)&lt;br /&gt;
  13     AD6    über Widerstände an Batteriespannung vor Regler&lt;br /&gt;
  14     AD5    Auswertung Taster (Seite Yaw-Throttle)&lt;br /&gt;
  15     VDD    Versorgung&lt;br /&gt;
  16     AD4    Poti &amp;quot;Throttle&amp;quot;&lt;br /&gt;
  17     AD3    Poti &amp;quot;Yaw&amp;quot;&lt;br /&gt;
  18     AD2    Poti &amp;quot;Roll&amp;quot;, Dämpfung mit RC Glied&lt;br /&gt;
  19     AD1    Poti &amp;quot;Pitch&amp;quot;, Dämpfung mit RC Glied&lt;br /&gt;
  20     AD0    Auswertung Taster (Seite Pitch-Roll)&lt;br /&gt;
&lt;br /&gt;
==== Pinbelegung des Sendemoduls ====&lt;br /&gt;
[[Bild:HOC_Fernbedienung_Sendemodul.jpeg|200px]]&lt;br /&gt;
&lt;br /&gt;
 1 3.3V&lt;br /&gt;
 2 MOSI an PIN6  MCU&lt;br /&gt;
 3 SCK  an PIN7  MCU&lt;br /&gt;
 4 MISO an PIN8  MCU&lt;br /&gt;
 5 CE&lt;br /&gt;
 6 GND&lt;br /&gt;
 7 IRQ&lt;br /&gt;
 8 CSN  an PIN9  MCU&lt;br /&gt;
 9 RXEN&lt;br /&gt;
&lt;br /&gt;
==== Protokoll ====&lt;br /&gt;
&lt;br /&gt;
Es handelt sich um das V202 Protokoll.&lt;br /&gt;
&lt;br /&gt;
* Die Payload hat eine Länge von 16-Byte&lt;br /&gt;
* Das letzte Byte entspricht der Summe aller vorherigen Bytes (bzw. den unteren 8 Bit der Summe)&lt;br /&gt;
* Das Datenformat passt zu dem im GitRepo beschriebenen (https://github.com/hackocopter/Documentation/tree/master/RemoteControl)&lt;br /&gt;
* Das Datenformat passt zu der Implementierung des V202 Protokolls in der Deviation firmware (https://bitbucket.org/PhracturedBlue/deviation/src...)&lt;br /&gt;
&lt;br /&gt;
Zum Channel Hopping:&lt;br /&gt;
* jedes Packet wird zweimal versendet&lt;br /&gt;
* es immer 16-Channel durchgehoppt (dann gehts wieder von vorne los)&lt;br /&gt;
* auch das passt zur Implementierung in der Deviation firmware&lt;br /&gt;
&lt;br /&gt;
Siehe auch: http://www.mikrocontroller.net/topic/309185?goto=3410375#3410373&lt;br /&gt;
&lt;br /&gt;
=== Propeller ===&lt;br /&gt;
&#039;&#039;→ Infos ergänzen&#039;&#039;&lt;br /&gt;
== Schnittstellen ==&lt;br /&gt;
=== SWD-Port ===&lt;br /&gt;
Der SWD-Port ist über … herausgeführt. &#039;&#039;→ Infos ergänzen&#039;&#039;&lt;br /&gt;
=== Serielle Schnittstelle ===&lt;br /&gt;
Die Anschlüsse führen zu den RX und TX Pins des MCUs.&lt;br /&gt;
&#039;&#039;→ Infos ergänzen&#039;&#039;&lt;br /&gt;
=== PIN 9 ===&lt;br /&gt;
&#039;&#039;→ Infos ergänzen&#039;&#039;&lt;br /&gt;
=== I²C-Schnittstelle ===&lt;br /&gt;
&#039;&#039;→ Infos ergänzen&#039;&#039;&lt;br /&gt;
= Tipps und Tricks =&lt;br /&gt;
== Bezugsquellen und Kauf ==&lt;br /&gt;
=== Direktkauf aus China ===&lt;br /&gt;
&#039;&#039;→ Infos zu Aliexpress, ebay, Einfuhrumsatzsteuer und Käuferschutz ergänzen&#039;&#039;&lt;br /&gt;
=== Lieferanten aus Europa ===&lt;br /&gt;
&#039;&#039;→ Infos ergänzen&#039;&#039;&lt;br /&gt;
== Ersatzakkus ==&lt;br /&gt;
Der Original-Akku hat …mAh und wiegt …g. &#039;&#039;→ Infos ergänzen&#039;&#039;&lt;br /&gt;
(380mAh, ca. 2,31€, …g) &#039;&#039;→ Infos ergänzen&#039;&#039;&lt;br /&gt;
== Reduzierung der Unfallfolgen ==&lt;br /&gt;
&#039;&#039;→ Infos ergänzen&#039;&#039;&lt;br /&gt;
= Ideen für neue Funktionen =&lt;br /&gt;
== Bessere Flugstabilisierung mit bestehender Sensorik ==&lt;br /&gt;
== Neue Funktionen mit GPS-Sensor ==&lt;br /&gt;
[[Bild:HOC_GPS_Groessenvergleich.jpg|200px]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;→ Ideen ergänzen&#039;&#039;&lt;br /&gt;
== Neue Funktionen mit Luftdruck-Sensor ==&lt;br /&gt;
&#039;&#039;→ Ideen ergänzen&#039;&#039;&lt;br /&gt;
== Neue Funktionen mit Kamera ==&lt;br /&gt;
Alternativen: Keycam, Y3000, … &#039;&#039;→ Infos ergänzen&#039;&#039;&lt;br /&gt;
== Neue Funktionen mit Ultraschallsensor ==&lt;br /&gt;
&#039;&#039;→ Ideen ergänzen&#039;&#039;&lt;br /&gt;
== Neue Funktionen mit Infrarot-Entfernungssensor ==&lt;br /&gt;
[[Bild:HOC_IR-Entfernungsmesser-Testplatine.jpg|200px]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;→ Ideen ergänzen&#039;&#039;&lt;br /&gt;
== Neue Funktionen mit Bluetooth ==&lt;br /&gt;
&#039;&#039;→ Ideen ergänzen&#039;&#039;&lt;br /&gt;
== Erweiterung der Original-Fernbedienung ==&lt;br /&gt;
=== Funkmodul mit PA + LNA ===&lt;br /&gt;
&#039;&#039;→ Details ergänzen&#039;&#039;&lt;br /&gt;
=== Erweiterung um ein Display ===&lt;br /&gt;
[[Bild:HOC_Fernbedienung_mit_C0802-04.jpeg|200px]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;→ Details ergänzen&#039;&#039;&lt;br /&gt;
== Neue Funktionen mit alternativer Fernbedienung ==&lt;br /&gt;
&#039;&#039;→ Ideen ergänzen&#039;&#039;&lt;br /&gt;
= Programmierung neuer Firmware =&lt;br /&gt;
== Beschreibung der Toolkette ==&lt;br /&gt;
&#039;&#039;→ Details ergänzen&#039;&#039;&lt;br /&gt;
=== Notwendige Hardware und Software ===&lt;br /&gt;
&#039;&#039;→ Details ergänzen&#039;&#039;&lt;br /&gt;
=== Installation der Toolkette ===&lt;br /&gt;
&#039;&#039;→ Details ergänzen&#039;&#039;&lt;br /&gt;
=== ISP und ICD ===&lt;br /&gt;
== Beschreibung der Firmware-Varianten ==&lt;br /&gt;
=== „Blinky“ ===&lt;br /&gt;
&#039;&#039;→ Details ergänzen&#039;&#039;&lt;br /&gt;
= Weiterführende Links und Quellen =&lt;br /&gt;
* http://www.jann.cc/2013/10/13/tiny_hackable_quadcopter.html &#039;&#039;→ Details ergänzen&#039;&#039;&lt;br /&gt;
* Multiwii &#039;&#039;→ Details ergänzen&#039;&#039;&lt;br /&gt;
* Paparazzi (http://paparazzi.enac.fr/wiki/Main_Page) &#039;&#039;→ Details ergänzen&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Df2au</name></author>
	</entry>
</feed>