Forum: Mikrocontroller und Digitale Elektronik Problem => UCSR0C-Register beim Mega162 setzen


von Asterix-007 (Gast)


Lesenswert?

Hallo Männers,

ich habe hier entweder einen bockigen MEGA162 vor mir, oder einen Bug 
ausgegraben.

Fakt ist, das die Datenübertragung mit USART0 nicht oder nur teilweise 
geht. Die Receive-Interrupts werden ordnungsgemäß ausgelöst und auch ist 
ein Empfang da. Aber leider kommt nur Datenmüll an!

Ich habe jetzt eine Parametrierung vorgenommen und dabei ist mir 
aufgefallen, dass der Befehl:

  UCSR0C |= ((1<<URSEL0)|(1<<UCSZ01)|(1<<UCSZ00));

zwar durch den Compiler läft, aber keinen Effekt (gesetzte Bits) im 
Debugger zeigt!
auch der Befehl aus dem Tutorial =>

        UCSRC |= (1<<URSEL)|(3<<UCSZ0);     // Asynchron 8N1

wird verweigert (Compilerfehler), da UCSZ0 so nicht ansprechbar sein 
soll.

Hat jemand von Euch eine Idee, wie ich dem Kollegen plausibel machen 
kann, dass ich 8Datenbits haben will?

Das gleiche Programm läuft mit einem MEGA128 ohne Probleme!

vielen Dank!

Ulf

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Lass das Register in Ruhe.  8N1 ist die Voreinstellung.  Das C-Register
ist bei einigen AVRs doppelt belegt und lässt sich dann nicht einfach
zurücklesen (weil du stattdessen das UBRRxH liest).

von Oliver (Gast)


Lesenswert?

Schau mal in iom162.h nach, wie die Register und bits dort heissen. Dann 
klappts auch mit dem Compiler.

Allerdings: Warum heissen die Register dort anders, als im Datenblatt?


Oliver

von Asterix-007 (Gast)


Lesenswert?

Hallo,

@Jörg: ok ist klar, aber:

ich muss ja irgendwie die Übertragungsrate einstellen.
Das heißt in meinem Fall bei 16 MHz Takt und 19,2 kbps => einen Teiler 
von 51 in UBRR.

laut Datenblatt geht das bei UBRRxH so =>

/* Set UBRRH to 2 */
UBRRH = 0x02;
...

bei mir dann analog => UBRR0H = 0x00;
wobei hier die 0 für USART0 steht.

Soweit so gut. Der Compiler läuft durch, aber im Debugger bekomme ich 
keine Rückmeldung, ob die Bits geschrieben sind.

Ist das normal?

Wenn ich testweise UBRR0H mit 0x02 fülle, sollte ich doch im Debugger 
(I/O-Viev) etwas sehen, oder?

Noch eine Frage zum UDR-FiFo. Wird jedesmal wenn ich das UDR auslese der 
Inhalt weitergeschoben? Es sollte ja, oder?.

Wird der RXCIE nach jedem empfangenem Byte ausgelöst oder erst wenn 2 
Byte da sind? Muss ich dann das UDR 2x in der ISR auslesen?

Das gleiche Programm läuft im mega128 problemlos!
Bei dem hier habe ich den Eindruck, das jedes 2. Zeichen verschwindet, 
zumindest bekomme ich nur noch sehr hohe ASCII-Werte, obwohl ich zum 
großen Teil Zahlen (Ziffern 0-9) übertrage!

Naja, langsam glaube ich an den Weihnachtsmann, und das Datenblatt kann 
ich bald rezitieren. Vielleicht sieht nach einem Bier und ein paar 
Stunden Schlaf die Welt wieder freundlicher aus....

Gute Nacht !

Ulf

von Udo (Gast)


Lesenswert?

Hallo,

