Forum: Mikrocontroller und Digitale Elektronik UART Problem --- nichts zu empfangen


von Sepp H. (vali1991)


Lesenswert?

Hallo, kann kein Zeichen über die UART empfangen. Hat jemand eine Idee?


#include <avr/io.h>
//#include <uart.h>
//#include <avr/delay.h>

int main(void)
{
  UCSRB = 0x08;          //UART TX einschalten
  UCSRC = 0xC6;

  UBRRH = 0x00;
  UBRRL = 0x17;

  while (UCSRA & 0x20)    //warten bis Senden möglich
  {
  UDR = 0x78;              //schreibt das Zeichen x auf die 
Schnittstelle
  }



  //return 0;
}

von Karl H. (kbuchegg)


Lesenswert?

AVR-GCC-Tutorial/Der UART

Schau dir den Code an, vergleich mit deinem.

Und PS: beim ersten mal ist es eine gute Idee, wenn der µC in einer 
Endlosschleife auf Dauersenden geht. Das macht die Fehlersuche ungleich 
einfacher, als wie wenn er nach einem Power-On nur ein einzelnes Zeichen 
sendet und sich dann wieder schlafen legt.

AVR Checkliste
Abschnitt 3.2

von Sepp H. (vali1991)


Lesenswert?

funktioniert noch immer nicht -.-

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Sepp Horst schrieb:
> funktioniert noch immer nicht -.-
Was?

Sepp Horst schrieb:
> Hallo, kann kein Zeichen über die UART empfangen. Hat jemand eine Idee?
Funktioniert deine Hardware?
Hast du schon mal den uC ausgesteckt, die Pins RX+TX gebrückt und vom PC 
aus ein Zeichen gesendet und sofort das selbe Zeichen wieder empfangen 
(das wäre ein sogenannter Loopback)?

von Mike M. (mikeii)


Lesenswert?

UCSRB = 0x08;          //UART TX einschalten

Willst du nicht empfangen?

von Mike M. (mikeii)


Lesenswert?

Ah du willst den µC Senden lassen.

Gewöhn dir erstmal eine andere Schreibweise an, um die bits zu setzten.

UCSRB = 0x08;

UCSR0 |= (1<<TXEN); oder wie das bei deinem Controller heißt

Dann Schau ob die Baudeinstellungen stimmen:
  UBRRH = 0x00;
  UBRRL = 0x17;

Ist das mit der Formel berechnet, bzw aus der Tabelle entnommen?


UCSRC = 0xC6;

Richtige zusammensetzung? Standart wäre 8N1 ??

Und welche Taktrate hat dein µC.
Wenn die nicht zur Baudeinstellung passt, kanns nicht gehen.

Zudem mal einen Externen Quarz anschließen, damit der Fehler bei der 
Baudrate geringer wird

von dummschwaetzer (Gast)


Lesenswert?

Was ist denn an dieser Schreibweise
> UCSRB = 0x08;
auszusetzen?
ich finde das leserlicher als
> UCSR0 |= (1<<TXEN);

von Mike M. (mikeii)


Lesenswert?

dummschwaetzer schrieb:
> Was ist denn an dieser Schreibweise
>> UCSRB = 0x08;
> auszusetzen?
> ich finde das leserlicher als
>> UCSR0 |= (1<<TXEN);



Was daran leserlicher ist?

Es geht nicht nur um Leserlicher, sondern darum das ich bits setzte und 
nicht ein ganzes Byte.

Zum Thema Leserlichkeit:

Was sagt mir 0x08 aus? 00001000

Toll jetzt weiß ich das ein Bit gesetzt ist, nur was macht das?

UCSR0 |= (1<<TXEN); Ah, das ist das TX bit.

Ich will das ganze jetzt auf einen anderen AVR Transportieren, also 
tausche ich nurnoch die Bitbezeichnungen aus und alles geht.

So muss ich jedes Bit vergleichen, wie es bei dem anderen heißt.

dummschwaetzer = Troll??

von dummschwaetzer (Gast)


Lesenswert?

mach ich alt
#define Konstante1 0x08U;//Bit3
#define Konstante2 0x04U;//Bit2

