Forum: Mikrocontroller und Digitale Elektronik UART bei atmega8


von Tim (Gast)


Lesenswert?

Hallo,

ich möchte UART an einem atmega8 nutzen. Der folgende Code soll dabei 
alle einkommenen Zeichen zurücksenden. Ich nutze ein fertiges Board von 
"myavr", Quarz ist, ~3,68 MHz.

Leider funktioniert das ganze nicht und finde keinen Fehler im 
Quellcode:



1
#include  <avr\io.h>    // AVR Register und Konstantendefinitionen
2
#include   <util\delay.h>  // Bibliothek mit Warteroutinen
3
#include <stdint.h>
4
#define   F_CPU 3686400  // Taktfrequenz des myAVR-Boards
5
6
7
// Define baud rate
8
9
#define USART_BAUD 9600ul
10
11
#define USART_UBBR_VALUE ((F_CPU/(USART_BAUD<<4))-1)
12
13
14
void USART_vInit(void)
15
16
{
17
18
// Set baud rate
19
20
UBRRH = (uint8_t)(USART_UBBR_VALUE>>8);
21
22
UBRRL = (uint8_t)USART_UBBR_VALUE;
23
24
25
// Set frame format to 8 data bits, no parity, 1 stop bit
26
27
UCSRC = (0<<USBS)|(1<<UCSZ1)|(1<<UCSZ0);
28
29
30
// Enable receiver and transmitter
31
32
UCSRB = (1<<RXEN)|(1<<TXEN);
33
34
}
35
36
37
void USART_vSendByte(uint8_t u8Data)
38
39
{
40
41
// Wait if a byte is being transmitted
42
43
while((UCSRA&(1<<UDRE)) == 0);
44
45
// Transmit data
46
47
UDR = u8Data;
48
49
}
50
51
52
uint8_t USART_vReceiveByte()
53
54
{
55
56
// Wait until a byte has been received
57
58
while((UCSRA&(1<<RXC)) == 0);
59
60
// Return received data
61
62
return UDR;
63
64
}
65
66
67
int main(void)
68
69
{
70
71
uint8_t u8Data;
72
73
74
// Initialise USART
75
76
USART_vInit();
77
78
79
// Send string
80
81
USART_vSendByte('A');
82
83
// Repeat indefinitely
84
85
for(;;)
86
87
{
88
89
// Echo received characters
90
91
u8Data  = USART_vReceiveByte();
92
93
USART_vSendByte(u8Data);
94
95
}
96
97
}

von Justus S. (jussa)


Lesenswert?

Tim schrieb:


> UCSRC = (0<<USBS)|(1<<UCSZ1)|(1<<UCSZ0);

-> Datenblatt!

von Andreas G. (andreasguter)


Lesenswert?

Was soll man den mit so einer Meldung anfangen? Wenn man offenkundig die 
Antwort weiß, darf man sie auch sagen.

von Stefan B. (Gast)


Lesenswert?

> UCSRC = (0<<USBS)|(1<<UCSZ1)|(1<<UCSZ0);

Was meint dein Datenblatt deines Atmega8 zu dem Bit URSEL in dieser 
Initialisierungsequenz?

von Stefan B. (Gast)


Lesenswert?

Solch kurze Hinweise sollen das Durchlesen des Datenblatts fördern. Das 
Datenblatt muss die Bibel des µC-Programmierers werden.

von Justus S. (jussa)


Lesenswert?

Andreas Guter schrieb:
> Was soll man den mit so einer Meldung anfangen?

Offenkundig ins Datenblatt schauen, was da zu dem Register steht...

von Sebastian M. (noobuntu)


Lesenswert?

Stefan B. schrieb:
> Was meint dein Datenblatt deines Atmega8 zu dem Bit URSEL in dieser
> Initialisierungsequenz?

• Bit 7 – URSEL: Register Select
This bit selects between accessing the UCSRC or the UBRRH Register. It 
is read as one whenreading UCSRC. The URSEL must be one when writing the 
UCSRC.

von Tim (Gast)


Lesenswert?

Hallo,

ich habe das Datenblatt nach URSEL durchsucht. Das Ergebnis findet sich 
im folgendem Screenshot:
http://img695.imageshack.us/img695/5830/bildschirmfotou.png