also, dieser Code läuft bei mir auf dem 162
1
#define F_CPU (deine Quarzfrequenz)  // Beispiel: #define F_CPU 14745460  
2
3
void uart0_init(int BaudRate)
4
{
5
  int ubrr0 = (F_CPU / 16 / BaudRate - 1);          // Baudrate UART0 einstellen  
6
  UBRR0H = (unsigned char)(ubrr0>>8);
7
  UBRR0L = (unsigned char)ubrr0;
8
         
9
  UCSR0C = (1<<URSEL0)|(3<<UCSZ00);              // UART0 Frame Format einstellen: 8data, 1 Stop-bit, keine Parity 
10
  UCSR0B = (1<<RXEN0)|(1<<TXEN0)|(1 << RXCIE0);        // UART0 Receiver und Transmitter einschalten
11
}
12
13
void uart1_init(int BaudRate)
14
{    
15
  int ubrr1 = (F_CPU / 16 / BaudRate - 1);          // Baudrate UART1 einstellen  
16
  UBRR1H = (unsigned char)(ubrr1>>8);
17
  UBRR1L = (unsigned char)ubrr1;
18
19
  UCSR1C = (1<<URSEL1)|(3<<UCSZ10)|(1<<UPM11);        // UART1 Frame Format einstellen: 8data, 1 Stop-Bit, even Parity 
20
  UCSR1B = (1<<RXEN1)|(1<<TXEN1)|(1<<RXCIE1);          // UART1 Receiver und Transmitter einschalten 
21
}
22
23
int main()                            // Hauptprogramm
24
25
{
26
  sei();                            // Interrupts einschalten
27
28
  uart1_init(9600);                      // USART's initialisieren (Baudrate auf 9600 )
29
  uart0_init(9600);
30
31
// tu was
32
33
  cli();
34
  return 0;
35
}

Achtung! die CKDIV8-Fuse ausschalten....

Gruß
Udo

von Asterix-007 (Gast)


Lesenswert?

Hallo,

danke Udo!!

Wobei, der springende Punkt war nicht die Initialisierung sondern:

Achtung! die CKDIV8-Fuse ausschalten....

;-)

Hab ich irgendwie bei der Portierung nicht gesehen!!!

Aber, irgendwie läuft das jetzt nur teilweise!

Die Datenübertragung funktioniert im Grunde, aber der µC liest nur Mist 
ein.  D.h. es werden nicht alle Daten erkannt! Ich habe gerade mit 
meinem Digiview das Datenpaket gecheckt => ist i.O.! Also bis zum 
USART-in im mega162 ist alles paletti.

Ich habe alle Takteinstellungen nochmals gecheckt, noch irgend welche 
verborgenen Teiler gesucht.....

Hat jemand noch eine Idee woran das liegen könnte??

Danke!!

Ulf

von Udo (Gast)


Lesenswert?

poste doch mal deinen Code

von Michael U. (amiga)


Lesenswert?

Hallo,

  UCSR0C |= ((1<<URSEL0)|(1<<UCSZ01)|(1<<UCSZ00));

bei einer OR-Verknüpfung muß erst das Register gelesen werden, dann 
verknüpft und wieder geschrieben.
Es wird aber nicht das Control-Register gelesen, sondern immer das 
Statusregister!

Solche Zugriffe nie verknüft machen, sonder direkt den Wert schreiben.

Also USR0C = ((1<<URSEL0)|(1<<UCSZ01)|(1<<UCSZ00));
Wenn noch mehr zu setzen ist, eben da mit dazu.

Ich weiß doch, warum mir ASM lieber ist, man ist viel näher an Hardware 
und am Datenblatt dran. ;-)

Gruß aus Berlin
Michael

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Asterix-007 wrote:

> Das heißt in meinem Fall bei 16 MHz Takt und 19,2 kbps => einen Teiler
> von 51 in UBRR.

Womit du wiederum UBRRH gar nicht erst anfassen musst, da es auf 0
voreingestellt ist.  UBRRH muss man nur setzen, wenn man auf relativ
schnell getakteten Prozessoren niedrige Baudraten erzielen will.  Die
allerersten AVR-UARTs hatten dieses Register überhaupt noch nicht.

> Soweit so gut. Der Compiler läuft durch, aber im Debugger bekomme ich
> keine Rückmeldung, ob die Bits geschrieben sind.
>
> Ist das normal?

Das kann für so ein Doppelregister schon normal sein.  Ich nehme an,
du redest von JTAG, ja?  Wenn überhaupt, dann kannst du nur eins
der beiden auf dieser Adresse liegenden Register im Debugger lesen.

von Asterix-007 (Gast)


Lesenswert?

Hallo,

PROBLEM GELÖST!!!!

Also es funktioniert jetzt alles!!

Ich glaube das Hauptproblem war der CKDIV8-Fuse! Alles weitere waren 
Änderungen, welche durch Probieren den Code verändert haben. Also saß 
letztendlich der Fehler wieder vorm Computer....


