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
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
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
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 ;)
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.
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
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.
@ 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...
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
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
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
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.