<?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=Frajo</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=Frajo"/>
	<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/articles/Spezial:Beitr%C3%A4ge/Frajo"/>
	<updated>2026-04-11T17:13:05Z</updated>
	<subtitle>Benutzerbeiträge</subtitle>
	<generator>MediaWiki 1.39.7</generator>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=DTMF&amp;diff=39714</id>
		<title>DTMF</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=DTMF&amp;diff=39714"/>
		<updated>2009-10-06T16:06:47Z</updated>

		<summary type="html">&lt;p&gt;Frajo: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Abkürzung für &#039;&#039;&#039;D&#039;&#039;&#039;ual &#039;&#039;&#039;T&#039;&#039;&#039;one &#039;&#039;&#039;M&#039;&#039;&#039;ulti-&#039;&#039;&#039;F&#039;&#039;&#039;requency&lt;br /&gt;
&lt;br /&gt;
Wird z.B. beim Telefon verwendet. Jeder Zahl ist ein Doppelton (zwei miteinander vermischte Frequenzen) zugeordnet (8 Frequenzen in einer 4 * 4 Matrix, also 16 mögliche Kodierungen).  Die Frequenzen sind so gewählt, dass sie im normalen Sprachspektrum möglichst nicht auftauchen können, da im Telefoniebereich eine &#039;&#039;in-band&#039;&#039; Signalisierung damit vorgenommen werden soll (d.h. diese Signale sollen sich eindeutig vom Nutzsignal unterscheiden können).&lt;br /&gt;
&lt;br /&gt;
Es gibt spezielle Schaltkreise für Erzeugung und Erkennung (M8870) von DTMF, die sich einfach an Mikrocontroller ankoppeln lassen.  Die Erkennung benötigt irgendeine Form von Filter, entweder analog (ziemlich aufwendig) oder digital ([[FFT]] o.ä.), so dass eine direkte Erkennung mit einem Controller selten benutzt wird.  Die Erzeugung von DTMF ist geringfügig einfacher und könnte z.B. über Sinustabellen erfolgen.&lt;br /&gt;
&lt;br /&gt;
DTMF wird gern als Lehrbeispiel für die Verwendung des [[Goertzel-Algorithmus]] benutzt, ein kleines IIR-Filter zur Tondecodierung.&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Datenübertragung]]&lt;/div&gt;</summary>
		<author><name>Frajo</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=Port-Expander_PCF8574&amp;diff=27721</id>
		<title>Port-Expander PCF8574</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=Port-Expander_PCF8574&amp;diff=27721"/>
		<updated>2008-04-30T13:33:29Z</updated>

		<summary type="html">&lt;p&gt;Frajo: /* I2C Kommunikation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;Autor: Alexander Starke&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=Einleitung=&lt;br /&gt;
&lt;br /&gt;
Einen weiteren nützlichen Baustein am [[I2C]]-Bus stellen Port-Expander dar. Wer schon einmal unter &amp;quot;chronischem Pinmangel&amp;quot; in einer seiner Applikationen gelitten hat, weiss was ich meine.&lt;br /&gt;
&lt;br /&gt;
Meine Wahl ist hier auf den PCF8574 gefallen, einen 8-Bit I/O Expander. Auch in diesem Abschnitt gilt analog zu den anderen über I2C-Bausteine: Falls ihr noch nie etwas mit dem I2C gemacht habt, dann lest euch bitte zuerst die entsprechende Rubrik durch. Danach wird das Verstehen wesentlich einfacher fallen.&lt;br /&gt;
&lt;br /&gt;
=Funktion=&lt;br /&gt;
&lt;br /&gt;
Die Funktionsweise ist schnell beschrieben: Ein seriell an den Baustein gesendeter Wert wird auf dessen Pins parallel ausgegeben. Es gibt drei Adresspins (A0:2), an welchen man die Adresse in Hardware einstellen kann (Pins jeweils auf Masse bzw. Vcc legen). Es können also maximal 2^3 = 8 Bausteine direkt am Bus betrieben werden. Will man mehr ICs anschliessen ist ein I2C-Multiplexer notwendig (z.B. PCA9544A).&lt;br /&gt;
&lt;br /&gt;
http://www.mikrocontroller.net/mc-project/Pages/Projekte/ICs/Port%20Expander/expander-pins.gif&lt;br /&gt;
&lt;br /&gt;
An den Pins P0:7 kann ein 8 Bit Wert ausgegeben bzw. eingelesen werden. SDA und SCL dienen der Kommunikation über den I²C-Bus. /INT dient dazu, eingehende Daten an den Pins des Bausteins zu signalisieren. Man kann diesen Pin direkt an einen der Pins (externe Interrupts: INT0, INT1) des Mikrocontrollers legen. Da der Expander mit einem Open-Drain Ausgang daher kommt, muss ein Pull-Up gegen Betriebsspannung geschaltet werden. So kann der PCF8574 dem Mikrocontrollers ohne den Umweg über den I2C übermitteln, dass sich die Eingangssignale geändert haben. Man kann ihn natürlich auch einfach offen lassen. Die Pins P0:7 können bis zu 25mA aufnehmen, aber nur gegen GND! Denn es handelt sich um [[Ausgangsstufen Logik-ICs|Open Collektor Ausgänge]]. Ausgeben können die IOs nur ca. 100µA über den interen Pull-Up Widerstand (welcher genaugenommen eine [[Konstantstromquelle]] ist). Kurzzeitig kann dieser Pull-Up 1mA liefern, wenn ein Ausgang von LOW auf HIGH schaltet, das verkürzt die Umschaltzeit wesentlich. Der gesamt aufgenommene Strom sollte 200mA nicht überschreiten.&lt;br /&gt;
&lt;br /&gt;
=I2C Kommunikation=&lt;br /&gt;
&lt;br /&gt;
Gestartet wird die Kommunikation durch das Senden der Start-Bedingung gefolgt vom Adressbyte.&lt;br /&gt;
&lt;br /&gt;
Das Adressbyte für den PCF8574:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
! Bit 7 || Bit 6 || Bit 5 || Bit 4 || Bit 3 || Bit 2 || Bit 1 || Bit 0 || Hexadezimal&lt;br /&gt;
|-&lt;br /&gt;
| align=&amp;quot;center&amp;quot; |  0 &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1 &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0 &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0 &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | A2 &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | A1 &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | A0 &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W &lt;br /&gt;
|| 0x40 + A[2:0]*2 + R/W&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Das Adressbyte für den PCF8574&#039;&#039;&#039;A&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
! Bit 7 || Bit 6 || Bit 5 || Bit 4 || Bit 3 || Bit 2 || Bit 1 || Bit 0 || Hexadezimal&lt;br /&gt;
|-&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 0 &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1 &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1 &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | 1 &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | A2 &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | A1 &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | A0 &lt;br /&gt;
| align=&amp;quot;center&amp;quot; | R/W &lt;br /&gt;
|| 0x70 + A[2:0]*2 + R/W&lt;br /&gt;
|}&lt;br /&gt;
Der Adresse (4Bit für die eindeutige Kennung + 3 frei wählbare Bits) folgt das obligatorische R/W-Bit, welches festlegt, ob ein Lese- oder Schreibzugriff ausgeführt werden soll (R/W=0 Schreiben, R/W=1 Lesen).&lt;br /&gt;
&lt;br /&gt;
Wurde ein ACK empfangen, d.h. hat sich ein Slave angesprochen gefühlt, so kann man nun ein Datenbyte senden (R/W=0) oder den Status der Eingänge einlesen (R/W=1), also ein Datenbyte empfangen. Wurde ein Byte gesendet, so bestätigt der Baustein dieses mit ACK. Der Anwender kann nun festlegen, ob er das nächste Byte senden möchte oder ein STOP senden. Wurde ein Byte gelesen, so hat der Master dieses per ACK zu bestätigen, so er denn gleich das nächste empfangen möchte. Ansonsten kann hier das ACK entfallen und ein STOP gesendet werden.&lt;br /&gt;
&lt;br /&gt;
Stellt sich nur noch die Frage: Wie regelt man nun, ob ein Pin als Ein- oder Ausgang arbeiten soll? Soviel gleich vorweg: So etwas wie die Datenrichtungsregister des [[AVR]]s gibt es hier nicht, man muss ohne sie auskommen. Den Ausgangspegel der Pins definiert man über einen Schreibzugriff. Sendet man beispielsweise nach der Adresse gefolgt vom ACK des Bausteins 0xF0, so bedeutet das, dass P0:3 nun L-Pegel haben und P4:7 H-Pegel. Will man einige IOs als Eingänge verwenden, muss man die entsprechenden Ausgänge zunächst auf H-Pegel setzen, da es sich um [[Ausgangsstufen Logik-ICs|Open Collektor Ausgänge]] handelt sind die Ausgänge somit inaktiv. Führt man nun einen Lesezugriff durch, so stehen im gelesenen Byte die Pegel der Pins.&lt;br /&gt;
&lt;br /&gt;
=Anwendung=&lt;br /&gt;
&lt;br /&gt;
Im nachfolgenden Bild sind verschiedene Anwendungen der IOs dargestellt.&lt;br /&gt;
&lt;br /&gt;
[[Bild:PCF8574.png|640px]]&lt;br /&gt;
&lt;br /&gt;
* P0..P3 - Ausgänge für LEDs: Die LEDS sind mit ihrer Anode über einen Vorwiderstand gegen VCC verdrahtet. Eine LED wird eingeschaltet, indem der jeweilige Ausgang auf LOW gesetzt wird (LOW aktive). Es ist &amp;lt;B&amp;gt;NICHT&amp;lt;/B&amp;gt; möglich, die LEDs mit ihrer Kathode gegen GND zu verdrahten, da die Ausgänge vom Typ [[Ausgangsstufen_Logik-ICs#Open_Collector| Open Collector]] sind und nur bei LOW große Ströme schalten können.&lt;br /&gt;
* P4 - Ausgänge für ULN2003 &amp;amp; Co: Hier wird bei HIGH doch schon richtig Strom gebraucht (ca. 1mA). Das kann der IC nicht selber liefern (typisch ca. 100µA). Deshalb wird hier ein relativ niederohmiger Pull-Up Widerstand benötigt.&lt;br /&gt;
* P5 - Ausgänge für Logikbausteine: Nichts besonderes.&lt;br /&gt;
* P6 - Eingänge für Logikbausteine: Der Logikbaustein muss bei LOW bis zu 300µA Strom liefern können, da die internen Pull-Up Widerstände darauf dimensioniert sind und man sie nicht abschalten kann.&lt;br /&gt;
* P7 - Eingänge für Taster: Die internen Pull-up Widerstände sind hier nützlich.&lt;br /&gt;
&lt;br /&gt;
=Software=&lt;br /&gt;
&lt;br /&gt;
Routinen zum Ansteuern des Baustein können hier herunter geladen werden:&lt;br /&gt;
* [http://www.mikrocontroller.net/mc-project/Pages/Projekte/ICs/Port%20Expander/Portexpander%20Beispiel.zip Portexpander Beispiel.zip]&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
Anwendung soll ein solcher Expander bei mir nat�rlich auch finden. Am meisten hat mich beim Anschluss von LCDs immer deren Pin-Hunger im 4-Bit-Modus gest�rt. Samt der Steuereing�nge kostet einen das 7 Pins. Da ein LCD selten viel zu tun hat, sollte die Verwendung eines solchen Bausteines kein Problem darstellen. Um nicht wieder bei Null anzufangen, werde ich einfach die oben erw�hnten Low-Level-Routinen in die vielfach bew�hrte LCD-Bibliothek von Peter Pfleury einbinden. Allerdings hat dieses kleine Projekt momentan noch den Status ToDo.&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
[[Category:Mc-project.de]]&lt;/div&gt;</summary>
		<author><name>Frajo</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=FAQ&amp;diff=27720</id>
		<title>FAQ</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=FAQ&amp;diff=27720"/>
		<updated>2008-04-30T13:08:04Z</updated>

		<summary type="html">&lt;p&gt;Frajo: /* Beispiele */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Ein Verzeichnis von im Forum oft gestellten und immer wieder beantworteten Fragen und den zugehörigen Antworten:&lt;br /&gt;
