Forum: Mikrocontroller und Digitale Elektronik Atmega48 UART Kommunikation funktioniert nicht


von A. B. (developer_x)


Lesenswert?

Sehr geehrtes Forum,
ich verzweifle schon seit zwei Tagen eine läpische UART Kommunikation 
zum PC hinzubekommen, mit einem Atmega48.

Das RS232 Modul und die Verbindung zum PC können es nicht sein, da habe 
ich schon versuche unternommen, dort eine Fehlerquelle zu entdecken.

Ich verwende am PC das Terminalprogramm H-Term.

Dies ist mein Quellcode:
1
#define F_CPU 4000000UL
2
#define BAUD  9600L
3
4
#include <util/setbaud.h>
5
#include <avr/io.h>          
6
#include <util/delay.h>
7
8
#ifdef UBRR0H
9
10
#define UART0_UBRRH                             UBRR0H
11
#define UART0_UBRRL                             UBRR0L
12
#define UART0_UCSRA                             UCSR0A
13
#define UART0_UCSRB                             UCSR0B
14
#define UART0_UCSRC                             UCSR0C
15
#define UART0_UDRE_BIT_VALUE                    (1<<UDRE0)
16
#define UART0_UCSZ1_BIT_VALUE                   (1<<UCSZ01)
17
#define UART0_UCSZ0_BIT_VALUE                   (1<<UCSZ00)
18
#ifdef URSEL0
19
#define UART0_URSEL_BIT_VALUE                   (1<<URSEL0)
20
#else
21
#define UART0_URSEL_BIT_VALUE                   (0)
22
#endif
23
#define UART0_TXEN_BIT_VALUE                    (1<<TXEN0)
24
#define UART0_UDR                               UDR0
25
#define UART0_U2X                               U2X0
26
        
27
#else
28
29
#define UART0_UBRRH                             UBRRH
30
#define UART0_UBRRL                             UBRRL
31
#define UART0_UCSRA                             UCSRA
32
#define UART0_UCSRB                             UCSRB
33
#define UART0_UCSRC                             UCSRC
34
#define UART0_UDRE_BIT_VALUE                    (1<<UDRE)
35
#define UART0_UCSZ1_BIT_VALUE                   (1<<UCSZ1)
36
#define UART0_UCSZ0_BIT_VALUE                   (1<<UCSZ0)
37
#ifdef URSEL
38
#define UART0_URSEL_BIT_VALUE                   (1<<URSEL)
39
#else
40
#define UART0_URSEL_BIT_VALUE                   (0)
41
#endif
42
#define UART0_TXEN_BIT_VALUE                    (1<<TXEN)
43
#define UART0_UDR                               UDR
44
#define UART0_U2X                               U2X
45
46
#endif //UBRR0H
47
48
static void
49
uart_init (void)
50
{
51
    UART0_UBRRH = UBRRH_VALUE;                                                                      // set baud rate
52
    UART0_UBRRL = UBRRL_VALUE;
53
54
#if USE_2X
55
    UART0_UCSRA |= (1<<UART0_U2X);
56
#else
57
    UART0_UCSRA &= ~(1<<UART0_U2X);
58
#endif
59
60
    UART0_UCSRC = UART0_UCSZ1_BIT_VALUE | UART0_UCSZ0_BIT_VALUE | UART0_URSEL_BIT_VALUE;
61
    UART0_UCSRB |= UART0_TXEN_BIT_VALUE;                                                            // enable UART TX
62
}
63
64
static void
65
uart_putc (unsigned char ch)
66
{
67
    while (!(UART0_UCSRA & UART0_UDRE_BIT_VALUE))
68
    {
69
        ;
70
    }
71
72
    UART0_UDR = ch;
73
}
74
75
static void
76
uart_puts (char * s)
77
{
78
    while (*s)
79
    {
80
        uart_putc (*s);
81
        s++;
82
    }
83
}
84
85
86
int main(void)
87
{
88
  uart_init();
89
  _delay_ms(100);
90
91
  DDRB  = 0xff;            
92
  PORTB = 0b00000001;  
93
            
94
  while(1)
95
  {
96
    uart_puts("Dies ist ein Test String\n");
97
98
    PORTB = 0b00000000; 
99
    _delay_ms(100);
100
    PORTB = 0b00000001; 
101
    _delay_ms(100);
102
  }
103
104
  return 0;
105
}

