Themen:

AVR, avr-gcc, CAN, CPLD, Elektronik, Mikrocontroller, MSP430, PIC, Roboter, Schaltungen, Sensoren, Software, Testboards

Ansteuerung des UART mit avr-gcc

Tags: AVR, Software, avr-gcc
Stand: 27. September 2006, 00:49
10 Kommentar(e)

Es gibt eine sehr schöne und unproblematische Bibliothek für den UART von Peter Fleury (http://homepage.hispeed.ch/peterfleury/avr-software.html > UART Library), wenn man den UART einfach nur benutzen möchte würde ich empfehlen diese zu verwenden.

UART

C:
#include <avr/io.h>
#include <inttypes.h>

// Sollte schon im Makefile definiert sein.
// In dem Fall hier einfach löschen.
#define F_CPU       7372800UL

#define BAUD        19200UL
#define UBRR_BAUD   ((F_CPU/(16UL*BAUD))-1)

// USART initialisieren
void
uart_init(void)
{
    // Baudrate einstellen (Normaler Modus)
    UBRRH = (uint8_t) (UBRR_BAUD>>8);
    UBRRL = (uint8_t) (UBRR_BAUD & 0x0ff);
   
    // oder einfacher:
    // UBRR = UBRR_BAUD;

    // Aktivieren von receiver und transmitter
    UCSRB = (1<<RXEN)|(1<<TXEN);

    // Einstellen des Datenformats: 8 Datenbits, 1 Stoppbit
    UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);
}

int
main(void)
{
    uint8_t buffer;

    // USART initialisieren
    uart_init();

    while (1)
    {
        // Warten bis Daten empfangen wurden
        while ( !(UCSRA & (1<<RXC)) )
            ;

        // Empfangsregister auslesen
        buffer = UDR;

        // Warten bis der Sendepuffer frei ist
        while ( !( UCSRA & (1<<UDRE)) )
            ;

        // Daten in den Puffer schreiben und damit senden
        UDR = buffer;
    }
}

Verwenden des UART mit Interrupts

C:
#include <avr/io.h>
#include <avr/interrupt.h>

// Sollte schon im Makefile definiert sein.
// In dem Fall hier einfach löschen.
#define F_CPU       7372800UL

#define BAUD        19200UL
#define UBRR_BAUD   ((F_CPU/(16UL*BAUD))-1)

void
uart_init(void)
{
    // Baudrate einstellen (Normaler Modus)
    UBRRH = (unsigned char) (UBRR_BAUD>>8);
    UBRRL = (unsigned char) (UBRR_BAUD & 0x0ff);
   
    // oder einfacher:
    // UBRR = UBRR_BAUD;

    // Aktivieren des Empfängers, des Senders und des "Daten empfangen"-Interrupts
    UCSRB = (1<<RXCIE)|(1<<RXEN)|(1<<TXEN);

    // Einstellen des Datenformats: 8 Datenbits, 1 Stoppbit
    UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);
}


int
main(void)
{
    // USART initialisieren
    uart_init();

    sei();

    // Nichts tun. Die Interrupts erledigten den Rest
    while (1)
        ;
}

// Interrupt wird ausgelöst sobald neue Daten im USART-Empfangspuffer liegen
ISR(USART_RXC_vect)
{
    unsigned char buffer;

    // Daten aus dem Puffer lesen ...
    buffer = UDR;

    // ... warten bis der Sendepuffer leer ist ...
    while ( !( UCSRA & (1<<UDRE)) )
        ;
    // ... und gleich wieder zurück schicken
    UDR = buffer;
}

Strings aus dem Flashspeicher ausgeben

C:
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>

// Sollte schon im Makefile definiert sein.
// In dem Fall hier einfach löschen.
#define F_CPU       7372800UL

#define BAUD        19200UL
#define UBRR_BAUD   ((F_CPU/(16UL*BAUD))-1)

// Für die bessere Lesbarkeit
#define TRUE    1
#define FALSE   0


volatile unsigned char daten_gesendet = TRUE;
const prog_char* volatile p_string;

// Zeichenkette im Flashspeicher
prog_char daten[] = "Hello World!\n";


// USART initialisieren
void
uart_init(void)
{
    // Baudrate einstellen ( Normaler Modus )
    UBRRH = (unsigned char) (UBRR_BAUD>>8);
    UBRRL = (unsigned char) (UBRR_BAUD & 0x0ff);
   
    // oder einfacher:
    // UBRR = UBRR_BAUD;
   
    // Aktivieren des Empfängers, des Senders und des "Daten empfangen"-Interrupts
    UCSRB = (1<<RXEN)|(1<<TXEN);

    // Einstellen des Datenformats: 8 Datenbits, 1 Stoppbit
    UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);
}

