<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="de">
		<id>https://rn-wissen.de/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Phaiax</id>
		<title>RN-Wissen.de - Benutzerbeiträge [de]</title>
		<link rel="self" type="application/atom+xml" href="https://rn-wissen.de/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Phaiax"/>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=Spezial:Beitr%C3%A4ge/Phaiax"/>
		<updated>2026-04-11T20:44:21Z</updated>
		<subtitle>Benutzerbeiträge</subtitle>
		<generator>MediaWiki 1.25.1</generator>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=Software-UART_mit_avr-gcc&amp;diff=15246</id>
		<title>Software-UART mit avr-gcc</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=Software-UART_mit_avr-gcc&amp;diff=15246"/>
				<updated>2009-08-13T20:36:52Z</updated>
		
		<summary type="html">&lt;p&gt;Phaiax: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Ein '''Software-UART''' ist eine Software, welche die Funktionalität eines [[UART]] (''Universal Asynchronous Receiver and Transmitter'') implementiert., oder kurz: eine serielle Schnittstelle in Software nachbildet.&lt;br /&gt;
&lt;br /&gt;
== Einführung ==&lt;br /&gt;
Stehen keine oder nicht genügend Hardware-UARTs zur Verfügung, muss man selbst Hand anlegen. Die Herausforderung ist dabei, die festgelegten Zeitrahmen bzw. Übertragungsraten/Bitlängen möglichst genau einzuhalten, um die Kommunikation fehlerfrei zu halten. Dies gilt in besonderem Maße für den Empfänger (Receiver), der nicht entscheiden kann, wann Daten eintreffen.&lt;br /&gt;
&lt;br /&gt;
Dafür benötigt man eine Zeitbasis. Am konfortabelsten geht das mit einem Timer. Ohne Timer muss man die Zeit durch Abzählen von Maschinenzyklen machen, während die restliche Software warten muss bzw. Interrupts deaktiviert sein müssen. &lt;br /&gt;
&lt;br /&gt;
Jeder diese Herangehensweisen hat ihre Vor- und Nachteile. Welcher Weg der bessere ist, kann nur im Gesamtzusammenhang des Programmes entschieden werden.&lt;br /&gt;
&lt;br /&gt;
Wie auch immer; Ziel der Software ist es, UART-Datenframes senden und empfangen zu können. Bei Inaktivität (idle) ist die Signalleitung auf 1 (High). Jeder Frame beginnt mit einem Startbit (S), das 0 ist. Danach folgen die 8 Datenbits und schliesslich ein Stop-Bit (P), das immer 1 ist. Danach ist die Leitung wieder inaktiv oder es folgen weitere Frames.&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
[[Bild:UART-Frame.png|UART-Frame]]&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Läuft der AVR mit einer Taktrate von &amp;lt;tt&amp;gt;F_CPU&amp;lt;/tt&amp;gt; und die Übertragung mit der Baudrate BAUDRATE, dann dauert ein Bit&lt;br /&gt;
:&amp;lt;math&amp;gt;Z_\mathrm{bit} = \frac\mathrm{F_{CPU}}\mathrm{BAUDRATE}&amp;lt;/math&amp;gt;&lt;br /&gt;
Zyklen. Bei 16MHz und 38400 Baud dauert ein Bit also rund 417 Zyklen, bei 1MHz und 9600 hat man nur rund 104 Zyklen Zeit.&lt;br /&gt;
&lt;br /&gt;
== Mit Verwendung von Timer1 ==&lt;br /&gt;
&lt;br /&gt;
=== Dateikopf ===&lt;br /&gt;
&lt;br /&gt;
Im Dateikopf wird festgelegt, an welchen Ports die Ein- und Ausgabe stattfindet, mit welcher Baudrate übertragen wird und welche Teile des Soft-UARTs aktiv sind, also übersetzt werden und als Funktionen zur Verfügung stehen bzw. Flash verbrauchen. Damit eintreffende Daten nicht verloren gehen, können die Eingabedaten in einer [[FIFO mit avr-gcc|FIFO]] zwischengespeichert werden. &lt;br /&gt;
&lt;br /&gt;
Die verwendeten Ports sind aus Effizienzgründen hartcodiert. Der Receiver-Eingang liegt an einem ICP (InputCapture-Eingang). Ebenfalls hartcodiert ist das Sendeformat 8N1 (8&amp;amp;nbsp;Datenbits, kein Parity, 1&amp;amp;nbsp;Stopbit).&lt;br /&gt;
;&amp;lt;tt&amp;gt;F_CPU&amp;lt;/tt&amp;gt;: ist die Taktrate des AVR und muss irgendwo definiert worden sein, entweder über ein &amp;lt;tt&amp;gt;#define&amp;lt;/tt&amp;gt; oder per Kommandozeile mit &amp;lt;tt&amp;gt;-DF_CPU=...&amp;lt;/tt&amp;gt;&lt;br /&gt;
;&amp;lt;tt&amp;gt;#define BAUDRATE ...&amp;lt;/tt&amp;gt;: Die Baudrate, gleich für Receiver und Transmitter.&lt;br /&gt;
;&amp;lt;tt&amp;gt;#define SUART_TXD&amp;lt;/tt&amp;gt;: Wenn dieses Define gesetzt ist, wird der Transmitter aktiv bzw. die für ihn notwendigen Code-Sequenzen werden eingeblendet.&lt;br /&gt;
;&amp;lt;tt&amp;gt;#define SUART_RXD&amp;lt;/tt&amp;gt;: Wenn dieses Define gesetzt ist, wird der Receiver aktiv bzw. die für ihn notwendigen Code-Sequenzen werden eingeblendet.&lt;br /&gt;
;FIFO aktivieren: Um die FIFO zu aktivieren, wird einfach der Header &amp;lt;tt&amp;gt;fifo.h&amp;lt;/tt&amp;gt; includet und dadurch die entsprechende Codeerzeugung veranlasst.&lt;br /&gt;
:;&amp;lt;tt&amp;gt;#define INBUF_SIZE ...&amp;lt;/tt&amp;gt;: Die Größe des Eingabe-Puffers für die Receiver-FIFO&lt;br /&gt;
&lt;br /&gt;
 #include &amp;amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
 #include &amp;amp;lt;avr/interrupt.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 #ifndef SIGNAL&lt;br /&gt;
 #include &amp;amp;lt;avr/signal.h&amp;gt;&lt;br /&gt;
 #endif {{ccomment|SIGNAL }}&lt;br /&gt;
 &lt;br /&gt;
 #include &amp;quot;uart.h&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
 {{ccomment|Folgende Zeile einkommentieren, falls FIFO verwendet werden soll }}&lt;br /&gt;
 {{ccomment|#include &amp;quot;fifo.h&amp;quot; }}&lt;br /&gt;
 &lt;br /&gt;
 #define BAUDRATE 38400&lt;br /&gt;
 &lt;br /&gt;
 #define nop() __asm volatile (&amp;quot;nop&amp;quot;)&lt;br /&gt;
 &lt;br /&gt;
 #ifdef SUART_TXD&lt;br /&gt;
     #define SUART_TXD_PORT PORTB&lt;br /&gt;
     #define SUART_TXD_DDR  DDRB&lt;br /&gt;
     #define SUART_TXD_BIT  PB1&lt;br /&gt;
     static volatile uint16_t outframe;&lt;br /&gt;
 #endif {{ccomment|SUART_TXD }}&lt;br /&gt;
 &lt;br /&gt;
 #ifdef SUART_RXD&lt;br /&gt;
     #define SUART_RXD_PORT PORTB&lt;br /&gt;
     #define SUART_RXD_PIN  PINB&lt;br /&gt;
     #define SUART_RXD_DDR  DDRB&lt;br /&gt;
     #define SUART_RXD_BIT  PB0&lt;br /&gt;
     static volatile uint16_t inframe;&lt;br /&gt;
     static volatile uint8_t inbits, received;&lt;br /&gt;
 &lt;br /&gt;
     #ifdef _FIFO_H_&lt;br /&gt;
         #define INBUF_SIZE 4&lt;br /&gt;
         static uint8_t inbuf[INBUF_SIZE];&lt;br /&gt;
         fifo_t infifo;&lt;br /&gt;
     #else {{ccomment|_FIFO_H_ }}&lt;br /&gt;
         static volatile uint8_t indata;&lt;br /&gt;
     #endif {{ccomment|_FIFO_H_ }}&lt;br /&gt;
 #endif {{ccomment|SUART_RXD }}&lt;br /&gt;
&lt;br /&gt;
=== Initialisierung ===&lt;br /&gt;
&lt;br /&gt;
Hier wird der Software-UART initialisiert. Die Initialisierung ist gegen Interrupts gesperrt. Das Modus- und OCR1A-Register von Timer1 werden so initialisiert, daß eine Zeitbasis für den UART entsteht.&lt;br /&gt;
&lt;br /&gt;
 {{ccomment|Initialisierung für einen ATmega8 }}&lt;br /&gt;
 {{ccomment|Für andere AVR-Derivate sieht dies vermutlich anders aus: }}&lt;br /&gt;
 {{ccomment|Registernamen ändern sich (zB TIMSK0 anstatt TIMSK, etc). }}&lt;br /&gt;
 void uart_init()&lt;br /&gt;
 {&lt;br /&gt;
     uint8_t tifr = 0;&lt;br /&gt;
     uint8_t sreg = SREG;&lt;br /&gt;
     cli();&lt;br /&gt;
 &lt;br /&gt;
     {{ccomment|Mode #4 für Timer1 }}&lt;br /&gt;
     {{ccomment|und volle MCU clock }}&lt;br /&gt;
     {{ccomment|IC Noise Cancel }}&lt;br /&gt;
     {{ccomment|IC on Falling Edge }}&lt;br /&gt;
     TCCR1A = 0;&lt;br /&gt;
     TCCR1B = (1 &amp;amp;lt;&amp;amp;lt; WGM12) | (1 &amp;amp;lt;&amp;amp;lt; CS10) | (0 &amp;amp;lt;&amp;amp;lt; ICES1) | (1 &amp;amp;lt;&amp;amp;lt; ICNC1);&lt;br /&gt;
 &lt;br /&gt;
     {{ccomment|OutputCompare für gewünschte Timer1 Frequenz }}&lt;br /&gt;
     OCR1A = (uint16_t) ((uint32_t) F_CPU/BAUDRATE);&lt;br /&gt;
 &lt;br /&gt;
 #ifdef SUART_RXD&lt;br /&gt;
     SUART_RXD_DDR  &amp;amp;= ~(1 &amp;amp;lt;&amp;amp;lt; SUART_RXD_BIT);&lt;br /&gt;
     SUART_RXD_PORT |=  (1 &amp;amp;lt;&amp;amp;lt; SUART_RXD_BIT);&lt;br /&gt;
     TIMSK |= (1 &amp;amp;lt;&amp;amp;lt; TICIE1);&lt;br /&gt;
     tifr  |= (1 &amp;amp;lt;&amp;amp;lt; ICF1) | (1 &amp;amp;lt;&amp;amp;lt; OCF1B);&lt;br /&gt;
 #else&lt;br /&gt;
     TIMSK &amp;amp;= ~(1 &amp;amp;lt;&amp;amp;lt; TICIE1);&lt;br /&gt;
 #endif {{ccomment|SUART_RXD }}&lt;br /&gt;
 &lt;br /&gt;
 #ifdef SUART_TXD&lt;br /&gt;
     tifr |= (1 &amp;amp;lt;&amp;amp;lt; OCF1A);&lt;br /&gt;
     SUART_TXD_PORT |= (1 &amp;amp;lt;&amp;amp;lt; SUART_TXD_BIT);&lt;br /&gt;
     SUART_TXD_DDR  |= (1 &amp;amp;lt;&amp;amp;lt; SUART_TXD_BIT);&lt;br /&gt;
     outframe = 0;&lt;br /&gt;
 #endif {{ccomment|SUART_TXD }}&lt;br /&gt;
 &lt;br /&gt;
     TIFR = tifr;&lt;br /&gt;
 &lt;br /&gt;
     SREG = sreg;&lt;br /&gt;
 &lt;br /&gt;
 #ifdef _FIFO_H_&lt;br /&gt;
    fifo_init (&amp;amp;infifo,   inbuf, INBUF_SIZE);&lt;br /&gt;
 #endif // _FIFO_H_&lt;br /&gt;
 &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Transmitter === &lt;br /&gt;
Das Senden ist am einfachsten: Zuerst wird gewartet, bis eine evtl. laufende Sendung abgeschlossen ist. Dann wird der Ausgabe-Frame zusammengebaut (1&amp;amp;nbsp;Startbit, 8&amp;amp;nbsp;Datenbits, 1&amp;amp;nbsp;Stopbit und 1&amp;amp;nbsp;Bit als interne Endekennung). Dann wird OutputCompare1A-Interrupt aktiviert das entsprechende Interrupt-Flag zurückgesetzt, damit das erste Bit nicht zu kurz wird (wenn das Flag gesetzt wäre, würde direkt nach dem &amp;lt;tt&amp;gt;sei()&amp;lt;/tt&amp;gt; ein Interrupt auftreten. Ein Transmit ist fertig, wenn &amp;lt;tt&amp;gt;outframe&amp;lt;/tt&amp;gt; gleich 0 ist. Das Auslesen von &amp;lt;tt&amp;gt;outframe&amp;lt;/tt&amp;gt; muss unter Interrupt-Deaktivierung geschehen. &amp;lt;tt&amp;gt;uart_putc&amp;lt;/tt&amp;gt; geht davon aus, daß Interrupts global aktiviert sind (ansonsten hängt es sich auf bzw. es wird nicht ausgegeben).&lt;br /&gt;
 #ifdef SUART_TXD&lt;br /&gt;
 void uart_putc (const char c)&lt;br /&gt;
 {&lt;br /&gt;
     do&lt;br /&gt;
     {&lt;br /&gt;
         sei(); nop(); cli(); {{ccomment|yield(); }}&lt;br /&gt;
     } while (outframe);&lt;br /&gt;
 &lt;br /&gt;
     {{ccomment|frame &amp;amp;#61; *.P.7.6.5.4.3.2.1.0.S   S&amp;amp;#61;Start(0), P&amp;amp;#61;Stop(1), *&amp;amp;#61;Endemarke(1) }}&lt;br /&gt;
     outframe = (3 &amp;amp;lt;&amp;amp;lt; 9) | (((uint8_t) c) &amp;amp;lt;&amp;amp;lt; 1);&lt;br /&gt;
 &lt;br /&gt;
     TIMSK |= (1 &amp;amp;lt;&amp;amp;lt; OCIE1A);&lt;br /&gt;
     TIFR   = (1 &amp;amp;lt;&amp;amp;lt; OCF1A);&lt;br /&gt;
 &lt;br /&gt;
     sei();&lt;br /&gt;
 }&lt;br /&gt;
 #endif {{ccomment|SUART_TXD }}&lt;br /&gt;
&lt;br /&gt;
Danach kommt es zu OC1A-Interrupts. Für jeden [[IRQ]] wird ein Bit ausgegeben. Im letzten Interrupt wird das Senden eingestellt und die [[ISR]] deaktiviert ihren eigenen IRQ.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#ifdef SUART_TXD&lt;br /&gt;
SIGNAL (SIG_OUTPUT_COMPARE1A)&lt;br /&gt;
{&lt;br /&gt;
    uint16_t data = outframe;&lt;br /&gt;
   &lt;br /&gt;
    if (data &amp;amp; 1)      SUART_TXD_PORT |=  (1 &amp;lt;&amp;lt; SUART_TXD_BIT);&lt;br /&gt;
    else               SUART_TXD_PORT &amp;amp;= ~(1 &amp;lt;&amp;lt; SUART_TXD_BIT);&lt;br /&gt;
   &lt;br /&gt;
    if (1 == data)&lt;br /&gt;
    {&lt;br /&gt;
        TIMSK &amp;amp;= ~(1 &amp;lt;&amp;lt; OCIE1A);&lt;br /&gt;
    }   &lt;br /&gt;
   &lt;br /&gt;
    outframe = data &amp;gt;&amp;gt; 1;&lt;br /&gt;
}&lt;br /&gt;
#endif // SUART_TXD&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Receiver ===&lt;br /&gt;
Eine fallende Flanke löst einen Input-Capture-IRQ aus. Der in ICR1 gesicherte Timer1-Wert wird gelesen, und die halbe Bit-Zeit OCR1A/2 wird draufaddiert, um den Empfangszeitpunkt (sample time) zu erhalten. Die ISR deaktiviert ihren IRQ und aktiviert stattdessen den OutputCompare1B-Interrupt, der die Bits einsammelt.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#ifdef SUART_RXD&lt;br /&gt;
SIGNAL (SIG_INPUT_CAPTURE1)&lt;br /&gt;
{&lt;br /&gt;
    uint16_t icr1  = ICR1;&lt;br /&gt;
    uint16_t ocr1a = OCR1A;&lt;br /&gt;
   &lt;br /&gt;
    // Eine halbe Bitzeit zu ICR1 addieren (modulo OCR1A) und nach OCR1B&lt;br /&gt;
    uint16_t ocr1b = icr1 + ocr1a/2;&lt;br /&gt;
    if (ocr1b &amp;gt;= ocr1a)&lt;br /&gt;
        ocr1b -= ocr1a;&lt;br /&gt;
    OCR1B = ocr1b;&lt;br /&gt;
   &lt;br /&gt;
    TIFR = (1 &amp;lt;&amp;lt; OCF1B);&lt;br /&gt;
    TIMSK = (TIMSK &amp;amp; ~(1 &amp;lt;&amp;lt; TICIE1)) | (1 &amp;lt;&amp;lt; OCIE1B);&lt;br /&gt;
    inframe = 0;&lt;br /&gt;
    inbits = 0;&lt;br /&gt;
}&lt;br /&gt;
#endif // SUART_RXD&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die OutputCompare1B-ISR sammelt die Bits ein. Wurden 10 Bits übertragen, wird das empfangene Byte gespeichert, falls es nicht ungültig ist. Gespeichert wird in der Modul-globalen Variablen &amp;lt;tt&amp;gt;indata&amp;lt;/tt&amp;gt; (oder bei aktiviertem FIFO-Mechanismus in &amp;lt;tt&amp;gt;infifo&amp;lt;/tt&amp;gt;), und der Empfangsmerker &amp;lt;tt&amp;gt;received&amp;lt;/tt&amp;gt; wird gesetzt.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#ifdef SUART_RXD&lt;br /&gt;
SIGNAL (SIG_OUTPUT_COMPARE1B)&lt;br /&gt;
{&lt;br /&gt;
    uint16_t data = inframe &amp;gt;&amp;gt; 1;&lt;br /&gt;
   &lt;br /&gt;
    if (SUART_RXD_PIN &amp;amp; (1 &amp;lt;&amp;lt; SUART_RXD_BIT))&lt;br /&gt;
        data |= (1 &amp;lt;&amp;lt; 9);&lt;br /&gt;
      &lt;br /&gt;
    uint8_t bits = inbits+1;&lt;br /&gt;
   &lt;br /&gt;
    if (10 == bits)&lt;br /&gt;
    {&lt;br /&gt;
        if ((data &amp;amp; 1) == 0)&lt;br /&gt;
            if (data &amp;gt;= (1 &amp;lt;&amp;lt; 9))&lt;br /&gt;
            {&lt;br /&gt;
#ifdef _FIFO_H_         &lt;br /&gt;
                _inline_fifo_put (&amp;amp;infifo, data &amp;gt;&amp;gt; 1);&lt;br /&gt;
#else            &lt;br /&gt;
                indata = data &amp;gt;&amp;gt; 1;&lt;br /&gt;
#endif // _FIFO_H_            &lt;br /&gt;
                received = 1;&lt;br /&gt;
            }&lt;br /&gt;
      &lt;br /&gt;
        TIMSK = (TIMSK &amp;amp; ~(1 &amp;lt;&amp;lt; OCIE1B)) | (1 &amp;lt;&amp;lt; TICIE1);&lt;br /&gt;
        TIFR = (1 &amp;lt;&amp;lt; ICF1);&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        inbits = bits;&lt;br /&gt;
        inframe = data;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
#endif // SUART_RXD&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Zwei Funktionen, um empfangene Daten zu lesen. Je nachdem, ob die FIFO verwendet wird, sind diese Funktionen unterschiedlich implementiert. Das Benutzer-Interface bleibt jedoch gleich, und die Verwendung einer FIFO transparent.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#ifdef SUART_RXD&lt;br /&gt;
#ifdef _FIFO_H_&lt;br /&gt;
&lt;br /&gt;
int uart_getc_wait()&lt;br /&gt;
{&lt;br /&gt;
    return (int) fifo_get_wait (&amp;amp;infifo);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int uart_getc_nowait()&lt;br /&gt;
{&lt;br /&gt;
    return fifo_get_nowait (&amp;amp;infifo);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#else // _FIFO_H_&lt;br /&gt;
&lt;br /&gt;
int uart_getc_wait()&lt;br /&gt;
{&lt;br /&gt;
    while (!received)   {}&lt;br /&gt;
    received = 0;&lt;br /&gt;
   &lt;br /&gt;
    return (int) indata;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int uart_getc_nowait()&lt;br /&gt;
{&lt;br /&gt;
    if (received)&lt;br /&gt;
    {&lt;br /&gt;
        received = 0;&lt;br /&gt;
        return (int) indata;&lt;br /&gt;
    }&lt;br /&gt;
   &lt;br /&gt;
    return -1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#endif // _FIFO_H_&lt;br /&gt;
#endif // SUART_RXD&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Benutzer-Interface und Header ===&lt;br /&gt;
Im Header &amp;lt;tt&amp;gt;uart.h&amp;lt;/tt&amp;gt; werden die Funktionen veröffentlicht und stehen in anderen Modulen zur Verfügung:&lt;br /&gt;
;&amp;lt;tt&amp;gt;extern void uart_init()&amp;lt;/tt&amp;gt;: Initialisiert den Soft-UART. Vor Verwendung des Soft-UARTs müssen Interrupts mit &amp;lt;tt&amp;gt;sei()&amp;lt;/tt&amp;gt; global aktiviert worden sein (egal, ob vor oder nach dem Aufruf von &amp;lt;tt&amp;gt;uart_init&amp;lt;/tt&amp;gt;).&lt;br /&gt;
;&amp;lt;tt&amp;gt;extern void uart_putc (const char c)&amp;lt;/tt&amp;gt;: Sendet das Zeichen &amp;lt;tt&amp;gt;c&amp;lt;/tt&amp;gt;. Vorher wird gewartet, bis eine evtl. laufende Sendung beendet ist.&lt;br /&gt;
;&amp;lt;tt&amp;gt;extern int uart_getc_wait()&amp;lt;/tt&amp;gt;: Wartet bis zum nächsten Empfang bzw. liefert das empfangene Zeichen im Wertebereich 0...255.&lt;br /&gt;
;&amp;lt;tt&amp;gt;extern int uart_getc_nowait()&amp;lt;/tt&amp;gt;: Schaut nach, ob ein Zeichen empfangen wurde und liefert dieses gegebenenfalls als &amp;lt;tt&amp;gt;int&amp;lt;/tt&amp;gt; zurück (Wertebereich ist 0...255). Wurde nichts empfangen, wird &amp;lt;tt&amp;gt;-1&amp;lt;/tt&amp;gt; geliefert.&lt;br /&gt;
Die Defines &amp;lt;tt&amp;gt;SUART_TXD&amp;lt;/tt&amp;gt; und &amp;lt;tt&amp;gt;SUART_RXD&amp;lt;/tt&amp;gt; zum Aktivieren der Code-Sequenzen für Transmitter resp. Receiver stehen hier im Header; das kann natürlich auch in die Kommandozeile/ins [[make|Makefile]] wandern und mit &amp;lt;tt&amp;gt;-DSUART_RXD&amp;lt;/tt&amp;gt; etc. angeschaltet werden, Gleiches gilt für &amp;lt;tt&amp;gt;F_CPU&amp;lt;/tt&amp;gt; und &amp;lt;tt&amp;gt;BAUDRATE&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#ifndef _UART_H_&lt;br /&gt;
#define _UART_H_&lt;br /&gt;
&lt;br /&gt;
#define SUART_TXD&lt;br /&gt;
#define SUART_RXD&lt;br /&gt;
&lt;br /&gt;
extern void uart_init();&lt;br /&gt;
&lt;br /&gt;
#ifdef SUART_TXD&lt;br /&gt;
    extern void uart_putc (const char);&lt;br /&gt;
#endif // SUART_RXD&lt;br /&gt;
&lt;br /&gt;
#ifdef SUART_RXD&lt;br /&gt;
    extern int uart_getc_wait ();&lt;br /&gt;
    extern int uart_getc_nowait();&lt;br /&gt;
#endif // SUART_RXD&lt;br /&gt;
&lt;br /&gt;
#endif /* _UART_H_ */&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Weblinks ==&lt;br /&gt;
* [http://www.roboternetz.de/phpBB2/dload.php?action=file&amp;amp;file_id=240 UART-Software-Simulation mit ISRs]&lt;br /&gt;
&lt;br /&gt;
== Siehe auch ==&lt;br /&gt;
&lt;br /&gt;
*[[UART]]&lt;br /&gt;
*[[RS232]]&lt;br /&gt;
*[[FIFO mit avr-gcc]]&lt;br /&gt;
*[[UART mit avr-gcc]]&lt;br /&gt;
*[[avr-gcc]]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Kommunikation|UART]]&lt;br /&gt;
[[Kategorie:Praxis|UART]]&lt;br /&gt;
[[Kategorie:Quellcode C|UART]]&lt;br /&gt;
[[Kategorie:Software|UART]]&lt;br /&gt;
[[Kategorie:Microcontroller|UART]]&lt;/div&gt;</summary>
		<author><name>Phaiax</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=Software-UART_mit_avr-gcc&amp;diff=15245</id>
		<title>Software-UART mit avr-gcc</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=Software-UART_mit_avr-gcc&amp;diff=15245"/>
				<updated>2009-08-13T20:36:29Z</updated>
		
		<summary type="html">&lt;p&gt;Phaiax: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Ein '''Software-UART''' ist eine Software, welche die Funktionalität eines [[UART]] (''Universal Asynchronous Receiver and Transmitter'') implementiert., oder kurz: eine serielle Schnittstelle in Software nachbildet.&lt;br /&gt;
&lt;br /&gt;
== Einführung ==&lt;br /&gt;
Stehen keine oder nicht genügend Hardware-UARTs zur Verfügung, muss man selbst Hand anlegen. Die Herausforderung ist dabei, die festgelegten Zeitrahmen bzw. Übertragungsraten/Bitlängen möglichst genau einzuhalten, um die Kommunikation fehlerfrei zu halten. Dies gilt in besonderem Maße für den Empfänger (Receiver), der nicht entscheiden kann, wann Daten eintreffen.&lt;br /&gt;
&lt;br /&gt;
Dafür benötigt man eine Zeitbasis. Am konfortabelsten geht das mit einem Timer. Ohne Timer muss man die Zeit durch Abzählen von Maschinenzyklen machen, während die restliche Software warten muss bzw. Interrupts deaktiviert sein müssen. &lt;br /&gt;
&lt;br /&gt;
Jeder diese Herangehensweisen hat ihre Vor- und Nachteile. Welcher Weg der bessere ist, kann nur im Gesamtzusammenhang des Programmes entschieden werden.&lt;br /&gt;
&lt;br /&gt;
Wie auch immer; Ziel der Software ist es, UART-Datenframes senden und empfangen zu können. Bei Inaktivität (idle) ist die Signalleitung auf 1 (High). Jeder Frame beginnt mit einem Startbit (S), das 0 ist. Danach folgen die 8 Datenbits und schliesslich ein Stop-Bit (P), das immer 1 ist. Danach ist die Leitung wieder inaktiv oder es folgen weitere Frames.&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
[[Bild:UART-Frame.png|UART-Frame]]&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Läuft der AVR mit einer Taktrate von &amp;lt;tt&amp;gt;F_CPU&amp;lt;/tt&amp;gt; und die Übertragung mit der Baudrate BAUDRATE, dann dauert ein Bit&lt;br /&gt;
:&amp;lt;math&amp;gt;Z_\mathrm{bit} = \frac\mathrm{F_{CPU}}\mathrm{BAUDRATE}&amp;lt;/math&amp;gt;&lt;br /&gt;
Zyklen. Bei 16MHz und 38400 Baud dauert ein Bit also rund 417 Zyklen, bei 1MHz und 9600 hat man nur rund 104 Zyklen Zeit.&lt;br /&gt;
&lt;br /&gt;
== Mit Verwendung von Timer1 ==&lt;br /&gt;
&lt;br /&gt;
=== Dateikopf ===&lt;br /&gt;
&lt;br /&gt;
Im Dateikopf wird festgelegt, an welchen Ports die Ein- und Ausgabe stattfindet, mit welcher Baudrate übertragen wird und welche Teile des Soft-UARTs aktiv sind, also übersetzt werden und als Funktionen zur Verfügung stehen bzw. Flash verbrauchen. Damit eintreffende Daten nicht verloren gehen, können die Eingabedaten in einer [[FIFO mit avr-gcc|FIFO]] zwischengespeichert werden. &lt;br /&gt;
&lt;br /&gt;
Die verwendeten Ports sind aus Effizienzgründen hartcodiert. Der Receiver-Eingang liegt an einem ICP (InputCapture-Eingang). Ebenfalls hartcodiert ist das Sendeformat 8N1 (8&amp;amp;nbsp;Datenbits, kein Parity, 1&amp;amp;nbsp;Stopbit).&lt;br /&gt;
;&amp;lt;tt&amp;gt;F_CPU&amp;lt;/tt&amp;gt;: ist die Taktrate des AVR und muss irgendwo definiert worden sein, entweder über ein &amp;lt;tt&amp;gt;#define&amp;lt;/tt&amp;gt; oder per Kommandozeile mit &amp;lt;tt&amp;gt;-DF_CPU=...&amp;lt;/tt&amp;gt;&lt;br /&gt;
;&amp;lt;tt&amp;gt;#define BAUDRATE ...&amp;lt;/tt&amp;gt;: Die Baudrate, gleich für Receiver und Transmitter.&lt;br /&gt;
;&amp;lt;tt&amp;gt;#define SUART_TXD&amp;lt;/tt&amp;gt;: Wenn dieses Define gesetzt ist, wird der Transmitter aktiv bzw. die für ihn notwendigen Code-Sequenzen werden eingeblendet.&lt;br /&gt;
;&amp;lt;tt&amp;gt;#define SUART_RXD&amp;lt;/tt&amp;gt;: Wenn dieses Define gesetzt ist, wird der Receiver aktiv bzw. die für ihn notwendigen Code-Sequenzen werden eingeblendet.&lt;br /&gt;
;FIFO aktivieren: Um die FIFO zu aktivieren, wird einfach der Header &amp;lt;tt&amp;gt;fifo.h&amp;lt;/tt&amp;gt; includet und dadurch die entsprechende Codeerzeugung veranlasst.&lt;br /&gt;
:;&amp;lt;tt&amp;gt;#define INBUF_SIZE ...&amp;lt;/tt&amp;gt;: Die Größe des Eingabe-Puffers für die Receiver-FIFO&lt;br /&gt;
&lt;br /&gt;
 #include &amp;amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
 #include &amp;amp;lt;avr/interrupt.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 #ifndef SIGNAL&lt;br /&gt;
 #include &amp;amp;lt;avr/signal.h&amp;gt;&lt;br /&gt;
 #endif {{ccomment|SIGNAL }}&lt;br /&gt;
 &lt;br /&gt;
 #include &amp;quot;uart.h&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
 {{ccomment|Folgende Zeile einkommentieren, falls FIFO verwendet werden soll }}&lt;br /&gt;
 {{ccomment|#include &amp;quot;fifo.h&amp;quot; }}&lt;br /&gt;
 &lt;br /&gt;
 #define BAUDRATE 38400&lt;br /&gt;
 &lt;br /&gt;
 #define nop() __asm volatile (&amp;quot;nop&amp;quot;)&lt;br /&gt;
 &lt;br /&gt;
 #ifdef SUART_TXD&lt;br /&gt;
     #define SUART_TXD_PORT PORTB&lt;br /&gt;
     #define SUART_TXD_DDR  DDRB&lt;br /&gt;
     #define SUART_TXD_BIT  PB1&lt;br /&gt;
     static volatile uint16_t outframe;&lt;br /&gt;
 #endif {{ccomment|SUART_TXD }}&lt;br /&gt;
 &lt;br /&gt;
 #ifdef SUART_RXD&lt;br /&gt;
     #define SUART_RXD_PORT PORTB&lt;br /&gt;
     #define SUART_RXD_PIN  PINB&lt;br /&gt;
     #define SUART_RXD_DDR  DDRB&lt;br /&gt;
     #define SUART_RXD_BIT  PB0&lt;br /&gt;
     static volatile uint16_t inframe;&lt;br /&gt;
     static volatile uint8_t inbits, received;&lt;br /&gt;
 &lt;br /&gt;
     #ifdef _FIFO_H_&lt;br /&gt;
         #define INBUF_SIZE 4&lt;br /&gt;
         static uint8_t inbuf[INBUF_SIZE];&lt;br /&gt;
         fifo_t infifo;&lt;br /&gt;
     #else {{ccomment|_FIFO_H_ }}&lt;br /&gt;
         static volatile uint8_t indata;&lt;br /&gt;
     #endif {{ccomment|_FIFO_H_ }}&lt;br /&gt;
 #endif {{ccomment|SUART_RXD }}&lt;br /&gt;
&lt;br /&gt;
=== Initialisierung ===&lt;br /&gt;
&lt;br /&gt;
Hier wird der Software-UART initialisiert. Die Initialisierung ist gegen Interrupts gesperrt. Das Modus- und OCR1A-Register von Timer1 werden so initialisiert, daß eine Zeitbasis für den UART entsteht.&lt;br /&gt;
&lt;br /&gt;
 {{ccomment|Initialisierung für einen ATmega8 }}&lt;br /&gt;
 {{ccomment|Für andere AVR-Derivate sieht dies vermutlich anders aus: }}&lt;br /&gt;
 {{ccomment|Registernamen ändern sich (zB TIMSK0 anstatt TIMSK, etc). }}&lt;br /&gt;
 void uart_init()&lt;br /&gt;
 {&lt;br /&gt;
     uint8_t tifr = 0;&lt;br /&gt;
     uint8_t sreg = SREG;&lt;br /&gt;
     cli();&lt;br /&gt;
 &lt;br /&gt;
     {{ccomment|Mode #4 für Timer1 }}&lt;br /&gt;
     {{ccomment|und volle MCU clock }}&lt;br /&gt;
     {{ccomment|IC Noise Cancel }}&lt;br /&gt;
     {{ccomment|IC on Falling Edge }}&lt;br /&gt;
     TCCR1A = 0;&lt;br /&gt;
     TCCR1B = (1 &amp;amp;lt;&amp;amp;lt; WGM12) | (1 &amp;amp;lt;&amp;amp;lt; CS10) | (0 &amp;amp;lt;&amp;amp;lt; ICES1) | (1 &amp;amp;lt;&amp;amp;lt; ICNC1);&lt;br /&gt;
 &lt;br /&gt;
     {{ccomment|OutputCompare für gewünschte Timer1 Frequenz }}&lt;br /&gt;
     OCR1A = (uint16_t) ((uint32_t) F_CPU/BAUDRATE);&lt;br /&gt;
 &lt;br /&gt;
 #ifdef SUART_RXD&lt;br /&gt;
     SUART_RXD_DDR  &amp;amp;= ~(1 &amp;amp;lt;&amp;amp;lt; SUART_RXD_BIT);&lt;br /&gt;
     SUART_RXD_PORT |=  (1 &amp;amp;lt;&amp;amp;lt; SUART_RXD_BIT);&lt;br /&gt;
     TIMSK |= (1 &amp;amp;lt;&amp;amp;lt; TICIE1);&lt;br /&gt;
     tifr  |= (1 &amp;amp;lt;&amp;amp;lt; ICF1) | (1 &amp;amp;lt;&amp;amp;lt; OCF1B);&lt;br /&gt;
 #else&lt;br /&gt;
     TIMSK &amp;amp;= ~(1 &amp;amp;lt;&amp;amp;lt; TICIE1);&lt;br /&gt;
 #endif {{ccomment|SUART_RXD }}&lt;br /&gt;
 &lt;br /&gt;
 #ifdef SUART_TXD&lt;br /&gt;
     tifr |= (1 &amp;amp;lt;&amp;amp;lt; OCF1A);&lt;br /&gt;
     SUART_TXD_PORT |= (1 &amp;amp;lt;&amp;amp;lt; SUART_TXD_BIT);&lt;br /&gt;
     SUART_TXD_DDR  |= (1 &amp;amp;lt;&amp;amp;lt; SUART_TXD_BIT);&lt;br /&gt;
     outframe = 0;&lt;br /&gt;
 #endif {{ccomment|SUART_TXD }}&lt;br /&gt;
 &lt;br /&gt;
     TIFR = tifr;&lt;br /&gt;
 &lt;br /&gt;
     SREG = sreg;&lt;br /&gt;
&lt;br /&gt;
 #ifdef _FIFO_H_&lt;br /&gt;
    fifo_init (&amp;amp;infifo,   inbuf, INBUF_SIZE);&lt;br /&gt;
 #endif // _FIFO_H_&lt;br /&gt;
&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Transmitter === &lt;br /&gt;
Das Senden ist am einfachsten: Zuerst wird gewartet, bis eine evtl. laufende Sendung abgeschlossen ist. Dann wird der Ausgabe-Frame zusammengebaut (1&amp;amp;nbsp;Startbit, 8&amp;amp;nbsp;Datenbits, 1&amp;amp;nbsp;Stopbit und 1&amp;amp;nbsp;Bit als interne Endekennung). Dann wird OutputCompare1A-Interrupt aktiviert das entsprechende Interrupt-Flag zurückgesetzt, damit das erste Bit nicht zu kurz wird (wenn das Flag gesetzt wäre, würde direkt nach dem &amp;lt;tt&amp;gt;sei()&amp;lt;/tt&amp;gt; ein Interrupt auftreten. Ein Transmit ist fertig, wenn &amp;lt;tt&amp;gt;outframe&amp;lt;/tt&amp;gt; gleich 0 ist. Das Auslesen von &amp;lt;tt&amp;gt;outframe&amp;lt;/tt&amp;gt; muss unter Interrupt-Deaktivierung geschehen. &amp;lt;tt&amp;gt;uart_putc&amp;lt;/tt&amp;gt; geht davon aus, daß Interrupts global aktiviert sind (ansonsten hängt es sich auf bzw. es wird nicht ausgegeben).&lt;br /&gt;
 #ifdef SUART_TXD&lt;br /&gt;
 void uart_putc (const char c)&lt;br /&gt;
 {&lt;br /&gt;
     do&lt;br /&gt;
     {&lt;br /&gt;
         sei(); nop(); cli(); {{ccomment|yield(); }}&lt;br /&gt;
     } while (outframe);&lt;br /&gt;
 &lt;br /&gt;
     {{ccomment|frame &amp;amp;#61; *.P.7.6.5.4.3.2.1.0.S   S&amp;amp;#61;Start(0), P&amp;amp;#61;Stop(1), *&amp;amp;#61;Endemarke(1) }}&lt;br /&gt;
     outframe = (3 &amp;amp;lt;&amp;amp;lt; 9) | (((uint8_t) c) &amp;amp;lt;&amp;amp;lt; 1);&lt;br /&gt;
 &lt;br /&gt;
     TIMSK |= (1 &amp;amp;lt;&amp;amp;lt; OCIE1A);&lt;br /&gt;
     TIFR   = (1 &amp;amp;lt;&amp;amp;lt; OCF1A);&lt;br /&gt;
 &lt;br /&gt;
     sei();&lt;br /&gt;
 }&lt;br /&gt;
 #endif {{ccomment|SUART_TXD }}&lt;br /&gt;
&lt;br /&gt;
Danach kommt es zu OC1A-Interrupts. Für jeden [[IRQ]] wird ein Bit ausgegeben. Im letzten Interrupt wird das Senden eingestellt und die [[ISR]] deaktiviert ihren eigenen IRQ.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#ifdef SUART_TXD&lt;br /&gt;
SIGNAL (SIG_OUTPUT_COMPARE1A)&lt;br /&gt;
{&lt;br /&gt;
    uint16_t data = outframe;&lt;br /&gt;
   &lt;br /&gt;
    if (data &amp;amp; 1)      SUART_TXD_PORT |=  (1 &amp;lt;&amp;lt; SUART_TXD_BIT);&lt;br /&gt;
    else               SUART_TXD_PORT &amp;amp;= ~(1 &amp;lt;&amp;lt; SUART_TXD_BIT);&lt;br /&gt;
   &lt;br /&gt;
    if (1 == data)&lt;br /&gt;
    {&lt;br /&gt;
        TIMSK &amp;amp;= ~(1 &amp;lt;&amp;lt; OCIE1A);&lt;br /&gt;
    }   &lt;br /&gt;
   &lt;br /&gt;
    outframe = data &amp;gt;&amp;gt; 1;&lt;br /&gt;
}&lt;br /&gt;
#endif // SUART_TXD&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Receiver ===&lt;br /&gt;
Eine fallende Flanke löst einen Input-Capture-IRQ aus. Der in ICR1 gesicherte Timer1-Wert wird gelesen, und die halbe Bit-Zeit OCR1A/2 wird draufaddiert, um den Empfangszeitpunkt (sample time) zu erhalten. Die ISR deaktiviert ihren IRQ und aktiviert stattdessen den OutputCompare1B-Interrupt, der die Bits einsammelt.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#ifdef SUART_RXD&lt;br /&gt;
SIGNAL (SIG_INPUT_CAPTURE1)&lt;br /&gt;
{&lt;br /&gt;
    uint16_t icr1  = ICR1;&lt;br /&gt;
    uint16_t ocr1a = OCR1A;&lt;br /&gt;
   &lt;br /&gt;
    // Eine halbe Bitzeit zu ICR1 addieren (modulo OCR1A) und nach OCR1B&lt;br /&gt;
    uint16_t ocr1b = icr1 + ocr1a/2;&lt;br /&gt;
    if (ocr1b &amp;gt;= ocr1a)&lt;br /&gt;
        ocr1b -= ocr1a;&lt;br /&gt;
    OCR1B = ocr1b;&lt;br /&gt;
   &lt;br /&gt;
    TIFR = (1 &amp;lt;&amp;lt; OCF1B);&lt;br /&gt;
    TIMSK = (TIMSK &amp;amp; ~(1 &amp;lt;&amp;lt; TICIE1)) | (1 &amp;lt;&amp;lt; OCIE1B);&lt;br /&gt;
    inframe = 0;&lt;br /&gt;
    inbits = 0;&lt;br /&gt;
}&lt;br /&gt;
#endif // SUART_RXD&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die OutputCompare1B-ISR sammelt die Bits ein. Wurden 10 Bits übertragen, wird das empfangene Byte gespeichert, falls es nicht ungültig ist. Gespeichert wird in der Modul-globalen Variablen &amp;lt;tt&amp;gt;indata&amp;lt;/tt&amp;gt; (oder bei aktiviertem FIFO-Mechanismus in &amp;lt;tt&amp;gt;infifo&amp;lt;/tt&amp;gt;), und der Empfangsmerker &amp;lt;tt&amp;gt;received&amp;lt;/tt&amp;gt; wird gesetzt.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#ifdef SUART_RXD&lt;br /&gt;
SIGNAL (SIG_OUTPUT_COMPARE1B)&lt;br /&gt;
{&lt;br /&gt;
    uint16_t data = inframe &amp;gt;&amp;gt; 1;&lt;br /&gt;
   &lt;br /&gt;
    if (SUART_RXD_PIN &amp;amp; (1 &amp;lt;&amp;lt; SUART_RXD_BIT))&lt;br /&gt;
        data |= (1 &amp;lt;&amp;lt; 9);&lt;br /&gt;
      &lt;br /&gt;
    uint8_t bits = inbits+1;&lt;br /&gt;
   &lt;br /&gt;
    if (10 == bits)&lt;br /&gt;
    {&lt;br /&gt;
        if ((data &amp;amp; 1) == 0)&lt;br /&gt;
            if (data &amp;gt;= (1 &amp;lt;&amp;lt; 9))&lt;br /&gt;
            {&lt;br /&gt;
#ifdef _FIFO_H_         &lt;br /&gt;
                _inline_fifo_put (&amp;amp;infifo, data &amp;gt;&amp;gt; 1);&lt;br /&gt;
#else            &lt;br /&gt;
                indata = data &amp;gt;&amp;gt; 1;&lt;br /&gt;
#endif // _FIFO_H_            &lt;br /&gt;
                received = 1;&lt;br /&gt;
            }&lt;br /&gt;
      &lt;br /&gt;
        TIMSK = (TIMSK &amp;amp; ~(1 &amp;lt;&amp;lt; OCIE1B)) | (1 &amp;lt;&amp;lt; TICIE1);&lt;br /&gt;
        TIFR = (1 &amp;lt;&amp;lt; ICF1);&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        inbits = bits;&lt;br /&gt;
        inframe = data;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
#endif // SUART_RXD&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Zwei Funktionen, um empfangene Daten zu lesen. Je nachdem, ob die FIFO verwendet wird, sind diese Funktionen unterschiedlich implementiert. Das Benutzer-Interface bleibt jedoch gleich, und die Verwendung einer FIFO transparent.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#ifdef SUART_RXD&lt;br /&gt;
#ifdef _FIFO_H_&lt;br /&gt;
&lt;br /&gt;
int uart_getc_wait()&lt;br /&gt;
{&lt;br /&gt;
    return (int) fifo_get_wait (&amp;amp;infifo);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int uart_getc_nowait()&lt;br /&gt;
{&lt;br /&gt;
    return fifo_get_nowait (&amp;amp;infifo);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#else // _FIFO_H_&lt;br /&gt;
&lt;br /&gt;
int uart_getc_wait()&lt;br /&gt;
{&lt;br /&gt;
    while (!received)   {}&lt;br /&gt;
    received = 0;&lt;br /&gt;
   &lt;br /&gt;
    return (int) indata;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int uart_getc_nowait()&lt;br /&gt;
{&lt;br /&gt;
    if (received)&lt;br /&gt;
    {&lt;br /&gt;
        received = 0;&lt;br /&gt;
        return (int) indata;&lt;br /&gt;
    }&lt;br /&gt;
   &lt;br /&gt;
    return -1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#endif // _FIFO_H_&lt;br /&gt;
#endif // SUART_RXD&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Benutzer-Interface und Header ===&lt;br /&gt;
Im Header &amp;lt;tt&amp;gt;uart.h&amp;lt;/tt&amp;gt; werden die Funktionen veröffentlicht und stehen in anderen Modulen zur Verfügung:&lt;br /&gt;
;&amp;lt;tt&amp;gt;extern void uart_init()&amp;lt;/tt&amp;gt;: Initialisiert den Soft-UART. Vor Verwendung des Soft-UARTs müssen Interrupts mit &amp;lt;tt&amp;gt;sei()&amp;lt;/tt&amp;gt; global aktiviert worden sein (egal, ob vor oder nach dem Aufruf von &amp;lt;tt&amp;gt;uart_init&amp;lt;/tt&amp;gt;).&lt;br /&gt;
;&amp;lt;tt&amp;gt;extern void uart_putc (const char c)&amp;lt;/tt&amp;gt;: Sendet das Zeichen &amp;lt;tt&amp;gt;c&amp;lt;/tt&amp;gt;. Vorher wird gewartet, bis eine evtl. laufende Sendung beendet ist.&lt;br /&gt;
;&amp;lt;tt&amp;gt;extern int uart_getc_wait()&amp;lt;/tt&amp;gt;: Wartet bis zum nächsten Empfang bzw. liefert das empfangene Zeichen im Wertebereich 0...255.&lt;br /&gt;
;&amp;lt;tt&amp;gt;extern int uart_getc_nowait()&amp;lt;/tt&amp;gt;: Schaut nach, ob ein Zeichen empfangen wurde und liefert dieses gegebenenfalls als &amp;lt;tt&amp;gt;int&amp;lt;/tt&amp;gt; zurück (Wertebereich ist 0...255). Wurde nichts empfangen, wird &amp;lt;tt&amp;gt;-1&amp;lt;/tt&amp;gt; geliefert.&lt;br /&gt;
Die Defines &amp;lt;tt&amp;gt;SUART_TXD&amp;lt;/tt&amp;gt; und &amp;lt;tt&amp;gt;SUART_RXD&amp;lt;/tt&amp;gt; zum Aktivieren der Code-Sequenzen für Transmitter resp. Receiver stehen hier im Header; das kann natürlich auch in die Kommandozeile/ins [[make|Makefile]] wandern und mit &amp;lt;tt&amp;gt;-DSUART_RXD&amp;lt;/tt&amp;gt; etc. angeschaltet werden, Gleiches gilt für &amp;lt;tt&amp;gt;F_CPU&amp;lt;/tt&amp;gt; und &amp;lt;tt&amp;gt;BAUDRATE&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#ifndef _UART_H_&lt;br /&gt;
#define _UART_H_&lt;br /&gt;
&lt;br /&gt;
#define SUART_TXD&lt;br /&gt;
#define SUART_RXD&lt;br /&gt;
&lt;br /&gt;
extern void uart_init();&lt;br /&gt;
&lt;br /&gt;
#ifdef SUART_TXD&lt;br /&gt;
    extern void uart_putc (const char);&lt;br /&gt;
#endif // SUART_RXD&lt;br /&gt;
&lt;br /&gt;
#ifdef SUART_RXD&lt;br /&gt;
    extern int uart_getc_wait ();&lt;br /&gt;
    extern int uart_getc_nowait();&lt;br /&gt;
#endif // SUART_RXD&lt;br /&gt;
&lt;br /&gt;
#endif /* _UART_H_ */&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Weblinks ==&lt;br /&gt;
* [http://www.roboternetz.de/phpBB2/dload.php?action=file&amp;amp;file_id=240 UART-Software-Simulation mit ISRs]&lt;br /&gt;
&lt;br /&gt;
== Siehe auch ==&lt;br /&gt;
&lt;br /&gt;
*[[UART]]&lt;br /&gt;
*[[RS232]]&lt;br /&gt;
*[[FIFO mit avr-gcc]]&lt;br /&gt;
*[[UART mit avr-gcc]]&lt;br /&gt;
*[[avr-gcc]]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Kommunikation|UART]]&lt;br /&gt;
[[Kategorie:Praxis|UART]]&lt;br /&gt;
[[Kategorie:Quellcode C|UART]]&lt;br /&gt;
[[Kategorie:Software|UART]]&lt;br /&gt;
[[Kategorie:Microcontroller|UART]]&lt;/div&gt;</summary>
		<author><name>Phaiax</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=Software-UART_mit_avr-gcc&amp;diff=15244</id>
		<title>Software-UART mit avr-gcc</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=Software-UART_mit_avr-gcc&amp;diff=15244"/>
				<updated>2009-08-13T20:36:03Z</updated>
		
		<summary type="html">&lt;p&gt;Phaiax: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Ein '''Software-UART''' ist eine Software, welche die Funktionalität eines [[UART]] (''Universal Asynchronous Receiver and Transmitter'') implementiert., oder kurz: eine serielle Schnittstelle in Software nachbildet.&lt;br /&gt;
&lt;br /&gt;
== Einführung ==&lt;br /&gt;
Stehen keine oder nicht genügend Hardware-UARTs zur Verfügung, muss man selbst Hand anlegen. Die Herausforderung ist dabei, die festgelegten Zeitrahmen bzw. Übertragungsraten/Bitlängen möglichst genau einzuhalten, um die Kommunikation fehlerfrei zu halten. Dies gilt in besonderem Maße für den Empfänger (Receiver), der nicht entscheiden kann, wann Daten eintreffen.&lt;br /&gt;
&lt;br /&gt;
Dafür benötigt man eine Zeitbasis. Am konfortabelsten geht das mit einem Timer. Ohne Timer muss man die Zeit durch Abzählen von Maschinenzyklen machen, während die restliche Software warten muss bzw. Interrupts deaktiviert sein müssen. &lt;br /&gt;
&lt;br /&gt;
Jeder diese Herangehensweisen hat ihre Vor- und Nachteile. Welcher Weg der bessere ist, kann nur im Gesamtzusammenhang des Programmes entschieden werden.&lt;br /&gt;
&lt;br /&gt;
Wie auch immer; Ziel der Software ist es, UART-Datenframes senden und empfangen zu können. Bei Inaktivität (idle) ist die Signalleitung auf 1 (High). Jeder Frame beginnt mit einem Startbit (S), das 0 ist. Danach folgen die 8 Datenbits und schliesslich ein Stop-Bit (P), das immer 1 ist. Danach ist die Leitung wieder inaktiv oder es folgen weitere Frames.&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
[[Bild:UART-Frame.png|UART-Frame]]&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Läuft der AVR mit einer Taktrate von &amp;lt;tt&amp;gt;F_CPU&amp;lt;/tt&amp;gt; und die Übertragung mit der Baudrate BAUDRATE, dann dauert ein Bit&lt;br /&gt;
:&amp;lt;math&amp;gt;Z_\mathrm{bit} = \frac\mathrm{F_{CPU}}\mathrm{BAUDRATE}&amp;lt;/math&amp;gt;&lt;br /&gt;
Zyklen. Bei 16MHz und 38400 Baud dauert ein Bit also rund 417 Zyklen, bei 1MHz und 9600 hat man nur rund 104 Zyklen Zeit.&lt;br /&gt;
&lt;br /&gt;
== Mit Verwendung von Timer1 ==&lt;br /&gt;
&lt;br /&gt;
=== Dateikopf ===&lt;br /&gt;
&lt;br /&gt;
Im Dateikopf wird festgelegt, an welchen Ports die Ein- und Ausgabe stattfindet, mit welcher Baudrate übertragen wird und welche Teile des Soft-UARTs aktiv sind, also übersetzt werden und als Funktionen zur Verfügung stehen bzw. Flash verbrauchen. Damit eintreffende Daten nicht verloren gehen, können die Eingabedaten in einer [[FIFO mit avr-gcc|FIFO]] zwischengespeichert werden. &lt;br /&gt;
&lt;br /&gt;
Die verwendeten Ports sind aus Effizienzgründen hartcodiert. Der Receiver-Eingang liegt an einem ICP (InputCapture-Eingang). Ebenfalls hartcodiert ist das Sendeformat 8N1 (8&amp;amp;nbsp;Datenbits, kein Parity, 1&amp;amp;nbsp;Stopbit).&lt;br /&gt;
;&amp;lt;tt&amp;gt;F_CPU&amp;lt;/tt&amp;gt;: ist die Taktrate des AVR und muss irgendwo definiert worden sein, entweder über ein &amp;lt;tt&amp;gt;#define&amp;lt;/tt&amp;gt; oder per Kommandozeile mit &amp;lt;tt&amp;gt;-DF_CPU=...&amp;lt;/tt&amp;gt;&lt;br /&gt;
;&amp;lt;tt&amp;gt;#define BAUDRATE ...&amp;lt;/tt&amp;gt;: Die Baudrate, gleich für Receiver und Transmitter.&lt;br /&gt;
;&amp;lt;tt&amp;gt;#define SUART_TXD&amp;lt;/tt&amp;gt;: Wenn dieses Define gesetzt ist, wird der Transmitter aktiv bzw. die für ihn notwendigen Code-Sequenzen werden eingeblendet.&lt;br /&gt;
;&amp;lt;tt&amp;gt;#define SUART_RXD&amp;lt;/tt&amp;gt;: Wenn dieses Define gesetzt ist, wird der Receiver aktiv bzw. die für ihn notwendigen Code-Sequenzen werden eingeblendet.&lt;br /&gt;
;FIFO aktivieren: Um die FIFO zu aktivieren, wird einfach der Header &amp;lt;tt&amp;gt;fifo.h&amp;lt;/tt&amp;gt; includet und dadurch die entsprechende Codeerzeugung veranlasst.&lt;br /&gt;
:;&amp;lt;tt&amp;gt;#define INBUF_SIZE ...&amp;lt;/tt&amp;gt;: Die Größe des Eingabe-Puffers für die Receiver-FIFO&lt;br /&gt;
&lt;br /&gt;
 #include &amp;amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
 #include &amp;amp;lt;avr/interrupt.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 #ifndef SIGNAL&lt;br /&gt;
 #include &amp;amp;lt;avr/signal.h&amp;gt;&lt;br /&gt;
 #endif {{ccomment|SIGNAL }}&lt;br /&gt;
 &lt;br /&gt;
 #include &amp;quot;uart.h&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
 {{ccomment|Folgende Zeile einkommentieren, falls FIFO verwendet werden soll }}&lt;br /&gt;
 {{ccomment|#include &amp;quot;fifo.h&amp;quot; }}&lt;br /&gt;
 &lt;br /&gt;
 #define BAUDRATE 38400&lt;br /&gt;
 &lt;br /&gt;
 #define nop() __asm volatile (&amp;quot;nop&amp;quot;)&lt;br /&gt;
 &lt;br /&gt;
 #ifdef SUART_TXD&lt;br /&gt;
     #define SUART_TXD_PORT PORTB&lt;br /&gt;
     #define SUART_TXD_DDR  DDRB&lt;br /&gt;
     #define SUART_TXD_BIT  PB1&lt;br /&gt;
     static volatile uint16_t outframe;&lt;br /&gt;
 #endif {{ccomment|SUART_TXD }}&lt;br /&gt;
 &lt;br /&gt;
 #ifdef SUART_RXD&lt;br /&gt;
     #define SUART_RXD_PORT PORTB&lt;br /&gt;
     #define SUART_RXD_PIN  PINB&lt;br /&gt;
     #define SUART_RXD_DDR  DDRB&lt;br /&gt;
     #define SUART_RXD_BIT  PB0&lt;br /&gt;
     static volatile uint16_t inframe;&lt;br /&gt;
     static volatile uint8_t inbits, received;&lt;br /&gt;
 &lt;br /&gt;
     #ifdef _FIFO_H_&lt;br /&gt;
         #define INBUF_SIZE 4&lt;br /&gt;
         static uint8_t inbuf[INBUF_SIZE];&lt;br /&gt;
         fifo_t infifo;&lt;br /&gt;
     #else {{ccomment|_FIFO_H_ }}&lt;br /&gt;
         static volatile uint8_t indata;&lt;br /&gt;
     #endif {{ccomment|_FIFO_H_ }}&lt;br /&gt;
 #endif {{ccomment|SUART_RXD }}&lt;br /&gt;
&lt;br /&gt;
=== Initialisierung ===&lt;br /&gt;
&lt;br /&gt;
Hier wird der Software-UART initialisiert. Die Initialisierung ist gegen Interrupts gesperrt. Das Modus- und OCR1A-Register von Timer1 werden so initialisiert, daß eine Zeitbasis für den UART entsteht.&lt;br /&gt;
&lt;br /&gt;
 {{ccomment|Initialisierung für einen ATmega8 }}&lt;br /&gt;
 {{ccomment|Für andere AVR-Derivate sieht dies vermutlich anders aus: }}&lt;br /&gt;
 {{ccomment|Registernamen ändern sich (zB TIMSK0 anstatt TIMSK, etc). }}&lt;br /&gt;
 void uart_init()&lt;br /&gt;
 {&lt;br /&gt;
     uint8_t tifr = 0;&lt;br /&gt;
     uint8_t sreg = SREG;&lt;br /&gt;
     cli();&lt;br /&gt;
 &lt;br /&gt;
     {{ccomment|Mode #4 für Timer1 }}&lt;br /&gt;
     {{ccomment|und volle MCU clock }}&lt;br /&gt;
     {{ccomment|IC Noise Cancel }}&lt;br /&gt;
     {{ccomment|IC on Falling Edge }}&lt;br /&gt;
     TCCR1A = 0;&lt;br /&gt;
     TCCR1B = (1 &amp;amp;lt;&amp;amp;lt; WGM12) | (1 &amp;amp;lt;&amp;amp;lt; CS10) | (0 &amp;amp;lt;&amp;amp;lt; ICES1) | (1 &amp;amp;lt;&amp;amp;lt; ICNC1);&lt;br /&gt;
 &lt;br /&gt;
     {{ccomment|OutputCompare für gewünschte Timer1 Frequenz }}&lt;br /&gt;
     OCR1A = (uint16_t) ((uint32_t) F_CPU/BAUDRATE);&lt;br /&gt;
 &lt;br /&gt;
 #ifdef SUART_RXD&lt;br /&gt;
     SUART_RXD_DDR  &amp;amp;= ~(1 &amp;amp;lt;&amp;amp;lt; SUART_RXD_BIT);&lt;br /&gt;
     SUART_RXD_PORT |=  (1 &amp;amp;lt;&amp;amp;lt; SUART_RXD_BIT);&lt;br /&gt;
     TIMSK |= (1 &amp;amp;lt;&amp;amp;lt; TICIE1);&lt;br /&gt;
     tifr  |= (1 &amp;amp;lt;&amp;amp;lt; ICF1) | (1 &amp;amp;lt;&amp;amp;lt; OCF1B);&lt;br /&gt;
 #else&lt;br /&gt;
     TIMSK &amp;amp;= ~(1 &amp;amp;lt;&amp;amp;lt; TICIE1);&lt;br /&gt;
 #endif {{ccomment|SUART_RXD }}&lt;br /&gt;
 &lt;br /&gt;
 #ifdef SUART_TXD&lt;br /&gt;
     tifr |= (1 &amp;amp;lt;&amp;amp;lt; OCF1A);&lt;br /&gt;
     SUART_TXD_PORT |= (1 &amp;amp;lt;&amp;amp;lt; SUART_TXD_BIT);&lt;br /&gt;
     SUART_TXD_DDR  |= (1 &amp;amp;lt;&amp;amp;lt; SUART_TXD_BIT);&lt;br /&gt;
     outframe = 0;&lt;br /&gt;
 #endif {{ccomment|SUART_TXD }}&lt;br /&gt;
 &lt;br /&gt;
     TIFR = tifr;&lt;br /&gt;
 &lt;br /&gt;
     SREG = sreg;&lt;br /&gt;
&lt;br /&gt;
#ifdef _FIFO_H_&lt;br /&gt;
    fifo_init (&amp;amp;infifo,   inbuf, INBUF_SIZE);&lt;br /&gt;
#endif // _FIFO_H_&lt;br /&gt;
&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Transmitter === &lt;br /&gt;
Das Senden ist am einfachsten: Zuerst wird gewartet, bis eine evtl. laufende Sendung abgeschlossen ist. Dann wird der Ausgabe-Frame zusammengebaut (1&amp;amp;nbsp;Startbit, 8&amp;amp;nbsp;Datenbits, 1&amp;amp;nbsp;Stopbit und 1&amp;amp;nbsp;Bit als interne Endekennung). Dann wird OutputCompare1A-Interrupt aktiviert das entsprechende Interrupt-Flag zurückgesetzt, damit das erste Bit nicht zu kurz wird (wenn das Flag gesetzt wäre, würde direkt nach dem &amp;lt;tt&amp;gt;sei()&amp;lt;/tt&amp;gt; ein Interrupt auftreten. Ein Transmit ist fertig, wenn &amp;lt;tt&amp;gt;outframe&amp;lt;/tt&amp;gt; gleich 0 ist. Das Auslesen von &amp;lt;tt&amp;gt;outframe&amp;lt;/tt&amp;gt; muss unter Interrupt-Deaktivierung geschehen. &amp;lt;tt&amp;gt;uart_putc&amp;lt;/tt&amp;gt; geht davon aus, daß Interrupts global aktiviert sind (ansonsten hängt es sich auf bzw. es wird nicht ausgegeben).&lt;br /&gt;
 #ifdef SUART_TXD&lt;br /&gt;
 void uart_putc (const char c)&lt;br /&gt;
 {&lt;br /&gt;
     do&lt;br /&gt;
     {&lt;br /&gt;
         sei(); nop(); cli(); {{ccomment|yield(); }}&lt;br /&gt;
     } while (outframe);&lt;br /&gt;
 &lt;br /&gt;
     {{ccomment|frame &amp;amp;#61; *.P.7.6.5.4.3.2.1.0.S   S&amp;amp;#61;Start(0), P&amp;amp;#61;Stop(1), *&amp;amp;#61;Endemarke(1) }}&lt;br /&gt;
     outframe = (3 &amp;amp;lt;&amp;amp;lt; 9) | (((uint8_t) c) &amp;amp;lt;&amp;amp;lt; 1);&lt;br /&gt;
 &lt;br /&gt;
     TIMSK |= (1 &amp;amp;lt;&amp;amp;lt; OCIE1A);&lt;br /&gt;
     TIFR   = (1 &amp;amp;lt;&amp;amp;lt; OCF1A);&lt;br /&gt;
 &lt;br /&gt;
     sei();&lt;br /&gt;
 }&lt;br /&gt;
 #endif {{ccomment|SUART_TXD }}&lt;br /&gt;
&lt;br /&gt;
Danach kommt es zu OC1A-Interrupts. Für jeden [[IRQ]] wird ein Bit ausgegeben. Im letzten Interrupt wird das Senden eingestellt und die [[ISR]] deaktiviert ihren eigenen IRQ.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#ifdef SUART_TXD&lt;br /&gt;
SIGNAL (SIG_OUTPUT_COMPARE1A)&lt;br /&gt;
{&lt;br /&gt;
    uint16_t data = outframe;&lt;br /&gt;
   &lt;br /&gt;
    if (data &amp;amp; 1)      SUART_TXD_PORT |=  (1 &amp;lt;&amp;lt; SUART_TXD_BIT);&lt;br /&gt;
    else               SUART_TXD_PORT &amp;amp;= ~(1 &amp;lt;&amp;lt; SUART_TXD_BIT);&lt;br /&gt;
   &lt;br /&gt;
    if (1 == data)&lt;br /&gt;
    {&lt;br /&gt;
        TIMSK &amp;amp;= ~(1 &amp;lt;&amp;lt; OCIE1A);&lt;br /&gt;
    }   &lt;br /&gt;
   &lt;br /&gt;
    outframe = data &amp;gt;&amp;gt; 1;&lt;br /&gt;
}&lt;br /&gt;
#endif // SUART_TXD&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Receiver ===&lt;br /&gt;
Eine fallende Flanke löst einen Input-Capture-IRQ aus. Der in ICR1 gesicherte Timer1-Wert wird gelesen, und die halbe Bit-Zeit OCR1A/2 wird draufaddiert, um den Empfangszeitpunkt (sample time) zu erhalten. Die ISR deaktiviert ihren IRQ und aktiviert stattdessen den OutputCompare1B-Interrupt, der die Bits einsammelt.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#ifdef SUART_RXD&lt;br /&gt;
SIGNAL (SIG_INPUT_CAPTURE1)&lt;br /&gt;
{&lt;br /&gt;
    uint16_t icr1  = ICR1;&lt;br /&gt;
    uint16_t ocr1a = OCR1A;&lt;br /&gt;
   &lt;br /&gt;
    // Eine halbe Bitzeit zu ICR1 addieren (modulo OCR1A) und nach OCR1B&lt;br /&gt;
    uint16_t ocr1b = icr1 + ocr1a/2;&lt;br /&gt;
    if (ocr1b &amp;gt;= ocr1a)&lt;br /&gt;
        ocr1b -= ocr1a;&lt;br /&gt;
    OCR1B = ocr1b;&lt;br /&gt;
   &lt;br /&gt;
    TIFR = (1 &amp;lt;&amp;lt; OCF1B);&lt;br /&gt;
    TIMSK = (TIMSK &amp;amp; ~(1 &amp;lt;&amp;lt; TICIE1)) | (1 &amp;lt;&amp;lt; OCIE1B);&lt;br /&gt;
    inframe = 0;&lt;br /&gt;
    inbits = 0;&lt;br /&gt;
}&lt;br /&gt;
#endif // SUART_RXD&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die OutputCompare1B-ISR sammelt die Bits ein. Wurden 10 Bits übertragen, wird das empfangene Byte gespeichert, falls es nicht ungültig ist. Gespeichert wird in der Modul-globalen Variablen &amp;lt;tt&amp;gt;indata&amp;lt;/tt&amp;gt; (oder bei aktiviertem FIFO-Mechanismus in &amp;lt;tt&amp;gt;infifo&amp;lt;/tt&amp;gt;), und der Empfangsmerker &amp;lt;tt&amp;gt;received&amp;lt;/tt&amp;gt; wird gesetzt.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#ifdef SUART_RXD&lt;br /&gt;
SIGNAL (SIG_OUTPUT_COMPARE1B)&lt;br /&gt;
{&lt;br /&gt;
    uint16_t data = inframe &amp;gt;&amp;gt; 1;&lt;br /&gt;
   &lt;br /&gt;
    if (SUART_RXD_PIN &amp;amp; (1 &amp;lt;&amp;lt; SUART_RXD_BIT))&lt;br /&gt;
        data |= (1 &amp;lt;&amp;lt; 9);&lt;br /&gt;
      &lt;br /&gt;
    uint8_t bits = inbits+1;&lt;br /&gt;
   &lt;br /&gt;
    if (10 == bits)&lt;br /&gt;
    {&lt;br /&gt;
        if ((data &amp;amp; 1) == 0)&lt;br /&gt;
            if (data &amp;gt;= (1 &amp;lt;&amp;lt; 9))&lt;br /&gt;
            {&lt;br /&gt;
#ifdef _FIFO_H_         &lt;br /&gt;
                _inline_fifo_put (&amp;amp;infifo, data &amp;gt;&amp;gt; 1);&lt;br /&gt;
#else            &lt;br /&gt;
                indata = data &amp;gt;&amp;gt; 1;&lt;br /&gt;
#endif // _FIFO_H_            &lt;br /&gt;
                received = 1;&lt;br /&gt;
            }&lt;br /&gt;
      &lt;br /&gt;
        TIMSK = (TIMSK &amp;amp; ~(1 &amp;lt;&amp;lt; OCIE1B)) | (1 &amp;lt;&amp;lt; TICIE1);&lt;br /&gt;
        TIFR = (1 &amp;lt;&amp;lt; ICF1);&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        inbits = bits;&lt;br /&gt;
        inframe = data;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
#endif // SUART_RXD&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Zwei Funktionen, um empfangene Daten zu lesen. Je nachdem, ob die FIFO verwendet wird, sind diese Funktionen unterschiedlich implementiert. Das Benutzer-Interface bleibt jedoch gleich, und die Verwendung einer FIFO transparent.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#ifdef SUART_RXD&lt;br /&gt;
#ifdef _FIFO_H_&lt;br /&gt;
&lt;br /&gt;
int uart_getc_wait()&lt;br /&gt;
{&lt;br /&gt;
    return (int) fifo_get_wait (&amp;amp;infifo);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int uart_getc_nowait()&lt;br /&gt;
{&lt;br /&gt;
    return fifo_get_nowait (&amp;amp;infifo);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#else // _FIFO_H_&lt;br /&gt;
&lt;br /&gt;
int uart_getc_wait()&lt;br /&gt;
{&lt;br /&gt;
    while (!received)   {}&lt;br /&gt;
    received = 0;&lt;br /&gt;
   &lt;br /&gt;
    return (int) indata;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int uart_getc_nowait()&lt;br /&gt;
{&lt;br /&gt;
    if (received)&lt;br /&gt;
    {&lt;br /&gt;
        received = 0;&lt;br /&gt;
        return (int) indata;&lt;br /&gt;
    }&lt;br /&gt;
   &lt;br /&gt;
    return -1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#endif // _FIFO_H_&lt;br /&gt;
#endif // SUART_RXD&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Benutzer-Interface und Header ===&lt;br /&gt;
Im Header &amp;lt;tt&amp;gt;uart.h&amp;lt;/tt&amp;gt; werden die Funktionen veröffentlicht und stehen in anderen Modulen zur Verfügung:&lt;br /&gt;
;&amp;lt;tt&amp;gt;extern void uart_init()&amp;lt;/tt&amp;gt;: Initialisiert den Soft-UART. Vor Verwendung des Soft-UARTs müssen Interrupts mit &amp;lt;tt&amp;gt;sei()&amp;lt;/tt&amp;gt; global aktiviert worden sein (egal, ob vor oder nach dem Aufruf von &amp;lt;tt&amp;gt;uart_init&amp;lt;/tt&amp;gt;).&lt;br /&gt;
;&amp;lt;tt&amp;gt;extern void uart_putc (const char c)&amp;lt;/tt&amp;gt;: Sendet das Zeichen &amp;lt;tt&amp;gt;c&amp;lt;/tt&amp;gt;. Vorher wird gewartet, bis eine evtl. laufende Sendung beendet ist.&lt;br /&gt;
;&amp;lt;tt&amp;gt;extern int uart_getc_wait()&amp;lt;/tt&amp;gt;: Wartet bis zum nächsten Empfang bzw. liefert das empfangene Zeichen im Wertebereich 0...255.&lt;br /&gt;
;&amp;lt;tt&amp;gt;extern int uart_getc_nowait()&amp;lt;/tt&amp;gt;: Schaut nach, ob ein Zeichen empfangen wurde und liefert dieses gegebenenfalls als &amp;lt;tt&amp;gt;int&amp;lt;/tt&amp;gt; zurück (Wertebereich ist 0...255). Wurde nichts empfangen, wird &amp;lt;tt&amp;gt;-1&amp;lt;/tt&amp;gt; geliefert.&lt;br /&gt;
Die Defines &amp;lt;tt&amp;gt;SUART_TXD&amp;lt;/tt&amp;gt; und &amp;lt;tt&amp;gt;SUART_RXD&amp;lt;/tt&amp;gt; zum Aktivieren der Code-Sequenzen für Transmitter resp. Receiver stehen hier im Header; das kann natürlich auch in die Kommandozeile/ins [[make|Makefile]] wandern und mit &amp;lt;tt&amp;gt;-DSUART_RXD&amp;lt;/tt&amp;gt; etc. angeschaltet werden, Gleiches gilt für &amp;lt;tt&amp;gt;F_CPU&amp;lt;/tt&amp;gt; und &amp;lt;tt&amp;gt;BAUDRATE&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#ifndef _UART_H_&lt;br /&gt;
#define _UART_H_&lt;br /&gt;
&lt;br /&gt;
#define SUART_TXD&lt;br /&gt;
#define SUART_RXD&lt;br /&gt;
&lt;br /&gt;
extern void uart_init();&lt;br /&gt;
&lt;br /&gt;
#ifdef SUART_TXD&lt;br /&gt;
    extern void uart_putc (const char);&lt;br /&gt;
#endif // SUART_RXD&lt;br /&gt;
&lt;br /&gt;
#ifdef SUART_RXD&lt;br /&gt;
    extern int uart_getc_wait ();&lt;br /&gt;
    extern int uart_getc_nowait();&lt;br /&gt;
#endif // SUART_RXD&lt;br /&gt;
&lt;br /&gt;
#endif /* _UART_H_ */&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Weblinks ==&lt;br /&gt;
* [http://www.roboternetz.de/phpBB2/dload.php?action=file&amp;amp;file_id=240 UART-Software-Simulation mit ISRs]&lt;br /&gt;
&lt;br /&gt;
== Siehe auch ==&lt;br /&gt;
&lt;br /&gt;
*[[UART]]&lt;br /&gt;
*[[RS232]]&lt;br /&gt;
*[[FIFO mit avr-gcc]]&lt;br /&gt;
*[[UART mit avr-gcc]]&lt;br /&gt;
*[[avr-gcc]]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Kommunikation|UART]]&lt;br /&gt;
[[Kategorie:Praxis|UART]]&lt;br /&gt;
[[Kategorie:Quellcode C|UART]]&lt;br /&gt;
[[Kategorie:Software|UART]]&lt;br /&gt;
[[Kategorie:Microcontroller|UART]]&lt;/div&gt;</summary>
		<author><name>Phaiax</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=Diskussion:Software-UART_mit_avr-gcc&amp;diff=14053</id>
		<title>Diskussion:Software-UART mit avr-gcc</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=Diskussion:Software-UART_mit_avr-gcc&amp;diff=14053"/>
				<updated>2008-10-08T22:52:04Z</updated>
		
		<summary type="html">&lt;p&gt;Phaiax: fifo_init&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Full oder Half-Duplex? ==&lt;br /&gt;
Sollte dazugesagt werden, ob das Verfahren full- oder halbduplex arbeiten kann. &lt;br /&gt;
&lt;br /&gt;
--PicNick 14:38, 7. Feb 2006 (CET)&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
Vom Konzept her hatte ich es als full duplex ausgelegt. Momentan denke ich auch, daß die Timer-Lösung das leistet. Allerdings ist das natürlich auch abhängig davon, was sonst so im System abgeht, insbesondere die Interrupt-Last und respond Zeiten. Falls die hoch werden, ist zu erwarten, daß die Übertragung nicht mehr immer korrekt ist, weil die Zeiten nicht eingehalten werden. Dadurch sampelt man nicht mehr in der Mitte eines Bits bzw. das Signal fängt an zu jittern, man verpasst Zeichen. Das Verpassen sollte durch eine FIFO   entschärft werden. Alternativ wäre an eine HW-Flussteuerung zu denken, zumindest in eine Richtung. Eingehende Analysen hab ich nicht gemacht und auch nicht die Mittel dazu. Falls du Vorschläge hast, können die ja eingebaut werden, oder falls du ne Stelle siehst, warum es nicht voll Duplex ist.&lt;br /&gt;
&lt;br /&gt;
--[[Benutzer:SprinterSB|SprinterSB]] 11:30, 8. Feb 2006 (CET)&lt;br /&gt;
----&lt;br /&gt;
Sollte keine Kritik sein. Ich hab zusammen mit einen Forum User mal die entsprechende AVR-Appl-Note f. Soft Uart durchgezogen, mir reicht es :-) . &lt;br /&gt;
--PicNick 19:44, 8. Feb 2006 (CET)&lt;br /&gt;
&lt;br /&gt;
== Senden ohneStart/Stop/Parität ? ==&lt;br /&gt;
&lt;br /&gt;
[[Benutzer:TurboFischer|TurboFischer]] schrieb:&lt;br /&gt;
:''Hallo,''&lt;br /&gt;
&lt;br /&gt;
:''ich bin neu hier und hab deinen Beitrag im Wiki über den Software Uart gesehen. Jetzt hätte ich da eine Frage dazu. Ich brauche für mein Projekt nur einen Teil und zwar um  Daten zu übertragen, empfangen brauch ich nichts.''&lt;br /&gt;
&lt;br /&gt;
:''Jetzt wollte ich fragen ob es möglich ist Daten ohne Start-, Stop- und Paritätsbit zu senden? Also rein nur die Daten das die in der eingestellten Baudrate an dem definierten PIN ausgesendet werden? Wenn ja wie man das realiesieren könnte bzw. was man ändern müste.''&lt;br /&gt;
&lt;br /&gt;
:''Wäre über deine Hilfe sehr dankbar. Vielen Dank im Voraus.''&lt;br /&gt;
:''Mit freundlichen Grüssen''&lt;br /&gt;
&lt;br /&gt;
:''Thomas''&lt;br /&gt;
&lt;br /&gt;
Das Paritätsbit wird ohnehin nicht bedient, die Software implementiert 8N1.&lt;br /&gt;
&lt;br /&gt;
Ob Code für Empfänger/Sender erzeugt wird, sollte durch die Defines SUART_RXD resp. SUART_TXD zu steuern sein, weil nur mit gesetzten Defines die Codesequenzen eingeblendet sind.&lt;br /&gt;
&lt;br /&gt;
Um Start/Stop zu vermeiden machst du folgende Änderung in &amp;lt;tt&amp;gt;uart_putc&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   // frame = *.7.6.5.4.3.2.1.0  *=Endemarke(1)&lt;br /&gt;
   outframe = (1 &amp;lt;&amp;lt; 8) | ((uint8_t) c);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Aber ich vermute mal, weder Start noch Stop zu senden ist nicht das, was du willst...&lt;br /&gt;
&lt;br /&gt;
== fifo_init ==&lt;br /&gt;
&lt;br /&gt;
Frage als Neuling: Müsste die FIFO nicht in der funktion uart_init initialisiert werden?&lt;/div&gt;</summary>
		<author><name>Phaiax</name></author>	</entry>

	</feed>