Hallo Zusammen! Ich bin langsam echt am verzweifeln. Ich Versuche eine LIN Kommunikation zu realisieren. Bei dem Evalboard was ich habe ist ein Chip mit einem ATmega168 und zusätzlichem LIN-Transceiver (ATA6624) drauf. Nun will ich per USART Zeichen senden (0x00,0x55 und 0x28 im 8N1-Frame). USART wird initialisiert, 0x00 soll mit halber Baudrate gesendet werden und der Rest dann mit "normaler" Baudrate. Entsprechend dachte ich, hätte ich mein Programm geschrieben. Das Problem was ich jetzt habe ist, dass er weder die Geschwindigkeit erhöht noch verringern. Außerdem wollte ich, dass nach 0x28 erstmal nichts gesendet wird sondern nur gewartet wird. Stattdessen sendet er die Zeichenreihenfolge wieder von vorne. Wäre schön wenn sich jemand das Prog mal anschaut! Danke und Gruß der Basti
Sorry, kann nicht konkret helfen. Aber einen Hinweis zu deinem Programmierstil:
1 | i = PINB; // Zuweisung der Variable i zum Zustand des Ports B |
Solche Kommentare sind überflüssig weil der Befehl so offensichtlich ist. Sie machen das Programm nur umständlicher zu lesen, was genau das Gegenteil vom eigentlichen Zweck ist. Wenn schon könntest du schreiben, was die Funktion von Port B ist (LEDs angeschlossen wenn als Ausgang benutzt, UART oder was auch immer). Ausserdem ist der Kommentar nicht einmal korrekt, weil du den Wert von PINB i zuweist, nicht umgekehrt.
1 | if (i != 0) // Abfrage ob der Inhalt von i ungleich 0 ist |
2 | {
|
3 | PORTB |= (1<<PB2); |
4 | PORTB &= ~(1<<PB1); |
5 | _delay_ms(1000); |
6 | PORTB |= (1<<PB1); |
7 | PORTB &= ~(1<<PB2); |
8 | _delay_ms(1000); |
9 | }
|
Bei solchen Blöcken ist allerdings ein kurzer Hinweis hilfreiche was der Block tut. Dein Kommentar beschreibt wieder nur das offensichtliche, was eh jedem Leser klar ist.
> UCSR0B |= (1<<TXEN0)|(1<<RXEN0)|(1<<TXCIE0);
Das Zulassen eines Interrupts ohne eine entsprechende Interruptroutine,
wird mit sofortigem Prozessorreset bei Auftreten des Ereignisses
bestraft.
+ alles was Jack gesagt hat
und noch etwas ausgeholt
Da steht
1 | i=PINB; // Zuweisung der Variable i zum Zustand des Ports B |
2 | i= i & 0x01; // Löschen der 7 MSB |
3 | if (i !=0) // Abfrage ob der Inhalt von i ungleich 0 ist |
4 | {
|
Alles, aber auch wirklich alles, was in den Kommentaren steht, steht auch im Quelltext. -> Der Kommentar erläutert und erklärt mir NICHTS, was ich nicht auch im Code sehen würde. Woran ich als Leser aber interessiert bin: Was bedeutet es denn, wenn das Bit 0 am PINB auf 1 ist? Geht dann die Welt unter? Ist ein Schalter betätigt worden? Hat der Feuermelder ausgelöst? Das würde mich interessieren! ABer, leider, leider. Das steht nicht dort. Dort steht nur dass hier eine Abfrage erfolgt ob i ungleich 0 ist. Also die Programmzeile if (i !=0) etwas anders (als deutscher Satz) formuliert.
> UCSR0B |= (1<<TXEN0)|(1<<RXEN0)|(1<<TXCIE0); ^^^^^^^^^^^ Dafür sehe ich keine ISR im Quellcode > UCSR0A&= ~(1<<U2X0); // Baudrate halbieren (9600) > UCSR0A|= (1<<U2X0); // Baudrate normal (19200) Unschöner Kommentar. Die Funktion ist eher: > UCSR0A &= ~(1<<U2X0); // Baudrate normal, d.h. wie Init (9600) > UCSR0A |= (1<<U2X0); // Baudrate verdoppeln (19200) Einen solchen dynamischer Baudratenwechsel habe ich noch nicht gesehen. Welches Terminalprogramm auf der Gegenseite benutzt du, um den Erfolg zu kontrollieren? > Stattdessen sendet er die Zeichenreihenfolge wieder von vorne. Ich denke dein AVR stürzt regelmäßig ab (rebootet). Das wird an der fehlenden ISR liegen. Du könntest eine RESET-Anzeige-LED zu Beginn von main() einrichten oder eine Statusmeldung auf UART, die dir das anzeigt!
Hallo Zusammen, danke für die Antworten. Also an PB0 hängt ein Taster, an PB1 und PB2 hängen jeweils LEDs. Das umschalten der Baudrate brauche ich, da beim LIN-Bus zunächst ein Syncfield mit nominal 13 Bits "low" gesendet werden muss. Benutzen tue ich kein Terminalprog sondern nur ein Oszilloskop und schaue mir das Bussignal an. Ich dachte mit (1<<TXCIE0) erlaube ich dem USART das schalten vom TXC0 Flag das ich ja abfrage. Gruß der Basti
Der Basti schrieb: > Ich dachte mit (1<<TXCIE0) erlaube ich dem USART das schalten vom TXC0 > Flag das ich ja abfrage. TX Transmit C Complete I Interrupt E Enable 0 an der Usart 0 ALles zusammen: Wenn ein Zeichen von der UART verschickt wurde, wird ein Interrupt ausgelöst. Zunächst wird das Transmit Complete Flag TXC0 gesetzt (das wird immer gesetzt, wenn ein Zeichen rausgegangen ist) und wenn dann mittels sei() die Interrupts auch noch erlaubt sind, wird die zugehörige ISR angesprungen. Die du nicht hast. > das schalten vom TXC0 > Flag das ich ja abfrage. Du meinst das hier? while(TXC0==0) {} das ist sowieso Unsinn. Wie fragt man denn ein Bit in einem Register ab, von dem man den Bitnamen kennt?
Also soviel ist sicher, das er resetet wurde. Wenn ich das TXCIE raus nehme, dann sendet er die Sache entsprechend mit dem delay. Die Baudrate verändert er trotzdem nicht. Muss das anders gemacht werden mit dem Umschalten?
Aus Datenblatt: • Bit 6 – TXCn: USART Transmit Complete This flag bit is set 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 (UDRn). The TXCn Flag bit is automatically cleared when a transmit complete interrupt is executed, or it can be cleared by writing a one to its bit location. The TXCn Flag can generate a Transmit Complete interrupt (see description of the TXCIEn bit). Dachte die Abfrage könnte ich so machen...
Der Basti schrieb: > Dachte die Abfrage könnte ich so machen... Das ist halt die Krux, wenn man die Grundlagen überspringt. Nochmal: Wie frägt man ein Bit in einem Register ab, von dem man den Bitnamen kennt? (Du hast das doch schon gemacht: Du hast abgefragt ob Bit PB0 (das war der Bitname) im Register PINB (das ist das Register) gesetzt ist oder nicht) Du hast das ein wenig umständlich gemacht i=PINB; i= i & 0x01; if (i !=0) { aber prinizpiell war es richtig. Die kürzere Schreibweise wäre gewesen if( PINB & ( 1 << PB0 ) ) und das wendest du jetzt auf das Bit namens TXC0 im Register UCSR0A an! (und dann überlegst du dir, wie du das Bit wieder auf 0 zurück kriegst. Aufpassen: derartige Bits werden durch das Schreiben einer 1 gelöscht!
Okay das werde ich dann mal tun. Mein Laptopacku ist dann auch fast alle und das Ladegerät ist zuhause, kann dann erst heute Abend bzw. morgen von Erfolgserlebnissen berichten...;-) Danke für eure Mühe! Gruß der Basti
Mahlzeit Zusammen, anbei der Code wie es dann funktioniert! Danke nochmal für eure Hilfe. Gruß der Basti
Der Basti schrieb: > Mahlzeit Zusammen, > > anbei der Code wie es dann funktioniert! Glaub ich nicht UCSR0B |= (1<<TXEN0)|(1<<RXEN0)|(1<<TXCIE0) Du hast immer noch den Interrupt enabled ohne eine ISR dafür zu haben. -> ständige Prozessor-resets. Man gibt keinen Interrupt frei, für den man keinen Handler hat!
Erwischt! Natürlich heißt es nur: UCSR0B |= (1<<TXEN0)|(1<<RXEN0); :-)
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.