====== USART ====== USART ist ein Universal Synchrones Serielles Interface, UART ist die vereinfachte Version - Universelles Asynchrones Interface. Der Unterschied zwischen beiden liegt darin, dass das USART auch eine Taktsignalleitung nutzt um Daten zu synchronisieren, während das UART nur Datenleitungen benutzt. Das UART des AVR Mikrocontrollers Duplexverkehr, 5- bis 9-Bit Datenworte (8-Bit Wort = 1 Byte), 1 oder 2 Stop Bits, 3 Paritätsmodi und eine Vielzahl an Baud-Raten zulässt. AVR Mikrocontroller verfügen normalerweise über bis zu 2 USART Interfaces, jedoch gibt es auch einige ohne USART. Datenübertragungen werden mit einen Wort für Wort ausgeführt - der AVR konvertiert das Wort, welches er vom Benutzer bekommt in Bits auf Hardwareeinheiten und übermittelt es unabhängig und andersherum. Der Benutzer kann das USART mit Schreib- und Lesekonfigurationen sowie Status- und Datenregistern kontrollieren. Jede Einstellungsoption hat ein eigenes Register, welches recht einfach anhand des Datenblatts konfiguriert werden kann. Die Baud-Rate ist allerdings etwas schwieriger einzustellen. Das Taktsignal für die Datenübertragung wird vom Taktgeber des Controllers generiert und der Nutzer kann eine Zahl von 1 bis 4096 eingeben, durch welche die Taktrate dividiert wird. Das Ergebnis wird darüber hinaus, je nach Modus, durch 2, 8 oder 16 dividiert. Das Problem ist, dass nicht alle Taktfrequenzen so dividiert werden können, dass das Ergebnis eine Standard-Baud-Rate ergibt. Bei einigen Frequenzen kann die Baud-Rate bis zu 10% vom Standardwert abweichen. Die Datenblätter des AVR beinhalten Tabellen mit Angaben zu den typischen Taktfrequenzen, Baud-Raten, den nötigen Multiplikatoren um die Baud-Raten zu erreichen sowie den möglichen Rechenfehlern. Da die Datenübertragung unabhängig vom Prozessor und viel langsamer geschieht, ist es nötig zu bestätigen, dass das Interface für das nächste Wort bereit ist, bevor eine weitere Übertragung stattfindet. Das kann gewährleistet werden, indem das Ready Bit des Sendepuffers beachtet wird, welches anzeigt ob der Puffer bereit ist, ein neues Wort zu empfangen oder nicht. Der Controller startet mit einen aktivierten Ready Bit. Sobald ein Wort übertragen wird und der Puffer leer ist, wird das Ready Bit „high“ gesetzt. Der Empfang eines Wortes ist wird durch ein spezielles Status-Bit gekennzeichnet. Zusätzlich gibt es Status-Bits, welche Rahmenfehler, Paritätsfehler und Pufferüberläufe anzeigen. Ein Pufferüberlauf tritt auf, wenn das letzte Wort noch aus dem Puffer gelesen werden muss, während ein neues ankommt. Aus diesem Grund ist es wichtig, die empfangenen Datenwörter stets so schnell wie möglich ins Programm zu lesen, z.B. mit Hilfe eines Interrupts. Es gibt drei mögliche Gründe für Interrupts: Sendepuffer bereit, Übertragung erfolgreich, Empfang erfolgreich. Der Sende- und Empfangspuffer sind physikalisch getrennte Register, aber sie nutzen die gleiche Speicheradresse und den gleichen Namen. Während des Schreibens in ein gemeinsam benutztes Register, werden die Daten im Sendepuffer gespeichert, beim Auslesen werden sie aus dem Empfangspuffer gelesen. Werden 9-Bit Worte benutzt, wird das 9. Bit mit Hilfe eines Einstellungsregister übertragen und ausgelesen. Aufgabe: Konfigurieren Sie die USART0 Schnittstelle eines 8 MHz ATmega128 so, dass sie ein 8-Bit-Wort asynchron überträgt, wobei die Baudrate 9600 bps beträgt, 1 Stoppbit und kein Paritätsbit genutzt werden soll. Senden Sie das Symbol “X”. #include int main() { // Setzt die Baud-Rate auf 9600 bps. Formel: // Faktor = Frequenz / 16 / Baudrate -1 // UBRR = 8000000 / 16 / 9600 - 1 = ~51 UBRR0H = 0; UBRR0L = 51; // Erlaube Senden UCSR0B = (1 << TXEN0); // Konfiguriere den asynchronen Modus, setze die Wortgröße auf 8 Bit, // 1 Stoppbit, kein Paritätsbit. UCSR0C = (1 << UCSZ01) | (1 << UCSZ00); // Warte solange, bis der Datenpuffer leer ist (das vorherige Wort wurde gesendet) // In diesem Beispiel ist es jedoch nicht nötig zu warten, da nur das erste Symbol // gesendet wird. Es sollte jedoch beachtet werden, wenn mehr als ein Symbol gesendet wird. while (!(UCSR0A & (1 << UDRE))) continue; // Schreibe das Symbol in den Sendepuffer. UDR0 = 'X'; // Endlosschleife while (1) continue; }