Ich empfange in Hterm folgendes:
1
<\0><\0>??<\0>????<\0>??<\0>?<\0><\0>?<\0>???<\0>?<\0>??<\0><\0>??<\0>??<\0>??<\0>??<\0><\0><\0>?????<\0>??<\0>?<\0>??<\0><\0>?<\0>??<\0>??<\0><\0>??<\0>??<\0>???<\0>?<\0>?<\0>
Wirre Daten, immer die gleichen.

Meine Einstellung bei Hterm:
Baud 9600, Stopbit 1.

Was mache ich falsch, was kann ich tun damit es funktioniert?

Danke,
m.f.G:: Developer_X

von Michael (Gast)


Lesenswert?

Läuft der controller wirklich mit 4MHz Takt? Quarz oder interner RC? RC 
Kalibriert?

von Marco G. (grmg2010)


Lesenswert?

Was für eine Chip hängt zwischen den uC und dem PC?
Wie bereits vorgeschlagen, die Frequenz des uCs kontrollieren. Versuch 
einfach mal ein anderes Terminalprogram zu nutzen(z.B Putty) bei mir 
hatte sich Hterm am Anfang auch ein wenig zickig verhalten, als ich mit 
meinem ATMEGA644 mit dem PC kommunizieren wollte. Versuche erst mal ein 
einfaches Zeichen zu senden, bevor du den String sendest. Oder 
funktioniert das bereits?

von A. B. (developer_x)


Lesenswert?

Nein dies funktioniert ebenfalls nicht.

Der ist nicht kalibriert, interner Takt.

Ich habe es auch schon mit einer sehr niedrigen Baud
Frequenz benutzt, und es hat nicht geklappt.

Früher hat es mit dem Chip zwischen Rs232 und Atmega auch
geklappt, und klappt es weiterhin mit z.B. einem Atmega88.

Mit einem Atmega48 habe ich es nur noch nie hinbekommen.

Mit hterm hatte es auch immer geklappt bis jetzt.

von Thomas E. (thomase)


Lesenswert?

Nimm dir die Datenblätter für den Atmega8 und den Atmega48 vor und 
setzte die Registereinstellungen vernünftig um. Bei deiner 
Umdefinierungsorgie eines Beispiels für den Atmega8 steigt ja überhaupt 
keiner durch.


1
UCSR0B = (1 << RXEN0) | (1 << TXEN0);
2
UBRR0 = UBRRVALUE;

Mehr muss nicht eingestellt werden.

mfg.

: Bearbeitet durch User
von A. B. (developer_x)


Lesenswert?

1
#define F_CPU 4000000UL
2
#define BAUD  9600L
3
#define UBRR_VAL ((F_CPU+BAUD*8)/(BAUD*16)-1)   // clever runden
4
5
#include <util/setbaud.h>
6
#include <avr/io.h>          
7
#include <util/delay.h>
8
9
#ifdef UBRR0H
10
11
#define UART0_UBRRH                             UBRR0H
12
#define UART0_UBRRL                             UBRR0L
13
#define UART0_UCSRA                             UCSR0A
14
#define UART0_UCSRB                             UCSR0B
15
#define UART0_UCSRC                             UCSR0C
16
#define UART0_UDRE_BIT_VALUE                    (1<<UDRE0)
17
#define UART0_UCSZ1_BIT_VALUE                   (1<<UCSZ01)
18
#define UART0_UCSZ0_BIT_VALUE                   (1<<UCSZ00)
19
#ifdef URSEL0
20
#define UART0_URSEL_BIT_VALUE                   (1<<URSEL0)
21
#else
22
#define UART0_URSEL_BIT_VALUE                   (0)
23
#endif
24
#define UART0_TXEN_BIT_VALUE                    (1<<TXEN0)
25
#define UART0_UDR                               UDR0
26
#define UART0_U2X                               U2X0
27
        
