Zeichenkodierungsproblem bei UART

Gast #4103706
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
Gast #4103717
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?
Gast #4103730
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
Gast #4103785
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
...
Gast #4103794
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.
Gast #4103808
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.
Gast #4103843
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 ;)
Gast #4104581
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
Gast #4104981
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!

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren