Forum: Mikrocontroller und Digitale Elektronik Baudratenumschaltung beim UART des ATMega16


von Georg S. (gspeth)


Lesenswert?

Hallo,

Ich schreibe grad an meiner Studienarbeit, wo ich auf der Hardwarebasis 
(ATMega16) meines Vorgängers einen LIN Slaveknoten programmieren soll. 
Das Empfangen der Frames klappt einwandfrei.
Mein Problem liegt beim Versenden eines Frames. Laut Spezifikation von 
LIN muss jeder Frame mit einem 13 Bitzeit-langen Syncbreak und 
anschliessend einem Syncfeld (0x55) beginnen. Da der ATMega16 selber 
kein Break-Syncfeld erzeugen kann, hab ich mich beim implementieren an 
einen Tipp aus dem Buch LIN-Bus von Andreas Grzemba gehalten:

"Ein Standard UART kann das Synchronisationsbreak nicht direkt erzeugen. 
Man kann sich aber mit einem Trick behelfen. Will man beispielsweise für 
19,2 KBits/s das Synchronisationsbreak erzeugen, setzt man die Baudrate 
auf ca. 13 KBit/s herab und sendet ein 0x00 Datenbyte. Das Senden der 8 
Bits zuzüglich des Startbits dauert etwas länger als die notwendigen 677 
Mikrosekungen des Synchronisationsbreaks. Anschließend wird die Baudrate 
wieder auf 19,2 KBit/s gesetzt und das Synchronisationsfeld gesendet."

Da die Kommunikation bei mir bei 9600 Bit/s läuft, versuche ich die 
Baudrate auf 6500 Bit/s herunterzusetzen. Allerdings werden die 
verschickten Frames nicht als LIN Frames erkannt und laut Oszi ist auch 
das Synchronisationsbreak zu kurz. Wenn ich zum Testen die Baudrate noch 
weiter herabsetze, verändert sich die Dauer des Synchronisationsbreak 
nicht. Daher nehme ich an, dass die Umschaltung der Baudrate nicht 
funktioniert.

Code zum Initialisieren des UART:
/**
 * Quartfrequenz des Lin - Knoten
 */
#define F_CPU 8000000    // Oszillator-Frequenz in Hz (8MHz)

/**
 * Baudrate für LIN-Kommunikation in bps festlegen
 */
#define UART_BAUD_RATE_NORMAL 9600

/**
 * Baudrate für LIN-Kommunikation in bps festlegen
 * fuer das Sync - Break Feld
 */
#define UART_BAUD_RATE_BREAKSYNC 6500

/**
 * Hilfsmakro zur UBRR-Berechnung fuer den ATMega16
 * ("Formel" laut Datenblatt)
 */
#define UART_UBRR_CALC(BAUD_,FREQ_) ((FREQ_)/((BAUD_)*16L)-1)


/*
 * setzten der Variablen mit den Werten
 * fuer die Baudrateneinstellung des
 * UARTs des ATMega16
 */
l_UBRRH_Normal = (uint8_t) (UART_UBRR_CALC (UART_BAUD_RATE_NORMAL, 
F_CPU) >> 8);
l_UBRRL_Normal = (uint8_t) UART_UBRR_CALC (UART_BAUD_RATE_NORMAL, 
F_CPU);

l_UBRRH_SyncBreak = (uint8_t) (UART_UBRR_CALC (UART_BAUD_RATE_BREAKSYNC, 
F_CPU) >> 8);
l_UBRRL_SyncBreak = (uint8_t) UART_UBRR_CALC (UART_BAUD_RATE_BREAKSYNC, 
F_CPU);

setBaudNormal ();

/*
 * Frameformat setzen
 */
UCSRB = (1 << TXEN);  // Sender einschalten
UCSRB &= ~(1 << RXCIE);  // Empfaengerinterrupt ausschalten
UCSRB &= ~(1 << RXEN);  // Empfaenger ausschalten


Code der Baudratenumschaltfunktionen:
void setBaudNormal (void)
{
    unsigned char leeren = UDR;

    UCSRC &= ~(1 << URSEL);
    UBRRH = l_UBRRH_Normal; // auf Baudrate fuer Normal stellen
    UBRRL = l_UBRRL_Normal; // auf Baudrate fuer Normal stellen

    UCSRC |= (1 << URSEL) | (3 << UCSZ0); // Asynchron 8 Bit mit 1 
Stoppbit

    leeren = UDR;
}

void setBaudSyncBreak (void)
{
    unsigned char leeren = UDR;

    UCSRC &= ~(1 << URSEL);
    UBRRH = l_UBRRH_SyncBreak;  // auf Baudrate fuer SyncBreak stellen
    UBRRL = l_UBRRL_SyncBreak;  // auf Baudrate fuer SyncBreak stellen

    UCSRC |= (1 << URSEL) | (3 << UCSZ0); // Asynchron 8 Bit mit 1 
Stoppbit

    leeren = UDR;
}

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.