Forum: Mikrocontroller und Digitale Elektronik Probleme mit USART bei ATmega168 (ATA6613-EK)


von Der Basti (Gast)


Angehängte Dateien:

Lesenswert?

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

von Jack (Gast)


Lesenswert?

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.

von Karl H. (kbuchegg)


Lesenswert?

>   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.

von Krapao (Gast)


Lesenswert?

>   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!

von Der Basti (Gast)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

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?

von Der Basti (Gast)


Lesenswert?

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?

von Der Basti (Gast)


Lesenswert?

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...

von Karl H. (kbuchegg)


Lesenswert?

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!

von Der Basti (Gast)


Lesenswert?

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

von Der Basti (Gast)


Angehängte Dateien:

Lesenswert?

Mahlzeit Zusammen,

anbei der Code wie es dann funktioniert!
Danke nochmal für eure Hilfe.

Gruß der Basti

von Karl H. (kbuchegg)


Lesenswert?

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!

von Der Basti (Gast)


Lesenswert?

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
Noch kein Account? Hier anmelden.