UART & ATmega324P20PU

Gast #1811629
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!
Angehängte Dateien:
Gast #1811684
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
Gast #1812364
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?
Gast #1812636
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
Gast #1812672
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.
Gast #1812784
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.
Gast #1813184
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
}
Gast #1813672
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
Gast #1813887
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.

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