28
#else
29
30
#define UART0_UBRRH                             UBRRH
31
#define UART0_UBRRL                             UBRRL
32
#define UART0_UCSRA                             UCSRA
33
#define UART0_UCSRB                             UCSRB
34
#define UART0_UCSRC                             UCSRC
35
#define UART0_UDRE_BIT_VALUE                    (1<<UDRE)
36
#define UART0_UCSZ1_BIT_VALUE                   (1<<UCSZ1)
37
#define UART0_UCSZ0_BIT_VALUE                   (1<<UCSZ0)
38
#ifdef URSEL
39
#define UART0_URSEL_BIT_VALUE                   (1<<URSEL)
40
#else
41
#define UART0_URSEL_BIT_VALUE                   (0)
42
#endif
43
#define UART0_TXEN_BIT_VALUE                    (1<<TXEN)
44
#define UART0_UDR                               UDR
45
#define UART0_U2X                               U2X
46
47
#endif //UBRR0H
48
49
static void
50
uart_init (void)
51
{
52
    UART0_UBRRH = UBRRH_VALUE;                                                                      // set baud rate
53
    UART0_UBRRL = UBRRL_VALUE;
54
55
#if USE_2X
56
    UART0_UCSRA |= (1<<UART0_U2X);
57
#else
58
    UART0_UCSRA &= ~(1<<UART0_U2X);
59
#endif
60
61
    UART0_UCSRC = UART0_UCSZ1_BIT_VALUE | UART0_UCSZ0_BIT_VALUE | UART0_URSEL_BIT_VALUE;
62
    UART0_UCSRB |= UART0_TXEN_BIT_VALUE;                                                            // enable UART TX
63
64
  UCSR0B = (1 << RXEN0) | (1 << TXEN0);
65
  UBRR0 = UBRR_VAL;
66
}
67
68
static void
69
uart_putc (unsigned char ch)
70
{
71
    while (!(UART0_UCSRA & UART0_UDRE_BIT_VALUE))
72
    {
73
        ;
74
    }
75
76
    UART0_UDR = ch;
77
}
78
79
static void
80
uart_puts (char * s)
81
{
82
    while (*s)
83
    {
84
        uart_putc (*s);
85
        s++;
86
    }
87
}
88
89
90
int main(void)
91
{
92
  uart_init();
93
  _delay_ms(100);
94
95
  DDRB  = 0xff;            
96
  PORTB = 0b00000001;  
97
            
98
  while(1)
99
  {
100
    uart_puts("Dies ist ein Test String\n");
101
102
    PORTB = 0b00000000; 
103
    _delay_ms(100);
104
    PORTB = 0b00000001; 
105
    _delay_ms(100);
106
  }
107
108
  return 0;
109
}

Es funktioniert trotzdem immer noch nicht

von A. B. (developer_x)


Lesenswert?

Jemand ne Idee was man sonst noch tun kann?

Keins der Tutorial die ich im Internet finde funktioniert,
warum funktioniert alles nie mit dem Atmega48?

von isidor (Gast)


Lesenswert?

K. R. schrieb:
> Es funktioniert trotzdem immer noch nicht

RXD und TXD sind beim ATMega48 auf PD0 und PD1 gemappt.

Ich finde jedoch keine Einstellung für Port D.

Mindestens müsste PD1 auf Output gesetzt werden damit TXD
was tun kann.

von g457 (Gast)


Lesenswert?

> Jemand ne Idee was man sonst noch tun kann?

Hast Du den Takt auch schon mal ∗überprüft∗, z.B. Blinken-LED im 
Sekundentakt oder mit einem Ossi? Wie sie die Baudrate auf einem Ossi 
aus?

von A. B. (developer_x)


Lesenswert?

ich habe DDRD auf output gesetzt, und trotzdem funktioniert es nicht.

es hat doch schon vorher funktioniert, er sendet doch daten, doch nur 
leider müll, und keine vernünftigen sachen.

von A. B. (developer_x)


Lesenswert?

Ich habe leider keinen Ossi, und bei den Blinkenden LEDs wird klar,
dass bei _delay_ms(100) durchaus ne halbe sekunde gewartet wird.

von isidor (Gast)


Lesenswert?

K. R. schrieb:
> ich habe DDRD auf output gesetzt, und trotzdem funktioniert es nicht.

Wo? Ich habe es nicht gefunden in dem Mini Code Urwald.