Register_irgendwas = Konstante1 + Konstante2;//Setze Bit 3 und 2

Register_irgendwas &= ~ Konstante2;//Lösche Bit 2

bei geeigneter Konstantenbenennung finde ich das übersichtlicher und ich 
kann mehrere Bits auf einmal setzen / löschen.

von Karl H. (kbuchegg)


Lesenswert?

dummschwaetzer schrieb:

> bei geeigneter Konstantenbenennung finde ich das übersichtlicher und ich
> kann mehrere Bits auf einmal setzen / löschen.

Na dann übertrag das mal auf einen anderne µC aus der gleichen Familie, 
bei dem die Bits zwar im gleichen Register aber an einer anderen 
Position sitzen.

Bei der Variante

   UCSRB |= ( 1 << TXEN ) | ( 1 << RXEN );

brauch ich genau gar nichts tun und kann direkt im Code lesen, dass 
sowohl Sender als auch Empfänger eingeschaltet werden.
Ich bin nicht darauf angewiesen, dass da irgendein Kommentar daneben 
steht (der dann auch noch tunlichst stimmen sollte) und ich bin nicht 
darauf angewiesen da irgendwelche Konstante einzuführen, die ebenfalls 
wieder falsch sein können.
Wenn dir die Schreibweise  1<<Bitname nicht gefällt, dann versteck sie 
meinetwegen in einem Makro

#define BIT(x)   (1<<(x))

dann kannst du schreiben

   UCSRB |= BIT(TXEN) | BIT(RXEN);

Aber lass die Finger davon, selber die Bits in Hex-Zahlen umzurechnen! 
Genau damit man das eben nicht machen muss, sind die Bitnamen alle 
vordefiniert. Und zwar so, dass sie ohne dein Zutun zum jeweiligen µC 
passen. Ideal wäre es noch, wenn sie dann auch noch so definiert wären, 
dass man ein falsches Bit im falschen Register gar nicht erst benennen 
kann, aber das ist zum jetzigen Zeitpunkt ohne massive Umstellung der 
Headerfilegenerierung und der Systematik nicht machbar.


Aber wahrscheinlich findest du ach das
1
  UDR = 0x78;              //schreibt das Zeichen x auf die Schnittstelle
lesbarer als das
1
  UDR = 'x';

(auch so ein Unsinn. Wenn ich ein Zeichen ausgeben will, dann schreibe 
ich es direkt hin und nicht seinen ASCII Code in Hex.)

von Mike M. (mikeii)


Lesenswert?

Register_irgendwas = Konstante1 + Konstante2;

So und jetz will ich Bit 5 Setzten und weiß nicht was vorher schon 
gesetzt war.
Also muss ich schreiben Bit 5 + bit 1 + bit 2, muss alle Konstanten 
definiert haben etc. etc.

Das ganze Bitdefinitionen steht schon im Datenblatt drin, und haben 
einen sinnvollen Namen (wenn man weiß was sie heißen).

Sowas gibt es nicht ohne grund.

Das ich mal einen Portzustand mit 0xFF oder 0x00 oder 0xF0 setzte ist 
natürlich einfacher, als wenn ich 0b00000000 oder 0b11111111 oder
gar PORTX|= (1<<0) | (1<<1) | ... je nach Beispiel.

Aber gerade bei Konfigurationsgeschichten ist das eine Sache die 
ungemein bei einer Fehlersuche hilft, da der Code absolut verständlich 
ist.

von Peter II (Gast)


Lesenswert?

Mike Mike schrieb:
> Ich will das ganze jetzt auf einen anderen AVR Transportieren, also
> tausche ich nurnoch die Bitbezeichnungen aus und alles geht.

in der Hoffnung das das Bit im gleich Register gemeint ist. Das das ist, 
finde ich der größte nachteil. Das bit und Register nicht gewarnt werden 
wenn sie nicht zusammenpassen. Man müsste eine enum für jedes Register 
anlegen.

von Mike M. (mikeii)


Lesenswert?

