Forum: Mikrocontroller und Digitale Elektronik Atmega128 UART LIN-Transceiver


von Roman (Gast)


Lesenswert?

Hallo Leute,

ich möchte mit dem Uart eines Atmega128 einen LIN-Transceiver ansteuern. 
Der Wiederum einen anderen Controller steuert. Ich habe mich in den 
letzten Tagen einwenig in das Thema eingelesen, bin aber noch nicht 
wirklich weiter gekommen. Und hoffe, dass Ihr mir hier weiter helfen 
könnt.

Muss ich über die UART Schnittstelle Break- und Syncfield senden und 
anschließen meine ID? Bestimmt die Baudrate und Teaktfrequenz die 
Periode eines Bits? Hat jemand einen Quellcode für die Anwendung?

Ich habe mir aus dem Internet folgendes Programm geladen und etwas 
verändert:


#include <avr/io.h>
#include <string.h> // Für "strcmp"
#include <stdlib.h> // Für "itoa"


#define  TAKT      16000000
#define UART_BAUDRATE  9600



// Berechnung der Konfigurationsparameter
#define UART_SETTING  ((TAKT/16L/UART_BAUDRATE)-1)


void setup_uart()
{
  /* Baudrate einstellen */
  UBRR1H = (char) (UART_SETTING >> 8);
  UBRR1L = (char) (UART_SETTING);

  /* Empfänger und Sender einschalten */
  UCSR1B = (1<<RXEN1) | (1<<TXEN1);

  /* Asynchron, 8N1 */
  UCSR1C =  (3<<UCSZ10);
}//(1<<UMSEL) |

void uart_send( uint8_t zeichen )
{
  while (!UCSR0A&(1<<UDRE0));  // Warte, bis Puffer frei ist
  UDR0 = zeichen;               // jetzt das Byte ins UDR schreiben
}


void uart_putstring(char *str)
{
  unsigned char i;

  for (i=0;i<255;i++) /* Maximal 255 Zeichen ausgeben ... */
  {
    if (str[i] != 0)
      uart_send(str[i]);
    else
      break; // Ende des Strings erreicht
  }
}

char uart_getchar()
{
  // Ist schon ein Zeichen im Buffer?
  if (bit_is_set(UCSR1A, RXC))
    return UDR1;
  else
    return -1;
}

void uart_readline(char *str)
{
  char c;
  unsigned char index;

  index = 0;

  while (1)
  {
    c = uart_getchar();
    if (c != -1)
    {
      if (c == 13) /* ASCII: NewLine */
      {
        /* Ende der Zeile erreicht,
           also String abschließen */
        str[index] = 0;

        /* Funktion beenden */
        return;
      }
      else /* Normales Zeichen, anhängen an die Zeichenkette */
      {
        str[index] = c;
        index++;
      }
    }
  }
}

int main(void)
{

  setup_uart();
  for(;;)

    uart_send(3);

  return 0;
}

Ich flashe dieses Programm mit AVR Studio auf den Atmega128 doch leider 
tut sich am TX Pin gar nichts. Es wäre wirklich sehr nett, wenn ihr mir 
vielleicht weiter helfen könntet.

Vielen Dank!
Gruß Roman

von Frank L. (florenzen)


Lesenswert?

Roman schrieb:

[...]
>   UBRR1H = (char) (UART_SETTING >> 8);
>   UBRR1L = (char) (UART_SETTING);
>   UCSR1B = (1<<RXEN1) | (1<<TXEN1);
>   UCSR1C =  (3<<UCSZ10);

[...]

>   while (!UCSR0A&(1<<UDRE0));  // Warte, bis Puffer frei ist
>   UDR0 = zeichen;               // jetzt das Byte ins UDR schreiben

[...]

>   // Ist schon ein Zeichen im Buffer?
>   if (bit_is_set(UCSR1A, RXC))
>     return UDR1;

[...]

> Vielen Dank!
> Gruß Roman

Entscheide dich für einen der zwei USART. Wenn du USART1 benutzen willst 
beachte den "ATmega103 compatiblity mode".

