UART

XMega Blockdiagramm

Der UART vom XMega stellt, wie bei allen anderen Atmel-Controllern, eine einfache und effektive Möglichkeit dar seine Programme zu „debuggen“ (kein richtiges Debuggen aber es ist möglich festzustellen bis wohin ein Programm durchläuft indem Textmarken gesetzt werden) oder Werte von einem Mikrocontroller zum anderen bzw. zum PC zu senden.
Der XMega128A1 besitzt 8 USARTs, wovon einer zur IrDA Modulation/Demodulation genutzt werden kann.

-> UART konfigurieren:

Bevor der UART genutzt werden kann, muss er (wie jede andere Peripherie vom Mikrocontroller) erst einmal eingestellt werden. In meinem Beispiel zeige ich euch wie der USART vom PortC mit einer Baudrate von 19200Baud bei einem Takt von 41MHz genutzt wird.
Als allererstes berechne ich den Wert den ich in das USARTC0.BAUDCTRL-Register schreiben muss. Hierfür wird die Formel aus dem Datenblatt genutzt:

Latex formula
Latex formula

Wenn ich nun meine Werte in die Formel einsetze bekomme ich einen Wert für BSEL von 132,666 bzw. 0x84 als Ergebnis raus. Diese Zahl wird nun in das USARTC0.BAUDCTRL-Register geschrieben. Dieses Register besteht aus einem Teil A und einen Teil B. Dadurch können auch größere Werte für die Baudrate aufgenommen werden.
Das Register B beinhaltet zudem noch drei Bits für einen Scale Faktor, der uns aber im Moment nicht interessiert.
Um das Baudratenregister mit dem korrekten Wert zu laden verwende ich diese beiden Zeilen:

Nachdem die Baudrate in das Register geschrieben ist, lege ich mit diesem Befehl

die Interruptpriorität beim Empfangen fest. Hier in diesem Beispiel bekommt der Rx-Interrupt die höchste Priorität.
Anschließend wird mit

das Empfangen und Senden des USARTs aktiviert und mit dem Befehl

wird die Größe der Zeichen auf 8 Bit festgelegt.
Falls ihr andere Größen verwenden wollt, seht ihr hier die Bitmuster die ihr an die ersten drei Stellen des USART Control-Register C Register schreiben müsst:

XMega_USART(1)

Als letztes wird noch der Tx-Pin vom UART als Ausgang eingestellt werden. Da laut Datenblatt für den USARTC0 der Pin C3 der Tx-Pin ist, stelle ich ihn mit diesem Befehl als Ausgang ein:

Nun ist der UART fertig konfiguriert und kann verwendet werden.

-> Zeichen senden:

Da der UART nun fertig eingerichtet ist, kann ich mit ihm Zeichen zu meinem PC senden. In meinen Experimenten habe ich den XMega über zwei XBee Funkmodule mit meinem Computer verbunden. Soll er aber über RS232 oder USB mit dem Computer verbunden werden sind andere Schaltungen zu benutzen (hierbei hilft Google oder falls ihr gar nicht weiter wisst, könnt ihr mir auch eine E-Mail schreiben).
Um ein Zeichen (in diesem Fall ein G) zu senden verwende ich diese Zeilen:

Die erste Zeile prüft ob das Flag, welches anzeigt das das Datenregister leer ist, gesetzt ist. Wenn das Bit gesetzt ist, ist das Datenregister leer d.h. sobald es voll ist wird dieses Flag gelöscht. Aus diesem Grund muss eine Negation (angedeutet durch das !) vor die Abfrage.
Die ganze While-Schleife bedeutet also:

Solange das Bit USART_DREIF im USARTC0 Status-Register (USARTC0.STATUS) NICHT (!) gesetzt ist wird die Schleife ausgeführt.