Naja, vielen Dank an alle welche sich den Kopf zerbrochen haben.

@ Jörg: ja, ich habe mit einem MKII gearbeitet! Allerdings scheint mir, 
dass der keines der Doppelregister anzeigt wird. Ich habe spasseshalber 
mal das UBRRH und das UCSR0C mit Werten beschrieben, weder der eine noch 
der andere war im Debugger zu sehen.

die Funktion scheint ja meine Vermutung zu bestätigen, aber noch mal 
meine Frage:

Der UDR auf der Empfangsseite ist ein "2fach-FIFO". Wird jedesmal wenn 
ich das UDR auslese der Inhalt weitergeschoben? Es sollte ja, oder?.

Wird der RXCIE nach jedem empfangenem Byte ausgelöst oder erst wenn 2
Byte da sind? Muss ich dann das UDR 2x in der ISR auslesen?

Nach meiner Beobachtung könnte die 2.Speicherstelle zum Puffern gedacht 
sein, denn die Doppelabfrage funktioniert nicht.

Wie siehst du das?

Nochmal an alle die sich Gedanken gemacht haben:

DANKE!!

Ulf

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Asterix-007 wrote:

> @ Jörg: ja, ich habe mit einem MKII gearbeitet! Allerdings scheint
> mir, dass der keines der Doppelregister anzeigt wird.

Ja, ich habe mir die IO bitmap im Devicedescriptor des JTAG ICE mkII
mal angesehen.  Ist richtig, UCSR0C und UCSR1C sind vom Lesen (und
Schreiben) des JTAG ICE ausgeblendet.  Das ist wohl eine Konsequenz
ihres Daseins als Doppelregister.

> Der UDR auf der Empfangsseite ist ein "2fach-FIFO". Wird jedesmal
> wenn ich das UDR auslese der Inhalt weitergeschoben? Es sollte ja,
> oder?

Ja, da es ja ein FIFO ist.

> Wird der RXCIE nach jedem empfangenem Byte ausgelöst

Ja.

> Muss ich dann das UDR 2x in der ISR auslesen?

Du kannst.  Du kannst es aber auch bleiben lassen, dann wird halt der
Interrupt sofort wieder ausgelöst, das bringt halt nur ein wenig mehr
Overhead.

von Udo (Gast)


Lesenswert?

Hallo,

das Datenblatt ist dein Freund:

"A second Buffer Register has been added. The two buffer registers 
operate as a circular FIFO buffer. Therefore the UDR must only be read 
once for each incoming data!"

und
"The Receiver Shift Register can now act as a third buffer level. This 
is done by allowing the received data to remain in the serial Shift 
Register (see Figure 75) if the Buffer Registers are full, until a new 
start bit is detected. The USART is therefore more resistant to Data 
OverRun (DOR) error conditions."

und
"The Receiver starts data reception when it detects a valid start bit. 
Each bit that follows the start bit will be sampled at the baud rate or 
XCK clock, and shifted into the Receive Shift Register until
the first stop bit of a frame is received. A second stop bit will be 
ignored by the Receiver. When the first stop bit is received, i.e., a 
complete serial frame is present in the Receive Shift Register,
the contents of the Shift Register will be moved into the receive 
buffer. The receive buffer can then be read by reading the UDR I/O 
location.

und
"When the Receive Complete Interrupt Enable (RXCIE) in UCSRB is set, the 
USART Receive Complete Interrupt will be executed as long as the RXC 
Flag is set (provided that global interrupts are enabled). When 
interrupt-driven data reception is used, the receive complete routine 
must read the received data from UDR in order to clear the RXC Flag, 
otherwise a new interrupt will occur once the interrupt routine 
terminates.

Gruß
Udo

von Asterix-007 (Gast)


Lesenswert?

Moin,

danke für die Antworten,

@Jörg:  mit der Doppelabfrage habe ich mir eigentlich erst die Probleme 
geschaffen. D.h. ich habe in der ISR 2x nacheinander das UDR abgefragt. 
Das Problem bestand dann darin, dass ein 2. Byte gelesen wurde, dieses 
aber nicht zum Datenstring passte!!!!!
Das 2. Byte war definitiv nicht von meiner Quelle gesendet!
Woher auch immer dieser 2. Wert kommt ist mir nicht klar!