gruß
f

von Roman (Gast)


Lesenswert?

Hallo Frank,

Danke für den Tipp! Muss wohl beim testen was vergessen haben. Habs in 
folgenden code angepasst:

#include <avr/io.h>
#include <string.h> // Für "strcmp"
#include <stdlib.h> // Für "itoa"


#define  TAKT      16000000UL
#define UART_BAUDRATE  9600



// Berechnung der Konfigurationsparameter
#define UART_SETTING  ((TAKT/16L/UART_BAUDRATE)-1)


void setup_uart()
{
  /* Baudrate einstellen */
  UBRR1H = (char) (UART_SETTING >> 8);
  UBRR1L = (char) (UART_SETTING);

  /* Empfänger und Sender einschalten */
  UCSR1B = (1<<RXEN1) | (1<<TXEN1);

  /* Asynchron, 8N1 */
  UCSR1C =(1<<UMSEL) | (3<<UCSZ10);
}

void uart_send( uint8_t zeichen )
{
  while (!UCSR1A&(1<<UDRE1));  // Warte, bis Puffer frei ist
  UDR1 = zeichen;               // jetzt das Byte ins UDR schreiben
}


void uart_putstring(char *str)
{
  unsigned char i;

  for (i=0;i<255;i++) /* Maximal 255 Zeichen ausgeben ... */
  {
    if (str[i] != 0)
      uart_send(str[i]);
    else
      break; // Ende des Strings erreicht
  }
}

char uart_getchar()
{
  // Ist schon ein Zeichen im Buffer?
  if (bit_is_set(UCSR1A, RXC))
    return UDR1;
  else
    return -1;
}

void uart_readline(char *str)
{
  char c;
  unsigned char index;

  index = 0;

  while (1)
  {
    c = uart_getchar();
    if (c != -1)
    {
      if (c == 13) /* ASCII: NewLine */
      {
        /* Ende der Zeile erreicht,
           also String abschließen */
        str[index] = 0;

        /* Funktion beenden */
        return;
      }
      else /* Normales Zeichen, anhängen an die Zeichenkette */
      {
        str[index] = c;
        index++;
      }
    }
  }
}

int main(void)
{

  setup_uart();
  for(;;)

    uart_send(3);

  return 0;
}


Die Änderung hat leider nichts gebracht... Immer noch kein Signal am TXD 
und die Compatibility Fuse ist auch nicht gesetzt.

Hast Du sonst noch eine Idee?

Danke!
Gruß Roman

von holger (Gast)


Lesenswert?

1
  /* Asynchron, 8N1 */
2
  UCSR1C =(1<<UMSEL) | (3<<UCSZ10);

Kommentar und Befehlszeile passen nicht zueinander.
Immer nur eine Sache ändern und ausprobieren.
Sonst schießt man sich selber ins Knie ;)

von Frederik K. (n0ll4k)


Lesenswert?

Willst du den Atmega als Master oder als Slave nutzen, oder einfach nur 
den physischen LIN Bus mit eigenem Protkoll nutzen.

Von Atmel gibts zur LIN Implementation ne recht gute App Note AVR322. 
Das ist zwar nur LIN 1.3 aber die zustäzlichen Funktionen für 2.0 bzw 
2.1 kann man recht einfach einbauen.

von Roman (Gast)


Lesenswert?

Hallo,

@ Holger: Danke für den Tipp! Hat geholfen, seh jetzt die Daten am 
TX-Pin

@ Frederik: Habe mir grad die App Note geladen. Werde sie dann mal 
durchlesen.

Steht da auch drin wie ich das Break- und Syncfield erzeuge?
Habe gerade versucht dan Syncfield mit generieren, hat aber leider nicht 
geklappt? Das besteht doch einfach nur aus 5x high-low oder?

Danke!
Gruß Roman

von Frederik K. (n0ll4k)


Lesenswert?

