Forum: Mikrocontroller und Digitale Elektronik Zeichenkodierungsproblem bei UART


von 0xf3 (Gast)


Lesenswert?

Hallo Mikrocontrollerfreunde,

ich versuche gerade mit meinem ATmega über UART zu sprechen. Leider 
verstehen wir uns aber noch nicht so gut. Wenn ich ein Zeichen vom PC an 
den AVR übertrage, soll es u. a. gleich wieder zurückgeschickt werden:
1
receivedByte = UDR0;
2
...
3
UDR0 = receivedByte:

Was ich dann aber im Terminal (screen oder minicom) sehe ist nicht das 
Zeichen, das es sein sollte, eher irgend ein Zeichensalat. Auf beiden 
Seiten liegen soweit die gleichen Einstellungen vor, also gleiche 
Baudrate, ein Stoppbit, kein Paritätsbit.

Kann vielleicht jemand nen Tipp geben, was hier noch falsch läuft bzw. 
was ich vergessen habe?

0xf3

von Peter II (Gast)


Lesenswert?

0xf3 schrieb:
> Kann vielleicht jemand nen Tipp geben, was hier noch falsch läuft bzw.
> was ich vergessen habe?

Hast du eine Quarz dran? Wie sieht die Hardware aus? MAX232 oder ähnlich 
verwendet?

von z42 (Gast)


Lesenswert?

Könntest du Fehlerbeschreibung und Indizien bitte noch mehr komprimieren 
und unnötiges weglassen?

von holger (Gast)


Lesenswert?

>Was ich dann aber im Terminal (screen oder minicom) sehe ist nicht das
>Zeichen, das es sein sollte, eher irgend ein Zeichensalat. Auf beiden
>Seiten liegen soweit die gleichen Einstellungen vor, also gleiche
>Baudrate, ein Stoppbit, kein Paritätsbit.

Nö, wenn auf beiden Seiten die gleichen Einstellungen
wären, würdest du das korrekte Echo sehen.
Falsche Taktrate des uC angegeben ist der wahrscheinlichste
Grund für deinen Zeichensalat.

Wie sehen deine Fuses aus?

von Peter II (Gast)


Lesenswert?

holger schrieb:
> Nö, wenn auf beiden Seiten die gleichen Einstellungen
> wären, würdest du das korrekte Echo sehen.

außer wenn das Signal invertiert ist, weil falsch verkabelt

von 0xf3 (Gast)


Lesenswert?

Richtig, vergessen zu erwähnen. Ein Quarz ist dran mit 3,6864 MHz. Den 
habe ich extra genommen, damit beim Prescaler für UART eine gerade Zahl 
rauskommt. Außerdem benutze ich ein Kabel mit USB-Adapter. Bin mir nicht 
ganz sicher, aber ich glaube da steckt ein FT232-Chip drin. Jedenfalls 
kann ich damit prima mit meinem Raspberry reden. Die Strippen sind so, 
wie sie meines Wissens auch sein sollen, also RX -> TX und TX -> RX.

Ansonsten:

#define F_CPU 3686400UL
#define BAUDRATE 57600UL
uint8_t myUBRR = (F_CPU / (16 * BAUDRATE)) - 1;


FUSES = -U lfuse:w:0xc8:m -U hfuse:w:0xd8:m -U efuse:w:0xff:m

von MaK (Gast)


Lesenswert?

Welcher ATMEGA ist es denn?

Außerdem: Masse Seriell-USB-Adapter mit Masse der Schaltung verbunden?

Daten/Stoppbits + Parität richtig?

von 0xf3 (Gast)


Lesenswert?

Es ist ein ATmega328P. Die Schaltung wird ausschließlich über das 
Adapterkabel mit Strom versorgt. Bin daher ziemlich sicher, dass Masse 
und 5V an der richtigen Stelle stecken. Die sonstigen Einstellungen 
müssen auch passen, hab mir gerade nochmal die minicom-Konfiguration 
angeschaut: 8 Bit pro Zeichen, ein Stoppbit und kein Paritätsbit.

Im Controller sieht das so aus:
1
...
2
UCSR0B |= (1 << TXEN0) | (1 << RXEN0);
3
UCSR0C |= (1 << UCSZ01) | (1 << UCSZ00);
4
UBRR0H = (uint8_t) (myUBRR >> 8);
5
UBRR0L = (uint8_t) myUBRR;
6
UCSR0B |= (1 << RXCIE0);
7
...

