<?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=213.95.4.66</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=213.95.4.66"/>
	<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/articles/Spezial:Beitr%C3%A4ge/213.95.4.66"/>
	<updated>2026-04-10T23:20:27Z</updated>
	<subtitle>Benutzerbeiträge</subtitle>
	<generator>MediaWiki 1.39.7</generator>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=Festkommaarithmetik&amp;diff=68296</id>
		<title>Festkommaarithmetik</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=Festkommaarithmetik&amp;diff=68296"/>
		<updated>2012-09-07T12:15:04Z</updated>

		<summary type="html">&lt;p&gt;213.95.4.66: /* ITOA selbst gemacht */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Das Problem ==&lt;br /&gt;
&lt;br /&gt;
Ein immer wiederkehrendes Problem ist die Anzeige von Messwerten per UART/RS232 oder LCD. Die Messwerte werden praktisch immer von [[AD-Wandler]]n oder anderen Sensoren in digitaler Form geliefert. Doch wie wandelt man diese in eine &amp;quot;normale&amp;quot; Anzeige wie z.&amp;amp;nbsp;B. 4,56V um?&lt;br /&gt;
&lt;br /&gt;
Der einfachste Ansatz ist der Einsatz von Gleitkommazahlen. Dabei gilt nahezu immer die Formel&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;\text{Eingangsspannung} = \frac{\text{ADC-Wert} \cdot \text{Referenzspannung}}{ 2^{\text{Bitbreite}_\text{ADC}}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Den so errechneten Wert der Eingangsspannung kann man einfach per C-Funktion&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
sprintf(mein_string, &amp;quot;%2.4f&amp;quot;, Eingangsspannung);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
in einen String umwandeln und dann auf ein LCD oder den UART ausgeben.&lt;br /&gt;
&lt;br /&gt;
Soweit so gut. Das Problem ist &amp;quot;nur&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
* Das Rechnen mit Gleitkommazahlen ist auf den meisten Mikrocontrollern mit recht viel Rechenzeit sowie Programmspeicher verbunden, da diese keine Befehle zur direkten Verarbeitung von Gleitkommazahlen haben. Alle Rechnungen werden mit Hilfe von Bibliotheksfunktionen nachgebildet.&lt;br /&gt;
* Die Ausgabe von Gleitkommazahlen per sprintf und Konsorten benötigt ebenfalls sehr viel Programmspeicher, da diese Funktionen sehr mächtig und damit umfangreich sind&lt;br /&gt;
&lt;br /&gt;
== Die Lösung ==&lt;br /&gt;
&lt;br /&gt;
Die allerwenigsten Anwendungen benötigen die volle Leistung von Gleitkommazahlen (Dynamikbereich). Wesentlich sinnvoller ist die Anwendung von Festkommazahlen. Diese sind normale Integerzahlen (ganzzahlig ohne Kommastellen), allerdings mit &amp;quot;gedachten&amp;quot; Kommastellen. Wie geht das? Ganz einfach. Anstatt 10,45 kann man auch 1045 schreiben und die beiden letzten Stellen als Nachkommastellen betrachten. 1045 kann man in einer ganz normalen 16 Bit Integervariable speichern. Und auch damit rechnen!&lt;br /&gt;
&lt;br /&gt;
Anstatt nun in Gleitkomma zu schreiben und zu rechnen&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;U = \frac{756 \cdot 5{,}0}{1024}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
wird geschrieben&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;U = \frac{756 \cdot 5000}{1024}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Referenzspannung wird in 1/1000 V (mV) ausgedrückt und damit gerechnet. Das Ergebnis ist eine Spannung in mV. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;B&amp;gt;Wichtig&amp;lt;/B&amp;gt; ist dabei, daß&lt;br /&gt;
&lt;br /&gt;
* erst alle Multiplikationen und dann erst die Divisionen durchgeführt werden, um Rundungsfehler zu minimieren&lt;br /&gt;
* in sämtlichen Zwischenergebnissen keine arithmetischen Überläufe auftreten, also genügend grosse Variablen benutzen (16/32/64 Bit Integer)&lt;br /&gt;
&lt;br /&gt;
;Achtung!: Ein klassischer Fehler ist die Benutzung zu kleiner Variablentypen für den Multiplikationsfaktor oder andere Variablen. Das geht schief, weil C dann nur mit dem kleinen Zahlentyp rechnet und es zum Überlauf kommt. Erst danach wird das nun falsche Ergebnis in den größeren Zahlentyp konvertiert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
int k, adc;&lt;br /&gt;
long kl;&lt;br /&gt;
long ergebnis;&lt;br /&gt;
&lt;br /&gt;
ergebnis = adc * k;          // Fehler, Berechung als int&lt;br /&gt;
ergebnis = adc * (long)k;    // richtig, Berechung als long durch Cast&lt;br /&gt;
ergebnis = adc * kl;         // richtig, Berechung als long, wegen kl&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Man sollte mindestens eine Variable auf der rechten Seite genauso groß deklarieren wie das Ergebnis auf der linken Seite oder einen Cast benutzen.&lt;br /&gt;
&lt;br /&gt;
Doch wie wird nun diese Zahl in einen darstellbaren String umgewandelt? Im einfachsten Fall durch Verwendung der C-Funktion itoa (Integer to ASCII). Diese ist auf vielen Mikrocontrollern als C-Bibliothek verfügbar. Wenn dies jedoch nicht so sein sollte muss man sie selber schreiben. Und da wir hier etwas lernen wollen, werden wir das auch tun.&lt;br /&gt;
&lt;br /&gt;
== ITOA selbst gemacht ==&lt;br /&gt;
&lt;br /&gt;
Wie funktioniert nun die Umwandlung einer Zahl in einen String? Ganz einfach. Für jede Stelle der Dezimalzahl muss ein ASCII-Zeichen erzeugt werden. Wenn z.&amp;amp;nbsp;B. die Zahl 28943 in einen String gewandelt werden soll muss am Ende der String die ASCII-Codes 0x32, 0x38, 0x39, 0x34, 0x33 und 0x00 (Stringabschlusszeichen, Stringterminator) enthalten. Wie man bei genauem Hinsehen sieht, besteht der ASCII-Code einer Ziffer zwischen 0..9 immer aus 0x30 + Ziffer. Das ist einfach. Und wie kommt man nun an die einzelnen Ziffern? Dazu wird eine MODULO Operation durchgeführt. Diese liefert den Rest einer ganzzahligen Division.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
28943 MOD 10 =       3&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nun gehts an die nächste Stelle. Dazu wird die Zahl einfach durch 10 dividiert&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
28943 / 10 = 2894&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Und nun das Spiel von vorn.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
2894 MOD 10 =        4&lt;br /&gt;
2894 / 10   = 289&lt;br /&gt;
289 MOD 10  =        9&lt;br /&gt;
289 / 10    = 28&lt;br /&gt;
28 MOD 10   =        8&lt;br /&gt;
28 / 10     = 2&lt;br /&gt;
2 MOD 10    =        2&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das wars eigentlich schon. Beachtet werden muss nur, dass bei dieser Methode die einzelnen Stellen in umgekehrter Reihenfolge entstehen: Die höchstwertigen Stellen kommen erst zum Schluss.&lt;br /&gt;
&lt;br /&gt;
Hier ist nun unsere erste einfache Funktion, um eine vorzeichenlose 32 Bit Zahl in einen String umzuwandeln. Diese kann maximal 10 Dezimalstellen haben (0..4294967295), also wird ein Speicher für 11 Bytes benötigt (letztes Byte für den Stringterminator).  Bei dem Verfahren wird die Zahl rückwärts berechnet. Das muss bei der Ablage im Speicher berücksichtigt werden. Im Sinne der Verständlichkeit wurde bewusst auf Optimierungen und kompakt/kryptische Schreibweisen verzichtet. Der Syntax ist Standard-C und somit auf jedem Compiler nutzbar.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
&lt;br /&gt;
Funktion zur Umwandlung einer vorzeichenlosen 32 Bit Zahl in einen String&lt;br /&gt;
&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
void my_uitoa(uint32_t zahl, char* string) {&lt;br /&gt;
  int8_t i;                             // schleifenzähler&lt;br /&gt;
&lt;br /&gt;
  string[10]=&#039;\0&#039;;                       // String Terminator&lt;br /&gt;
  for(i=9; i&amp;gt;=0; i--) {&lt;br /&gt;
    string[i]=(zahl % 10) +&#039;0&#039;;         // Modulo rechnen, dann den ASCII-Code von &#039;0&#039; addieren&lt;br /&gt;
    zahl /= 10;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Diese Funktion gibt auch führende Nullen aus. Das ist erstmal OK, denn so wissen wir immer wo unser gedachtes Komma ist. Bei der Ausgabe können die führenden Nullen unterdrückt werden. Wie das geht, wird weiter unten beschrieben.&lt;br /&gt;
&lt;br /&gt;
Benötigt man neben der Ausgabe für vorzeichenlose (unsigned) Werte auch noch eine Funktion für vorzeichenbehaftete Werte, so ist auch dieses keine Hexerei. Dazu verwenden wir ein zusätzliches Byte im String um das Vorzeichen zu speichern. Der String muss nun also mindestens 12 Bytes Speicherplatz zur Verfügung stellen. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
// Funktion zur Umwandlung einer vorzeichenbehafteten &lt;br /&gt;
// 32-Bit Zahl in einen String&lt;br /&gt;
&lt;br /&gt;
void my_itoa(int32_t zahl, char* string) {&lt;br /&gt;
  uint8_t i;&lt;br /&gt;
&lt;br /&gt;
  string[11]=&#039;\0&#039;;                  // String Terminator&lt;br /&gt;
  if( zahl &amp;lt; 0 ) {                  // ist die Zahl negativ?&lt;br /&gt;
    string[0] = &#039;-&#039;;              &lt;br /&gt;
    zahl = -zahl;&lt;br /&gt;
  }&lt;br /&gt;
  else string[0] = &#039; &#039;;             // Zahl ist positiv&lt;br /&gt;
&lt;br /&gt;
  for(i=10; i&amp;gt;=1; i--) {&lt;br /&gt;
    string[i]=(zahl % 10) +&#039;0&#039;;     // Modulo rechnen, dann den ASCII-Code von &#039;0&#039; addieren&lt;br /&gt;
    zahl /= 10;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Allerdings ist diese Vorgehesweise durch die modulo und anschliessende Divisionsoperation extrem ineffizient. Es werden tatsächlich zwei Divisionen durchgeführt, obwohl nur eine notwendig wäre.&lt;br /&gt;
&lt;br /&gt;
== Beispiele ==&lt;br /&gt;
&lt;br /&gt;
=== Digitaler Temperatursensor ===&lt;br /&gt;
&lt;br /&gt;
Anstatt eines ADC-Wertes werden oft auch Digitalwerte von Temperatursensoren verarbeitet. Der Weg ist hier identisch. Allerdings hat man keine Referenzspannung oder Referenztemperatur. Das ist aber kein Beinbruch. Z.B. der LM74 hat eine Auflösung von 1/16°C = 0,0625°C. Um das Messergebnis ohne Verlust von Auflösung auszugeben könnte man als erstes den Digitalwert auf 1/100 °C umrechnen. Das geschieht mit der Multiplikation mit 6,25. Doch Stop, das ist ja schon wieder ne Gleitkommazahl. Doch kein Problem, wir wissen ja wie wir das Problem lösen. Wir schieben das Komma um zwei Stellen nach rechts und multiplizieren mit 625 und wissen, dass das Ergbniss nun in 1/10000°C vorliegt. Über den physikalischen Sinn dieser Auflösung müssen wir nicht nachdenken, wichtig ist für uns nur, dass jetzt die Zahl einfach per itoa() umwandelbar ist. Allgemein kann man folgenden Ablauf zur Berechnung des Korrekturfaktors angeben&lt;br /&gt;
&lt;br /&gt;
* Den Korrekturfaktor &amp;lt;B&amp;gt;K&amp;lt;/B&amp;gt; mit vollen Kommastellen berechnen, dabei ist die neue Auflösung sinnvollerweise eine Dezimalzahl ( 0,1; 0,001 etc.) und kleiner als die alte Auflösung.&lt;br /&gt;
&lt;br /&gt;
::&amp;lt;math&amp;gt;K = \frac{\mathrm{alte\ Aufl\ddot osung}}{\mathrm{neue\ Aufl\ddot osung}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Den berechneten Korrekturfaktor solange mit 10 multiplizieren bis alle Nachkommastellen verschwunden sind bzw. durch Rundung ein akzeptabler Fehler entsteht. Für jede Multiplikation des Faktors mit 10 muss die neue Auflösung durch 10 dividiert werden.&lt;br /&gt;
&lt;br /&gt;
::&amp;lt;math&amp;gt;\text{Temperatur} = \text{Sensorwert} \cdot K&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;B&amp;gt;Beispiel:&amp;lt;/B&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Alte Auflösung: 1/32°C&amp;lt;BR&amp;gt;&lt;br /&gt;
Neue Auflösung: 1/100°C&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;K = \frac{\frac{1}{32}}{\frac{1}{100}} = 3{,}125&amp;lt;/math&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Der Korrekturfaktor 3,125 kann zweimal mit 10 multipliziert werden und dann auf 312 gerundet werden, das entspricht einem Rundungsfehler von gerade mal 1/624 = 0,16% ! Die neue Auflösung beträgt 1/10000°C. Wenn der Sensor nur 7 Bit Werte liefert kann das Ergebnis in einer 16 Bit Variablen gespeichert werden, darüber hinaus ist eine 32 Bit Variable notwendig.&lt;br /&gt;
&lt;br /&gt;
=== ADC allgemein ===&lt;br /&gt;
&lt;br /&gt;
Wenn man das obige ADC-Beispiel allgemein beschreiben will, dann gilt folgender Ablauf&lt;br /&gt;
&lt;br /&gt;
* Korrekturfaktor mit vollen Kommastellen berechnen&lt;br /&gt;
&lt;br /&gt;
::&amp;lt;math&amp;gt;\mathrm{alte\ Aufl\ddot osung} = \frac{\text{Referenzspannung}}{2^{\text{Bitbreite}_\text{ADC}}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
::&amp;lt;math&amp;gt;K  = \frac{\mathrm{alte\ Aufl\ddot osung}}{\mathrm{neue\ Aufl\ddot osung}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Den berechneten Korrekturfaktor K solange mit 10 multiplizieren bis alle Nachkommastellen verschwunden sind bzw. durch Rundung ein akzeptabler Fehler entsteht. Für jede Multiplikation des Faktors mit 10 muss die neue Auflösung durch 10 dividiert werden.&lt;br /&gt;
&lt;br /&gt;
::&amp;lt;math&amp;gt;\text{Eingangsspannung} = \text{ADC-Wert} \cdot K&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;B&amp;gt;Beispiel:&amp;lt;/B&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Referenzspannung : 5V&amp;lt;BR&amp;gt;&lt;br /&gt;
ADC Bitbreite : 10&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\mathrm{alte\ Aufl\ddot osung} = \frac{5V}{2^{10}} = \frac{5}{1024} = 0{,}0048828125\,V&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
neue Auflösung:  0,001 V = 1mV&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;K = \frac{0{,}0048828125 V}{0{,}001V} = 4{,}8828125&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Korrekturfaktor 4,8828125 wird zweimal mit 10 multipliziert und dann auf 488 gerundet, das entspricht einem Rundungsfehler von gerade mal 0,05% ! Die neue Auflösung ist 0,00001 V = 10µV. Das Ergebnis muss in einer 32 Bit Variablen gespeichert werden, denn der grösste Messwert ergibt 1023*488 = 499224. Der Vorteil dieses allgemeinen Ansatzes ist vor allem, daß nur eine Multiplikation benötigt wird, im Gegensatz zu unserem allerersten Beispiel, welches eine Multiplikation und eine Division benötigt. Das spart einiges an Rechenzeit und Programmspeicherplatz.&lt;br /&gt;
&lt;br /&gt;
=== Division durch Konstanten ===&lt;br /&gt;
&lt;br /&gt;
Manchmal muss man in in einer Formel durch eine Konstante dividieren, z.B. a = b / 0.5432. Das kann man zunächst mathematisch korrekt umformen zu a = b * ( 1 / 0.5432) = b * 1.8409426. Die Divison ist identisch mit der Multiplikation des Kehrwertes. Auch hier kann man wieder auf das bewährte Prinzip zurückgreifen. Und zwar solange mit 10 multiplizieren, bis alle Nachkommastellen verschwunden sind oder der Fehler vernachlässigbar klein ist. In diesem Beispiel könnte man z.B. rechnen a = b * 18409 / 10000. Dabei kann man zu einem weiteren Trick greifen, um die echte Division durch 10000, welche einiges an Zeit und Programmspeicher kostet, zu sparen. Und zwar kann man anstatt einer Zehnerpotenz (10,100, 1000 etc.) auf eine Zweierpotenz ausweichen. Man multipliziert den Faktor also in unserem Beispiel mit 2^13=8192. Die Rechnung lautet nun a = b * 15081 / 8192. Die Division durch 8192 kann man aber deutlich schneller als eine Bitverschiebung um 13 Stellen nach rechts ausführen. Einge Compiler sind schlau genug das automatisch zu erkennen und umzusetzen, bei anderen muss man es explizit hinschreiben. Auch hier muss man wie immer dafür sorgen, daß es in den Zwischenergebnissen nicht zu Überläufen kommt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
int32_t a,b;&lt;br /&gt;
&lt;br /&gt;
a = b / 0.5432;         // direkte Formel, Division durch Konstante&lt;br /&gt;
                        // mit Fließkommaarithmetik&lt;br /&gt;
a = b * 18409 / 10000;  // Umformung in Kehrwert und Festkommaarthimetik&lt;br /&gt;
                        // mit Zehnerpotenzen&lt;br /&gt;
a = b * 15081 / 8192;   // Festkommaarithmetik mit Zweierpotenzen.&lt;br /&gt;
a = (b * 15081) &amp;gt;&amp;gt; 13;  // Division explizit ausgeführt als Schiebeoperation&lt;br /&gt;
                        // für nicht so schlaue Compiler&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Ergebnis runden ==&lt;br /&gt;
&lt;br /&gt;
Nach der Umrechung des ADC/Sensor-Wertes und dem Aufruf von my_uitoa() kann man sehr einfach eine Rundung durchführen. Dazu muss nur die erste Stelle, welche durch Rundung wegfallen soll, geprüft werden. Ist sie kleiner als der ASCII-Code von &#039;5&#039; (0x35) dann muss abgerundet werden, sprich alles bleibt wie es ist. Im anderen Fall muss aufgerundet werden, was bedeutet dass die letzte angezeigte Dezimalstelle um eins erhöht werden muss. Doch aufgepasst! Wenn z.&amp;amp;nbsp;B. in unserem String die Zahl 1995 steht und die letzte Stelle durch Rundung wegfallen soll, kommte es zum Übertrag. Die letzte 9 wird zur 0 + Übertrag. Die nächste linksstehende Stelle muss erhöht werden. Das ist &amp;quot;dummerweise&amp;quot; auch eine 9, also wieder ein Übertrag. Die letzte Ziffer ist 1, die wird nur auf zwei erhöht und der Übertrag endet.&lt;br /&gt;
&lt;br /&gt;
Basierend auf unserer Funktion my_uitoa() soll hier eine einfache Rundungsfunktion gezeigt werden. Auch diese arbeitet mit einem 11 Byte String, welcher vorher durch my_uitoa erzeugt wurde.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
&lt;br /&gt;
Funktion zur Rundung einer vorzeichenlosen 32 Bit Zahl im Stringformat&lt;br /&gt;
&lt;br /&gt;
Parameter:&lt;br /&gt;
&lt;br /&gt;
char* string:  Zeiger auf String, welcher mit my_uitoa() erzeugt wurde&lt;br /&gt;
uint8_t digit: Offset im String, zeigt auf die Stelle welche zur Rundung ausgewertet werden soll&lt;br /&gt;
               gültiger Wertebereich ist 1..9 !&lt;br /&gt;
               Der Offset von 1 zeigt auf die zweite Stelle von links&lt;br /&gt;
               Der Offset von 9 zeigt auf die letzte Stelle von links&lt;br /&gt;
&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
void my_round(char* string, uint8_t digit) {&lt;br /&gt;
  uint8_t i;&lt;br /&gt;
&lt;br /&gt;
  if (string[digit]&amp;gt;=&#039;5&#039;) {         // Aufrunden?&lt;br /&gt;
    for(i=(digit-1); i&amp;gt;=0; i--) {&lt;br /&gt;
      string[i] += 1;               // Aufrunden&lt;br /&gt;
      if (string[i]&amp;lt;=&#039;9&#039;)&lt;br /&gt;
        break;                      // kein Übertrag, schleife verlassen&lt;br /&gt;
      else&lt;br /&gt;
        string[i]=&#039;0&#039;;              // Übertrag und Überlauf&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for(i=digit; i&amp;lt;10; i++) string[i] =&#039;0&#039;;   // gerundete Stellen auf Null setzen&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Funktion ist auch auf einen String anwendbar, welcher mit my_itoa() erzeugt wurde (also vorzeichenbehaftete Zahlen). Allerdings muss der Funktion ein Pointer auf das zweite Byte (char) übergeben werden, da im ersten das Vorzeichen gespeichert ist. Das geschieht am einfachsten so.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
my_round(my_string+1, 5);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Etwas einfacher ist es hier übrigens, zur letzten Stelle die &amp;quot;weggerundet&amp;quot; werden soll, einfach fünf zu addieren. Die Rundung wird dann durch eine simple Division durch die entsprechende Zehnerpotenz ersetzt. Wenn die letzte wegfallende Stelle vorher größer oder gleich 5 war, wurde durch die Addition die vorletzte Stelle um eins erhöht, also aufgerundet. Wenn die letzte Stelle kleiner als 5 war, dann spielt die Veränderung keine Rolle und die vorletzte Stelle bleibt gleich. Durch die Division wird dann also abgerundet.&lt;br /&gt;
&lt;br /&gt;
== Ergebnis ausgeben ==&lt;br /&gt;
&lt;br /&gt;
Nun haben wir unseren Messwert in eine Zahl mit der richtigen Einheit umgewandelt und gerundet. Jetzt folgt der letzte Schritt, die Ausgabe auf einen UART oder LCD. Dazu ist es meist wünschenswert führende Nullen nicht anzuzeigen. Also anstatt 0095,89 will man 95,89 ausgeben. Bei negativen Zahlen kommt noch das Vorzeichen hinzu.&lt;br /&gt;
&lt;br /&gt;
=== Ausgabe auf LCD (HD44780 &amp;amp; CO) ===&lt;br /&gt;
&lt;br /&gt;
Zunächst wollen wir unsere Zahl auf einem LCD ausgeben. Dazu braucht man die entsprechende Funktion lcd_data(), wie sie z.&amp;amp;nbsp;B. im [[AVR-GCC-Tutorial#LCD_Ansteuerung]] zu finden ist.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
&lt;br /&gt;
Funktion zur Anzeige einer 32 Bit Zahl im Stringformat&lt;br /&gt;
auf einem LCD mit HD44780 Controller&lt;br /&gt;
&lt;br /&gt;
Parameter:&lt;br /&gt;
&lt;br /&gt;
char* string  : Zeiger auf String, welcher mit my_itoa() erzeugt wurde&lt;br /&gt;
uint8_t start : Offset im String, ab der die Zahl ausgegeben werden soll,&lt;br /&gt;
                das ist notwenig wenn Zahlen mit begrenztem Zahlenbereich&lt;br /&gt;
                ausgegeben werden sollen&lt;br /&gt;
                Vorzeichenlose Zahlen      : 0..10&lt;br /&gt;
                Vorzeichenbehaftete zahlen : 1..11&lt;br /&gt;
uint8_t komma : Offset im String, zeigt auf die Stelle an welcher das virtuelle&lt;br /&gt;
                Komma steht (erste Nachkommastelle)&lt;br /&gt;
                komma muss immer grösser oder gleich start sein !&lt;br /&gt;
&lt;br /&gt;
uint8_t frac  : Anzahl der Nachkommastellen&lt;br /&gt;
&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
void my_print_LCD(char* string, uint8_t start, uint8_t komma, uint8_t frac) {&lt;br /&gt;
&lt;br /&gt;
  uint8_t i;            // Zähler&lt;br /&gt;
  uint8_t flag=0;       // Merker für führende Nullen&lt;br /&gt;
&lt;br /&gt;
  // Vorzeichen ausgeben  &lt;br /&gt;
  if (string[0]==&#039;-&#039;) lcd_data(&#039;-&#039;); else lcd_data(&#039; &#039;);&lt;br /&gt;
&lt;br /&gt;
  // Vorkommastellen ohne führende Nullen ausgeben&lt;br /&gt;
  for(i=start; i&amp;lt;komma; i++) {&lt;br /&gt;
    if (flag==1 || string[i]!=&#039;0&#039;) {&lt;br /&gt;
      lcd_data(string[i]);&lt;br /&gt;
      flag = 1;&lt;br /&gt;
    }&lt;br /&gt;
    else lcd_data(&#039; &#039;);         // Leerzeichen&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  lcd_data(&#039;,&#039;);                // Komma ausgeben&lt;br /&gt;
&lt;br /&gt;
  // Nachkommastellen ausgeben&lt;br /&gt;
  for(; i&amp;lt;(komma+frac); i++) lcd_data(string[i]);&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Funktion gibt zunächst das Vorzeichen aus, das ist einfach. Danach werden die Vorkommastellen ausgegeben. Aber es wird nur dann ein Zeichen ausgegeben, wenn vorher schon mal eins ausgegeben wurde (flag ==1) oder das aktuelle Zeichen keine &#039;0&#039; ist. Danach werden ganz normal die Nachkommastellen ausgegeben, hier ist eine Unterdrückung führender Nullen sogar mathematisch falsch!&lt;br /&gt;
&lt;br /&gt;
Genutzt wird die Funktion beispielsweise so, um dreistellige Zahlen bis 999 mit zwei Nachkommastellen auszugeben. Die Zahl selber hat sechs Nachkommastellen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
char my_string[12]=&amp;quot;-0034567891\0&amp;quot;;&lt;br /&gt;
my_print_LCD(my_string, 2, 5, 2);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Auf dem LCD erscheint dann &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- 34.56&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Diese Funktion kann auch verwendet werden, um vorzeichenlose Zahlen auszugeben, welche mit my_uitoa() erzeugt wurden. Da an der ersten Stelle nie ein &#039;-&#039; steht, wird auch nie ein &#039;-&#039; ausgegeben.&lt;br /&gt;
&lt;br /&gt;
=== Ausgabe auf UART ===&lt;br /&gt;
&lt;br /&gt;
Die Ausgabe auf einen UART ist nahezu identisch. Auch hier braucht man eine Funktion putc(), welche ein einzelnes Zeichen auf den UART schreiben kann wie z.&amp;amp;nbsp;B. im [[AVR-GCC-Tutorial/Der UART]] beschrieben ist. Der Unterschied zur LCD-Ausgabe besteht darin, dass zwischen dem Vorzeichen und der Zahl keinerlei Leerzeichen eingefügt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
&lt;br /&gt;
Funktion zur Ausgabe einer 32 Bit Zahl im Stringformat&lt;br /&gt;
auf den UART&lt;br /&gt;
&lt;br /&gt;
Parameter:&lt;br /&gt;
&lt;br /&gt;
char* string  : Zeiger auf String, welcher mit my_itoa() erzeugt wurde&lt;br /&gt;
uint8_t start : Offset im String, ab der die Zahl ausgegeben werden soll,&lt;br /&gt;
                das ist notwenig wenn Zahlen mit begrenztem Zahlenbereich&lt;br /&gt;
                ausgegeben werden sollen&lt;br /&gt;
                Vorzeichenlose Zahlen      : 0..10&lt;br /&gt;
                Vorzeichenbehaftete zahlen : 1..11&lt;br /&gt;
uint8_t komma : Offset im String, zeigt auf die Stelle an welcher das virtuelle&lt;br /&gt;
                Komma steht (erste Nachkommastelle);&lt;br /&gt;
                komma muss immer grösser oder gleich start sein !&lt;br /&gt;
&lt;br /&gt;
uint8_t frac  : Anzahl der Nachkommastellen&lt;br /&gt;
&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
void my_print_UART(char* string, uint8_t start, uint8_t komma, uint8_t frac) {&lt;br /&gt;
&lt;br /&gt;
  uint8_t i;            // Zähler&lt;br /&gt;
  uint8_t flag=0;       // Merker für führende Nullen&lt;br /&gt;
&lt;br /&gt;
  // Vorkommastellen ohne führende Nullen ausgeben&lt;br /&gt;
  for(i=start; i&amp;lt;komma; i++) {&lt;br /&gt;
    if (flag==1 || string[i]!=&#039;0&#039;) {&lt;br /&gt;
      if (flag==0 &amp;amp;&amp;amp; string[0]==&#039;-&#039;) putc(&#039;-&#039;);     // negatives Vorzeichen ausgeben&lt;br /&gt;
      putc(string[i]);&lt;br /&gt;
      flag = 1;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  putc(&#039;,&#039;);                // Komma ausgeben&lt;br /&gt;
&lt;br /&gt;
  // Nachkommastellen ausgeben&lt;br /&gt;
  for(; i&amp;lt;(komma+frac); i++) putc(string[i]);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Diese Funktion kann auch verwendet werden, um vorzeichenlose Strings auszugeben, welche mit my_uitoa() erzeugt wurden. Da an der ersten Stelle nie ein &#039;-&#039; steht, wird auch nie ein &#039;-&#039; ausgegeben.&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Grundlagen]]&lt;br /&gt;
[[Kategorie:Algorithmen und Arithmetik]]&lt;/div&gt;</summary>
		<author><name>213.95.4.66</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=Wellenwiderstand&amp;diff=50495</id>
		<title>Wellenwiderstand</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=Wellenwiderstand&amp;diff=50495"/>
		<updated>2010-09-09T09:17:24Z</updated>

		<summary type="html">&lt;p&gt;213.95.4.66: /* Links */&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 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;
Eine elektrische Leitung muß man bei hohen Frequenzen als ein Netzwerk aus&lt;br /&gt;
&lt;br /&gt;
* Serienwiderstand Rs&lt;br /&gt;
* Parallelwiderstand Rp&lt;br /&gt;
* Serieninduktivität Ls&lt;br /&gt;
* Parallelkapazität Cp&lt;br /&gt;
&lt;br /&gt;
betrachten.&lt;br /&gt;
&lt;br /&gt;
[[bild:wellenwiderstand_ersatzschaltbild.png]]&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. Die unvermeidlichen und ausschlaggebenden Parameter sind jedoch Ls und Cp. Jeder elektrische Leiter, welcher von einem Strom durchflossen wird, erzeugt ein Magnetfeld. Das ist gleichbedeutend mit der Induktivität Ls. Ebenso besteht zwischen zwei isolierten Leitern immer ein elektrisches Feld, wodurch der Kondensator Cp gebildet wird. Ls und Cp sind die entscheidenden Grössen 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{Ls}{Cp}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Er ist eine charkteristische Grösse 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&amp;amp;Omega; &lt;br /&gt;
* Koaxialkabel RG59, 75&amp;amp;Omega;&lt;br /&gt;
* Twisted Pair CAT3/5/7 für Ethernet, 100&amp;amp;Omega;&lt;br /&gt;
* Flachbandkabel, 150&amp;amp;Omega; typ.&lt;br /&gt;
* Leiterbahnen auf Platinen mit 30...150&amp;amp;Omega;&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össer 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 1/6 ~ 0,83ns betragen. Bei einer Ausbreitungsgeschwindigkeit von 21cm/ns ergibt das eine maximal zulässige Leitungslänge von 21cm/ns * 0,83ns ~ 17,5cm. Das heißt, bei einer Leitungslänge von bis zu 17,5cm &#039;&#039;&#039;und&#039;&#039;&#039; halbwegs sauberer Leitungsführung treten keine nennenswerten Reflexionen auf, 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;
Serienterminierung arbeitet bewußt mit Reflexionen. Von der Quelle wird ein Signal mit einem Innenwiderstand gleich dem Wellenwiderstand eingespeist. Dadurch ergibt sich ein Spannungsteiler 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 Spannungspegel. Wenn die rücklaufende Reflexion die Quelle wieder erreicht wird sie vom Innenwiderstand der Quelle, welcher gleich dem Wellenwiderstand ist, absorbiert, es entsteht keine weitere Reflexion. Idealerweise sollte der externe Serienwiderstand Rs plus der Innenwiderstand des Ausgangs Ri gleich dem Wellenwiderstand sein. CMOS-ICs haben Ausgangswiderstände zwischen 15..50 Ohm.&lt;br /&gt;
&lt;br /&gt;
[[bild:wellenwiderstand_serienterminierung.png]]&lt;br /&gt;
&lt;br /&gt;
Datensignale können meist problemlos mit Serienterminierung 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;
Parallelterminierung absorbiert die ankommende Welle am Ende einer Leitung. Damit treten zu keinem Zeitpunkt Reflexionen auf.&lt;br /&gt;
&lt;br /&gt;
[[bild:wellenwiderstand_parallelterminierung.png]]&lt;br /&gt;
&lt;br /&gt;
Nachteilig ist der Stromverbrauch bei HIGH Pegel. Den kann man halbieren, indem man mit einem speziellen Spannungsregler eine sog. Terminierungsspannung 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 Stromverbrauch noch recht beachtlich. 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 Serienterminierung.&lt;br /&gt;
&lt;br /&gt;
[[bild:wellenwiderstand_vt-terminierung.png]]&lt;br /&gt;
&lt;br /&gt;
Ohne Terminierungsspannung kommt man mit der sog. Thevenin-Terminierung aus. Dabei wird der Terminierungswiderstand durch zwei doppelt so große Widerstände ersetzt. Aus Sicht des Kabels sind diese beiden Widerstände &#039;&#039;&#039;parallel&#039;&#039;&#039; geschaltet! Daher auch der Name, Thevenin Equivalent 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.&lt;br /&gt;
&lt;br /&gt;
[[bild:wellenwiderstand_theveninterminierung.png]]&lt;br /&gt;
&lt;br /&gt;
=== AC-Terminierung ===&lt;br /&gt;
&lt;br /&gt;
Um den Stromverbrauch allgemein zu senken kann AC-Terminierung eingesetzt werden. Dazu wird ein Kondensator in Reihe zum Terminierungswiderstand 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 Terminierungswiderstand nicht voll wirksam ist. Andererseits darf er nicht zu groß sein, damit der Umladevorgang vor dem nächsten Flankenwechsel abgeschlossen ist (Taktfrequenz). Hier muß man ggf. experimentieren und &#039;&#039;&#039;richtig&#039;&#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 Terminierungsspannung. Der Vorteil ist der eingesparte Spannungsregler, der Stromverbrauch ist identisch mit der Parallelterminierung. Als grobe Orientierung sollte die Zeitkonstante aus Terminierungswiderstand 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 &amp;gt;= 1000 \cdot T_{CLK}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[bild:wellenwiderstand_ac-terminierung.png]]&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 Ohm layoutet, bei differentiellen Signalen auch 100 Ohm (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 vor allem für Takte es 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.&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 ohne 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;
== Links ==&lt;br /&gt;
&lt;br /&gt;
* [http://de.wikipedia.org/wiki/Wellenimpedanz Wellenwiderstand bei Wikipedia]&lt;br /&gt;
* [http://www.signalintegrity.com Die Bibel der hochfrequenten Digitalsignale]&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;/div&gt;</summary>
		<author><name>213.95.4.66</name></author>
	</entry>
</feed>