Da die Schleife keinen Inhalt hat, sprich nichts zwischen „{„und „}“ steht, wird solange eine Endlosschleife ausgeführt bis das Bit gesetzt wird, also die Schleifenabfrage unwahr wird. Dies Schleife sorgt dafür, dass kein neues Byte gesendet werden kann solange der Controller die Übertragung noch nicht abgeschlossen hat. Dadurch werden Übertragungsfehler vermieden.
Anschließend wird der ASCII-Wert für den Buchstaben G (0x47) in das Datenregister vom USARTC0 geladen.
Falls ihr andere Zeichen senden wollt, findet ihr hier eine ASCII-Tabelle:

-> ASCII-Tabelle

-> Text senden:

Einen Text zu senden bedarf etwas mehr Code, da es sich bei dem Text um einen String, also eine Verkettung mehrerer Zeichen, handelt.
Ich zeige euch mal wie ein Hallo Welt gesendet wird. Als erstes wird (wie oben beschrieben) der USART konfiguriert und anschließend konfiguriere ich noch einen Timer der im 1 Sekunde Takt einen Interrupt auslöst.
In die ISR vom Timer schreibe ich diesen Befehl:

Damit wird eine Funktion aufgerufen die Send_UART heißt. Als Übergabewert wird der Text Hallo Welt übergeben. Die Funktion sieht so aus:

So und was genau macht diese Funktion nun?
In der Zeile

wird der Wert, hier der String Hallo Welt in einem String mit dem Namen data gespeichert. Die Zeilen char Counter und char lenght = 0x00 legen zwei lokale Variablen fest die nachher für die Funktion benötigt werden.
Die Zeile

stellt mit dem Befehl strlen(data) fest wie lang der String data ist. Das Ergebnis wird anschließend in der Variable lenght gespeichert.
Als nächstes wird eine While-Schleife aufgerufen die solange ausgeführt wird, wie die Variable Counter kleiner ist als die Variable lenght.
Innerhalb der While-Schleife finden sich die zwei Codezeilen wieder mit denen weiter oben bereits das G versendet wurde. Die Zeile

hat haargenau die selbe Funktion wie weiter oben, aber die Zeile

lädt diesmal ein Zeichen von dem String data in den Buffer. Welches Zeichen des Strings in den Buffer geladen wird, wird dem Controller durch die Variable Counter mitgeteilt. Am Anfang wird also das Zeichen, welches an der Stelle 0 vom String steht (in diesem Fall das H) in das Datenregister geladen und anschließend gesendet.
In der Zeile

wird anschließend die Variable Counter um eins erhöht. Dann beginnt die ganze Schleife von vorne, und das solange bis „Counter“ größer ist als lenght. Wenn dies der Fall ist, wird die Schleife verlassen, der Counter wird auf 0 zurück gesetzt und es wird noch ein CR (0x0D) und ein LF (0x0A) gesendet. Dies sieht dann so aus:

Nun wird im 1 Sekunde Takt der String Hallo Welt an den Rechner gesendet.
Ein fertiges Hallo Welt-Programm könnt ihr euch unter Software/Atmel AVR oder unter diesem Link

-> Hallo Welt

downloaden.

Der User „Andreas“ war so freundlich und hat mir die Arbeit für eine Empfangsroutine abgenommen! Vielen herzlichen Dank dafür!
Ihr könnt sie euch hier downloaden:

-> X-Mega Empfangsroutine

 

-> Zurück zum XMega Tutorial