&lt;br /&gt;
=Wie kann ich Zahlen auf [[LCD]]/[[UART]] ausgeben?=&lt;br /&gt;
&lt;br /&gt;
Aber die Bibliothek, die Sie benutzen, stellt nur eine Funktion zur Verfügung, mit der man einen String ausgeben kann... Was tun? &lt;br /&gt;
&lt;br /&gt;
In den folgenden Beispielen wird eine selbstgeschriebene Funktion zur Stringausgabe auf LCD - die Funktion lcd_string() - aus dem [[AVR-GCC-Tutorial#Programmierung|LCD-Teil des AVR-GCC-Tutorials]] verwendet:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
lcd_string( &amp;quot;Hallo Welt&amp;quot; );  // ggf. auch lcd_out() o.ä. in anderen Libraries&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Um also eine Zahl (numerische Konstante oder Variableninhalt) auszugeben, muss von dieser Zahl zunächst ihre String-Repräsentierung ermittelt werden. Dazu gibt es mehrere Möglichkeiten:&lt;br /&gt;
&lt;br /&gt;
===itoa()===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;itoa()&amp;lt;/b&amp;gt; ist keine C-Standardfunktion (wohl aber ihre Umkehrung &amp;lt;b&amp;gt;atoi()&amp;lt;/b&amp;gt; ). Auf manchen Compilern heisst diese Funktion dann folgerichtig &amp;lt;b&amp;gt;_itoa()&amp;lt;/b&amp;gt;, wobei der führende _ eben anzeigt, dass es sich um eine Erweiterung des C-Standards handelt. Bei [[WinAVR]] ist itoa() Bestandteil der mitgelieferten Library avr-libc.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
  int i = 25;&lt;br /&gt;
&lt;br /&gt;
  char Buffer[20];&lt;br /&gt;
  itoa( i, Buffer, 10 );&lt;br /&gt;
  lcd_string( Buffer ); // ggf. auch lcd_out() o.ä. in anderen Libraries&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;itoa( i, Buffer, 10 );&amp;lt;/b&amp;gt; - Die Zahl i wird nach ASCII gewandelt und die String Repräsentierung davon wird in Buffer abgelegt. Die Basis, in der diese Wandlung erfolgt, ist das 10-er System.&lt;br /&gt;
&lt;br /&gt;
Wichtig ist, darauf zu achten, dass das Array &amp;lt;i&amp;gt;Buffer&amp;lt;/i&amp;gt; groß genug dimensioniert wird, um alle Zeichen der Textrepräsentierung der Zahl aufzunehmen.&lt;br /&gt;
&lt;br /&gt;
===sprintf()===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
  int i = 25;&lt;br /&gt;
&lt;br /&gt;
  char Buffer[20];&lt;br /&gt;
  sprintf( Buffer, &amp;quot;%d&amp;quot;, i );&lt;br /&gt;
  lcd_string( Buffer ); // ggf. auch lcd_out() o.ä. in anderen Libraries&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Diese Methode funktioniert auch bei long oder float Werten. Unbedingt beachtet werden muss allerdings, dass die Typkennzeichnungen im sog. Format-String (hier &amp;quot;%d&amp;quot;) mit den tatsächlichen Typen der auszugebenden Werten übereinstimmt. Und dass der Buffer, der den Text aufnimmt, auch groß genug dimensioniert wird.&lt;br /&gt;
&lt;br /&gt;
Mit sprintf() hat man dieselben Möglichkeiten zur Formatierung wie bei &amp;lt;b&amp;gt;printf()&amp;lt;/b&amp;gt; (siehe unten). Insbesondere gibt es natürlich die Möglichkeit die Zahl gleich in einen umgebenden Text einzubetten bzw. Formatierungen anzugeben:&lt;br /&gt;
  &lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
  int i = 25;&lt;br /&gt;
&lt;br /&gt;
  char Buffer[20];&lt;br /&gt;
  sprintf( Buffer, &amp;quot;Anzahl: %d Stueck&amp;quot;, i );&lt;br /&gt;
  lcd_out( Buffer );&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der &amp;quot;Haken&amp;quot; an der mächtigen Funktion sprintf() ist, daß sie auch bei minimalisierter Konfiguration verhältnismäßig viel Programmspeicher (Flash-ROM) belegt und relativ viel Prozesszeit benötigt. Daher sollte man sprintf() nur verwenden, wenn kein Speicher- und Prozesszeitmangel besteht. Sonst sollte itoa() oder eine eigene, auf die Bedürfnisse optimierte Implementierung auf jeden Fall vorgezogen werden.&lt;br /&gt;
&lt;br /&gt;
====Formatierungen mit printf====&lt;br /&gt;
&lt;br /&gt;
Für jedes auszugebende Argument muss es im Formatstring einen entsprechenden Formatbezeichner geben. Der Aufbau eines Formatbezeichners ist immer&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;b&amp;gt;%[Modifizierer][Feldbreite][.Präzision]Typ&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Typ&amp;lt;/b&amp;gt; ist dabei eine Kennung, der mit dem Datentyp des jeweiligen auszugebenden Argumentes übereinstimmen muss. Einige oft benutzte Kennungen, ohne Anspruch auf Vollständigkeit, sind:&lt;br /&gt;
  &amp;lt;b&amp;gt;c&amp;lt;/b&amp;gt;    char&lt;br /&gt;
  &amp;lt;b&amp;gt;d&amp;lt;/b&amp;gt;    int&lt;br /&gt;
  &amp;lt;b&amp;gt;f&amp;lt;/b&amp;gt;    float, double&lt;br /&gt;
  &amp;lt;b&amp;gt;ld&amp;lt;/b&amp;gt;   long&lt;br /&gt;
  &amp;lt;b&amp;gt;u&amp;lt;/b&amp;gt;    unsigned int&lt;br /&gt;
  &amp;lt;b&amp;gt;lu&amp;lt;/b&amp;gt;   unsigned long&lt;br /&gt;
  &amp;lt;b&amp;gt;p&amp;lt;/b&amp;gt;    pointer&lt;br /&gt;
  &amp;lt;b&amp;gt;s&amp;lt;/b&amp;gt;    string&lt;br /&gt;
&lt;br /&gt;
Die &amp;lt;b&amp;gt;Feldbreite&amp;lt;/b&amp;gt; gibt die Breite des Ausgabefeldes an, in die die Ausgabe durchgeführt werden soll. Reicht die angegebene Feldbreite nicht aus, so vergrößert printf diese Breite eigenmächtig. Die Feldbreite muß nicht angegeben werden. In diesem Fall bestimmt printf selbst die Feldbreite, so dass die Ausgabe darin Platz findet.&lt;br /&gt;
&lt;br /&gt;
Der &amp;lt;b&amp;gt;Modifizierer&amp;lt;/b&amp;gt; bestimmt, wie und womit nicht benutzte Felder des Ausgabefeldes gefüllt werden sollen, wie die Ausrichtung innerhalb des Feldes erfolgen soll und ob ein Vorzeichen auch dann ausgegeben werden soll wenn die auszugebende Zahl positiv ist. Wird kein Modifizierer angegeben, so werden nicht benutzte Felder mit einem Leerzeichen gefüllt, positive Vorzeichen unterdrückt und die Ausgabe im Feld rechts ausgerichtet.&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;b&amp;gt;+&amp;lt;/b&amp;gt;    Vorzeichen wird immer ausgegeben&lt;br /&gt;
  &amp;lt;b&amp;gt;-&amp;lt;/b&amp;gt;    Die Ausgabe wird im Ausgabefeld linksbündig ausgerichtet&lt;br /&gt;
  &amp;lt;b&amp;gt;0&amp;lt;/b&amp;gt;    anstelle von Leerzeichen werden führende 0-en ausgegeben&lt;br /&gt;
&lt;br /&gt;
Die &amp;lt;b&amp;gt;Präzision&amp;lt;/b&amp;gt; kommt nur bei float oder double Zahlen zum Einsatz. Sie legt fest, wieviele Positionen der kompletten Feldbreite für die Ausgabe von Nachkommastellen reserviert werden sollen. Auch sie muss wiederrum nicht angegeben werden und printf benutzt in so einem Fall Standardvorgaben.&lt;br /&gt;
&lt;br /&gt;
===== Beispiele =====&lt;br /&gt;
* &amp;lt;b&amp;gt;&amp;quot;%d&amp;quot;&amp;lt;/b&amp;gt; Ausgabe eines Integer&lt;br /&gt;
* &amp;lt;b&amp;gt;&amp;quot;%5d&amp;quot;&amp;lt;/b&amp;gt; Ausgabe eines Integer in einem Feld mit 5 Zeichen Breite&lt;br /&gt;
* &amp;lt;b&amp;gt;&amp;quot;%05d&amp;quot;&amp;lt;/b&amp;gt; Ausgabe eines Integer in einem Feld mit 5 Zeichen Breite, wobei das Feld links mit führenden Nullen auf 5 Zeichen aufgefüllt wird&lt;br /&gt;
* &amp;lt;b&amp;gt;&amp;quot;%-5d&amp;quot;&amp;lt;/b&amp;gt; Ausgabe eines Integer in einem Feld mit 5 Zeichen Breite. Die Zahl wird linksbündig in das Feld gestellt.&lt;br /&gt;
&lt;br /&gt;
===Eigene Umwandlungsfunktionen===&lt;br /&gt;
&lt;br /&gt;
Möchte man &amp;lt;b&amp;gt;itoa()&amp;lt;/b&amp;gt; nicht benutzen oder hat es gar auf seinem System nicht zur Verfügung, dann ist es auch nicht schwer, sich selbst eine Funktion dafür zu schreiben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
void ItoA( int z, char* Buffer )&lt;br /&gt;
{&lt;br /&gt;
  int i = 0;&lt;br /&gt;
  int j;&lt;br /&gt;
  char tmp;&lt;br /&gt;
  &lt;br /&gt;
  unsigned u; // In u bearbeiten wir den Absolutbetrag von z.&lt;br /&gt;
  &lt;br /&gt;
    // ist die Zahl negativ?&lt;br /&gt;
    // gleich mal ein - hinterlassen und die Zahl positiv machen&lt;br /&gt;
    if( z &amp;lt; 0 ) {&lt;br /&gt;
      Buffer[0] = &#039;-&#039;;&lt;br /&gt;
      Buffer++;&lt;br /&gt;
      // -INT_MIN ist idR. größer als INT_MAX und nicht mehr &lt;br /&gt;
      // als int darstellbar! Man muss daher bei der Bildung &lt;br /&gt;
      // des Absolutbetrages aufpassen.&lt;br /&gt;
      u=((unsigned)-(z+1))+1; &lt;br /&gt;
    }&lt;br /&gt;
    else { &lt;br /&gt;
      u=(unsigned)z;&lt;br /&gt;
    }&lt;br /&gt;
    // die einzelnen Stellen der Zahl berechnen&lt;br /&gt;
    do {&lt;br /&gt;
      Buffer[i++] = &#039;0&#039; + u % 10;&lt;br /&gt;
      u /= 10;&lt;br /&gt;
    } while(u&amp;gt;0);&lt;br /&gt;
     // den String in sich spiegeln&lt;br /&gt;
    for( j = 0; j &amp;lt; i / 2; ++j ) {&lt;br /&gt;
      tmp = Buffer[j];&lt;br /&gt;
      Buffer[j] = Buffer[i-j-1];&lt;br /&gt;
      Buffer[i-j-1] = tmp;&lt;br /&gt;
    }&lt;br /&gt;
    Buffer[i] = &#039;\0&#039;;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Grundprinzip ist einfach:&amp;lt;br&amp;gt;&lt;br /&gt;
Die Ermittlung der einzelnen Stellen erfolgt in der zentralen Schleife&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
    do {&lt;br /&gt;
      Buffer[i++] = &#039;0&#039; + u % 10;&lt;br /&gt;
      u /= 10;&lt;br /&gt;
    } while(u&amp;gt;0);&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
durch fortgesetzte Division durch 10. Nur leider erhält man dadurch die einzelnen Ziffern der Zahl in umgekehrter Reihenfolge im String. Dies ist aber kein Problem, die nachfolgende Schleife&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
  for( j = 0; j &amp;lt; i / 2; ++j ) {&lt;br /&gt;
    tmp = Buffer[j];&lt;br /&gt;
    Buffer[j] = Buffer[i-j-1];&lt;br /&gt;
    Buffer[i-j-1] = tmp;&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
spiegelt den String in sich, sodass danach der String eine korrekte Repräsentierung der ursprünglichen Zahl darstellt. Der Funktionsteil vor der &#039;Zerlegeschleife&#039; behandelt den Sonderfall daß die Zahl 0 ist bzw. negative Zahlen. Negative Zahlen werden behandelt indem im Endergebnis ein &#039;-&#039; vermerkt wird und danach die Zahl positiv gemacht wird.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Siehe auch:&lt;br /&gt;
* Forenbeitrag [http://www.mikrocontroller.net/topic/67405#541885 Integer-Zahl in String mit bestimmter Zeichenlänge]&lt;br /&gt;
* Forenbeitrag [http://www.mikrocontroller.net/topic/84005#704736 (Resourcenschonend) Wert einer Variable am LCD ausgeben] von Niels Hüsken &lt;br /&gt;
* [[Festkommaarithmetik]]&lt;br /&gt;
&lt;br /&gt;
=Aktivieren der Floating Point Version von sprintf beim WinAVR mit AVR-Studio=&lt;br /&gt;
Beim WinAVR/AVR-Studio wird standardmässig eine Version der printf-Bibliothek verwendet, die keine Floating Point Verarbeitung unterstützt. Die meisten Programme benötigen keine Floating Point Unterstützung, sodass hier wertvoller Programmspeicherplatz gespart werden kann.&lt;br /&gt;
&lt;br /&gt;
Benutzt man dann allerdings eine printf Variante für die Ausgabe von Floating Point Zahlen, so erscheint an Stelle der korrekt formatierten Zahl lediglich ein &#039;?&#039;. Dies ist ein Indiz, dass die Floating Point Verarbeitung im Projekt aktiviert werden muss.&lt;br /&gt;
&lt;br /&gt;
Um die Floating Point Verarbeitung zu aktivieren, geht man im AVR-Studio wie folgt vor:&lt;br /&gt;
Menüpunkt: &amp;quot;&amp;lt;b&amp;gt;Project&amp;lt;/b&amp;gt;&amp;quot;/&amp;quot;&amp;lt;b&amp;gt;Configuration Options&amp;lt;/b&amp;gt;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Im sich öffnenden Dialog wird in der linken Navigationsleiste der Eintrag &amp;quot;&amp;lt;b&amp;gt;Libraries&amp;lt;/b&amp;gt;&amp;quot; ausgewählt.&lt;br /&gt;
Unter &#039;&amp;lt;b&amp;gt;&amp;lt;i&amp;gt;Available Link Objects&amp;lt;/i&amp;gt;&amp;lt;/b&amp;gt;&#039; werden alle möglichen Bibliotheken angeboten. Für die Aktivierung der Floating Point Unterstützung sind 2 interessant: &lt;br /&gt;
* &amp;lt;b&amp;gt;libprintf_flt.a&amp;lt;/b&amp;gt;&lt;br /&gt;
* &amp;lt;b&amp;gt;libm.a&amp;lt;/b&amp;gt;&lt;br /&gt;
Beide Bibliotheken werden durch aktivieren und einen Druck auf &amp;quot;&amp;lt;b&amp;gt;Add Library --&amp;gt;&amp;lt;/b&amp;gt;&amp;quot; in die rechte Spalte übernommen.&lt;br /&gt;
&lt;br /&gt;
[[Bild:AVR_Studio_float1.gif]]&lt;br /&gt;
&lt;br /&gt;
Danach wählt man in der Navigationsleiste den Eintrag &amp;quot;&amp;lt;b&amp;gt;Custom Options&amp;lt;/b&amp;gt;&amp;quot;. Unter &#039;&amp;lt;b&amp;gt;&amp;lt;i&amp;gt;Custom Compilation Options&amp;lt;/i&amp;gt;&amp;lt;/b&amp;gt;&#039; wird &#039;&amp;lt;i&amp;gt;[Linker Options]&amp;lt;/i&amp;gt;&#039; ausgewählt und in das Textfeld rechts/unten wird der Text&lt;br /&gt;
&amp;lt;b&amp;gt;-Wl,-u,vfprintf&amp;lt;/b&amp;gt;&lt;br /&gt;
eingegeben. Ein Druck auf &amp;quot;&amp;lt;b&amp;gt;Add&amp;lt;/b&amp;gt;&amp;quot; befördert die Zeile in das Listenfeld darüber, welches die Kommandos an den Linker enthält.&lt;br /&gt;
&lt;br /&gt;
[[Bild:AVR_Studio_float2.gif]]&lt;br /&gt;
&lt;br /&gt;
Damit ist die Konfiguration abgeschlossen, &amp;quot;&amp;lt;b&amp;gt;OK&amp;lt;/b&amp;gt;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=Wie funktioniert String-Verarbeitung in C?=&lt;br /&gt;
&lt;br /&gt;
In C gibt es, anders als in anderen Programmiersprachen, keinen eigenen String-Datentyp. Als Ersatz dafür werden Character-Arrays benutzt, in denen die einzelnen Character (=Zeichen) gespeichert werden. Allerdings gibt es noch einen Zusatz: Das letzte Zeichen eines Strings ist immer ein &#039;\0&#039;-Zeichen, dass das Ende des Strings markiert. Schlieslich kann ja das Array wesentlich größer sein, als der in ihm gespeicherte String und irgendwie müssen ja diverse Funktionen das tatsächliche Ende eines Strings erkennen können.&lt;br /&gt;
&lt;br /&gt;
Möchte mal also die Zeichenkette &amp;quot;Hello World&amp;quot; in einem String speichern, so wird dafür ein Array mit mindestens der Länge 12 benötigt. 11 für die Zeichen die &amp;quot;Hello World&amp;quot; bilden, plus eine zusätzliche Position für das abschliesende &#039;\0&#039;-Zeichen.&lt;br /&gt;
&lt;br /&gt;
Da Strings in char-Arrays gespeichert werden, können selbstverständlich normale Array Operationen dafür benutzt werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
  char Test[12];&lt;br /&gt;
&lt;br /&gt;
  Test[0] = &#039;H&#039;;&lt;br /&gt;
  Test[1] = &#039;a&#039;;&lt;br /&gt;
  Test[2] = &#039;l&#039;;&lt;br /&gt;
  Test[3] = &#039;l&#039;;&lt;br /&gt;
  Test[4] = &#039;o&#039;;&lt;br /&gt;
  Test[5] = &#039; &#039;;&lt;br /&gt;
  Test[6] = &#039;W&#039;;&lt;br /&gt;
  Test[7] = &#039;o&#039;;&lt;br /&gt;
  Test[8] = &#039;r&#039;;&lt;br /&gt;
  Test[9] = &#039;l&#039;;&lt;br /&gt;
  Test[10] = &#039;d&#039;;&lt;br /&gt;
  Test[11] = &#039;\0&#039;;   // das abschliessende \0 nicht vergessen! Sonst ist&lt;br /&gt;
                     // das kein String!&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Einige Stringfunktionen ==&lt;br /&gt;
Arrays sind in C keine vollwertigen Datentypen, z.B. ist es nicht möglich einem Array in einem Rutsch ein anderes Array zuzuweisen oder 2 Arrays miteinander zu vergleichen. Genau das möchte man aber in der Stringverarbeitung häufig, sodass es dafür Standardfunktionen gibt, die allesamt im Headerfile &amp;quot;string.h&amp;quot; zusammengefasst sind und deren Namen alle mit str... beginnen. Allen diesen Funktionen gemeinsam ist, dass sie sich &amp;lt;font color=FF0000&amp;gt;&amp;lt;b&amp;gt;nicht&amp;lt;/b&amp;gt;&amp;lt;/font&amp;gt; um die korrekte Bereitstellung von Arrays kümmern, sondern davon ausgehen, dass dies vom Programmierer korrekt erledigt wird.&lt;br /&gt;
&lt;br /&gt;
=== strcpy( char* dest, const char* src ) ===&lt;br /&gt;
Kopieren eines Strings von der Speicherfläche auf die src zeigt, zur Speicherfläche, auf die dest zeigt.&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
  char Ziel1[20];&lt;br /&gt;
  char Ziel2[20];&lt;br /&gt;
&lt;br /&gt;
  strcpy( Ziel1, &amp;quot;Hallo Welt&amp;quot; );&lt;br /&gt;
  strcpy( Ziel2, Ziel1 );&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== strcat( char* dest, const char* src ) ===&lt;br /&gt;
Anhängen eines Strings an einen bestehenden String.&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
  char Ziel[20];&lt;br /&gt;
  char Temp[20];&lt;br /&gt;
&lt;br /&gt;
  strcpy( Ziel, &amp;quot;Hallo &amp;quot; );    // Ziel enthält jetzt den String &amp;quot;Hallo &amp;quot;&lt;br /&gt;
  strcat( Ziel, &amp;quot;Welt&amp;quot; );      // Ziel enthält jetzt den String &amp;quot;Hallo Welt&amp;quot;&lt;br /&gt;
&lt;br /&gt;
  strcpy( Temp, &amp;quot; !&amp;quot; );&lt;br /&gt;
  strcat( Ziel, Temp );        // Ziel enthält jetzt den String &amp;quot;Hallo Welt !&amp;quot;&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== strcmp( const char* str1, const char* str2 ) ===&lt;br /&gt;
Vergleichen 2-er Strings. Das Ergebnis ist 0, wenn die beiden Strings identisch sind.&lt;br /&gt;
&lt;br /&gt;
=== strlen( const char* str ) ===&lt;br /&gt;
Die Länge eines Strings feststellen. Die Länge beinhaltet nicht das abschliessende &#039;\0&#039; Zeichen.&lt;br /&gt;
&lt;br /&gt;
Unter &#039;Länge&#039; wird hier die tatsächliche Länge des Strings (also die Anzahl der im String gespeicherten Zeichen) verstanden und nicht die &#039;Länge&#039; des Arrays in dem der String gespeichert ist. Wird der Text &amp;quot;test&amp;quot; in einem char-Array der Größe 20 gespeichert, so lautet das Ergebnis von strlen() 4 und nicht etwa 20&lt;br /&gt;
&lt;br /&gt;
&amp;lt;C&amp;gt;&lt;br /&gt;
  char string[20];&lt;br /&gt;
  strcpy( string, &amp;quot;test&amp;quot; );&lt;br /&gt;
  i = strlen( string );      // i bekommt hier den Wert 4&lt;br /&gt;
&amp;lt;/C&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Beispiele ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;quot;string.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
int main()&lt;br /&gt;
{&lt;br /&gt;
  char Meldung[14];&lt;br /&gt;
  strcpy( Meldung, &amp;quot;Hello World&amp;quot; );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
Mittels der Definition&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
  char Meldung[14];&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
wird ein Array bereitgestellt, welches maximal 14 Zeichen aufnehmen kann. &amp;lt;b&amp;gt;Hello World&amp;lt;/b&amp;gt; verbraucht für die lesbaren Zeichen 11 Array-Positionen, dazu noch das obligatorische abschliessende &#039;\0&#039; Zeichen, macht in Summe 12 Positionen. Eine Definition von 14 Zeichen ist also mehr als minimal notwendig&lt;br /&gt;
wäre. Das macht aber nichts, da durch das abschliessende &#039;\0&#039; Zeichen immer feststellbar ist, an welcher Stelle der tatsächliche String zu Ende ist. Die restlichen 2 Array-Positionen sind zur Zeit halt einfach unbenutzt.&lt;br /&gt;
&amp;lt;b&amp;gt;strcpy()&amp;lt;/b&amp;gt; kopiert den 2.ten angegebenen String an die Position auf die sein erstes Argument zeigt. Im obigen Beispiel zeigt das 1.te Argument auf den Beginn von &amp;lt;i&amp;gt;Meldung&amp;lt;/i&amp;gt;, also auf das Array. Folgerichtig wird der String &amp;quot;Hello World&amp;quot; in das Array &amp;lt;i&amp;gt;Meldung&amp;lt;/i&amp;gt; umkopiert. Nach Ausführung der &amp;lt;b&amp;gt;strcpy()&amp;lt;/b&amp;gt; Funktion enthält also &amp;lt;i&amp;gt;Meldung&amp;lt;/i&amp;gt; den Inhalt:&lt;br /&gt;
&lt;br /&gt;
     +---+---+---+---+---+---+---+---+---+---+---+---+---+---+&lt;br /&gt;
     | H | e | l | l | o |   | W | o | r | l | d | \0|   |   |&lt;br /&gt;
     +---+---+---+---+---+---+---+---+---+---+---+---+---+---+&lt;br /&gt;
     &lt;br /&gt;
Möchte man an diesen Text jetzt noch etwas anfügen, z.B. ein &amp;quot;?&amp;quot;, so würde das so aussehen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;quot;string.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
int main()&lt;br /&gt;
{&lt;br /&gt;
  char Meldung[14];&lt;br /&gt;
  strcpy( Meldung, &amp;quot;Hello World&amp;quot; );&lt;br /&gt;
  strcat( Meldung, &amp;quot;?&amp;quot; );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;font color=&amp;quot;FF0000&amp;quot;&amp;gt;&lt;br /&gt;
Man beachte: auch wenn hier scheinbar nur ein einzelnes Zeichen angehängt wird, so handelt es sich doch um einen String. Strings werden in C immer mit einem &amp;quot; eingeleitet und abgeschlossen. Im Gegensatz zu einzelnen Zeichen, die in einfache &#039; eingefasst werden. &amp;quot;?&amp;quot; ist also nicht dasselbe wie &#039;?&#039;! Das&lt;br /&gt;
erste ist ein String (der mit dem obligatorischen &#039;\0&#039; Zeichen insgesamt aus 2 Zeichen besteht), während letzteres ein einzelnes Zeichen darstellt! Die meisten str... Funktionen arbeiten nur mit Strings!&lt;br /&gt;
&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Da &amp;lt;i&amp;gt;Meldung&amp;lt;/i&amp;gt; maximal 14 Zeichen umfassen kann, der Text &amp;quot;Hello World?&amp;quot; aber nur aus 13 Zeichen besteht, funktioniert Obiges auch ohne Probleme. Der Array-Inhalt sieht dann wie folgt aus:&lt;br /&gt;
&lt;br /&gt;
     +---+---+---+---+---+---+---+---+---+---+---+---+---+---+&lt;br /&gt;
     | H | e | l | l | o |   | W | o | r | l | d | ? | \0|   |&lt;br /&gt;
     +---+---+---+---+---+---+---+---+---+---+---+---+---+---+&lt;br /&gt;
&lt;br /&gt;
Ein schwerwiegender Fehler wäre es, wenn der komplette String nach dem &amp;lt;b&amp;gt;strcat()&amp;lt;/b&amp;gt; aus mehr als 14 Zeichen (das &#039;\0&#039;-Zeichen nicht vergessen!) bestehen würde.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;quot;string.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
int main()&lt;br /&gt;
{&lt;br /&gt;
  char Meldung[14];&lt;br /&gt;
  strcpy( Meldung, &amp;quot;Hello World&amp;quot; );&lt;br /&gt;
  strcat( Meldung, &amp;quot; von mir&amp;quot; );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
würde also das Array überlaufen lassen.&lt;br /&gt;
&lt;br /&gt;
     +---+---+---+---+---+---+---+---+---+---+---+---+---+---+&lt;br /&gt;
     | H | e | l | l | o |   | W | o | r | l | d |   | v | o | n       m   i   r   \0&lt;br /&gt;
     +---+---+---+---+---+---+---+---+---+---+---+---+---+---+&lt;br /&gt;
&lt;br /&gt;
Man sieht sehr schön, daß in diesem Fall die weiteren Zeichen einfach an die Folgepositionen im Speicher geschrieben werden und dadurch ungewollt Speicher verändern, der nicht zu &amp;lt;i&amp;gt;Meldung&amp;lt;/i&amp;gt; gehört. Abhängig von den Details des Programmes können aber an dieser Stelle im Speicher z.B. ganz andere Variablen liegen, die dann verändert werden. &amp;lt;b&amp;gt;strcpy()&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;strcat()&amp;lt;/b&amp;gt; oder alle anderen String-Funktionen können den Programmierer gegen diesen Fall nicht schützen! Dazu müssten sie die Größe des Speicherbereichs kennen, was sie nicht tun. Es obliegt einzig und alleine der Sorgfalt des Programmierers, das Programm gegen solche Fälle abzusichern!&lt;br /&gt;
Seit einiger Zeit wurde das Sammelsurium der str... Funktionen durch Varianten ergänzt, die dieses Manko beheben. Diesen Funktionen muß die Größe des Zielbereiches mitgegeben werden. Dadurch werden die Funktionen in die Lage versetzt, zu überprüfen ob sie den Zielbereich überlaufen würden und entsprechend zu reagieren. Diese Funktionen heißen grundsätzlich gleich wie die str... Funktionen, nur befindet sich ein kleines &#039;n&#039; im Funktionsnamen. Aus &amp;lt;b&amp;gt;strcpy&amp;lt;/b&amp;gt; wird so &amp;lt;b&amp;gt;strncpy&amp;lt;/b&amp;gt;, aus &amp;lt;b&amp;gt;strcat&amp;lt;/b&amp;gt; wird &amp;lt;b&amp;gt;strncat&amp;lt;/b&amp;gt; usw. Für Details dazu sei auf Literatur oder Web-Recherche verwiesen. Auch wenn einen diese Funktionen gegen die gefürchteten Array-Overflows schützen können, so muß man sich trotzem klarmachen, daß dieser Schutz nur die halbe Miete ist. Denn was soll &amp;lt;b&amp;gt;strncpy&amp;lt;/b&amp;gt; denn tun, wenn der zu kopierende String nicht in das Zielarray passt? &amp;lt;b&amp;gt;strncpy&amp;lt;/b&amp;gt; kopiert soviel wie es kann und gibt dann auf. Aber: Dadurch ist der String aber nicht zur Gänze in den Zielbereich kopiert worden. Programmteile die darauf angewiesen sind, daß der String vollständig kopiert wurde, werden dann nicht mehr oder nicht richtig funktionieren usw. Auch wenn die strn... Funktionen eine gewisse Abhilfe bringen und zumindest den Absturz eines Programmes verhindern können, stellen sie dennoch keine Allheilmittel dar. Um die korrekte Abschätzung der benötigten Arraygrößen kommt man nicht umhin.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;strlen()&amp;lt;/b&amp;gt; liefert die Länge eines Strings. Die Längenangabe beinhaltet dabei nicht das abschliessende &#039;\0&#039; Zeichen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#include &amp;quot;string.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
int main()&lt;br /&gt;
{&lt;br /&gt;
  char Meldung[14];&lt;br /&gt;
  int  Len;&lt;br /&gt;
  &lt;br /&gt;
  strcpy( Meldung, &amp;quot;Hello World&amp;quot; );&lt;br /&gt;
  Len = strlen( Meldung );&lt;br /&gt;
  &lt;br /&gt;
  /* Hier enthaelt Len den Wert 11 */&lt;br /&gt;
&lt;br /&gt;
  Len = strlen( &amp;quot;Hallo Welt&amp;quot; );&lt;br /&gt;
&lt;br /&gt;
  /* Hier enthält Len den Wert 10 */&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;strcmp()&amp;lt;/b&amp;gt; schlussendlich vergleicht 2 Strings auf Gleichheit. Der Rückgabewert spiegelt dabei die Position des ersten Unterschiedes in den beiden Strings wieder. Folgerichtig sagt ein Wert von 0 daher aus, dass die beiden Strings identisch sind:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#include &amp;quot;string.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
int main()&lt;br /&gt;
{&lt;br /&gt;
  char Meldung1[14];&lt;br /&gt;
  char Meldung2[14];&lt;br /&gt;
&lt;br /&gt;
  strcpy( Meldung1, &amp;quot;Hello World&amp;quot; );&lt;br /&gt;
  strcpy( Meldung2, &amp;quot;Hallo Welt&amp;quot; );&lt;br /&gt;
&lt;br /&gt;
  if( strcmp( Meldung1, Meldung2 ) == 0 ) {&lt;br /&gt;
    /* die Strings sind identisch */&lt;br /&gt;
  }&lt;br /&gt;
  else {&lt;br /&gt;
    /* die Strings sind nicht identisch */&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  if( strcmp( Meldung2, &amp;quot;Hallo Welt&amp;quot; ) == 0 ) {&lt;br /&gt;
    /* Meldung2 war &amp;quot;Hallo Welt&amp;quot; */&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Es gibt noch weitere String-Funktionen, dafür sei aber auf die Verwendung der zum Compiler gehörenden Dokumentation bzw. auf einführende Literatur zum Thema &#039;Programmieren in C&#039; verwiesen.&lt;br /&gt;
&lt;br /&gt;
=Funktionszeiger=&lt;br /&gt;
Um Menüs oder ähnliche Dinge aufzubauen ist es oft praktisch ein Array von Funktionszeigern zu definieren. Der Aufruf einer Funktion kann dann indirekt über eine Variable erfolgen, wobei die Variable die Adresse der aufzurufenden Funktion enthält.&lt;br /&gt;
&lt;br /&gt;
Um mit Funktionszeigern zu arbeiten ist es in der Praxis sinnvoll sich einen &amp;lt;b&amp;gt;typedef&amp;lt;/b&amp;gt; für den Typ des Funktionszeigers zu definieren. Ein &amp;lt;b&amp;gt;typedef&amp;lt;/b&amp;gt; definiert einen neuen (kürzeren) Namen für einen Datentyp. Und wie wir sehen werden, ist der Datentyp eines Funktionszeigers in der Schreibweise ganz schön umfangreich.&lt;br /&gt;
&lt;br /&gt;
==typedef==&lt;br /&gt;
Einen &amp;lt;b&amp;gt;typedef&amp;lt;/b&amp;gt; zu definieren ist eigentlich ganz einfach: Man schreibt die Deklaration so, als ob man eine Variable definieren würde. Vor das ganze Konstrukt kommt das Schlüsselwort &amp;lt;b&amp;gt;typedef&amp;lt;/b&amp;gt;. Es bewirkt, dass der Name an der Position des Variablennamens zum Namen für den neuen Datentyp wird, der dann in weiterer Folge wie jeder andere Datentyp benutzt werden kann.&lt;br /&gt;
&lt;br /&gt;
Wir wollen einen Funktionszeiger auf eine Funktion definieren, die keine Argumente entgegen nimmt und auch nichts liefert. Also Funktionen nach&lt;br /&gt;
dem Muster:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
void foo( void )&lt;br /&gt;
{&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein entsprechender &amp;lt;b&amp;gt;typedef&amp;lt;/b&amp;gt; würde zB so aussehen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
typedef void (*VoidFnct)( void );&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das vereinbart einen neuen Datentyp &amp;lt;b&amp;gt;VoidFnct&amp;lt;/b&amp;gt;. Dieser ist ein Funktionszeiger auf Funktionen, die keine Argumente nehmen und auch nichts zurückliefern.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
typedef int (*IntFnct)( void );&lt;br /&gt;
typedef int (*IntFnct2)( int );&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;IntFnct&amp;lt;/b&amp;gt; ist ein Zeiger auf eine Funktion, die keine Argumente nimmt aber einen &amp;lt;b&amp;gt;int&amp;lt;/b&amp;gt; zurückliefert. &amp;lt;b&amp;gt;IntFnct2&amp;lt;/b&amp;gt; hingegen ist ein Zeiger auf eine Funktion, die einen &amp;lt;b&amp;gt;int&amp;lt;/b&amp;gt; als Argument nimmt und einen &amp;lt;b&amp;gt;int&amp;lt;/b&amp;gt; zurückliefert. Andere Argumenttypen bzw. Rückgabetypen folgen dem gleichen Muster. Wichtig ist, dass sowohl Argumenttypen als auch Rückgabetypen Teil der Signatur eines Funktionszeigers ist. Es ist also nicht möglich einen Funktionszeigertyp zu vereinbaren, der auf beliebige Funktionen mit beliebigen Argumenttypen bzw. Rückgabetypen verweist. Hier muss man ev. auf einen cast ausweichen. Generell ist das aber meist keine gute Idee.&lt;br /&gt;
&lt;br /&gt;
==Funktionszeigertabellen==&lt;br /&gt;
Mit einem &amp;lt;b&amp;gt;typedef&amp;lt;/b&amp;gt; ist es nun ein leichtes ein Array von Funktionszeigern zu vereinbaren:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
typedef void (*VoidFnct)( void );&lt;br /&gt;
&lt;br /&gt;
VoidFnct MeineFunktionen[5];&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dies vereinbart &amp;lt;i&amp;gt;MeineFunktionen&amp;lt;/i&amp;gt; als ein Array von Funktionszeigern, wobei jeder Funktionszeiger auf eine Funktion vom Typ void-void zeigt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
typedef void (*VoidFnct)( void );&lt;br /&gt;
&lt;br /&gt;
void Funct1()&lt;br /&gt;
{&lt;br /&gt;
  printf( &amp;quot;Dies ist Funktion 1\n&amp;quot; );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void Funct2()&lt;br /&gt;
{&lt;br /&gt;
  printf( &amp;quot;Dies ist Funktion 2\n&amp;quot; );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
VoidFnct MeineFunktionen[] = { Funct1, Funct2 };&lt;br /&gt;
&lt;br /&gt;
int main()&lt;br /&gt;
{&lt;br /&gt;
  //&lt;br /&gt;
  // ruft die Funktion auf, deren Adresse in MeineFunktionen[0]&lt;br /&gt;
  // steht. In diesem Fall wäre das Funct1()&lt;br /&gt;
  //&lt;br /&gt;
  MeineFunktionen[0]();&lt;br /&gt;
&lt;br /&gt;
  //&lt;br /&gt;
  // und jetzt die MeineFunktionen[1]&lt;br /&gt;
  //&lt;br /&gt;
  MeineFunktionen[1]();&lt;br /&gt;
&lt;br /&gt;
  //&lt;br /&gt;
  // jetzt wird MeineFunktionen[0] umgeleitet auf Funct2()&lt;br /&gt;
  // Achtung: Auf der rechten Seite wird kein () angegeben.&lt;br /&gt;
  // Ansonsten würde ja die Funktione Funct2 aufgerufen. Wir&lt;br /&gt;
  // wollen aber nur ihre Speicheradresse haben! Daher unterbleibt&lt;br /&gt;
  // das ()&lt;br /&gt;
  //&lt;br /&gt;
  MeineFunktionen[0] = Funct2;&lt;br /&gt;
&lt;br /&gt;
  //&lt;br /&gt;
  // welche Funktion wird jetzt aufgerufen?&lt;br /&gt;
  //&lt;br /&gt;
  MeineFunktionen[0]();&lt;br /&gt;
  // Richtig: Die Funktion, deren Adresse in MeineFunktionen[0]&lt;br /&gt;
  //          steht. Und das ist jetzt Funct2.&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Menüs mit Funktionszeigern==&lt;br /&gt;
Besonders bei Menüs ist es oft hilfreich, sich eine Struktur bestehend&lt;br /&gt;
aus dem Menütext und der aufzurufenden Funktion zu definieren&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
typedef void (*VoidFnct)( void );&lt;br /&gt;
&lt;br /&gt;
struct MenuEntry {&lt;br /&gt;
  char     Text[20];&lt;br /&gt;
  VoidFnct Function;&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein Menü ist dann einfach ein Array aus derartigen Strukturelementen&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
void HandleEdit()&lt;br /&gt;
{&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void HandleCopy()&lt;br /&gt;
{&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void HandlePaste()&lt;br /&gt;
{&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
struct MenuEntry MainMenu[] = {&lt;br /&gt;
 { &amp;quot;Edit&amp;quot;, HandleEdit },&lt;br /&gt;
 { &amp;quot;Copy&amp;quot;, HandleCopy },&lt;br /&gt;
 { &amp;quot;Paste&amp;quot;, HandlePaste }&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
#define ARRAY_SIZE(X) ( sizeof(X) / sizeof(*(X)) )&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
void DoMenu( int NrEntries, struct MenuEntry[] Menu )&lt;br /&gt;
{&lt;br /&gt;
  int i;&lt;br /&gt;
  int Auswahl;&lt;br /&gt;
  &lt;br /&gt;
  do {&lt;br /&gt;
    //&lt;br /&gt;
    // Das Menue anzeigen. Für jeden Menuepunkt noch eine Zahl&lt;br /&gt;
    // davor stellen, damit der Benutzer auch was zum Eingeben hat&lt;br /&gt;
    //&lt;br /&gt;
    for( i = 0; i &amp;lt; NrEntries; ++i )&lt;br /&gt;
      printf( &amp;quot;%d) %s\n&amp;quot;, i + 1, Menu[i].Text ); &lt;br /&gt;
&lt;br /&gt;
    printf( &amp;quot;9) Exit\n\n&amp;quot; );&lt;br /&gt;
&lt;br /&gt;
    // &lt;br /&gt;
    // Jetzt die Benutzereingabe abwarten ...&lt;br /&gt;
    //&lt;br /&gt;
    printf( &amp;quot;Ihre Eingabe: &amp;quot; );&lt;br /&gt;
    scanf( &amp;quot;%d&amp;quot;, &amp;amp;Auswahl );&lt;br /&gt;
&lt;br /&gt;
    //&lt;br /&gt;
    // ... und auswerten&lt;br /&gt;
    //&lt;br /&gt;
    if( Auswahl == 9 )&lt;br /&gt;
      return;&lt;br /&gt;
&lt;br /&gt;
    Auswahl = Auswahl - 1;&lt;br /&gt;
    if( Auswahl &amp;lt; 0 || Auswahl &amp;gt; NrEntries )&lt;br /&gt;
      printf( &amp;quot;Ungültige Eingabe\n&amp;quot; );&lt;br /&gt;
&lt;br /&gt;
    else&lt;br /&gt;
      // Die Eingabe war gültig. Zugehörige Funktion aufrufen&lt;br /&gt;
      Menu[Auswahl].Function();&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int main()&lt;br /&gt;
{&lt;br /&gt;
  // Das Menü arbeiten lassen.&lt;br /&gt;
  // Die Funktion DoMenu ruft selbsttätig die zu den jeweiligen&lt;br /&gt;
  // Menüpunkten gehörenden Funktionen auf. DoMenu kommt erst&lt;br /&gt;
  // dann wieder zurück, wenn der Benutzer den Menüpunkt&lt;br /&gt;
  // 9) Exit&lt;br /&gt;
  // ausgewählt hat.&lt;br /&gt;
&lt;br /&gt;
  DoMenu( ARRAY_SIZE( MainMenu ), MainMenu );&lt;br /&gt;
&lt;br /&gt;
  while( 1 )&lt;br /&gt;
    ;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Auf einem Mikrocontroller wird man natürlich die Ein/Ausgabe nicht über &amp;lt;b&amp;gt;printf&amp;lt;/b&amp;gt;/&amp;lt;b&amp;gt;scanf&amp;lt;/b&amp;gt; abwickeln. Hier geht es aber um das Prinzip der Funktionszeiger und wie man mit ihnen arbeitet, daher wurde die allereinfachste Art der Benutzerinteraktion gewählt. Gegebenenfalls muss &amp;lt;b&amp;gt;printf&amp;lt;/b&amp;gt; und &amp;lt;b&amp;gt;scanf&amp;lt;/b&amp;gt; durch die Möglichkeiten auf dem konkreten System ersetzt werden. Auch ist die Art und Weise wie das Menü präsentiert bzw. die Benutzereingabe ausgewertet wird, nicht der Weisheit letzter Schluss. Anstatt den Benutzer Zahlen eingeben zu lassen, könnte man auch einen Auswahl-Balken vom Benutzer mit 2 Tasten über die Menüeinträge bewegen lassen. Oder einen Drehencoder nehmen, ...&lt;br /&gt;
&lt;br /&gt;
=Ich hab da mehrere *.c und *.h Dateien. Was mache ich damit?=&lt;br /&gt;
Zunächst ist es wichtig, sich zu vergegenwärtigen wie denn der C Compiler/Linker überhaupt arbeitet. Ein komplettes Programmier-Projekt kann und wird im Normalfall aus mehreren Source Code Dateien bestehen die alle zusammengenommen das komplette Programm bilden.&lt;br /&gt;
&lt;br /&gt;
Der Prozess des Erstellens des Programmes geschieht in mehrerern Schritten:&lt;br /&gt;
* zunächst werden alle Einzelteile (jede *.c Datei) für sich compiliert. Dabei ensteht für jede *.c Datei eine sog. Object-Datei in der bereits der Maschinencode für die im *.c programmierten Funktionen enthalten ist&lt;br /&gt;
* danach werden die einzelnen Object-Dateien zusammen mit zusätzlichen Bibliotheken zum fertigen Programm gelinkt.&lt;br /&gt;
&lt;br /&gt;
Angenommen das komplette Projekt besteht aus 2 Dateien&lt;br /&gt;
&lt;br /&gt;
Datei: &amp;lt;b&amp;gt;main.c&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
int twice(int i);&lt;br /&gt;
&lt;br /&gt;
int main()&lt;br /&gt;
{&lt;br /&gt;
  foo( 5 );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Datei: &amp;lt;b&amp;gt;func.c&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
int twice( int number )&lt;br /&gt;
{&lt;br /&gt;
  return 2 * number;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
dann werden &amp;lt;b&amp;gt;main.c&amp;lt;/b&amp;gt; und &amp;lt;b&amp;gt;func.c&amp;lt;/b&amp;gt; &amp;lt;i&amp;gt;unabhängig&amp;lt;/i&amp;gt; voneinander compiliert. Als Ergebnis erhält man die Dateien &amp;lt;b&amp;gt;main.o&amp;lt;/b&amp;gt; und &amp;lt;b&amp;gt;func.o&amp;lt;/b&amp;gt; die den besagten Object-Code enthalten. Erst diese beiden Zwischenergebnisse werden dann zusammen mit eventuellen Bibliotheken zum fertigen Programm gebunden (gelinkt), das dann ausgeführt werden kann.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
        +---------+                         +----------+&lt;br /&gt;
        | main.c  |                         | func.c   |&lt;br /&gt;
        +---------+                         +----------+&lt;br /&gt;
             |                                   |&lt;br /&gt;
             |                                   |&lt;br /&gt;
             v                                   v&lt;br /&gt;
         Compiler                            Compiler&lt;br /&gt;
             |                                   |&lt;br /&gt;
             |                                   |&lt;br /&gt;
             v                                   v&lt;br /&gt;
        +---------+                         +----------+&lt;br /&gt;
        | main.o  |                         | func.o   |&lt;br /&gt;
        +---------+                         +----------+&lt;br /&gt;
             |                                   |&lt;br /&gt;
             +-----------+   +-------------------+&lt;br /&gt;
                         |   |&lt;br /&gt;
                         v   v&lt;br /&gt;
                         Linker  &amp;lt;------ zus. Bibliotheken&lt;br /&gt;
                           |&lt;br /&gt;
                           v&lt;br /&gt;
                      +----------+&lt;br /&gt;
                      | fertiges |&lt;br /&gt;
                      | Programm |&lt;br /&gt;
                      +----------+&lt;br /&gt;
&lt;br /&gt;
Bekommt man also von irgendwo bereits fertige *.c (und zugehörige *.h) Dateien, so genügt es, die *.c Dateien ganz einfach in das Projekt mit aufzunehmen. Daduch wird das entsprechende *.c File compiliert und das Ergebnis davon, das Object-file, wird dann in das fertige Programm mit eingelinkt.&lt;br /&gt;
&lt;br /&gt;
Wie eine *.c Datei in das Projekt mit aufgenommen wird, hängt im wesentlichen von der benutzten Entwicklungsumgebung ab.&lt;br /&gt;
&lt;br /&gt;
==Makefile==&lt;br /&gt;
Die zusätzliche *.c Datei wird in die SRC Zeile im makefile eingetragen.&lt;br /&gt;
==AVR-Studio==&lt;br /&gt;
Hier ist es besonders einfach eine Datei in das Projekt mit aufzunehmen. Dazu wird im Projektbaum einfach der Knoten &amp;quot;Source Files&amp;quot; aktiviert und mit der rechten Maustaste das Kontextmenü geöffnet. Im Menü wird der Punkt &amp;quot;Add existing Source File(s)&amp;quot; ausgewählt und anschliessend zeigt man AVR-Studio das zusätzliche *.c File. AVR-Studio berücksicht dann dieses File bei der Projekterzeugung, compiliert es und sorgt dafür, daß es zum fertigen Programm dazugelinkt wird.&lt;/div&gt;</summary>
		<author><name>Frajo</name></author>
	</entry>
</feed>