Ich kann das Datenblatt nur so interpretieren, dass der 2. Speicherplatz 
im FIFO nur als Puffer gedacht ist. In meinem Fall ist es besser auf den 
nächsten Interrupt zu warten, sonst zerfällt mir mein Datenstring!!

@Udo: ja, klar das Datenblatt.... Ich glaube das habe ich die letzten 
Wochen zur Genüge durch. Und manchmal ist halt nicht mehr alles so klar, 
wie es bei oberflächlicher Betrachtung zuerst scheint!

mfg

Ulf

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Asterix-007 wrote:

> D.h. ich habe in der ISR 2x nacheinander das UDR abgefragt.

Das darfst du natürlich nur tun, nachdem du zuvor das entsprechende
Interruptflag abgefragt hast um rauszufinden, ob denn auch wirklich
derzeit noch etwas anliegt an Daten.

von Udo (Gast)


Lesenswert?

Hallo Ulf,

sorry, war nicht so negativ gemeint wie es vielleicht rüber gekommen 
ist.
Ich habe die Erfahrung gemacht, dass je öfter ich das Datenblatt gelesen 
habe, desto mehr kam ich dahinter, was die Verfasser eigentlich gemeint 
haben.

> Das darfst du natürlich nur tun, nachdem du zuvor das entsprechende
> Interruptflag abgefragt hast um rauszufinden, ob denn auch wirklich
> derzeit noch etwas anliegt an Daten.

mmmh, da bin ich anderer Ansicht. Die ISR sollte, wenn das RXC-Flag vom 
UART gesetzt wird, nur die Daten abholen. Je kürzer die ISR, desto 
besser, damit das RXC-Flag schnell wieder gelöscht wird. Das RXC-Flag 
signalisiert der ISR ja, dass wieder neue Daten bereitgestellt sind. Da 
muß nichts abgefragt werden.

Gruß
Udo

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Udo wrote:

> ... Da
> muß nichts abgefragt werden.

Ja, es muss nicht, aber es kann.  Im Falle des FIFO, der mit 2
Zeichen gefüllt ist, spart es dir einen erneuten sofortigen Interrupt
mit all seinem Overhead (der wesentlich aufwändiger ist als die
Abfrage des Flags).

von Asterix-007 (Gast)


Lesenswert?

Hallo,

@ Jörg: ich hab natürlich nur auf den Interrupt reagiert und dann 2x 
gelesen. Wenn ich dich jetzt richtig verstehe hätte ich vor dem 2x lesen 
das RXC-Flag abfragen sollen. Klingt einleuchtend!

@Udo: hab ich auch nicht so aufgefasst. Nur wird man hier sehr oft in 
einem Tonfall "abgebügelt", der mir sehr missfällt.

Jedenfalls war es bei mir so, dass mich das häufige Lesen des 
Datenblattes mehr verwirrt hat als aufgeklärt. Gerade in einem solchen 
speziellen Fall.

Aber inzwischen ist ja der Sachverhalt geklärt!!!

Vielen Dank!

Ulf

von Udo (Gast)


Lesenswert?

Hallo Jörg,

aber das RXC-Flag wird ja erst dann gesetzt, wenn ein komplettes Byte in 
den Teil des FIFO's, das als UDR-Register bezeichnet ist, gelangt ist. 
Das passiert aber erst dann, wenn aus dem Shiftregister wieder Daten ins 
FIFO gelangen. Ungünstigenfalls, wenn keine Daten mehr empfangen werden, 
pollst du in deiner ISR lange auf das RXC-Flag....

Gruß
Udo

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Udo wrote:

> ... Ungünstigenfalls, wenn keine Daten mehr empfangen werden,
> pollst du in deiner ISR lange auf das RXC-Flag....

Nee, das natürlich nicht. ;-)  Du hast das irgendwie flashc verstanden.
Ich würde sowas machen:
1
ISR(USART0_RXC_vect)
2
{
3
   do {
4
      uint8_t c = UDR;
5
      // process c
6
   } while ((UCSR0A & RXC0) != 0);
7
}

statt einfach nur:
1
ISR(USART0_RXC_vect)
2
{
3
   uint8_t c = UDR;
4
   // process c
5
}

(Die endgetestete Schleife absichtlich, da beim ersten Einstieg in
die ISR durch einen Interrupt ja das RXC immer gesetzt sein sollte.)

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.