Der UART, Teil 2

Nun habt ihr wahrscheinlich alle schon Daten vom Controller zum PC geschickt. Es gibt aber durchaus auch Anwendungen, bei denen wir Informationen vom PC oder anderen Geräten über die serielle Schnittstelle an den Controller schicken können.

Empfangen mit dem UART

Bevor wir Daten über den UART einlesen können müssen wir diesen natürlich auch wieder initialisieren. Ich erinnere dazu auch an den UART, Teil 1, in welchem das Senden besprochen wurde.
Um grundsätzlich mal Empfangen zu können, muss das Receiver Enable Bit im UART Control Register gesetzt werden:

outp ((1 << RXEN), UCR);

Wenn wir senden und empfangen wollen muss zusätzlich das Transmitter Enable Bit gesetzt werden. Dann sieht der Befehl so aus:

outp ((1 << RXEN) | (1 << TXEN), UCR);

Und denkt daran, dass wir auch noch die Baudrate festlegen müssen.

#define F_CPU 4000000       // Zum Beispiel 4Mhz-Quarz
#define UART_BAUD_RATE 9600 // Wir versuchen mal mit 9600 Baud

outp (F_CPU / (UART_BAUD_RATE * 16L) - 1, UBRR);

Sodele, jetzt müssen wir in unserer Programmschleife bloss noch prüfen, ob eventuell ein Zeichen empfangen wurde. Dies wird vom UART im Status Register angezeigt, indem das RXC Bit gesetzt wird. Nun müssen wir möglichst schnell das UART Daten Register auslesen, damit das nächste Zeichen empfangen werden kann.

char ch;   // Variable zur Speicherung des gelesenen Zeichens

for (;;) {                           // Endlosschleife
    if (inp (USR) & (1 << RXC)) {    // Bit RXC im USR gesetzt ?
        ch = inp (UDR);              // Datenregister auslesen
    }
    ...
    ...
}

Wenn wir sicher sein wollen, dass wir auch alle Zeichen empfangen haben müssen wir jeweils noch das OverRun Bit testen. Wenn wir nämlich zu lange warten mit dem Auslesen des Datenregisters kann es passieren, dass bereits wieder ein Zeichen in das Empfangs-Schieberegister eingelesen wurde. Da aber das Datenregister noch belegt ist schmeisst der UART das neue Zeichen weg und setzt das OR Bit im Status Register.

char ch;   // Variable zur Speicherung des gelesenen Zeichens

for (;;) {                           // Endlosschleife
    if (inp (USR) & (1 << RXC)) {    // Bit RXC im USR gesetzt ?
        ch = inp (UDR);              // Datenregister auslesen
        if (inp (USR) & (1 << OR)) { // OverRun Bit gesetzt ?
            // Autsch, jetzt ist
            // was verloren gegangen
            ...
        }
    }
    ...
    ...
}

AVR's ohne UART

Wer jetzt glaubt, eine serielle Schnittstelle könne nur mit denjenigen AVR's realisiert werden welche auch einen  UART an Bord haben, der hat sich geschnitten.
Selbstverständlich können wir mit einer entsprechenden Software eine serielle Schnittstelle auf 2 beliebigen Pin's des Controllers realisieren. Allerdings ist der Aufwand für eine entsprechende Software schon erheblich. Beispiele dafür findet ihr auf den einschlägigen Seiten im Internet. Man spricht in diesem Fall von einem Software-UART.
Mit dieser Methode ist es auch möglich, einen AVR mit mehreren seriellen Schnittstellen zu versehen.

Zusammenfassung

Wir haben jetzt gesehen, wie wir mit dem UART ohne Verwendung der Interrupts Daten senden und empfangen können.
Wenn wir die Interrupts zur Hilfe nehmen geht das ganze noch viel komfortabler, aber dazu später mehr.