Forum: Mikrocontroller und Digitale Elektronik UART & ATmega324P20PU


von Carsten (Gast)


Angehängte Dateien:

Lesenswert?

Hey Jungs,

ich habe folgendes Problem, ich möchte ein Signal auf eine EIA-232 
Schnittstelle bringen. Als Compiler benutze ich AVR Studio und meine 
Empfangssoftware heißt "Terminal".Als Baudrate sind dort 9600 
eingestellt.

Ich bin dem Tutorial auf der Homepage für UART gefolgt.
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/Der_UART#Die_Hardware

Allerdings ist mir schon früh aufgefallen, dass für meinen yC die 
Bezeichnungen nicht stimmen. Ich habe daher im Datenblatt nachgeschaut 
und nun sieht es so aus:
1
#include "baud.c"
2
#include <avr/io.h>
3
#include <util/delay.h>
4
#include <stdint.h>
5
#include <inttypes.h>
6
7
//Prototypes
8
void uart_init(void);
9
10
11
int main(void)
12
{
13
uart_init();
14
15
while(!(UCSR0A & (1<<UDRE0)))
16
{
17
18
}
19
20
UDR0 = 'x';
21
22
23
return 0;
24
}
25
26
void uart_init(void)
27
{
28
  UCSR0B |= (1<<TXEN0);  // UART TX einschalten
29
  UCSR0C |= (1<<UMSEL00);  // Asynchron 8N1 
30
 
31
   UBRR1H = UBRR_VAL >> 8;
32
    UBRR1L = UBRR_VAL & 0xFF;
33
}

Es kommt allerdings nichts an. Ich bin mir auch extrem unsicher, ob 
meine Änderungen nach dem Datenblatt stimmen. Die Datei "baud.c" ist 
einfach die Berechnung von dem Link ("UART initialisieren"). Der Rest 
ist von weiter unten kopiert und verändert.

In der vorletzten Zeile habe ich 2 Sachen löschen müssen, weil ich dazu 
im datenblatt kein pendant gefunden habe

Danke schonmal im Voraus!

von ich (Gast)


Lesenswert?

> #include "baud.c"

ein .c Datei includieren, so was habe ich noch nie gesehen. Geht so was 
überhaupt?

von Michael F. (startrekmichi)


Lesenswert?

ich schrieb:
>> #include "baud.c"
>
> ein .c Datei includieren, so was habe ich noch nie gesehen. Geht so was
> überhaupt?

Klar, warum nicht?

@Carsten:
Was hast du da löschen müssen?

von gerd (Gast)


Lesenswert?

ich schrieb:
> ein .c Datei includieren, so was habe ich noch nie gesehen. Geht so was
> überhaupt?

Geht, ist aber "unschön".

- gerd

von Carsten (Gast)


Lesenswert?

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

die letzten beiden zuweisungen musste ich weglassen und dazu habe ich 
nicht gefunden

von Michael F. (startrekmichi)


Lesenswert?

Carsten schrieb:
>
1
UCSRC |= (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);  // Asynchron 8N1
>
> die letzten beiden zuweisungen musste ich weglassen und dazu habe ich
> nicht gefunden

Und das ist genau dein Problem.
1
UCSR0C = (1<<UCSZ01)|(1<<UCSZ00);
Und lass das "UMSEL00" weg.

Steht bei mir übrigens in der Register Description des USART im 
Datenblatt (Seite 193)

von Carsten (Gast)


Lesenswert?

Leider kommt immer noch nichts an. Liegt das evtl am ext. Quarz?

Hast du noch einen Link zu dem Datenblatt?

von g457 (Gast)


Lesenswert?

> UCSRC |= (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);  // Asynchron 8N1
>
> die letzten beiden zuweisungen musste ich weglassen und dazu habe ich
> nicht gefunden

Kuckst Du Datenblatt [1] Kapitel 16 "USART" (Hint: URSEL gibbet nicht im 
m324p). Zum Debuggen würde ich etwas mehr senden als nur ein einzelnes 
'x'. Und anschließend [2].

HTH

[1] http://atmel.com/dyn/resources/prod_documents/doc8011.pdf
[2] http://www.mikrocontroller.net/articles/AVR_Checkliste#UART.2FUSART

von Carsten (Gast)


Lesenswert?

korrigiere:

es kommt was an: nur anstatt einem "a" kommt ein "Á"


-.-

von Carsten (Gast)


Lesenswert?

ich schreibe morgen weiter, bin jetzt erstmal weg, danke schonmal!!

von Carsten (Gast)


Lesenswert?

sooooo

ich habe mir das Kapitel UART im Datenblatt durchgelesen. Allerdings bin 
ich mir bei den Fuses noch nicht sehr sicher. Wenn ich nun auf Seite 197 
gucke sehe ich die UBBR Werte für meinen externen 16 Mhz Quarz oder? Nur 
wo muss ich die dann setzen?