int
main(void)
{
    // USART initialisieren
    uart_init();

    sei();

    while (1)
    {
        if (daten_gesendet)
        {
            // Flag zurücksetzen
            daten_gesendet = FALSE;

            // Pointer zeigt auf die Daten im Flashspeicher
            p_string = daten;

            /* Interrupt aktivieren, damit wird sofort zur
               Interruptroutine gesprungen und das erste Zeichen gesendet. */

            UCSRB |= (1<<UDRIE);
        }
    }
}

// Interrupt wird ausgelöst sobald der Sendepuffer leer ist
ISR(USART_UDRE_vect)
{
    char buffer = pgm_read_byte(p_string++);

    /* Wenn nicht das Ende der Zeichenkette erreicht wurde,
       dann weiteres Zeichen senden */

    if ( buffer != '\0' ) {
        UDR = buffer;

    } else {
        // Flag setzen, das der String gesendet wurde
        daten_gesendet = TRUE;

        // Interrupt deaktivieren
        UCSRB &= ~(1<<UDRIE);
    }
}

Zum Anfang

Kommentare

# Jürgen Focke meinte am 12. Januar 2007, 23:47 dazu:

Hallo

ich arbeite mich derzeit in die Programmierung des Atmel Mega8 Controllers ein. Von früheren Projekten her kenne ich den Aufwand, den es kostet, in die elementaren Initialisierungen der Peripherie einzusteigen. Daher finde ich die gut dokumentierten Beispiele sehr hilfreich um eine Sammlung von Modulen zu bekommen, die ich in eigene Programme einbauen kann

Danke

Jürgen

# Thomas Schrein meinte am 17. August 2007, 11:32 dazu:

Finde ich prima, Deine Beispiele: arbeite mich, nach langer Pause (Jahre) wieder in das Thema Mikros ein und werde mit Deinen Beispielen als erstes üben. Danke und Gruß Thomas

# Werner Quednau meinte am 24. November 2008, 01:11 dazu:

Diese Seite ist sehr gut !
Kurzer Aufbau, nur das Wesentliche wird vermittelt.
Die Beispiele funktionieren !
Sie zeigen ein hohes Niveau des Authors.
Die Seite hat mir eine weitere Nacht des Ausprobierens erspart.
Vielen Dank
Werner Quednau

# jpcolli meinte am 28. Januar 2009, 17:17 dazu:

Echt klasse.
Ich habe bei 0 angefangen und hab das hier gleich alles verstanden.
Vielen Dank

# ThoWaBu meinte am 3. August 2010, 22:18 dazu:

Ein bisschen Kritik bei :

“Verwenden des UART mit Interrupts”

Also eine Warteschleife in einem Interrupt würde ich jetzt nicht unbedingt online stellen…

# Fabian Greif meinte am 4. August 2010, 00:32 dazu:

Also eine Warteschleife in einem Interrupt würde ich jetzt nicht unbedingt online stellen…

Generell ist das richtig, allerdings kommt die Schleife hier nur im unwahrscheinlichen Fall zum tragen, dass gerade im Hauptprogramm Daten gesendet werden.

In dem Beispiel also gar nicht, man könnte sie also auch weglassen.

# Thomas meinte am 22. November 2010, 11:25 dazu:

Hallo, wollte das Stringbeispiel implementieren, beim compilieren mit AVR Studio nölt der Compiler: bei const prog_char* volatile p_string; meldet er: error: expected’,’,’;’,’=’befor ‘*’ token

wie können die Kollegen, die vorher gepostet haben das Beispiel problemlos compiliert haben?

Was muss ich ändern?

Gruß

Thomas

# Thomas meinte am 23. November 2010, 17:17 dazu:

Hallo, sorry für den Quark, den ich geschrieben habe! Ich hatte verzockt die #include avr/pgmspace einzufügen!! Erst denken, dann posten! Also: auch ich finde die Beispiele oben super. Und sie laufen!!

Vielen Dank

# Stefan meinte am 10. Mai 2011, 15:46 dazu:

Super Beispiele, aber bei den Interrupts sollte man nicht mehr SIGNAL sondern ISR verwenden. Ansonsten sehr gute Seite!

Gruß Stefan

# Fabian Greif meinte am 10. Mai 2011, 16:53 dazu:

Ja, und anstelle von SIG_UART_RECV sollte man UART_RX_vect verwenden. Gleiches bei SIG_UART_DATA. Die Beispiel sind schon mehrere Jahre alt, da gab es die neuen Namen noch nicht ;-)

Ist jetzt aber geändert.

Grüße Fabian

Deine Meinung:

  • Textformatierung ist mit Markdown möglich.
  • HTML wird entfernt.
  • Kommentare werden moderiert und sind daher eventuell nicht sofort sichtbar.
  • Irrelevante Kommentare werden gelöscht.