28 thoughts on “UART
  1. Hallo,

    erstmal vielen Dank für dieses Tutorial.

    Ich bräuchte eine Schaltung um die USART-Ports an
    [code]
    …zwei XBee Funkmodule mit meinem Computer verbunden. Soll er aber über RS232 oder USB mit dem Computer…
    [/code]

    zu betreiben.
    Vielen Dank im Voraus.

    kwr4711

    • Hallo,

      XBee Funkmodule kannst du direkt mit dem Raspberry verbinden. Für die Anbindung an den PC verwende ich ein FT232 Modul. Dieses stellt einen Wandler von UART nach USB bereit + 3,3V Spannungsquelle.
      Einfach beim XBee 3,3V + GND an das Raspberry anschließen und Tx an Din vom Funkmodul und Rx an Dout vom Funkmodul. Beim FT232 dasselbe nochmal.

      Gruß
      Daniel

    • Hallo,

      stimmt….das wollte ich auch noch schreiben. Das ist bisher komplett untergegangen.
      Im Prinzip musst du nur nach einem Rx Interrupt das Datenregister auslesen und alles zu einem String zusammenbauen.
      Sobald ich etwas Zeit habe schreibe ich dazu noch was.
      Danke für den Hinweis. Das ist mir komplett entfallen!

      Gruß
      Daniel

  2. Nicht vergessen die Variable „counter“ in der Funktion „void Send_UART(char data[])“ zu initialisieren, da sonst evtl. die Ausgabeschleife nie durchlaufen werden kann!

    counter = 0x00;

  3. Hi,
    echt ein super Tutorial. Allerding brauchte ich etwas Hilfe ich soll das ganze mit Bluetooth(BTM 232) realisieren und habe noch nie mit C gearbeitet und auch noch nie mit einem ATXMega sondern nur mit ATMega. Mein Problem ist jetzt wie kann ich damit empfangen und senden.
    Hab das oben schon versucht hat aber irgendwie nicht funktioniert. Kann auch sein das ich zu blöd bin.
    Für Hilfe wäre ich dankbar.

  4. Hey,
    super Sache mit dem Tutorial. Leider hab ich ein kleines Problem mit der Kommunikation und hoffe, dass du mir vielleicht dabei weiterhelfen kannst.

    Ich habe dein Bsp.Code zu „Hallo World“ verwendet. 1 x XBee sitzt am ATxMega32A4, der zweite sitzt am Sparkfun XBee Explorer USB. Das Problem ist nur, dass ich keine Kommunikation zwischen den beiden in der Konstellation erhalte.

    Vorneweg: Mit Arduino und XBee Explorer funktioniert ohne Probleme, nur nicht mit dem Xmega32A4.

    So bald ich dein Bsp. via DragonBoard auf den XMega lade, kann ich am EmpfangsPin des Xbee 3,3V messen.

    PS: Die Diskussion über den MPU6050 würde mich brennend interessieren (kann leider die Diskussion zwischen Dir und einem User nicht mehr finden, weiß jedoch, dass Ihr weiter per mail kommunizieren wolltet.), da ich in näherer Zeit auch ein MPU6050 (Beschleunigungssensor) mit dem XMega32A4 auslesen und über Xbee an ein PC schicken möchte.

    Bin für jede Hilfe sehr Dankbar.

    Gruß
    Bexx

    • Hey,

      die Verkabelung hast du schon geprüft? Tx vom XMega muss an DIN vom XBee und
      DOUT muss an Rx.
      Hast du im Programm auch darauf geachtet, dass du den richtigen USART
      verwendest?
      Schick mir am besten mal einen Schaltplan und dein Programm zu. Dann gucke ich
      mal drüber.

      Gruß
      Daniel

  5. Hallo Daniel,

    Ich finde diese Artikel sind sehr schoen geschrieben. Ich habe mich lange nicht mehr mit AVRs (oder C) beschaeftigt und wollte mal wieder ddamit rumspielen :-)

    Ich habe immer direkt in Assembler geschrieben weil man dann genau weiss was los ist. Ich finde, dass hoehere Sprachen einem zu Ineffizienz verleiten. Manche meinen jedoch, dass sie einem von Kodierfehler bewahren :-)
    Ich weiss, dass dies kein C Kurs ist, denoch finde ich, dass man immer Effizienz im Hinterfopf haben sollte, und wissen was fuer Code erzeugt wird…

    Zu diesem Code faellt mir folgendes ein. In C sind Strings NULL-terminiert, d.h. der String der ueberreicht wird ist ‚Hallo Welt‘. Die Funktion strlen() macht nichts anderes, als diesen String char fuer char nach dem zu durchsuchen. Warum also den String zwei Mal durchlesen? Und warum zwei zusaetzliche Variablen verwenden? Da gehen register drauf, es werden Sachen auf Stacks gepusht und gepopt usw….

    Ich empfehle an dieser Stelle The C Programming Language, Kernighan & Ritchie. Das beste Buch ueberhaupt um eine Sprache zu lernen.

    Natuerlich werden durch Code wie folgendes die ganzen Securityprobleme verursacht. Aber die Verwendung von strlen() ist nicht besser :-)

    void Send_UART(char *data)
    {
    char c;

    while(c = *data++) // c ist data[0]. Danach wird data um eins erhoeht
    // und zeigt auf den naechsten Buchstaben
    // wenn c == “, also 0, hoert die Schleife auf.

    // C Strings hoeren DESWEGEN mit einem 0 auf, damit man Code so
    // schreiben kann. :-)

    {
    while (!(USARTC0.STATUS & USART_DREIF_bm));
    USARTC0.DATA = c;
    }

    while (!( USARTC0.STATUS & USART_DREIF_bm));
    USARTC0.DATA = 0x0A;
    while (!( USARTC0.STATUS & USART_DREIF_bm));
    USARTC0.DATA = 0x0D;
    }

    • Arrrgh! Meine backslash-zeros und Formatierung wurden geloescht! :-)

      Es waren zwei im Paragraphen ueber NULL-terminerte Strings. :
      ‚Hallo WeltNULL‘
      nach dem NULL zu durchsuchen

      Und eins in der dritten Komentarzeile:
      // Wenn c == NULL, also 0, hoert die Schleife auf.

    • Hey,

      danke für deine Anmerkung.
      Klar es gibt effizientere Wege und der Punkt Effizienz ist auch wichtig (gerade bei größeren Programmen).
      Bei diesem Beispiel habe ich einfach nicht an die strlen-Funktion gedacht ;)
      Aber das Buch was du da empfiehlst ist ein sehr gutes Buch…hab da mal reinschauen dürfen und kann nicht meckern :)

      Gruß
      Daniel

  6. Hey super tutoria, super Beschreibungen, super Codebeispiele!
    Hast du auch ein Codebeispeil mit dem man Zeichen oder ein Wort über ein Terminal empfangen kann?

    • Hey,

      Danke für das Lob :)
      Nein habe ich noch nicht geschrieben und ausprobiert, da ich im Moment keine Hardware besitze auf der ich das testen kann.

      Gruß
      Daniel

  7. „Soll er aber über RS232 oder USB mit dem Computer verbunden werden sind andere Schaltungen zu benutzen (hierbei hilft Google oder falls ihr gar nicht weiter wisst, könnt ihr mir auch eine E-Mail schreiben).“

    Hallo Kampi,

    super Einführung!!
    kannst du mir sagen was ich genau einstellen muss wenn ich eine RS232 Verbindung benutze ?:)

    Beste Grüße!

      • Danke für deine schnelle Antwort.
        Ja sowas habe ich bereits. @MAX232

        Die Frage war eher auf den Code bezogen bezüglich der RS232 Verbindung.

        Kannst du mir vllt. noch sagen ob man den oszi noch extra einstellen muss?

        Der Code hat leider nicht bei mir funktioniert aber mein Verständnis dafür schon weitergebracht.

        Grüße Lukas

        • Hallo Lukas,

          extra einstellen musst du dafür nichts.
          Den Pegelwandler musst du einfach nur entsprechend verdrahten und mit dem PC verbinden.
          Sicher das die Probleme mit dem Programm vom Code her kommen und nicht wegen einer falschen Verdrahtung (sehr beliebter Fehler :) ).

          Gruß
          Daniel

  8. Hallo Daniel,

    danke, dass du es angeboten hast, fragen zu stellen.
    Ich verwende auch das xplained Board und habe verstanden und ausprobiert, wie man damit Zeichen Senden kann. ich schaff es leider nicht, damit auch sachen zu empfangen (z. B. über J1) und dann auszuwerten (blinken)
    kannst du mir vielleicht weiterhelfen? (wenn das nicht zu Zeitaufwendig ist)

    Gruß
    :-)

    • Hallo Dustin,

      ich habe leider keinen fertigen Code zum Empfangen über UART und kann dir deswegen auch nur begrenzt helfen (hab da im Moment auch nicht soviel Zeit mich dahinter zu klemmen).
      Im Grunde musst du nur den USART Recieve Interrupt aktivieren und dann in der ISR des Interrupts das Zeichen aus dem Datenbuffer einlesen und zu einem String zusammen fügen.
      Schau mal hier:

      http://kampis-elektroecke.de/wp-content/uploads/2012/12/UART_Empfangen.zip

      Hier habe ich sowas ähnliches für das Raspberry Pi aber ohne ISR geschrieben.
      Im Grunde kannst du das Mainprogramm in deine ISR übernehmen. Es empfängt bis zu 255 Zeichen bzw. bis zu dem Zeichen 0x0D. Sobald eine der beiden Bedingungen erfüllt wurden, wird der Text in eine Textdatei geschrieben (diesen Teil lässt du weg, aber du könntest den Text dann z.B. in einen anderen String kopieren).
      Du musst also nur die Funktionen „WriteFile()“ und „UART_Init()“ weglassen. Den Rest solltest du eigentlich mit ein paar Anpassungen auf den Problem übertragen können.
      Den Rest, sprich den Interrupt aktivieren, musst du selber raus finden ;) (gibt aber genug im Internet dazu :)

      Viel Erfolg!
      Gruß
      Daniel

      • Hallo,

        erstmal Danke für die Website. Das Xmega Tutorial hat mir schon ne Menge an Arbeit erspart.

        Da hier schon öfter nach einer Empfangsroutine gefragt wurde, will ich mal meine zur Verfügung stellen. Bei mir funktioniert sie wunderbar.
        Hab ich nur schnell zusammengebastelt, sind bestimmt noch einige Verbesserungen möglich. Soll auch nur als Anregung dienen.

        https://dl.dropboxusercontent.com/u/70583964/usart-kampi.c

        Lg Andreas

        • Hallo Andreas,

          vielen Dank für deine Mühe!
          Sowas weiß ich wirklich zu schätzen. Ich habe den Code gedownloadet und veröffentliche ihn direkt bei mir (die Dropbox Links laufen irgendwann aus, bzw. funktionieren nicht mehr).
          Solange es funktioniert reicht es doch :)
          Verbessern kann man dann immer noch!

          Gruß
          Daniel

  9. Servus erstmal,
    super Seite die mich viel weiter gebracht hat, allerdings bekomme ich es grade nicht hin den inhalt einer speicherzelle (egal ob char oder sonst etwas) zu senden. Gibt es dafür eine andere Funktion als die Send_UART da diese ja „nur“ einen String sendet?!

    Liebe Grüße,
    Klaus

    • Hey,

      C bietet bereits eine Option an, einen Zahlenwert in einen String zu konvertieren:

      http://www.cplusplus.com/reference/cstdlib/itoa/

      Eine Ausgabe machst du (am PC und am Mikrocontroller) immer über Strings, daher sendet das Programm nur Strings. Wenn du also Registerwerte senden willst, musst du das Register lesen, den Wert in einen String umwandeln und dann senden.
      Empfangen geht ähnlich….String empfangen, mit der Funktion atoi in eine Zahl umwandeln, Zahl weiter nutzen.
      Hoffe das hilft dir weiter :)

      Gruß
      Daniel

  10. Hallo Kampi,
    oben bei der Berechnung für das Baudratenregister (BSEL) fehlt noch die „minus 1“ am Ende.

    Super Seite, hab mir schon viele Ideen geholt

    LG Andreas

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.

Time limit is exhausted. Please reload CAPTCHA.