<?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=78.53.221.64</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=78.53.221.64"/>
	<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/articles/Spezial:Beitr%C3%A4ge/78.53.221.64"/>
	<updated>2026-04-10T21:36:52Z</updated>
	<subtitle>Benutzerbeiträge</subtitle>
	<generator>MediaWiki 1.39.7</generator>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=Diskussion:LED-Fading&amp;diff=68125</id>
		<title>Diskussion:LED-Fading</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=Diskussion:LED-Fading&amp;diff=68125"/>
		<updated>2012-08-28T18:08:14Z</updated>

		<summary type="html">&lt;p&gt;78.53.221.64: Meine eigene sparsame Implementierung aktuallisiert&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Hinweise zu Anpassungen an andere AVRs als ATmega32 ==&lt;br /&gt;
&lt;br /&gt;
* Atmega8 [http://www.mikrocontroller.net/topic/158008#1496399]&lt;br /&gt;
&lt;br /&gt;
=== Sparsamere Implementierung ===&lt;br /&gt;
&lt;br /&gt;
Hallo, ich habe vorhin auch einen Farbverlauf implementiert, und erst im nach hinein den Artikel gesehen. Soweit kein Problem, da mir die theoretischen Hintergründe eh bekannt sind. Da mein Code wesentlich platzsparender ist (ich verwende ATtiny2x MCUs) werde ich den hier mal präsentieren.&lt;br /&gt;
&lt;br /&gt;
Ich verwende in meinem Programm ein 7 Bit (0..127) auf 8 Bit (1..255) Mapping. Das ist noch recht kompakt und sehr speichereffizient, und die Stufen sind kaum sichtbar. Soweit ich das aus dem optimierten Code sehen kann, braucht er 8 zusätzliche Taktzyklen und 28 Byte an Speicher.&lt;br /&gt;
&amp;lt;c&amp;gt; &lt;br /&gt;
uint8_t exptable4[16] PROGMEM =&lt;br /&gt;
  {133, 139, 145, 151, 158, 165, 172, 180,&lt;br /&gt;
  188, 196, 205, 214, 224, 234, 244, 255};&lt;br /&gt;
&lt;br /&gt;
inline uint8_t expvalue7( const uint8_t linear )&lt;br /&gt;
{/* Returns the exponential value (approx. 1.0443^x).                        *&lt;br /&gt;
  * argument: 7 bit unsigned (0..127)  return: 8 bit unsigned (1..255)       */&lt;br /&gt;
  // look up exponential&lt;br /&gt;
  uint8_t exp = pgm_read_byte(&amp;amp;exptable4[ linear % 16 ]);&lt;br /&gt;
  // scale magnitude&lt;br /&gt;
  return exp &amp;gt;&amp;gt; (7 - linear / 16);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
Ich speichere also nur die Zwischenwerte für einen Bereich von Max bis Max/2. Kleinere Werte kann ich dann sehr schnell durch Schieben der Zahlen erhalten.&lt;br /&gt;
&lt;br /&gt;
Die Exponentialfunktion hat die Eigenschaft, dass exp(0) == 1. Daher bietet es sich für LEDs an, entweder bei einem Sollwert von 0 das PWM auf 0 zu stellen, oder einfach vom Ergebnis eins abzusiehen. So werden die LEDs auch dunkel (ggf. mit allgemeiner Einschränkung des PWM).&lt;br /&gt;
&lt;br /&gt;
Die 127 Stufen sind bei 8-Bit schon sehr verschwenderisch, aber es kostet aber fast nix (8 Byte mehr als 64er, bzw. 12 Byte mehr als 32er).&lt;br /&gt;
&lt;br /&gt;
Falls sich jetzt jemand fragt, wie ich die Wertetabelle erstellt habe: Dazu habe ich einfach 2^(7+n/16) ausgerechnet. Die 7 sind log2(res)-1 also entsprechend für uint8_t. Die Anzahl der Stufen (hier 16) kann beliebig gewählt werden, wobei 2er Potenzen in Schiebefunktionen umgewandelt werden, und daher (gerade auf ATtinys) sehr viel schneller berechnet werden.&lt;br /&gt;
&lt;br /&gt;
Wer möglichst jedes Byte einsparen will, der wird so etwas verwenden:&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
uint8_t exptable2[4] PROGMEM = {151, 180, 214, 255};&lt;br /&gt;
&lt;br /&gt;
inline uint8_t expvalue5( const uint8_t linear )&lt;br /&gt;
{/* Returns the exponential value (approx. 1.19^x).                          *&lt;br /&gt;
  * argument: 5 bit unsigned (0..31)  return: 8 bit unsigned (1..255)        */&lt;br /&gt;
  // look up exponential&lt;br /&gt;
  uint8_t exp = pgm_read_byte(&amp;amp;exptable2[ linear % 4 ]);&lt;br /&gt;
  // scale magnitude&lt;br /&gt;
  return exp &amp;gt;&amp;gt; (7 - linear / 4);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
Wer dagegen bei einem 16-Bit Timer Ressourcen weniger Beachtung schenkt, wird vielleicht eher diese Zeilen verwenden.&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
uint8_t exptable5[32] PROGMEM =&lt;br /&gt;
  {130, 133, 136, 139, 142, 145, 148, 151, 155, 158, 161, 165, 169, 172, 176, 180,&lt;br /&gt;
  184, 188, 192, 196, 201, 205, 210, 214, 219, 224, 229, 234, 239, 244, 249, 255};&lt;br /&gt;
&lt;br /&gt;
inline uint16_t expvalue9(const uint16_t linear)&lt;br /&gt;
{/* Returns the exponential value (approx. 1.0219^x).                          *&lt;br /&gt;
  * argument: 9 bit unsigned (0..511)  return: 16 bit unsigned (1..65280)    */&lt;br /&gt;
  // look up exponential&lt;br /&gt;
  uint16_t exp = pgm_read_byte(&amp;amp;exptable5[ linear % 32 ]) &amp;lt;&amp;lt; 8;&lt;br /&gt;
  // scale magnitude&lt;br /&gt;
  return exp &amp;gt;&amp;gt; (15 - linear / 32);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
Man könnte das Ganze noch weiter treiben, doch ist sicher für das Auge sicher keine Verbesserung mehr wahrnehmbar. Eine Speicherung der Werte als uint16_t ist eigentlich nie sinnvoll, da uint8_t bis 10 Bit Eingangsauflösung nicht schlechter ist (Schritte &amp;gt; 1 LSB). Eine Ausgangsauflösung von 16 Bit kann schon ein 10 Bit Eingangssignal etwa in der unteren Hälfte (1..428) nicht mehr auflösen (Schritte &amp;lt; 1 LSB).&lt;br /&gt;
&lt;br /&gt;
Ach noch was: Ich bin neu auf dieser Seite (und auch mit AVR Programmierung). Daher wollte ich nicht enfach umfangreiche Änderungen in den Artikel einpflegen. Wenn jemand hier etwas mehr zu Hause ist, dann kann er gerne diesen Code in den Artikel einpflegen.&lt;br /&gt;
&lt;br /&gt;
== Diskussion wissenschaftl.-technischer Hintergrund ==&lt;br /&gt;
&lt;br /&gt;
Das Helligkeitsempfinden des Auges ist NICHT logarithmisch!&lt;br /&gt;
&lt;br /&gt;
Es genügt der Gleichung (für nahezu alle unsere Anwendungsfälle):&lt;br /&gt;
&lt;br /&gt;
E = R ^ γ&lt;br /&gt;
&lt;br /&gt;
wobei:&lt;br /&gt;
&lt;br /&gt;
E = Empfinden&lt;br /&gt;
&lt;br /&gt;
R = Reizintensität (Tastverhältnis der PWM)&lt;br /&gt;
&lt;br /&gt;
γ = Gammakorrekturwert&lt;br /&gt;
&lt;br /&gt;
Je nach Größe der Lichtquelle wählt man:&lt;br /&gt;
&lt;br /&gt;
γ = 0.5 für punktförmige oder aufblitzende Helligkeiten&lt;br /&gt;
&lt;br /&gt;
γ = 0.33 für Lichtquellen bei 5° Blickwinkel&lt;br /&gt;
&lt;br /&gt;
γ = 1/2.2 ist meine Empfehlung für diffus strahlende LEDs - entspricht der Gamma-korrektur von VGA-Bildschirmen - hat in unseren Selbstversuchen hervorragende Ergebnisse geliefert&lt;br /&gt;
&lt;br /&gt;
Die umgekehrte Look-Up-Wertetabelle ergibt sich aus:&lt;br /&gt;
&lt;br /&gt;
R = E ^ 1/γ (wie man sieht auch hier KEIN Logarithmus! Der Exponent ist fix!)&lt;br /&gt;
&lt;br /&gt;
oder für diskrete Werte:&lt;br /&gt;
&lt;br /&gt;
R[i] = round((z - 1) * (i / (n - 1)) ^ (1/γ))&lt;br /&gt;
&lt;br /&gt;
oder (je nachdem welche Rundungsfunktion verfügbar ist)&lt;br /&gt;
&lt;br /&gt;
R[i] = floor((z - 1) * (i / (n - 1)) ^ (1/γ) + 0.5)&lt;br /&gt;
&lt;br /&gt;
mit&lt;br /&gt;
&lt;br /&gt;
n = Anzahl der Einträge in der Look-Up-Tabelle (z.B. 256)&lt;br /&gt;
&lt;br /&gt;
i = Laufindex [0..n-1]&lt;br /&gt;
&lt;br /&gt;
z = Anzahl der linearen Stufen, die die PWM-Routine wiedergeben kann (z.B. 65536)&lt;br /&gt;
&lt;br /&gt;
Oder eingesetzt für den typischen Anwendungsfall:&lt;br /&gt;
&lt;br /&gt;
R[i] = floor(65535.0 * (i / 255.0) ^ 2.2 + 0.5)&lt;br /&gt;
&lt;br /&gt;
In Wikipedia ist&#039;s übrigens auch falsch beschrieben:&lt;br /&gt;
&lt;br /&gt;
Der Artikel [http://de.wikipedia.org/wiki/Gammakorrektur Gammakorrektur] verweist fälschlicher Weise auf das [http://de.wikipedia.org/wiki/Weber-Fechner-Gesetz Weber-Fechner-Gesetz] welches den Logarithmus zur Grundlage hat. Weiter unten im Weber-Fechner-Gesetz-Artikel findet sich der Hinweis, das die [http://de.wikipedia.org/wiki/Stevenssche_Potenzfunktion Stevensschen Potenzfunktionen] besser geeignet seien. In besagtem Artikel finden sich dann auch wieder die Verallgemeinerungen der Gamma-Korrektur wieder.&lt;br /&gt;
Im [http://en.wikipedia.org/wiki/Stevens%27_power_law Englischen Artikel zum Stevensschen Potenzgesetz] sind auch einige Exponenten für die Reizfunktionen zu finden.&lt;br /&gt;
&lt;br /&gt;
Komme mir hier im Forum manchmal wie ein Geisterfahrer vor... das wird einfach so oft falsch verwendet...&lt;br /&gt;
&lt;br /&gt;
Ich hoffe mal, dass sich hier noch Gleichgesinnte einfinden und jemand (im Einverständnis mit dem Originalautor) den Artikel entsprechend anpasst - oder die entsprechende Gegenaussage begründen kann.&lt;br /&gt;
&lt;br /&gt;
in diesem Sinne... schönen Restabend noch!&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
Ich bin der Autor des Artikels. Was die biologisch-physiologische Seite des Problems angeht, bin ich sicher nicht die Fachkraft, meine Kenntnisse bauen auch nur auf Wikipedia &amp;amp; Co auf. Wobei der praktische Unterschied zwischen Weber Fechner und Stevenssche Potenzfunktion relativ gering ist und bestenfalls für die Profis interessant ist. Aber meinestwegen kann der Artikel von dir dahingehend angepasst werden. Man lernt ja nie aus ;-)&lt;br /&gt;
&lt;br /&gt;
MfG&lt;br /&gt;
Falk&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
Bob Pease hat mal den Dynamikumfag des Auges abgeschätzt&lt;br /&gt;
&lt;br /&gt;
http://electronicdesign.com/Articles/Index.cfm?AD=1&amp;amp;AD=1&amp;amp;ArticleID=6059&lt;br /&gt;
&lt;br /&gt;
&amp;quot;What&#039;s All This Optical Stuff, Anyhow?&amp;quot;&lt;br /&gt;
Er rechnet mit dB, also logarithmischen Maßen, und kommt auf 145 dB. &lt;br /&gt;
Er gibt allerdings zu, dass er in optischen Maßeinheiten nicht so bewandert ist.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
Danke euch für das schnelle Feedback. Ich schau mal, dass ich &#039;nen Millimeter Zeit finde um den Artikel (und die Wertetabellen) anzupassen.&lt;br /&gt;
&lt;br /&gt;
Der Unterschied ist wirklich nicht groß, aber wenn&#039;s passende Formeln gibt, die zu dem nicht schwieriger zu rechnen sind, sollten die meiner Meinung nach verwendet werden. Die Unterschiede sind leider gerade im unteren Helligkeitsbereich nicht ohne :( Das Auge könnte da ruhig was kooperativer sein.&lt;br /&gt;
&lt;br /&gt;
Danke und n8&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
Ihr macht folgenden Denkfehler: Die LED wird nicht alleine betrachtet sondern mitsamt ihrer Umgebunb! Daher passt sich das Auge insgesamt nicht stark an, wenn die LEd die Helligkeit ändert - höchstens lokal ist das im Geringen Umfang der Fall. Damit gilt weder die globale Logarithmische Empfindlichkeit, noch kann man Linearität unterstellen.&lt;br /&gt;
&lt;br /&gt;
Der Umstand, dass eine PWM beim linearen durchfahren keinen linearen H-Verluf produziert, liegt zudem an der LED! Das kann man leicht nachmessen.&lt;br /&gt;
&lt;br /&gt;
== Danke! ==&lt;br /&gt;
&lt;br /&gt;
Erstmal herzlichen Dank für diesen Artikel! Der hat mir schon sehr geholfen. Mir ist schon klar, dass das Hauptaugenmerk auf der Helligkeitsverteilung liegt. Was mir nur beim Studieren des Programms schwer gefallen ist, war die Initialisierung des Timers. Dort wird immer das ganze Register auf einmal geschrieben, mit einem Wert in Hex-Form. Könnte man das nicht ändern in die übliche Schreibweise register = (1&amp;lt;&amp;lt;BITNAME) | (1&amp;lt;&amp;lt;NOCHNBIT)? Dann wüsste man sofort welche Bits gesetzt sind und welche nicht. Ich würde mich auch dafür zur VErfügung stellen, das alles umzurechnen/nachzuschlagen. Was hälst du davon, Falk?&lt;br /&gt;
&lt;br /&gt;
LG, Björn&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
Mach mal, klingt vernünftig. Aber bitte dann den Code REAL testen, damit sich keine Fehler einschleichen.&lt;br /&gt;
&lt;br /&gt;
MFg&lt;br /&gt;
Falk&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&amp;gt;Interessant wäre ja noch, ob denn die LED nicht auch noch ein unlineares &amp;gt;Verhalten hat.&lt;br /&gt;
&lt;br /&gt;
Hat sie, ist aber für diese Anwendung verschwindend gering.&lt;br /&gt;
&lt;br /&gt;
&amp;gt; Die ist ja ein Diode. Im &amp;quot;Knick&amp;quot; der LED steigt doch die Helligkeit auch&lt;br /&gt;
&amp;gt; nicht linear an. Ist das bei den Formeln schon berücksichtigt?&lt;br /&gt;
&lt;br /&gt;
Welcher &amp;quot;Knick&amp;quot;? Die Strom-Spannungskennlinie? Ist bei LEDs im Wesentlichen uninteressant. Die werden sowiso mit einer Konstantstromquelle betrieben, siehe Artikel [[LED]].&lt;br /&gt;
&lt;br /&gt;
MfG&lt;br /&gt;
Falk&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Stimmt, war ein Denkfehler von mir. --&amp;gt; Ist ja PWM-Betrieb, nicht linear...&lt;/div&gt;</summary>
		<author><name>78.53.221.64</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=LED-Fading&amp;diff=68122</id>
		<title>LED-Fading</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=LED-Fading&amp;diff=68122"/>
		<updated>2012-08-28T16:12:22Z</updated>

		<summary type="html">&lt;p&gt;78.53.221.64: /* Die Erklärung */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Das Problem ==&lt;br /&gt;
&lt;br /&gt;
Die Aufgabe klingt eigentlich recht einfach. Eine [[LED]] soll mittels [[PWM]] in ihrer Helligkeit gesteuert werden. Und weils so schön ist, möchte man sie geheimnisvoll aufleuchten lassen, sprich langsam heller und dunkler werden lassen. Der Fachmann nennt das Fading. Das Problem zeigt sich allerdings recht schnell. Wenn man eine 8-Bit PWM linear zwischen 0..255 laufen lässt, dann scheint die LED nicht linear gedimmt zu werden. Sie wird relativ schnell hell und bleibt lange hell.&lt;br /&gt;
&lt;br /&gt;
== Die Theorie ==&lt;br /&gt;
&lt;br /&gt;
Des Rätsels Lösung liegt in der Kennline des menschlichen Auges. Diese ist nichtlinear, genauer gesagt: sie ist nahezu logarithmisch. Das ermöglicht die Wahrnehmung eines sehr großen Helligkeitsbereichs, angefangen von Vollmond mit ~1/4 [http://de.wikipedia.org/wiki/Lux_%28Einheit%29 Lux] über eine normale Schreibtischbeleuchtung mit ca. 750 Lux bis zu einem hellen Sommertag mit bis zu 100.000 Lux. Solche hochdynamischen Signale sind nur mit einer logarithmischen Kennlinie in den Griff zu kriegen, auch von Mutter Natur und Erfinder Papa.&lt;br /&gt;
&lt;br /&gt;
=== Die Kennlinie des Auges genau betrachtet ===&lt;br /&gt;
&lt;br /&gt;
Die Kennlinie des menschlichen Auges ist annähernd logarithmisch. Das wurde vor langer Zeit durch das [http://de.wikipedia.org/wiki/Weber-Fechner-Gesetz Weber-Fechner-Gesetz] beschrieben. Genauere Untersuchungen zur [http://de.wikipedia.org/wiki/Gammakorrektur Gammakorrektur] führten jedoch zur [http://de.wikipedia.org/wiki/Stevenssche_Potenzfunktion Stevenschen Potenzfunktion]. Diese beschreibt das menschliche Auge etwas besser. (s. auch [[Talk:LED-Fading#Diskussion wissenschaftl.-technischer Hintergrund|Diskussionsseite]]). Die Unterschiede sind jedoch marginal.&lt;br /&gt;
&lt;br /&gt;
Praktisch heißt das, daß wir unserem Auge große physikalische Helligkeitsunterschiede präsentieren müssen, damit es das als lineare Helligkeitsteigerung erkennt. Etwas wissenschaftlicher formuliert heißt das, wir müssen durch Verkettung der logarithmischen Kennlinie des Auges mit einer exponentiellen Kennlinie eine physiologisch lineare Helligkeitsverteilung erzielen.&lt;br /&gt;
&lt;br /&gt;
Berechnet werden kann eine passende Tabelle beispielsweise mit folgender Funktion:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;y=\frac{b^{\,x/r_x}-1}{b-1}\cdot r_y&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dabei sind x und y die Ein-, bzw. Ausgabewerte der Funktion, jeweils im Bereich von 0 bis r–1. b ist die Basis der Exponentialfunktion und bestimmt, wann und wie stark die Kurve ansteigen soll. Hier ist etwas ausprobieren erforderlich, gute Ergebnisse liefern Werte im Bereich 10–100.&lt;br /&gt;
&lt;br /&gt;
== Das Demoprogramm ==&lt;br /&gt;
&lt;br /&gt;
Das folgende Beispielprogramm gemacht demonstriert die Wirkung verschiedener PWM-Auflösungen. Eine 8-Bit PWM wird mit 4/8/16 und 32 nichtlinearen Stufen betrieben, welche über eine Exponentialfunktion berechnet wurden. Dazu dient die [[media:pwm_table.zip|Exceltabelle]]&amp;lt;ref&amp;gt;Anmerkung: Bitte die Exceltabelle nochmal erklären, die Werte in der Tabelle stimmen nicht mit denen im Programm überein&amp;lt;/ref&amp;gt;. Die einzelnen, benachbarten Werte haben zueinander ein konstantes Verhältnis, das in der Exceltabelle als &#039;&#039;Factor&#039;&#039; berechnet wird. Ausserdem werden eine 10-Bit PWM mit 64 Stufen sowie eine 16-Bit PWM mit 256 Stufen betrieben.&lt;br /&gt;
&lt;br /&gt;
Das Programm ist ursprünglich auf einem [[AVR]] vom Typ ATmega32 entwickelt und getestet worden. Aber es ist leicht auf jeden AVR portierbar, welcher eine PWM zur Verfügung hat. Der AVR muss mit etwa 8 MHz getaktet werden, egal ob mit internem Oszillator oder von aussen mit Quarz. Man muss nur noch eine [[LED]] mittels Vorwiderstand von ca. 1 kΩ an Pin D5 anschliessen und los gehts. Es sollte hier noch erwähnt werden, dass das Programm mit eingeschalteter Optimierung compiliert werden muss, sonst stimmen die Zeiten der Warteschleifen aus &amp;lt;tt&amp;gt;util/delay.h&amp;lt;/tt&amp;gt; nicht.&lt;br /&gt;
&lt;br /&gt;
Bei Verwendung der LEDs auf dem STK500 bzw. bei der Verwendung von invertierenden Treiberstufen ist das&lt;br /&gt;
 #define STK500 0&lt;br /&gt;
durch&lt;br /&gt;
 #define STK500 1&lt;br /&gt;
zu ersetzen.&lt;br /&gt;
&lt;br /&gt;
Das Programm durchläuft alle 6 PWMs und lässt dabei die LED jeweils 3 mal glimmen. Mit 4 Schritten Auflösung ist das natürlich ruckelig, mit 8 schon wesentlich besser. Mit 16 Stufen sieht man bei langsamen Änderungen noch Stufen, dreht man die Ein- und Ausblendzeiten runter, ist der Übergang schon recht flüssig. Die 8-Bit PWM mit 32 Stufen unterscheidet sich praktisch nicht von der 10-Bit PWM mit 64 Stufen, es sei denn, man macht extrem langsame Einblendungen. Hier schlägt die Stunde der 16-Bit PWM. Diese wird bewußt sehr langsam ausgeführt um zu demonstrieren, daß hiermit praktisch keine Stufen mehr sichtbar sind, egal wie langsam gedimmt wird. Wie man auch sieht sind die drei höherauflösenden PWMs im unteren Bereich an ihrer Auflösungsgrenze, da einige PWM-Werte mehrfach vorkommen. Da heißt gleichzeitig, daß eine Steigerung der Stufenanzahl relativ sinnlos ist.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
//**************************************************************************&lt;br /&gt;
//*&lt;br /&gt;
//*  LED fading test&lt;br /&gt;
//*  uses exponential PWM settings to achive visual linear brightness&lt;br /&gt;
//*&lt;br /&gt;
//*  ATmega32 @ 8 MHz&lt;br /&gt;
//*                  &lt;br /&gt;
//**************************************************************************&lt;br /&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;
#define F_CPU 8000000L&lt;br /&gt;
#include &amp;lt;util/delay.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#define STK500 0&lt;br /&gt;
&lt;br /&gt;
#if STK500&lt;br /&gt;
// inverted PWM on OC1A for STK500&lt;br /&gt;
#define INVERT_PWM (1 &amp;lt;&amp;lt; COM1A0)&lt;br /&gt;
#else&lt;br /&gt;
// non-inverted PWM on OC1A&lt;br /&gt;
#define INVERT_PWM 0&lt;br /&gt;
#endif // STK500&lt;br /&gt;
&lt;br /&gt;
const uint16_t pwmtable_8A[4]  PROGMEM = { 0, 16, 64, 255 };&lt;br /&gt;
const uint16_t pwmtable_8B[8]  PROGMEM =&lt;br /&gt;
{&lt;br /&gt;
    0, 4, 8, 16, 32, 64, 128, 255&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
const uint16_t pwmtable_8C[16] PROGMEM =&lt;br /&gt;
{&lt;br /&gt;
    0, 2, 3, 4, 6, 8, 11, 16, 23, 32, 45, 64, 90, 128, 181, 255&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
const uint16_t pwmtable_8D[32] PROGMEM =&lt;br /&gt;
{&lt;br /&gt;
    0, 1, 2, 2, 2, 3, 3, 4, 5, 6, 7, 8, 10, 11, 13, 16, 19, 23,&lt;br /&gt;
    27, 32, 38, 45, 54, 64, 76, 91, 108, 128, 152, 181, 215, 255&lt;br /&gt;
};&lt;br /&gt;
 &lt;br /&gt;
const uint16_t pwmtable_10[64] PROGMEM =&lt;br /&gt;
{&lt;br /&gt;
    0, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 6, 6, 7, 8, 9, 10,&lt;br /&gt;
    11, 12, 13, 15, 17, 19, 21, 23, 26, 29, 32, 36, 40, 44, 49, 55,&lt;br /&gt;
    61, 68, 76, 85, 94, 105, 117, 131, 146, 162, 181, 202, 225, 250,&lt;br /&gt;
    279, 311, 346, 386, 430, 479, 534, 595, 663, 739, 824, 918, 1023&lt;br /&gt;
};&lt;br /&gt;
 &lt;br /&gt;
const uint16_t pwmtable_16[256] PROGMEM =&lt;br /&gt;
{&lt;br /&gt;
    0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3,&lt;br /&gt;
    3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 6, 6, 6, 6, 7,&lt;br /&gt;
    7, 7, 8, 8, 8, 9, 9, 10, 10, 10, 11, 11, 12, 12, 13, 13, 14, 15,&lt;br /&gt;
    15, 16, 17, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,&lt;br /&gt;
    31, 32, 33, 35, 36, 38, 40, 41, 43, 45, 47, 49, 52, 54, 56, 59,&lt;br /&gt;
    61, 64, 67, 70, 73, 76, 79, 83, 87, 91, 95, 99, 103, 108, 112,&lt;br /&gt;
    117, 123, 128, 134, 140, 146, 152, 159, 166, 173, 181, 189, 197,&lt;br /&gt;
    206, 215, 225, 235, 245, 256, 267, 279, 292, 304, 318, 332, 347,&lt;br /&gt;
    362, 378, 395, 412, 431, 450, 470, 490, 512, 535, 558, 583, 609,&lt;br /&gt;
    636, 664, 693, 724, 756, 790, 825, 861, 899, 939, 981, 1024, 1069,&lt;br /&gt;
    1117, 1166, 1218, 1272, 1328, 1387, 1448, 1512, 1579, 1649, 1722,&lt;br /&gt;
    1798, 1878, 1961, 2048, 2139, 2233, 2332, 2435, 2543, 2656, 2773,&lt;br /&gt;
    2896, 3025, 3158, 3298, 3444, 3597, 3756, 3922, 4096, 4277, 4467,&lt;br /&gt;
    4664, 4871, 5087, 5312, 5547, 5793, 6049, 6317, 6596, 6889, 7194,&lt;br /&gt;
    7512, 7845, 8192, 8555, 8933, 9329, 9742, 10173, 10624, 11094,&lt;br /&gt;
    11585, 12098, 12634, 13193, 13777, 14387, 15024, 15689, 16384,&lt;br /&gt;
    17109, 17867, 18658, 19484, 20346, 21247, 22188, 23170, 24196,&lt;br /&gt;
    25267, 26386, 27554, 28774, 30048, 31378, 32768, 34218, 35733,&lt;br /&gt;
    37315, 38967, 40693, 42494, 44376, 46340, 48392, 50534, 52772,&lt;br /&gt;
    55108, 57548, 60096, 62757, 65535&lt;br /&gt;
};&lt;br /&gt;
 &lt;br /&gt;
// long, variable delays&lt;br /&gt;
 &lt;br /&gt;
void my_delay (uint16_t milliseconds)&lt;br /&gt;
{&lt;br /&gt;
    for (; milliseconds &amp;gt; 0; milliseconds--)&lt;br /&gt;
        _delay_ms (1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
void pwm_up_down (const uint16_t pwm_table[], int16_t size, uint16_t delay)&lt;br /&gt;
{&lt;br /&gt;
    int16_t tmp;&lt;br /&gt;
&lt;br /&gt;
    for (tmp = 0; tmp &amp;lt; size; tmp++)&lt;br /&gt;
    {&lt;br /&gt;
        OCR1A = pgm_read_word (&amp;amp; pwm_table[tmp]);&lt;br /&gt;
        my_delay (delay);&lt;br /&gt;
    }&lt;br /&gt;
 &lt;br /&gt;
    for (tmp = size-1; tmp &amp;gt;= 0; tmp--)&lt;br /&gt;
    {&lt;br /&gt;
        OCR1A = pgm_read_word (&amp;amp; pwm_table[tmp]);&lt;br /&gt;
        my_delay (delay);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
// 8-Bit PWM with only 4 different settings&lt;br /&gt;
 &lt;br /&gt;
void pwm_8_4 (uint16_t delay)&lt;br /&gt;
{&lt;br /&gt;
    // 8 Bit Fast PWM&lt;br /&gt;
    TCCR1A = 0x81 | INVERT_PWM;&lt;br /&gt;
    // prescaler 256 -&amp;gt; ~122 Hz PWM frequency&lt;br /&gt;
    TCCR1B = (1 &amp;lt;&amp;lt; WGM12) | 4;&lt;br /&gt;
    &lt;br /&gt;
    pwm_up_down (pwmtable_8A, 4, delay);&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
// 8-Bit PWM with 8 different settings&lt;br /&gt;
 &lt;br /&gt;
void pwm_8_8 (uint16_t delay)&lt;br /&gt;
{&lt;br /&gt;
    // 8 Bit Fast PWM&lt;br /&gt;
    TCCR1A = 0x81 | INVERT_PWM;&lt;br /&gt;
    // prescaler 256 -&amp;gt; ~122 Hz PWM frequency&lt;br /&gt;
    TCCR1B = (1 &amp;lt;&amp;lt; WGM12) | 4;&lt;br /&gt;
 &lt;br /&gt;
    pwm_up_down (pwmtable_8B, 8, delay);&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
// 8-Bit PWM with 16 different settings&lt;br /&gt;
 &lt;br /&gt;
void pwm_8_16 (uint16_t delay)&lt;br /&gt;
{&lt;br /&gt;
    // 8 Bit Fast PWM&lt;br /&gt;
    TCCR1A = 0x81 | INVERT_PWM;&lt;br /&gt;
    // prescaler 256 -&amp;gt; ~122 Hz PWM frequency&lt;br /&gt;
    TCCR1B = (1 &amp;lt;&amp;lt; WGM12) | 4;&lt;br /&gt;
 &lt;br /&gt;
    pwm_up_down (pwmtable_8C, 16, delay);&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
// 8-Bit PWM with 32 different settings&lt;br /&gt;
 &lt;br /&gt;
void pwm_8_32 (uint16_t delay)&lt;br /&gt;
{&lt;br /&gt;
    //  8 Bit Fast PWM&lt;br /&gt;
    TCCR1A = 0x81 | INVERT_PWM;&lt;br /&gt;
    // prescaler 256 -&amp;gt; ~122 Hz PWM frequency&lt;br /&gt;
    TCCR1B = (1 &amp;lt;&amp;lt; WGM12) | 4;&lt;br /&gt;
 &lt;br /&gt;
    pwm_up_down (pwmtable_8D, 32, delay);&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
// 10-Bit PWM with 64 different settings&lt;br /&gt;
 &lt;br /&gt;
void pwm_10_64 (uint16_t delay)&lt;br /&gt;
{ &lt;br /&gt;
    // 10 Bit Fast PWM&lt;br /&gt;
    TCCR1A = 0x83 | INVERT_PWM;&lt;br /&gt;
    // prescaler 64 -&amp;gt; ~122 Hz PWM frequency&lt;br /&gt;
    TCCR1B = (1 &amp;lt;&amp;lt; WGM12) | 3;&lt;br /&gt;
 &lt;br /&gt;
    pwm_up_down (pwmtable_10, 64, delay);&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
// 16-Bit PWM with 256 different settings&lt;br /&gt;
 &lt;br /&gt;
void pwm_16_256 (uint16_t delay)&lt;br /&gt;
{&lt;br /&gt;
    // 16 Bit Fast PWM&lt;br /&gt;
    TCCR1A = 0x82 | INVERT_PWM;&lt;br /&gt;
    // stop timer&lt;br /&gt;
    TCCR1B = 0;&lt;br /&gt;
    // TOP for PWM, full 16 Bit&lt;br /&gt;
    ICR1 = 0xFFFF;&lt;br /&gt;
    // prescaler 1 -&amp;gt; ~122 Hz PWM frequency&lt;br /&gt;
    TCCR1B = (1 &amp;lt;&amp;lt; WGM12) | (1 &amp;lt;&amp;lt; WGM13) | 1;&lt;br /&gt;
 &lt;br /&gt;
    pwm_up_down (pwmtable_16, 256, delay);&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
int main (void)&lt;br /&gt;
{&lt;br /&gt;
    int8_t i;&lt;br /&gt;
    // delay in milliseconds for one fading step&lt;br /&gt;
    int16_t step_time = 400;&lt;br /&gt;
 &lt;br /&gt;
    // LED uses OC1A&lt;br /&gt;
    DDRD |= 1 &amp;lt;&amp;lt; PD5;&lt;br /&gt;
 &lt;br /&gt;
    // test all fading routines&lt;br /&gt;
 &lt;br /&gt;
    while (1)&lt;br /&gt;
    {&lt;br /&gt;
        for (i=0; i&amp;lt;3; i++) pwm_8_4 (step_time);&lt;br /&gt;
        my_delay (1000);&lt;br /&gt;
        &lt;br /&gt;
        for (i=0; i&amp;lt;3; i++) pwm_8_8 (step_time/2);&lt;br /&gt;
        my_delay (1000);    &lt;br /&gt;
        &lt;br /&gt;
        for (i=0; i&amp;lt;3; i++) pwm_8_16 (step_time/4);&lt;br /&gt;
        my_delay (1000);&lt;br /&gt;
        &lt;br /&gt;
        for (i=0; i&amp;lt;3; i++) pwm_8_32 (step_time/8);&lt;br /&gt;
        my_delay (1000);&lt;br /&gt;
        &lt;br /&gt;
        for (i=0; i&amp;lt;3; i++) pwm_10_64 (step_time/16);&lt;br /&gt;
        my_delay (1000);&lt;br /&gt;
        &lt;br /&gt;
        for (i=0; i&amp;lt;3; i++) pwm_16_256 (step_time/16);&lt;br /&gt;
        my_delay (1000);&lt;br /&gt;
    }&lt;br /&gt;
 &lt;br /&gt;
    return 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== FAQ ==&lt;br /&gt;
&lt;br /&gt;
; Wieso geht die LED nie ganz aus?: Es ist normal, dass die LED selbst bei OCR1A = 0 immer noch ganz schwach leuchtet. Die Hardware-PWM funktioniert so, dass bei einem Timerwert von 0 auf jeden Fall der Ausgang eingeschaltet wird. Danach kommt der Compare Match bei 0 und schaltet gleich wieder aus. Daher ist der Ausgang für einen PWM-Takt eingeschaltet. Um das zu ändern, muss man entweder invertierte PWM nutzen, dann ist allerdings der Ausgang nie zu 100% High, sondern hat immer einen Takt Low beim maximalem PWM-Wert. Oder man schaltet bei 0 einfach die PWM-Funktion ab und und setzt den Ausgang normal auf Low. [http://www.mikrocontroller.net/topic/200173#1965686].&lt;br /&gt;
&lt;br /&gt;
; Wieso dimmt man eine LED nicht besser mit einer variablen Stromquelle?: Nur so ist es möglich, die LEDs von nahezu 0 bis 100% zu dimmen, ohne dass es zu Farbänderungen kommt, was besonders bei RGB-Anwendungen wichtig ist.&lt;br /&gt;
&lt;br /&gt;
; Wieso flimmern LEDs bei Autorücklichtern? Wieso werden diese nicht mit Konstant-Stromquellen betrieben?:&lt;br /&gt;
&lt;br /&gt;
== Fußnoten ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Siehe auch ==&lt;br /&gt;
* [[PWM]]&lt;br /&gt;
* [[AVR-GCC-Tutorial#PWM (Pulsweitenmodulation)|AVR-GCC-Tutorial: PWM]]&lt;br /&gt;
* [[Soft-PWM]] - optimierte Software-PWM in C&lt;br /&gt;
* [http://www.b-kainka.de/bastel108.htm Eine LED weich blinken lassen ohne Mikrocontroller]&lt;br /&gt;
* [http://www.solstice.de/cms/upload/pdf/Veroeffentlichungen/Weber-Fechner-PHidS-1994.pdf Experimente zur logarithmischen Empfindungsskala, Weber-Fechner]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:AVR-Projekte]]&lt;br /&gt;
[[Category:Displays und Anzeigen]]&lt;/div&gt;</summary>
		<author><name>78.53.221.64</name></author>
	</entry>
</feed>