Muss ich dann meine F_CPU auch auf die 16 Mhz setzen?

von Carsten (Gast)


Lesenswert?

zusätzlich: bei einer eingegeben Frequenz in der baud.c von 1 Mhz(soweit 
ich weiß ist das die interne Frequenz) kommt nur "<0><0>" oder anderer 
Mist raus.

von g457 (Gast)


Lesenswert?

> Allerdings bin ich mir bei den Fuses noch nicht sehr sicher.

Ich habs gesehen im anderen Fred - gut dass bei euch ein Parallelprommer 
im Haus ist.. aber damit bist Du nicht alleine, schau Dir mal [1] an, 
dort ist auch ein sehr praktischer Fuse-Rechner verlinkt.

> Wenn ich nun auf Seite 197 gucke sehe ich die UBBR Werte für meinen
> externen 16 Mhz Quarz oder?

Ja. Dazu muss der Quarz 1. auch in Verwendung und 2. die CKDIV8-Fuse 
adäquat gesetzt sein. Geht übrigens auch flexibler (zumindest wenn man 
einen anständigen Präprozessor hat), siehe Code in [2].

> Nur wo muss ich die dann setzen?

Irgendwo(tm) bevor Du den UART aktivierst. Vorzugsweise macht man das 
gesammelt in einer eigenen Funktion, z.B. 'uart_init()', die die 
Register passend beschreibt und anschließend den UART (nebst ggf. dessen 
IRQs) aktiviert.

> Muss ich dann meine F_CPU auch auf die 16 Mhz setzen?

'Müssen' ist relativ :-) Es ist zumindest zweckmäßig, auch F_CPU auf den 
tatsächlichen Wert zu setzen. Alles andere wäre ein guter Kandidat für 
'code obfuscation'.

> bei einer eingegeben Frequenz in der baud.c von 1 Mhz(soweit
> ich weiß ist das die interne Frequenz) kommt nur "<0><0>" oder anderer
> Mist raus.

Das überrascht mich garnicht :-) Erstens ist der interne Takt recht 
ungenau (den müsste man erst kalibrieren, und dann ist er Temperatur- 
und Spannungsabhängig) und zweitens kann die UART-Einheit 9600 Baud 
nicht gut aus einem Takt von 1MHz erzeugen - das schleppt einen 
systemischen Fehler von etwa 7.5% ein [3], das ist zu viel.

HF

[1] http://www.mikrocontroller.net/articles/AVR_Fuses
[2] http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/Der_UART
[3] http://www.wormfood.net/avrbaudcalc.php

von Carsten (Gast)


Lesenswert?

danke ersteinmal für deine antwort:

g457 schrieb:
> Ja. Dazu muss der Quarz 1. auch in Verwendung und 2. die CKDIV8-Fuse
>
> adäquat gesetzt sein. Geht übrigens auch flexibler (zumindest wenn man
>
> einen anständigen Präprozessor hat), siehe Code in [2].

In verwendung heißt, dass ich bei AVR Studio unter "Fuses"-> "SUT_CKSEL" 
einen Ext. Crystal Osc. 8.0 -    MHz auswähle oder? Welche Startuptime 
muss ich da wählen? 4.1ms,0ms, 65 ms? 258 CK,lK CK, 16K CK?

Was meinst du mit Adequat gesetzt sein? Muss ich dann einfach nur im 
selben Menü bei AVR Studio das Häkchen bei CKDIV8 setzen?

den Code habe ich mal in die Datei kopiert: sieht jetzt so aus:
1
#include <avr/io.h>
2
#include <util/delay.h>
3
#include <stdint.h>
4
#include <inttypes.h>
5
6
/* 
7
  UART-Init: 
8
Berechnung des Wertes für das Baudratenregister 
9
aus Taktrate und gewünschter Baudrate
10
*/
11
 
12
#ifndef F_CPU
13
/* In neueren Version der WinAVR/Mfile Makefile-Vorlage kann
14
   F_CPU im Makefile definiert werden, eine nochmalige Definition
15
   hier wuerde zu einer Compilerwarnung fuehren. Daher "Schutz" durch
16
   #ifndef/#endif 
17
 
18
   Dieser "Schutz" kann zu Debugsessions führen, wenn AVRStudio 
19
   verwendet wird und dort eine andere, nicht zur Hardware passende 
20
   Taktrate eingestellt ist: Dann wird die folgende Definition 
21
   nicht verwendet, sondern stattdessen der Defaultwert (8 MHz?) 
22
   von AVRStudio - daher Ausgabe einer Warnung falls F_CPU
23
   noch nicht definiert: */
24
#warning "F_CPU war noch nicht definiert, wird nun nachgeholt mit 16000000"
25
#define F_CPU 16000000UL  // Systemtakt in Hz - Definition als unsigned long beachten 
26
                         // Ohne ergeben sich unten Fehler in der Berechnung
27
#endif
28
 
29
#define BAUD 9600UL      // Baudrate
30
 