von Tim (Gast)


Lesenswert?

Und was kann ich jetzt mit der Information anfangen vor der Hintergrund, 
dass das Bit URSEL in meinem Code nicht vorkommt?

von Grisu (Gast)


Lesenswert?

Tim schrieb:
> Und was kann ich jetzt mit der Information anfangen vor der Hintergrund,
> dass das Bit URSEL in meinem Code nicht vorkommt?

IM DATENBLATT NACHLESEN, WAS DAS BIT URSEL MACHT!!!!!!!!!!!!!!!!! HASTES 
JETZT?

von Justus S. (jussa)


Lesenswert?

Tim schrieb:
> Und was kann ich jetzt mit der Information anfangen vor der Hintergrund,
> dass das Bit URSEL in meinem Code nicht vorkommt?

seufz schau doch einfach, was beim USCRC-Register steht, wie es 
gesetzt wird...ist Lesen denn so schwer?

von Sebastian M. (noobuntu)


Lesenswert?

Hallo Tim,

das habe ich im Datenblatt auf Seite 152 gefunden:

The UBRRH Register shares the same I/O location as the UCSRC Register. 
Therefore some special consideration must be taken when accessing this 
I/O location.
When doing a write access of this I/O location, the high bit of the 
value written, the USART Register. Select (URSEL) bit, controls which 
one of the two registers that will be written. If URSEL is zero during a 
write operation, the UBRRH value will be updated. If URSEL is one, the 
UCSRC setting will be updated.
The following code examples show how to access the two registers.
1
/* Set UBRRH to 2 */
2
UBRRH = 0x02;
3
...
4
/* Set the USBS and the UCSZ1 bit to one, and */
5
/* the remaining bits to zero. */
6
UCSRC = (1<<URSEL)|(1<<USBS)|(1<<UCSZ1);
7
...

Sprich wenn du in dein UCSRC Register schreiben willst, musst du erst 
das Bit URSEL auf 1 setzen. Sonst schreibst du in UBRRH (und veränderst 
dadurch deine Baudrate -> da bin ich mir jetzt nicht so sicher, als 
lyncht mich nicht sofort.)

von Andreas G. (andreasguter)


Lesenswert?

Probere mal folgendes

UCSRC = (1<<URSEL)|(1<<USBS)|(1<<UCSZ1);

von Tim (Gast)


Lesenswert?

Ist es also so richtig?
1
#include  <avr\io.h>    // AVR Register und Konstantendefinitionen
2
#include   <util\delay.h>  // Bibliothek mit Warteroutinen
3
#include <stdint.h>
4
#define   F_CPU 3686400  // Taktfrequenz des myAVR-Boards
5
6
7
// Define baud rate
8
9
#define USART_BAUD 9600ul
10
11
#define USART_UBBR_VALUE ((F_CPU/(USART_BAUD<<4))-1)
12
13
14
void USART_vInit(void)
15
16
{
17
18
// Set baud rate
19
20
UBRRH = (uint8_t)(USART_UBBR_VALUE>>8);
21
22
UBRRL = (uint8_t)USART_UBBR_VALUE;
23
24
25
// Set frame format to 8 data bits, no parity, 1 stop bit
26
27
28
29
30
31
//Hier die Änderung:
32
33
34
UBRRH = 0x02;
35
36
UCSRC = (1<<URSEL)|(1<<USBS)|(1<<UCSZ1);
37
38
39
//Änderungende
40
41
42
43
44
45
46
// Enable receiver and transmitter
47
48
UCSRB = (1<<RXEN)|(1<<TXEN);
49
50
}
51
52
53
void USART_vSendByte(uint8_t u8Data)
54
55
{
56
57
// Wait if a byte is being transmitted
58
59
while((UCSRA&(1<<UDRE)) == 0);
60
61
// Transmit data
62
63
UDR = u8Data;
64
65
}
66
67
68
uint8_t USART_vReceiveByte()
69
70
{
71
72
// Wait until a byte has been received
73
74
while((UCSRA&(1<<RXC)) == 0);
75
76
// Return received data
77
78
return UDR;
79
80
}
81
82
83
int main(void)
84
85
{
86
87
uint8_t u8Data;
88
89
90
// Initialise USART
91
92
USART_vInit();
93
94
95
// Send string
96
97
USART_vSendByte('A');
98
99
// Repeat indefinitely
100
101
for(;;)
102
103
{
104
105
// Echo received characters
106
107
u8Data  = USART_vReceiveByte();
108
109
USART_vSendByte(u8Data);
110
111
}
112
113
}