Das würde bedeuten dass alle Pins auf Output stehen, damit bekommst
du einen Treiberkonflikt mit dem RXD Pfad deines RS232 Bausteins.

von A. B. (developer_x)


Lesenswert?

Ach verdammt, es lag an dem Atmega48, mit diesen
Mistdingern werde ich wohl einfach nicht mehr arbeiten.

Ich habe einfach nen anderen Atmega eingesetzt, e voila, es 
funktioniert.

Damit hätte ich mir viel Zeit und Ärger sparen können.

Übrigstens geht es auch ohne DDRB = 0xFF;

Danke und
m.f.G.:  Developer_X

von Dietrich L. (dietrichl)


Lesenswert?

K. R. schrieb:
> Ich habe leider keinen Ossi, und bei den Blinkenden LEDs wird klar,
> dass bei _delay_ms(100) durchaus ne halbe sekunde gewartet wird.

Dann wirst Du in Wirklichkeit keine 4 MHz CPU-Takt haben. Wenn Du die 
Fuses nicht verändert hast, hast Du 1 MHz mit +/-10% Genauigkeit:
"The device is shipped with internal RC oscillator at 8.0MHz and with 
the fuse CKDIV8 programmed, resulting in 1.0MHz system clock."

Also erstmal #define F_CPU 4000000UL auf #define F_CPU 1000000UL ändern.

Gruß Dietrich

von isidor (Gast)


Lesenswert?

K. R. schrieb:
> Ach verdammt, es lag an dem Atmega48, mit diesen
> Mistdingern werde ich wohl einfach nicht mehr arbeiten.

Ja echd, dieser Misd ..... dass der überhaupt noch verkauft
wird bzw. verkauft werden darf ....

Im Zeifelsfall liegt es ja immer am Hersteller, gelle ?

Und wenn der nicht Schuld sein kann, dann war es der
Verkäufer, gelle?

von g457 (Gast)


Lesenswert?

> [..] und bei den Blinkenden LEDs wird klar,
> dass bei _delay_ms(100) durchaus ne halbe sekunde gewartet wird.
                  ^^^^^^              ^^^^^^^^^^^^^
Takt richtig einstellen und gut iss - mit Rundungsfehler läuft Dein m48 
mit 1MHz statt mit 4MHz.

von isidor (Gast)


Lesenswert?

g457 schrieb:
> Takt richtig einstellen und gut iss - mit Rundungsfehler läuft Dein m48
> mit 1MHz statt mit 4MHz.

Die Clock Fuses scheinen sich noch nicht zum Thread-Ersteller
durchgesprochen zu haben .....

von A. B. (developer_x)


Lesenswert?

Also ich habe das ganze jetzt mit nem Atmega88 hinbekommen, 8MHz.

Das Problem jetzt: Wenn ich Buchstaben senden lasse, indem ich sie über
ihre Nummer definiere, z.B. 042, kommt bei Hterm auch 42 an.
Wenn ich chars aber über 'T' definiere, kommen sie auch an, sind aber in 
HTerm nicht dargestellt.

Wenn man die berühmte Methode itoa benutze, in Verbindung mit
uart_puts (char * s)
dann kommen bei mir nur wirre Zeichen an,
ich weiß nicht woran das liegt.

Liegt das daran, dass Hterm falsch eingestellt ist, oder dass
Atmegas ein Problem mit ASCII haben?

von A. B. (developer_x)


Lesenswert?

oder z:B. beim senden von strings wie:
1
uart_puts ("Dies ist ein Test");

kommt bei hterm zwar die richtige Anzahl an Zeichen an, aber nur
das D und das T werden dargestellt, die anderen Buchstaben werden durch
Rechtecke ersetzt.

Woran könnte das liegen?

Danke,
m.f.G.: Developer_X

von spess53 (Gast)


Lesenswert?

Hi

>Also ich habe das ganze jetzt mit nem Atmega88 hinbekommen, 8MHz.

Wenn das der interne RC-Oszillator ist, sind die beschriebenen Probleme 
nicht verwunderlich.

MfG Spess

von A. B. (developer_x)


Lesenswert?

und jetzt plötzlich, ohne etwas verändert zu haben,
funktioniert es plötzlich.