31
// Berechnungen
32
#define UBRR_VAL ((F_CPU+BAUD*8)/(BAUD*16)-1)   // clever runden
33
#define BAUD_REAL (F_CPU/(16*(UBRR_VAL+1)))     // Reale Baudrate
34
#define BAUD_ERROR ((BAUD_REAL*1000)/BAUD) // Fehler in Promille, 1000 = kein Fehler.
35
 
36
#if ((BAUD_ERROR<990) || (BAUD_ERROR>1010))
37
  #error Systematischer Fehler der Baudrate grösser 1% und damit zu hoch! 
38
#endif 
39
40
41
//Prototypes
42
void uart_init(void);
43
44
45
int main(void)
46
{
47
uart_init();
48
49
while(!(UCSR0A & (1<<UDRE0)))
50
{
51
52
}
53
54
UDR0 = 'e';
55
56
57
return 0;
58
}
59
60
void uart_init(void)
61
{
62
    UCSR0B |= (1<<TXEN0);  // UART TX einschalten
63
    UCSR0C |= (1<<UCSZ00)|(1<<UCSZ01);  // Asynchron 8N1 
64
 
65
    UBRR0H = UBRR_VAL >> 8;
66
     UBRR0L = UBRR_VAL & 0xFF;
67
}

Allerdings wirft er dann den Error(der ja auch gewollt ist) raus, dass 
die Baudrate zu sehr abweicht.

von Carsten (Gast)


Lesenswert?

Ich habe mittlerweile auch schonmal getestet, ob der Quarz verwendet 
wird. Habe dazu die LED Blink funktion übernommen, 16 Mhz eingestellt 
und dann noch zusätzlich bei AVR Studio unter "Fuses"-> "SUT_CKSEL"
einen "Ext. Crystal Osc. 8.0 -    MHz;Startuptime 258 CK,+4.1ms" 
ausgewählt und zusätzlich bei CKDIV8 keinen Haken gesetzt.

Die LED blinkt exakt jede Sekunde.

von g457 (Gast)


Lesenswert?

> Allerdings wirft er dann den Error(der ja auch gewollt ist) raus, dass
> die Baudrate zu sehr abweicht.

Das sollte eigentlich nicht. 16MHz und 9600 Baud, da sollte der Fehler 
bei etwa 0.2% liegen (das ist noch im grünen Bereich).

Achja wie Du die Fuses korrekt setzen musst (willst..), das steht im 
Datenblatt (Kapitel 6 'System clock and clock options'). Mit der 
langsamsten Startup-time macht man sicher nichts verkehrt.

..und schick mal etwas mehr als immer nur ein einzelnes Zeichen, z.B. 
so:
1
while (1)
2
{
3
   while(!(UCSR0A & (1<<UDRE0)))
4
   {}
5
  
6
   UDR0 = 'e';
7
   _delay_ms(100);  // <- hierfür brauchts noch ein #include <util/delay.h>
8
}

von Carsten (Gast)


Lesenswert?

Danke für die Tipps, nach einigem rumprobieren habe ich das Problem 
gefunden. Ich muss in der Zeile
1
#define BAUD 9600UL      // Baudrate

den Wert auf 600 setzen. Dann funktioniert alles, wenn ich im 
Empfangsprogramm 9600 auswähle. Irgendwo scheint da ein Faktor in der 
Berechnung nicht zu stimmen. Mir egal, es funktioniert!

danke an alle

von spess53 (Gast)


Lesenswert?

Hi

Das ist ein Faktor von 16. Sollte zu Denken geben. Steht bei dir noch 
irgendwo 1MHz als Controllertakt?

MfG Spess

von Carsten (Gast)


Lesenswert?

Aber wo sollte das sein, wenn nicht im Programm selbst? Im Makefile ist 
auch nichts erkenbares ind er Hinsicht zu finden

von g457 (Gast)


Lesenswert?

..Faktor 16.. das könnte auch CKDIV8 mit Double-speed-UART sein.. 
irgendwo(tm) ist da jedenfalls noch der Wurm drin :-)

Achja wenn du wissen willst, ob Dein F_CPU tatsächlich auf 16MHz steht 
(oder doch noch irgendwo versaut wird), dann füg bei der 
Baudratenberechnung (und ggf. auch mal bei der 
LED-blinkt-im-Sekundentakt-Routine) ein Statement à la
1
#if F_CPU == 16000000UL
2
#error ..iss wirklich 16MHz
3
#else
4
#error ..Pustekuchen..
5
#endif

Warum der Umweg? Tja, leider war es den Erfindern von C/.. nicht 
möglich, eine gute Lösung für das 'Ich will wissen welchen Wert mein 
Define hier an genau dieser Stelle im Code tatsächlich hat'-Problem zu 
finden. Kleiner (nerviger) Workaround und man kanns zumindest auf 
gewünschte (bekannte) Werte abtesten.

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.