von Sebastian M. (noobuntu)


Lesenswert?

Denke schon. Funktioniert es jetzt ?

von Stefan B. (Gast)


Lesenswert?

Nicht richtig.

// Set frame format to 8 data bits, no parity, 1 stop bit
UCSRC = (1<<URSEL)|(1<<USBS)|(1<<UCSZ1);

Du hast bei dieser Initialisierung nicht 8-Datenbits und nicht 1 
Stoppbit.

von Tim (Gast)


Lesenswert?

Achso. Und warum nicht?
Wie muss es richtig heißen?

von Stefan B. (Gast)


Lesenswert?

Mit solchen Fragen 1 Min. später ohne jegliche Initiative selbst im 
Datenblatt zu lesen machst du dich nicht beliebt.

// Set frame format to 8 data bits, no parity, 1 stop bit
UCSRC = (1<<URSEL)|(0<<USBS)|(1<<UCSZ1)|(1<<UCSZ0);

Over and out.

von Ben _. (burning_silicon)


Lesenswert?

übrigens ist 8N1 oft die standardeinstellung, die der AVR von sich aus 
nach dem anlegen der betriebsspannung einnimmt. wenn man also nichts 
anderes braucht erübrigt sich eine änderung dieser werte.

von Tim (Gast)


Lesenswert?

Danke, leider funktioniert es weiterhin nicht:
1
#include  <avr\io.h>    // AVR Register und Konstantendefinitionen
2
#include   <util\delay.h>  // Bibliothek mit Warteroutinen
3
#include <stdint.h>
4
#define   F_CPU 3686400  // Taktfrequenz des myAVR-Boards
5
6
7
// Define baud rate
8
9
#define USART_BAUD 9600ul
10
11
#define USART_UBBR_VALUE ((F_CPU/(USART_BAUD<<4))-1)
12
13
14
void USART_vInit(void)
15
16
{
17
18
// Set baud rate
19
20
UBRRH = (uint8_t)(USART_UBBR_VALUE>>8);
21
22
UBRRL = (uint8_t)USART_UBBR_VALUE;
23
24
25
// Set frame format to 8 data bits, no parity, 1 stop bit
26
27
28
29
30
31
//Hier die Änderung:
32
33
UCSRC = (1<<URSEL)|(0<<USBS)|(1<<UCSZ1)|(1<<UCSZ0);
34
35
//Änderungende
36
37
38
39
40
41
42
// Enable receiver and transmitter
43
44
UCSRB = (1<<RXEN)|(1<<TXEN);
45
46
}
47
48
49
void USART_vSendByte(uint8_t u8Data)
50
51
{
52
53
// Wait if a byte is being transmitted
54
55
while((UCSRA&(1<<UDRE)) == 0);
56
57
// Transmit data
58
59
UDR = u8Data;
60
61
}
62
63
64
uint8_t USART_vReceiveByte()
65
66
{
67
68
// Wait until a byte has been received
69
70
while((UCSRA&(1<<RXC)) == 0);
71
72
// Return received data
73
74
return UDR;
75
76
}
77
78
79
int main(void)
80
81
{
82
83
uint8_t u8Data;
84
85
86
// Initialise USART
87
88
USART_vInit();
89
90
91
// Send string
92
93
USART_vSendByte('A');
94
95
// Repeat indefinitely
96
97
for(;;)
98
99
{
100
101
// Echo received characters
102
103
u8Data  = USART_vReceiveByte();
104
105
USART_vSendByte(u8Data);
106
107
}
108
109
}

von Karl H. (kbuchegg)


Lesenswert?

Tim schrieb:
> Danke, leider funktioniert es weiterhin nicht:


Du sendest am Anfang ein einzelnes 'A'.
Siehst du das auf der anderen Seite?