WTF?

von nixundnul (Gast)


Lesenswert?

Ähnliches habe ich gestern durch: ein gebrauchter mega8, der schon 1 
Jahr im outdoor-Einsatz war, hat in 1MHz intern nur 0.9 MHz. Kein 
Zeichen erkennbar. Dank Anfangsverdacht und Logikanalyzer aber kein 
wirkliches Problem. Ein neuer m8 ist besser, aber nicht gut. Ein 8MHz 
Quarz ist noch besser, wenn vorhanden, ist aber nur ein baudrate-Quarz 
optimal.

Am Besten, Du nimmst eine fertige lib, zB von Peter Dannegger oder 
andere. Dann hast Du ggf einen Puffer für RX und TX gleich mit dabei. 
Und Beispiele, die funktionieren.

von A. B. (developer_x)


Lesenswert?

Ich habe 8MHz eingestellt, denn mein Atmega88 hat 8MHz

von spess53 (Gast)


Lesenswert?

Hi

>Ich habe 8MHz eingestellt, denn mein Atmega88 hat 8MHz

Mit den Werkseinstellungen darf er irgendwo zwischen 7,2 und 8,8MHz 
liegen.

MfG Spess

von Thomas E. (thomase)


Lesenswert?

K. R. schrieb:
> Das Problem jetzt: Wenn ich Buchstaben senden lasse, indem ich sie über
> ihre Nummer definiere, z.B. 042, kommt bei Hterm auch 42 an.

Das ist totaler Mist. Eine vorangestellte '0' kennzeichnet in C eine 
Oktalzahl.

Mach einen ganz einfachen Test:
1
#define F_CPU 4000000UL
2
#define BAUD  9600L
3
#define UBRR_VAL ((F_CPU+BAUD*8)/(BAUD*16)-1)   // clever runden
4
5
#include <avr/io.h>
6
#include <avr/interrupt.h>
7
#include <avr/power.h>
8
9
int main(void)
10
{
11
  clock_prescale_set(clock_div_2);  //4MHz
12
  UCSR0B = (1 << RXEN0) | (1 << TXEN0) | (1 << TXCIE0);
13
  UBRR0 = UBRR_VAL;
14
  DDRB |= (1 << 0);
15
  sei();
16
  while(1)
17
  {
18
  }
19
}
20
21
ISR(USART_TX_vect)
22
{
23
  UDR0 = UDR0;
24
  PINB |= (1 << 0);
25
}

Klemm dein Terminal an und sende irgendwas. Wenn das Zeichen nicht 
quittiert wird, stimmt entweder deine Baudrate(CPU-Takt?) nicht oder an 
deiner Hardware ist was faul. Die LED an PB0 toggelt bei jedem 
empfangenen Zeichen.

spess53 schrieb:
> Mit den Werkseinstellungen darf er irgendwo zwischen 7,2 und 8,8MHz
> liegen.

Kommt auf die Spannung und Temperatur an. Bei 3V und 25° liegt er 0,1% 
daneben.


mfg.

: Bearbeitet durch User
von spess53 (Gast)


Lesenswert?

Hi

Das Datenblatt (Table 29-1) sagt

               Frequency   VCC   Temperature    Calibration Accuracy
Factory          8.0MHz    3V       25°C                  ±10%
Calibration

MfG Spess

von Thomas E. (thomase)


Lesenswert?

spess53 schrieb:
> Das Datenblatt (Table 29-1) sagt
>
>                Frequency   VCC   Temperature    Calibration Accuracy
> Factory          8.0MHz    3V       25°C                  ±10%
> Calibration
>
> MfG Spess

0,1% stimmt auch nicht. 1% ist richtig.

Der Takt ist bei 3V/25°C kalibriert. Dabei hat er eine Toleranz von 1%. 
Über den gesamten zulässigen Temperatur- und Spannungsbereich hat er 
eine Abweichung von 10%. Mit User-Calibration dagegen lässt sich zu 
jeder Spannung und Temperatur 1% Toleranz herstellen.

Das steht da zwar nicht eindeutig so, lässt sich aber eindeutig 
nachmessen.

mfg.

: Bearbeitet durch User
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.