von Tom (Gast)


Lesenswert?

Ich wurde zu Beginn meiner uc-Basteleien von einem vorinstallierten 
Bootloader verarscht, der bei der UART das double-speed-Bit gesetzt hat. 
Die Symptome waren ähnlich, die Ursache zu finden hat etwas gedauert.

von 0xf3 (Gast)


Lesenswert?

>Ich wurde zu Beginn meiner uc-Basteleien von einem vorinstallierten
>Bootloader verarscht, der bei der UART das double-speed-Bit gesetzt hat.
>Die Symptome waren ähnlich, die Ursache zu finden hat etwas gedauert.

Hm, also das scheint hier wohl nicht der Fall zu sein. Habe jetzt 
explizit
1
UCSR0A &= ~(1 << U2X0);
gesetzt. Sieht aber alles noch genau so doof aus wie vorher.

von Wolfgang (Gast)


Lesenswert?

0xf3 schrieb:
> FUSES = -U lfuse:w:0xc8:m -U hfuse:w:0xd8:m -U efuse:w:0xff:m

Und du bist sicher, dass ein 3,6864 MHz Quarz mit einer Frequenz im 
Bereich zwischen 0,4 und 0,9 MHz schwingt, oder warum hast du CKSEL so 
gewählt?

von MaK (Gast)


Lesenswert?

Probier mal lfuse:w:0xdc:m oder
lfuse:w:0xd6:m (Full swing oscillator)

von 0xf3 (Gast)


Lesenswert?

>Und du bist sicher, dass ein 3,6864 MHz Quarz mit einer Frequenz im
>Bereich zwischen 0,4 und 0,9 MHz schwingt, oder warum hast du CKSEL so
>gewählt?

Oh, stimmt. Da habe ich wohl nicht beachtet, dass die Fusebits 
invertiert gesetzt werden ^^

0xdc und 0xd6 habe ich probiert. Hat aber nichts geändert. Allerdings 
sind diese beiden Werte laut Datenblatt doch für Keramikoszillatoren, 
oder?! Ich hätte glaube ich eher 0xf7 gewählt. Naja, aber das 
funktioniert genau so wenig ;)

von Irgendwer (Gast)


Lesenswert?

0xf3 schrieb:
> Außerdem benutze ich ein Kabel mit USB-Adapter

Sicher das dies ein USB<->UART und keine USB<->RS232 Umsetzer ist?
Oder hast du auf auf der µC Seite eine UART<->RS232 Umsetzer drin?

von Andreas K. (andreasmc)


Lesenswert?

Um zu prüfen ob der Takt richtig eingestellt ist, hat es sich bewährt 
beim Start eine LED ein paar mal im Sekundentakt blinken zu lassen...

Und anschliessend SetBaud.h verwenden statt einer eigenen Definition ;-)

: Bearbeitet durch User
von 0xf3 (Gast)


Lesenswert?

Das Kabel macht USB auf TTL. Ist doch richtig so, oder?!

Ah, Tatsache. Habe jetzt auch LEDs dran und offenbar ist der uC-Takt ein 
ganzes Stück langsamer als er sein sollte. Jedenfalls leuchten sie 
deutlich länger als vorgegeben. Hab zwar gerade keine Stoppuhr zur Hand 
aber es ist gut möglich, dass sie ca. 3,6864 mal länger leuchten ;) ich 
weiß bloß nicht wieso ^^

Hm... Also den Quarz habe ich mal ausgetauscht. Kaputt scheint er nicht 
zu sein. Er steckt zwischen XTAL1 und 2 und von jedem Pin gehen noch 22 
pF nach Masse.

Die Fusebits habe ich mir vom Calculator auf engbedded.com abgeschaut:
lfuse:w:0xc6:m  hfuse:w:0xd9:m  efuse:w:0xff:m