Joa das dürfte da drin stehen. Ich selbst hab nur einen LIN Slave 
programmiert, da braucht man das ja nicht erzeugen, da Break Feld, Sync 
Feld und ID ja immer vom Master versendet werden. Aber in der AppNote 
ist ja auch ein Master Beispiel vorhanden meine ich. Wenn nicht gibts 
auch noch eine seperate LIN AppNote, ich glaub 308 wars.

von Elux (Gast)


Lesenswert?

@ Roman
Da ich mich z.Z. auch mit diesem Thema befasse:
Wenn Du den USART benutzen möchtest, so wirst Du zur Erzeugung des Break 
den USART (Baudrate) umkonfigurieren müssen (es sind sicher auch noch 
andere Lösungen möglich...), um auf die 13 Bit (ohne Stoppbit) zu 
kommen, danach stellst Du die Baudrate zurück auf Deinen gewünschten 
Wert (19200?) und sendest eine 0x55, gefolgt von der ID u.s.w.
Du solltest den Baudratenwechsel also entsprechend vorbereiten.

Sie mal bei Vector nach, da haben die das sehr anschaulich erklärt 
(http://www.vector-elearning.com).
Bei meinem Projekt habe ich mich für einen Soft-UART entschieden, da mir 
die Erzeugung des Break da wesenlich einfacher erscheint und letztlich 
der zu verwendende AVR ein Tiny44 wurde...

von Roman (Gast)


Lesenswert?

Hallo Leute, sorry dass ich mich solange nicht mehr gemeldet habe...

@Elux: Danke für Deinen Tipp. Habe mir die Sachen bei Vector 
durchgelesen.
Habe die Programmierung aber noch nicht hinbekommen.
Wenn ich versuche die Baudrate während des Programms zu ändern, dann 
nimmt der Mikrocontroller diese Änderung nicht an.
Hat jemand schonmal die Baudrate oder den Takt im Programm geändert und 
kann mir dabei behilflich sein? Oder gibt es noch andere Möglichkeiten 
das Break-field zu senden?
Vielen Dank!

mfg

Roman

von Max H. (maxheadroom)


Lesenswert?

Hallo Roman,

hast du schon eine Lösung für dein Problem?
Wie hast du die Baudrateänderung im Programm vorgenommen?
Ich denke die Lösung liegt im Bit TXCn im Register UCSRnA

mfg

max

von Reiner O. (elux)


Lesenswert?

Roman schrieb:
> Oder gibt es noch andere Möglichkeiten
> das Break-field zu senden?

Wie heißt es doch so schön:
>The Transmitter will override normal port operation for the TxDn pin when 
>enabled.

Naja, Du kannst ja in UCSRB TXEN ausschalten und den TX-PIN als GPIO für 
13 Taktzeiten auf O legen, dann TXEN wieder an und auf gehts...

Andererseits sollte der Wechsel der Geschwindigkeit kein Problem 
darstellen, wenn entsprechend vorbereitet.

Ich hatte mir seinerzeit auch verschiedene Alternativen überlegt, die 
Entscheidung fiel dann letztlich auf den Tiny44 und der hat gar keinen 
UART...

Gruss aus Berlin

Elux

von Max H. (maxheadroom)


Lesenswert?

The Transmit Complete (TXC) flag bit is set one when the entire frame in 
the Transmit Shift Register has been shifted out and there are no new 
data currently present in the transmit buffer. The TXC flag bit is 
automatically cleared when a transmit complete inter- rupt is executed, 
or it can be cleared by writing a one to its bit location.

Ich würde in der uart_send Funktion das TXCn setzen.
Damit wird das bit gelöscht.

void uart_send( uint8_t zeichen )
{
  UCSR1A |= (1 << TXC1);

  while (!UCSR1A&(1<<UDRE1));  // Warte, bis Puffer frei ist
  UDR1 = zeichen;               // jetzt das Byte ins UDR schreiben
}

Das Synch-Break erzeugst du dann folgendermaßen:

- Setze Baud auf 9600*9/13
- uart_send(0x00);
- Warte bis TXC1 ist gesetzt
- Setze Baud wieder auf 9600
- uart_send(0x55);              // Sende Synchbyte
- Sende ID-Byte
- ....

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.