This is an old revision of the document!
USART ist ein Universal Synchrones Serielles Interface, UART ist die vereinfachte Version - Universelles Asynchrones Interface. Der Unterschied zwischen beiden ist, dass das USART auch eine Taktsignalleitung nutzt um Daten zu synchronisieren, aber das UART nur Datenleitungen benutzt. Das UART des AVR's kann Vollduplex Kommunikation nutzen, 5- bis 9-Bit Datenworte (8-Bit Wort = 1 Byte), 1 oder 2 Stop Bits, 3 Paritätsmodi und eine Vielzahl an Baud-Raten. AVR Microcontroller haben normalerweise bis zu 2 USART Interfaces, aber manche haben auch gar kein USART. Datenübertragungen werden mit einen Wort auf einmal ausgeführt - der AVR konvertiert das Wort was er vom Benutzer bekommt in Bits auf Hardwarelevel und sendet es unhabhängig und vice veersa. Der Benutzer kann das USART mit Schreib- und Lesekonfigurationen und Status- und Datenregister kontrollieren.
Jede Einstellungsoption hat ihr eigenes Register, welche recht einfach mit dem Datasheet einzustellen sind. Die Baud-Rate jedoch, ist etwas schwieriger einzustellen. Das Taktsignal für die Datenübertragung kommt vom Taktgeber des Controllers und der Nutzer kann eine Nummer von 1 bis 4096 eingeben, durch welche die Taktrate dividiert wird. Das Ergebnis wird zusätzlich durch 2, 8 oder 16 dividiert, je nach Modus. Das Problem ist, dass nicht alle Taktfrequenzen so dividiert werden können, dass das Ergebnis eine standard Baud-Rate ist. Mit manchen Frequenzen kann die Baud-Rate mit bis zu 10% vom standard abweichen. Das Datenblatt des AVRs haben Tabellen mit den typischen Taktfrequenzen, Baud-Raten, und den nötigen Multiplikatoren um die Baud-Raten zu erreichen mit ggf. anfallenden Abweichungen.
Da die Datenübertragung unabhängig vom Prozessor und viel langsamer geschiet, ist es notwendig festzustellen, ob das Interface bereit ist für das nächste Wort bevor eine weitere Übertragung stattfindet. Das kann bewerkstellig werden, wenn man auf das Ready Bit des Transmit Buffers achtet, welches anzeigt ob der Buffer bereit ist ein neues Wort zu empfangen oder nicht. Der Controller startet mit einen aktivierten Ready Bit. Sobald ein Wort übertragen wird und der Buffer leer ist, wird das Ready Bit “high” gesetzt.
Das Empfangen eines Wort ist wird durch ein spezielles Status-Bit gekennzeichnet. Zusätzlich gibt es Status-Bits Framingerror, Paritätserror und Bufferoverflows anzuzeigen. Ein Bufferoverflow kann stattfinden, wenn das letzte Wort noch aus dem Buffer gelesen werden muss, wenn ein neues Wort ankommt - darum ist es immer wichtig die empfangenen Datenwörter so schnell wie möglich ins Programm zu lesen, z.B. mit Hilfe eines Interrupts. Es gibt drei verschiedene Interruptgründe: Transmitbuffer bereit, Übertragung erfolgreich, Empfang erfolgreich.
Der Übertragung- und Empfangsbuffer sind physikalisch getrennte Register, aber sie nutzen die gleiche Speicheradresse und Namen. Wenn man in ein gemeinsam benutztes Register schreibt, werden die Daten im Transmitbuffer gespeichert, und wenn man davon liest, werden die Daten aus dem Empfangsbuffer gelesen. Wenn man ein 9-Bit Wort benutzt, wird das 9. Bit in ein Einstellungsregister gesendet und ausgelesen.
Example
Aufgabe: Konfiguriere ein 8 MHz ATmega128 USART0 Interface um ein 8-Bit Wort asynchron mit einer 9600 bps Baud-Rate, 1 Stop-Bit und keinem Paritätsbit zu übertragen. Sende das Symbol “X” Task: Configure an 8 MHz ATmega128's USART0 interface to transmit 8-bit words asynchronously using 9600 bps baud rate, 1 stop bit and no parity bits. Send the symbol “X”.
#include <avr/io.h> int main() { // Setzt die Baud-Rate auf 9600 bps. Formel: // Multiplikator = Taktfrequenz / 16 / Baud rate - 1 // UBRR = 8000000 / 16 / 9600 - 1 = ~51 UBRR0H = 0; UBRR0L = 51; // Übertragen erlauben UCSR0B = (1 << TXEN0); // Konfiguriert asynchronen Modus, setzt die Datenwortgröße auf 8-Bits // 1 stop Bit, kein Paritätsbit. UCSR0C = (1 << UCSZ01) | (1 << UCSZ00); // warte darauf dass der Datenbuffer leer ist (previous word to transmit) // In diesem Beispiel brauch man nicht warten, da das erste Symbol noch // gesendet werden muss, aber es sollte gemacht werden, wenn man mehere Symbole sendet while (!(UCSR0A & (1 << UDRE))) continue; // Schreibt das Symbol in den Buffer für die Übertragung UDR0 = 'X'; // Endlosschleife while (1) continue; }