Ist sicher ein ganz dummer Fehler für den ich einfach nur zu blind bin. 
Hier mal die main.c:
1
#define F_CPU 3686400UL
2
#define BAUD 57600UL
3
4
#include <avr/io.h>
5
#include <avr/interrupt.h>
6
#include <util/delay.h>
7
#include <util/setbaud.h>
8
9
volatile char receivedByte;
10
11
void UART_init(void)  {
12
     UCSR0B |= (1 << TXEN0) | (1 << RXEN0);
13
     // enable TX and RX circuitry
14
     UCSR0C |= (1 << UCSZ01) | (1 << UCSZ00);
15
     // 8 bit character size
16
     UBRR0H = UBRRH_VALUE;
17
     UBRR0L = UBRRL_VALUE;
18
     // set baud rate
19
     UCSR0B |= (1 << RXCIE0);
20
     // enable RX interrupt
21
     UCSR0A &= ~(1 << U2X0);
22
     // disable double speed
23
}
24
25
void IO_init(void)  {
26
     DDRD |= (1 << PD3) | (1 << PD2);
27
     // PD3 and PD2 are now outputs
28
}
29
30
int flash_LED(uint8_t pin)  {
31
    // pin: 2 = yellow (PD2), 3 = green (PD3)
32
    if(pin != 2 && pin != 3)
33
  return 1;
34
    for(uint8_t i = 0; i <= 4; i++)  {
35
  _delay_ms(1000);
36
  PORTD ^= (1 << pin);
37
    }
38
    return 0;
39
}
40
41
ISR(USART_RX_vect)  {
42
    receivedByte = UDR0;
43
    flash_LED(3);
44
    loop_until_bit_is_set(UCSR0A, UDRE0);
45
    UDR0 = receivedByte;
46
    flash_LED(2);
47
}
48
49
int main(void)  {
50
     IO_init();
51
     UART_init();
52
     sei();
53
     while (1) {
54
  //...
55
     }
56
     return 0;
57
}

Und das Makefile:
1
DEVICE = atmega328p
2
CLOCK = 3686400
3
PROGRAMMER = -c arduino -P /dev/ttyACM0 -b 19200
4
OBJECTS = main.o
5
FUSES = -U lfuse:w:0xc6:m -U hfuse:w:0xd9:m -U efuse:w:0xff:m 
6
7
AVRDUDE = avrdude $(PROGRAMMER) -p $(DEVICE)
8
COMPILE = avr-gcc -Wall -Os -DF_CPU=$(CLOCK) -mmcu=$(DEVICE) -std=c99
9
10
# symbolic targets:
11
all:  main.hex
12
13
.c.o:
14
  $(COMPILE) -c $< -o $@
15
16
.S.o:
17
  $(COMPILE) -x assembler-with-cpp -c $< -o $@
18
19
.c.s:
20
  $(COMPILE) -S $< -o $@
21
22
flash:  all
23
  $(AVRDUDE) -U flash:w:main.hex:i
24
25
fuse:
26
  $(AVRDUDE) $(FUSES)
27
28
install: flash fuse
29
30
load: all
31
  bootloadHID main.hex
32
33
clean:
34
  rm -f main.hex main.elf $(OBJECTS)
35
36
# file targets:
37
main.elf: $(OBJECTS)
38
  $(COMPILE) -o main.elf $(OBJECTS)
39
40
main.hex: main.elf
41
  rm -f main.hex
42
  avr-objcopy -j .text -j .data -O ihex main.elf main.hex
43
44
disasm:  main.elf
45
  avr-objdump -d main.elf
46
47
cpp:
48
  $(COMPILE) -E main.c

von Samuel C. (neoexacun)


Lesenswert?

Schreib die Fuses mal manuell in den AVR. Wenn die LEDs tatsächlich 3,x 
mal so lang leuchten wie sie sollten läuft der AVR wohl auf 
standardmäßigen 1MHz.

von 0xf3 (Gast)


Lesenswert?

Super, das scheint's gewesen zu sein!
1
#avrdude -p atmega328p -c arduino -P /dev/ttyACM0 -Ulfuse:w:0xc6:m -U hfuse:w:0xd9:m -U efuse:w:0xff:m
2
3
avrdude: stk500_getsync(): not in sync: resp=0xe0
4
5
avrdude done.  Thank you.

Jetzt passt die Taktung und auch die Zeichen kommen richtig ins Terminal 
zurück. Aber diese Meldung verstehe ich nicht. Und lesen kann ich die 
Fuses auch nicht.
1
#avrdude -p atmega328p -c arduino -P /dev/ttyACM0 -U lfuse:r:fuse.txt:h
2
3
avrdude: stk500_getsync(): not in sync: resp=0xe0
4
5
avrdude done.  Thank you.
Die fuse.txt wird nicht erzeugt (ja, ich habe Schreibrechte). Und warum 
klappt das anscheinend nur manuell?

Naja, immerhin bin ich schon mal ein ganzes Stück weiter. Vielen Dank 
bis dahin für die Hilfe!

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.