Hallo an alle,
erst mal ich bin ein absoluter Neuling in diesem Gebiet, verzeicht mir
also bitte meine (Anfänger-) Fehler =)
Ich möchte Daten zwischen einem Terminal (PC über RS-232) und meinem
Mikrocontroller (ATMEGA 164 PA) austauschen. Beim senden vom atmega an
den PC sehe ich die Zeichen auch auf dem Terminal, nur das empfangen
klappt nicht so recht
Programmaufbau (theoretisch):
UART initialisieren
leere Endlosschleife
Interrupt wenn Controller Daten senden soll (TX)
Interrupt wenn Controller Daten empfangen soll (RX)
Die Daten sollen dann entweder direkt in der ISR gesendet/empfangen
werden oder in der ISR soll ein Flag gesetzt werden, welches dann in der
Endlosschleife überprüft wird.
Ich hoffe das war jetzt verständlich...wär lieb wenn jemand helfen
könnte
danke schon mal an alle
Hier noch mein Codevorschlag:
das ist Quatsch.
Erst mal: lass die Enable Bits in Ruhe. Zweites brauchst du auch nicht
prüfen, ob etwas empfangen wurde. Die ISR wurde aufgerufen WEIL etwas
empfangen wurde - d.h. du weißt an dieser Stelle, dass was da ist.
Drittens: wozu die for-Schleife? Der Interrupt wird für jedes Zeichen
einzeln aufgerufen und ja - du MUSST das UDR auslesen.
ISR (USART0_RX_vect)
{
char c = UDR;
// mach was mit c
}
und lass die ENable Bits in Ruhe! Wenn die UART aktiv ist, dann bleibt
sie auch die ganze Zeit aktiv.
Also entweder entscheidest du dich für einen Empfang per Interrupt oder
per Polling. Momentan schmeisst du beides zusammen.
Hast du dich bei deinem Programm an den Besipielen im Datenblatt
orientiert?
Danke schon mal für die Hilfe...
eigentlich würde ich das ganze gern Interrupt-gesteuert machen
orientiert habe ich mich am Datenblatt...wenn ich das allerdings
übernommen habe, hat das bei mir nicht funktioniert =(
Hier die Funktion für das Empfangen aus dem Datenblatt
unsigned char USART_Receive( void )
{
/* Wait for data to be received */
while ( !(UCSRnA & (1<<RXCn)) );
/* Get and return received data from buffer */
return UDRn;
}
@ Karl Heinz Buchegger:
danke für den Tipp, wie gesagt bin blutiger Anfänger, unerfahren und
noch etwas verwirrt =( hab das mal so ausprobiert, leider kann ich immer
noch nichts empfangen, bin ich echt so blöd =(
ist .... ich sags nicht, was mir da auf der Zunge liegt.
Das ist eine rekursive Funktion, ist dir das bewusst, was damit
zusammenhängt?
Ausserdem ist das viel zu kompliziert
1
voidsendenByte(unsignedchardata)
2
{
3
while(!(UCSR0A&(1<<UDRE0))
4
;
5
6
UDR0=data;
7
}
das ist eine Funktion, die 1 Byte versendet. Wenn du mehrere Bytes
verschicken willst, dann rufst du die Funktion eben mehrfach auf:
1
voidsendeMehrfach(unsignedcharc)
2
{
3
uint8_ti;
4
5
for(i=0;i<8;++i)
6
sendenByte(c);
7
}
Aber du musst VOR jeder Ausgabe an UDR prüfen, ob dir UDRE0 das
überhaupt erlaubt. Du kannst nicht einfach 30 Bytes an UDR0 zuweisen.
Der letzte Ansatz gewährleistet das, weil sendenByte genau das tut: Bei
jedem einzelnen Byte so lange zuzuwarten, bis die UART wieder frei ist.
Also ich hab mal einen Breakpoint in die ISR gesetzt, leider wird die
bei mir nie ausgeführt, der Sprung in den Interrupt wird durchgeführt...
Kann es sein dass "USART0_RX_vect" nie wahr wird, muss ich dafür erst
etwas gesendet haben um in diese ISR zu kommen?
Tut mir Leid wenn ich mich so blöd anstelle, aber ich weiß es wirklich
nicht besser, hab davor eher Java, etc. gemacht
Hast du irgendwelche Warnungen vom Compiler.
Irgendwas in Richtung: xxxxx seems to be an illegal Interrupt Name
> ISR (USART0_RX_vect)
meistens heißt die irgendwas in Richtung
ISR (USART0_RXC_vect)
RX steht für Receive und das C für Complete. Genau aus dem Grund heißt
ja auch die Freigabe für den Interrupt
> UCSR0B = (1<<RXEN0)|(1<<TXEN0)|(1<<RXCIE0);
RXCIE0
RX Receive
C Complete
I Interrupt
E Enable
0 der UART 0
Lisa K. schrieb:> @ Karl Heinz Buchegger:> danke für den Tipp, wie gesagt bin blutiger Anfänger, unerfahren und> noch etwas verwirrt =( hab das mal so ausprobiert, leider kann ich immer> noch nichts empfangen, bin ich echt so blöd =(
Dann solltest du vielleicht nicht gerade gleich mal mit Interrupts
einsteigen.
AVR-GCC-Tutorial
Errors habe ich nicht, aber 2 Warnings:
#warning "F_CPU not defined for <util/delay.h>"
Warning unused variable 'c'
xxxxx seems to be an illegal Interrupt Name kommt bei mir nicht
Stimmt.
Der Vector heisst wirklich
#define USART0_RX_vect _VECTOR(20)
(zu finden in iomxx4.h welches von iom64.h includiert wird, welches von
io.h includiert wird - wenn die µC Einstellung stimmt.)
> //Interrupts enable, receiver und transmitter enable> UCSR0B = 0xF8;
Was macht das alles?
Mach deine erste Kommunikation erst mal ohne INterrupts, ok?
Karl Heinz Buchegger schrieb:>> //Interrupts enable, receiver und transmitter enable>>> UCSR0B = 0xF8;
das sollte laut Registerbeschreibung (wenn ich das so richtig verstanden
habe) RXC Interrupt, TXC Interrupt und UDR empty Interrupt aktivieren,
sowie den Empfänger und den Sender aktivieren
OK.
Paule hats oben schon gesagt: du hast da einen höllischen Mischmasch
veranstaltet.
Langsam vorgehen. Eins nach dem anderen.
Geh von deiner Polling Lösung aus und mach erst mal nur den
Empfangsinterrupt.
> UCSR0B=0x18;> //asynchroner Modus, kein Parity, 1 Stop Bit, 8 Datenbits
Bitte nicht.
Die Bits haben Namen. Niemand hier hat Lust, das Datenblatt zu wälzen
nur um rauszufinden, welche BIts du benutzt hast.
Im AVR-GCC-Tutorial gibt es einen Abschnitt über den UART. Orientier
dich daran.
Also ich hab das Ganze jetzt noch eine Weile probiert, finde das gar
nicht so einfach wie alle immer sagen :D
Danke noch an Uwe S. für das Datenblatt
Hier noch mal mein bisheriger Code (der leider immer noch nicht
funktioniert)
1
//Header einbinden
2
#include<avr/io.h>
3
#include<util/delay.h>
4
#include<stdint.h>
5
#include<avr/interrupt.h>
6
7
//Definitionen
8
#define RXB8 1
9
#define TXB8 0
10
#define UPE 2
11
#define OVR 3
12
#define FE 4
13
#define UDRE 5
14
#define RXC 7
15
16
#define FRAMING_ERROR (1<<FE)
17
#define PARITY_ERROR (1<<UPE)
18
#define DATA_OVERRUN (1<<OVR)
19
#define DATA_REGISTER_EMPTY (1<<UDRE)
20
#define RX_COMPLETE (1<<RXC)
21
22
23
//Prototypen der Funktionen
24
voidUSART_Init(void);
25
voidsendenByte(unsignedchardata);
26
voidsendeMehrfach(unsignedcharc);
27
28
//Variablen deklarieren
29
charreceivedData;
30
31
intmain(void)
32
{
33
34
//UART initialisieren
35
USART_Init();
36
//Interrupts aktivieren
37
//SREG |= (1<<7);
38
39
40
while(1)
41
{
42
sendenByte(0xAA);
43
}
44
}
45
46
voidUSART_Init(void)
47
{
48
//Baudrate setzen: 8MHz, 9600 baud
49
//33 hex nach Datenblatt-Tabelle
50
UBRR0H=0x0;
51
UBRR0L=0x33;
52
//Interrupts enable
53
UCSR0B|=(1<<RXCIE0);
54
UCSR0B|=(1<<TXCIE0);
55
UCSR0B|=(1<<UDRIE0);
56
//Receiver und Transmitter enable
57
UCSR0B|=(1<<RXEN0);
58
UCSR0B|=(1<<TXEN0);
59
//asynchroner modus, kein parity bit, 1 stop bit, 8 datenbits
60
UCSR0C|=(1<<UCSZ01);
61
UCSR0C|=(1<<UCSZ00);
62
63
}
64
65
voidsendenByte(unsignedchardata)
66
{
67
while(!(UCSR0A&(1<<UDRE0)))
68
;
69
70
UDR0=data;
71
}
72
73
74
voidsendeMehrfach(unsignedcharc)
75
{
76
uint8_ti;
77
78
for(i=0;i<8;++i)
79
sendenByte(c);
80
}
81
82
83
//Daten erhalten (wenn es ungelesene Daten gibt, diese empfangen)
84
ISR(USART0_RX_vect)
85
{
86
receivedData=UDR0;
87
}
Allerdings habe ich es noch nie geschafft, dass mit USART0_RX_vect oder
USART0_TX_vect ein Interrupt ausgelöst wird. Bisher hat das bei mir nur
mit USART0_UDRE_vect geklappt. Woran könnte das liegen oder was mache
ich alles falsch?
Senden klappt inzwischen leider auch nicht mehr =(
Hallo Lisa.
wie Karl-Heinz schon schrieb, mache es erstmal ohne Interrupts.
Auch darfst Du nicht gleich alle ISR frei schalten, dann fehlen noch die
passenden ISR dazu und du musst auch verstehen, wann einer der ISR frei
geschaltet werden darf !
Lisa K. schrieb:> //Interrupts enable> UCSR0B |= (1 << RXCIE0);> UCSR0B |= (1 << TXCIE0);> UCSR0B |= (1 << UDRIE0);
Hüte dich vor solchen Rundumschlägen!
Wenn du einen INterrupt freigibst, dann MUSS es dafür auch eine ISR
geben! Das ist ganz wichtig. Denn wenn du keine ISR dafür hast, dann
tritt ein Default in Kraft, der zu einem µC-Reset führt!
Eventuell ist es für dich sinnvoll, am Programmstart, nachdem die UART
initialisiert wird, erst mal einen bekannten Text (oder zeichen)
auszugeben, damit dir solche Dinge nicht verborgen bleiben
1
voidsendeString(char*text)
2
{
3
while(*text)
4
sendenByte(*text++);
5
}
6
7
8
intmain(void)
9
{
10
//UART initialisieren
11
USART_Init();
12
13
14
sendeString("Reset\n");
15
16
//Interrupts aktivieren
17
//SREG |= (1<<7);
18
19
sei();// <------
20
21
while(1)
22
{
23
sendenByte(0xAA);
24
}
25
}
Das geht allerdings nur so lange, solange du das Senden noch nicht über
Interrupts abwickelst. Denn dann geht natürlich vor den sei() erst mal
auch das Senden nicht. Aber bis dahin ist ja noch Zeit.
Ok also hier noch die abgeänderte Polling-Version:
1
//Header einbinden
2
#include<avr/io.h>
3
#include<util/delay.h>
4
#include<stdint.h>
5
6
//Definitionen
7
#define RXB8 1
8
#define TXB8 0
9
#define UPE 2
10
#define OVR 3
11
#define FE 4
12
#define UDRE 5
13
#define RXC 7
14
15
#define FRAMING_ERROR (1<<FE)
16
#define PARITY_ERROR (1<<UPE)
17
#define DATA_OVERRUN (1<<OVR)
18
#define DATA_REGISTER_EMPTY (1<<UDRE)
19
#define RX_COMPLETE (1<<RXC)
20
21
22
23
//Prototypen der Funktionen
24
voidinitUART(void);
25
voidsendenByte(unsignedchardata);
26
voidsendeMehrfach(unsignedcharc)´;
27
unsignedcharempfangenByte(void);
28
voidsendeString(char*text);
29
30
//Variablen deklarieren
31
unsignedcharausgabe;
32
intbaud=9600;
33
34
35
intmain(void)
36
{
37
initUART();
38
39
sendeString("Reset\n");
40
41
//Interrupts aktivieren
42
sei();
43
44
while(1)
45
{
46
//Daten senden
47
sendenByte(0xAA);
48
49
}
50
}
51
52
voidUSART_Init(void)
53
{
54
//Baudrate setzen: 8MHz, 9600 baud --> 33 hex nach Datenblatt-Tabelle
55
UBRR0H=0x0;
56
UBRR0L=0x33;
57
//Interrupts enable
58
UCSR0B|=(1<<RXCIE0);
59
UCSR0B|=(1<<TXCIE0);
60
UCSR0B|=(1<<UDRIE0);
61
//Receiver und Transmitter enable
62
UCSR0B|=(1<<RXEN0);
63
UCSR0B|=(1<<TXEN0);
64
//asynchroner modus, kein parity bit, 1 stop bit, 8 datenbits
65
UCSR0C|=(1<<UCSZ01);
66
UCSR0C|=(1<<UCSZ00);
67
68
}
69
70
71
voidsendenByte(unsignedchardata)
72
{
73
while(!(UCSR0A&(1<<UDRE0)))
74
;
75
76
UDR0=data;
77
}
78
79
80
voidsendeMehrfach(unsignedcharc)
81
{
82
uint8_ti;
83
84
for(i=0;i<8;++i)
85
sendenByte(c);
86
}
87
unsignedcharempfangenByte(void)
88
{
89
unsignedchardata;
90
//solange RXC noch nicht gesetzt Daten empfangen
91
while(UCSR1A|(1<<RXC1))
92
{
93
//Daten empfangen
94
}
95
data=UDR1;
96
returndata;
97
}
98
voidsendeString(char*text)
99
{
100
while(*text)
101
sendenByte(*text++);
102
}
jetzt war ich nur so blöd und hab nicht ganz verstanden, was ich mit der
sendeString Funktion anstellen soll...so wie ich das sehe, wird da reset
übergeben...und solange ( *text ) soll diese Übergabevariable gesendet
werden? Weiß nicht ob ich das o richtig verstanden habe, aber danke für
deine Hilfe
Wenn ich den Code nun compilieren will, bekomme ich den Error
stray'\246' in programm bei der Funktion sehndeMehrfach. Als ich nach
dieser Fehlermeldung gegoolet habe, hieß es, dass keine boolean-Werte in
Char gespeichert werden dürfen. Aber wo mache ich das?
Vielen Dank noch mal für eure Hilfe und Gedult
Hallo,
ich will dich noch auf diesen Fehler hinweisen:
UCSR0A != UCSR1A
==> es gibt zwei usart im µC !
Also musst du auch die richtigen Pins beschalten !!!!
er meint das da ...
Lisa K. schrieb:> unsigned char empfangenByte( void )> {> unsigned char data;> //solange RXC noch nicht gesetzt Daten empfangen> while (UCSR1A | (1 << RXC1))> {> //Daten empfangen> }> data = UDR1;> return data;> }
du willst auf UART1 empfangen und auf UART0 senden ...
bitte entscheide dich ^^
das mit UART1 war versehentlich noch drin...aber inzwischen geht ja
leider nicht mal mehr das senden...empfangen wurde in diesem Code ja gar
nicht aufgerufen...
Hier trotzdem noch mal in verbesserter Form:
Hallo,
hast Du dir mal die MÜHE gemacht und das Datenblatt "gegen" deinen Code
abgeglichen, um zu verstehen was da eigentlich passiert ?
Nicht einfach probieren, sondern alles 1 zu 1 im Datenblatt nachlesen,
verstehen und auf deiner Checkliste abhaken !
Also was und wie bewirkt das Bit RXCIE0 in UCSR0B, wenn es 1 ist ?