Was ist wenn du den µC einfach mal ständig 'A' senden lässt? Kommen die 
auf der anderen Seite richtig an?

Und bitte: Zieh den Code doch nicht so in die Länge! Code wird nicht 
übersichtlicher, wenn man mehr Leerzeilen einfügt. Er zieht sich nur in 
die Länge und sonst gar nichts. Wenn du Übersicht haben willst, dann 
kümmere dich um die Einrückungen.

von Andreas G. (andreasguter)


Lesenswert?

Nein, es kommt rein gar nichts an. Weder die As, noch die 
Repeater-Funktion.
Ich mache das ganze übrigens mit hterm unter Windows Vista, da ich kein 
anderes Betriebssystem zu Verfügung habe.

von Karl H. (kbuchegg)


Lesenswert?

Andreas Guter schrieb:
> Nein, es kommt rein gar nichts an. Weder die As, noch die
> Repeater-Funktion.
> Ich mache das ganze übrigens mit hterm unter Windows Vista, da ich kein
> anderes Betriebssystem zu Verfügung habe.

Dann solltest du fürs erste den Repeater zur Seite legen und dich nur 
auf das Senden konzentrieren (eine Fehlerquelle weniger).

http://www.mikrocontroller.net/articles/AVR_Checkliste#UART.2FUSART

Insebsondere könntest du mit dem vorletzten Punkt im Abschnitt "Sonstige 
Fehlerquellen bei UART/USART" anfangen und zunächst feststellen ob die 
Hardware-Kette vom µC zum PC in Ordnung ist, bzw. ob das Kabel korrekt 
ausgekreuzt ist. Diesen Test würde ich dir zur Sicherheit sowieso 
empfehlen. Solange dieser Test nicht einwandfrei klappt, hat es keinen 
Sinn nach anderen Ursachen zu fahnden.
Also: Mega8 aus dem Sockel raus. RX/TX im Sockel mit einem Stück Draht 
verbinden und im hTerm drauflosklimpern. Alles was du tippst, muss im 
hTerm auch aufscheinen. Gegentest machen: Drahtbrücke entfernen. Jetzt 
darf Getipptes im hTerm nicht mehr aufscheinen.

von Stefan B. (Gast)


Angehängte Dateien:

Lesenswert?

Das Programm im Anhang ist dein neustes Programm leicht geändert für 
einen Test mit Attiny2313 @ 8 MHz. Dein Programm funktioniert. Ich 
vermute daher ein Hardwareproblem.

Prüfe dein RS232-Kabel.

Bei dem myAVR Board MK1 LPT endet TXD des Atmega auf Pin 3 des 
DB9-Anschlusses. 
http://shop.myavr.de/index.php?ws=download_file.ws.php&dlid=44&filename=produkte/myavr_board_mk1/techb_schaltplan-myavr-board-mk1-lpt.png 
D.h. das Board ist beschaltet sich wie ein PC (DTE Data Terminal 
Equipment). Zur Verbindung zweiter DTEs also myAVR<->PC brauchst du ein 
sog. Nullmodemkabel mit gekreuzten Leitungen.

Bei dem myAVR Board MK2 USB, Version 2.1 ist das im Schaltplan nicht 
offensichtlich. Ich vermute aber, es ist genauso wie beim MK1 
implementiert.

Zusätzlich kannst du noch auf dem myAVR Board CTS/RTS per Jumper 
brücken. Wenn der PC auf Hardwareflusskontrolle eingestellt wäre, würde 
das helfen. Und wenn er nicht auf Hardwareflusskontrolle eingestellt 
ist, schadet es nicht.

Die Übertragungsstrecke (Buchsen, Kabel, MAX232) kannst du ausserdem so 
prüfen: Atmega8 in den Dauerreset versetzen (z.B. Drahtjumper RESET nach 
GND). RXD und TXD sind dann als Eingang geschaltet. Dann Drahtjumper 
zwischen RXD und TXD anbringen. Jedes vom PC aus gesendete Zeichen 
sollte jetzt als Echo zurückkommen. Die drei Buchsen für die Jumper 
sitzen unmittelbar am Atmega8.

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.