Peter II schrieb:
> Mike Mike schrieb:
>> Ich will das ganze jetzt auf einen anderen AVR Transportieren, also
>> tausche ich nurnoch die Bitbezeichnungen aus und alles geht.
>
> in der Hoffnung das das Bit im gleich Register gemeint ist. Das das ist,
> finde ich der größte nachteil. Das bit und Register nicht gewarnt werden
> wenn sie nicht zusammenpassen. Man müsste eine enum für jedes Register
> anlegen.

Da hast du auch wieder recht, aber das kann man am Ende vom Datenblatt 
immer schön mit der Tabelle vergleichen. Da ist jedes Register und der 
dazugehörige Bitname aufgelistet.

von Karl H. (kbuchegg)


Lesenswert?

Sepp Horst schrieb:
> funktioniert noch immer nicht -.-

Zurück zum Sepp Horst

Was hast du alles gemacht?

Bist du die Checkliste durchgegangen?
* Hast du den Loopbacktest gemacht?
* Hast du den Timingtest gemacht?
* Bist du auf Dauersenden gegangen?

von dummschwaetzer (Gast)


Lesenswert?

kbuchegg schrieb:
> Bei der Variante
>
>    UCSRB |= ( 1 << TXEN ) | ( 1 << RXEN );

und wo sinr TXEN Bzw RXEN definiert?

meine Variante:
irgendwo in der Header-Datei des Schaltkreises
#define TXEN 0x01;
#define RXEN 0x02;

im Programm:
Uart_Register = TXEN + RXEN;

vergleiche mit:
UCSRB |= ( 1 << TXEN ) | ( 1 << RXEN );

mikeii schrieb:
> So und jetz will ich Bit 5 Setzten und weiß nicht was vorher schon
> gesetzt war.
> Also muss ich schreiben Bit 5 + bit 1 + bit 2, muss alle Konstanten
> definiert haben etc. etc.

port_neuer_inhalt |= 0x20u;
Und wenn die 0x20u einen guten Namen uber #define erhalten haben:
port_neuer_inhalt |= guter_name;

> dummschwaetzer = Troll??

dummschwaetzer != Troll

was macht da eigentlich der Kompiler daraus?
ist das dann im ASM-File mit "<<" mehr Code?

von Mike M. (mikeii)


Lesenswert?

dummschwaetzer schrieb:
> kbuchegg schrieb:
>> Bei der Variante
>>
>>    UCSRB |= ( 1 << TXEN ) | ( 1 << RXEN );
>
> und wo sinr TXEN Bzw RXEN definiert?



in der Entsprechenden ioXXXX.h die zur Controllerfamilie (oder Typ?) 
gehört

> meine Variante:
> irgendwo in der Header-Datei des Schaltkreises
> #define TXEN 0x01;
> #define RXEN 0x02;
>
> im Programm:
> Uart_Register = TXEN + RXEN;
>
> vergleiche mit:
> UCSRB |= ( 1 << TXEN ) | ( 1 << RXEN );

Wofür alles definieren was schon da ist?

Einmal die avr/io.h einbinden und gut ist
> mikeii schrieb:

>> So und jetz will ich Bit 5 Setzten und weiß nicht was vorher schon
>> gesetzt war.
>> Also muss ich schreiben Bit 5 + bit 1 + bit 2, muss alle Konstanten
>> definiert haben etc. etc.
>
> port_neuer_inhalt |= 0x20u;
> Und wenn die 0x20u einen guten Namen uber #define erhalten haben:
> port_neuer_inhalt |= guter_name;

Ich kanns mir auch noch schwerer machen...

>> dummschwaetzer = Troll??
>
> dummschwaetzer != Troll

eher nicht Lernbereit

> was macht da eigentlich der Kompiler daraus?
> ist das dann im ASM-File mit "<<" mehr Code?

ist SHL und SHR in Assembler.

Und ich glaube nicht, dass das Bitshift mehr Speicher braucht, als die 
Werzuweisung.

Und vom #define her ist das absolut wurscht, da das 
Präcompilerdirectiven sind

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

dummschwaetzer schrieb:
> was macht da eigentlich der Kompiler daraus?
Eine Konstante Zuweisung.

von Rüttiger (Gast)


Lesenswert?

Mike Mike schrieb:
> Und ich glaube nicht, dass das Bitshift mehr Speicher braucht, als die
> Werzuweisung.

das shiften macht schon der präcompiler

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.