Hallo,
mein Problem ist, wie der Titel schon aussagt, der UART. Ich möchte
zurzeit entweder Buchstaben oder zahlen an den PC senden. Leider
funktioniert es nicht. Ich benutze den ATMEGA32, das STK500,
Entwicklungsumgebung ist das AVR Studio 4. Habe mir eine "Mini-USB to
UART" vom Conrad gekauft.
http://www.conrad.at/ce/de/product/197326/MINI-USB-TO-UART-CONVERTER
Ich benutze einen externen Quarz(7,3728MHz). Die Fuses habe ich
hoffentlich richtig gesetzt. Ich habe als Clock-Source "Ext.
Crystal/Resonator High Freq.; Start-up time:16K CK+64ms" ausgewählt.
So zum Problem. Wenn ich nun im Hyperterminal (benutze als hyperterminal
hTerm) die empfangen Zeichen anschaue, muss ich leider feststellen, dass
immer falsche zeichen kommen, zB ich sende 22 und es kommt die zahl 27
an.
Hier mein Code:
1
#include<avr/io.h>
2
#include<avr/delay.h>
3
4
#ifndef F_CPU
5
#define F_CPU 7372800UL //Frequency: 7,3728 MHz
6
#endif
7
8
/* ****************************** */
9
/* function prototypes */
10
/* ****************************** */
11
12
voidPort_Init();
13
voidUART_Init(uint16_taBaud,uint8_taU2X);
14
voidUART_Write(charaData);
15
16
17
voidmain(void)
18
{
19
//Port_Init();
20
UART_Init(9600,0);//Init Uart: BaudRate 9600, no double transmission speed
21
while(1)
22
{
23
24
UART_Write('7');
25
26
//test: is frequency true or false
27
//PORTB^=0xFF;
28
//_delay_ms(1000);
29
}
30
}
31
32
33
voidPort_Init()
34
{
35
DDRB=0xFF;
36
PORTB=0x00;
37
}
38
39
voidUART_Init(uint16_taBaud,uint8_taU2X)
40
{
41
UBRRH=0;
42
if(aU2X)
43
{
44
UCSRA|=0x02;//use double Speed
45
UBRRL=((uint32_t)F_CPU/(8*aBaud))-1;//Calculate BaudRate using U2X
46
}
47
else
48
{
49
UCSRA=0;
50
UBRRL=((uint32_t)F_CPU/(16*aBaud))-1;//Calculate BaudRate without U2X
51
}
52
53
UCSRB|=0x18;//Enable Receiver and Transmitter
54
UCSRC|=0x83;//asynchronous mode, 8 data bits, 1 stop bit, no parity bit
55
56
}
57
58
voidUART_Write(charaData)
59
{
60
while(!(UCSRA&0x20));//Wait for empty transmit buffer
Hi,
hast Du auf dem STK500 auch den Oszillator auf den Quarz konfiguriert?
Du kannst auch den RS232 spare connector vom STK500 und dann via COM in
den PC gehen, wenn COM port vorhanden, um mal das MiniUSB Dingens als
Fehlerquelle auszuschliessen.
Apropos MiniDingensfehler: hast Du geprüft, ob Du eine Kommunikation via
Hyperterm und MiniDings herstellen kannst (TestLoop)?
Gruss,
Bernd
Hallo Joschi, ich glaube Du castest da falsch.
Joschi Kraxner schrieb:> void UART_Init(uint16_t aBaud,uint8_t aU2X)>> {>> UBRRH=0;>> if(aU2X)>> {>> UCSRA|=0x02; //use double Speed>> UBRRL=((uint32_t)F_CPU/(8*aBaud))-1; //Calculate BaudRate using U2X>> }>> else>> {>> UCSRA=0;>> UBRRL=((uint32_t)F_CPU/(16*aBaud))-1; //Calculate BaudRate without U2X>> }>>>> UCSRB|=0x18; //Enable Receiver and Transmitter>> UCSRC|=0x83; //asynchronous mode, 8 data bits, 1 stop bit, no parity bit>>>> }
Das UBRRL ist ein 8-Bit Register. Du führst einen CAST auf F_CPU durch
und teilst im Anschluß die 32 Bit-Variable durch eine 16 BIt-Variable.
PCLINT würde dabei meckern.
Außerdem halte ich den CAST von F_CPU für überflüssig, weil F_CPU
bereits ein unsigned long ist!
Du müßtest auch Warnings haben, wie calculation on different
signedness... oder so.
besser wäre UBRRL = (uint8_t) ( F_CPU / (uint32_t)(16*aBaud)) - 1;
Ich benutze die Funktion:
void USART_SetCommBaudRate(unsigned int param_BaudRateToSet,
unsigned long param_ProcessorClockRate)
{
float varl_BaudRateRegister = (param_ProcessorClockRate / (16.0 *
(float) param_BaudRateToSet));
unsigned int varl_IntBRR = (unsigned int) varl_BaudRateRegister;
float varl_Remainder = varl_BaudRateRegister - (float) varl_IntBRR;
/* laut Formel einen abziehen und das im Integer. */
if(varl_Remainder < 0.5)
{
varl_IntBRR --;
}
UBRRL = (unsigned int) (varl_IntBRR & 0x00FF);
UBRRH = (unsigned int) ((varl_IntBRR & 0xFF00) >> 8);
}
Die Fließkommazahlen sind entweder nur während der Laufzeit der Routine
gültig. Der Aufruf wäre so:
USART_SetCommBaudRate(2400,16000000.0);
Bei liefert Sie die erwarteten Baudraten. Auch wenn die Funktion etwas
umständlich geschrieben ist. Aber so konnte ich im Debugger die
Berechnung nachvollziehen. Sie stimmt.
Viel Erfolg.
cskulkw schrieb:> Das UBRRL ist ein 8-Bit Register. Du führst einen CAST auf F_CPU durch> und teilst im Anschluß die 32 Bit-Variable durch eine 16 BIt-Variable.> PCLINT würde dabei meckern.
Mag sein, dass der meckert. Die ganze Operation ist aber eindeutig
definiert. Die Division wird in 32 Bit gemacht.
>> Außerdem halte ich den CAST von F_CPU für überflüssig, weil F_CPU> bereits ein unsigned long ist!
Prinzipiell richtig. Schadet aber auch nichts. Und wenn man bei der
Definition von F_CPU einen Fehler macht, dann sorgt der Cast wenigstens
immer noch für eine 32 Bit unsigned Operation.
Ist ein wenig doppelt gemoppelt, aber bei Sicherheitsleinen schadet das
nicht.
>> Du müßtest auch Warnings haben, wie calculation on different> signedness... oder so.
Wieso sollte er die haben?
>> besser wäre UBRRL = (uint8_t) ( F_CPU / (uint32_t)(16*aBaud)) - 1;
Ist völlig gleichwertig.
Und zwar in allen Belangen.
Edit: stimmt nicht ganz. Dein Ergebnis wird zuerst auf 8 Bit reduziert
und dann 1 abgezogen. Bei ihm läuft eine 32 Bit Subtraktion, wenn der
Compiler nicht erkennt, dass er das runtercasten vorziehen kann, weil
das Ergebnis dasselbe ist.
Arithmetisch sind die beiden Ergebnisse allerdings gleichwertig.
>> Ich benutze die Funktion:>> void USART_SetCommBaudRate(unsigned int param_BaudRateToSet,> unsigned long param_ProcessorClockRate)> {> float varl_BaudRateRegister = (param_ProcessorClockRate / (16.0 *> (float) param_BaudRateToSet));
Ähm.
float?
Das ist jetzt aber nicht dein Ernst.
Seine Funktion ist soweit ok, auch wenn das hier
UCSRB|=0x18; //Enable Receiver and Transmitter
UCSRC|=0x83; //asynchronous mode, 8 data bits, 1 stop bit, no parity
bit
die dümmste Schreibweise ist, die er finden konnte. Und ich werde das
jetzt nicht in Bits aufdröseln um zu sehen, ob er sich da bei einer
Bitposition verhaut hat.
Die Nichtberechnung von UBRRH ist auch nicht wirklich toll, bei seinen
Zahlenwerten aber auch noch kein Problem.
Wenn die Übertragung grundsätzlich läuft, dann ist das schon mal ein
gutes Zeichen, denn dann ist Kabel und dergleichen schon mal kein
Problem mehr.
Kommen falsche Zeichen an, dann liegt das Problem praktisch immer daran,
dass der µC mit einer anderen Frequenz taktet, als mit der gerechnet
wurde.
hallo,
sorry das ich erst jetzt schreibe, habe nicht so schnell antworten
erwartet.
@Bernd: also eine Kommunikation findet statt. Ich empfange ja Zeichen.
nur die passen eben nicht. Ich habe mir eine eigene kleine Miniplatine
gebaut, auf der die Grundschaltung mit externen Quarz schon drauf ist.
jetzt muss ich immer nur den Atmega programmieren und steck den
Controller dann in die Platine. Hab mir gedacht, dass ich es vielleicht
bei späteren Projekten gebrauchen könnte. Also brauch ich nicht den
Oszillator am STK500 konfigurieren, oder?
so zum Rest:
danke für die Funktion. Hab sie auch gleich ausprobiert. Also wenn ich
jetzt zB. ein 'a' sende empfange ich ein a, doch danach ein X, dann
wieder a und wieder X...
also es passt noch nicht ganz. Habe auch versucht ein delay einzubauen,
doch dann kommt wieder ein anderes Zeichen.
Tut mir leid dass ich alles in hexadezimal schreib. Nur ich programmiere
noch nicht so lange mit dem ATMEGA. In der Schule benutzen wir den
LPC935 und die Prof. wollen alle, dass wir hexadezimal schreiben. Werde
aber in den nächsten Tagen in z.B.: UCSRB|=(1<<REN) umändern. Ich glaub
so ca. funktioniert es.
Ja das mit der Frequenz habe ich mir auch immer gedacht. Dann habe ich
ein Licht im Sekundentakt blinken lassen (mit der delay funktion), und
es hat auch im sekundentakt geblinkt. Genau kann ich es nicht
nachschauen, habe kein Oszi daheim.
Habe auch oft gelesen, dass es Probleme mit der Spannungsversorgung
geben kann, benutze aber ein Netzgerät, und die sollte ja schon ziemlich
konstante Spannung liefern.
mfg Joschi
so also ich habe meinen Fehler jetzt gefunden. Ich habe mich bei den
bits wirklich verschaut. Habe mich im Datenblatt auch falsch abgeschaut.
hab nicht 8 bit character size, sondern ein anderen wert ausgewählt.
Jetzt funktioniert alles. Benutze aber noch die Funktion von cskulkw -
möchte auch danke sagen - , denn ich habe es mit meiner zurzeit noch
nicht getestet.
Danke auch noch an alle anderen, dass ihr ziemlich schnell geantwortet
habt.
@Karl Heinz Buchegger: Glaube jetzt auch wirklich, dass es besser wäre,
eine einfachere Schreibweise zu nehmen :)
thread kann glaub ich geschlossen werden.
mfg Joschi
Karl Heinz Buchegger schrieb:> Ähm.>> float?>>>> Das ist jetzt aber nicht dein Ernst.
Doch sehr verehrter Moderator Karl-Heinz. Ich mache das nicht erst seit
gestern. Diesen Code habe ich mehr als einmal mittels Debugger
überprüft.
Wo ist das Problem eine Initialisierungsfunktion mit float-Werten
berechnen zu lassen, solange sie lokal definiert sind? Dann werden sie
nur auf dem Stack angelegt und sind im Betriebsmodus GESCHICHTE !!!!
Aber Herr Moderator weiß das natürlich besser. Also, ich habe keine
Ahnung welche Qualifikation Du hast, aber mach es, wie Du es für richtig
hälst. Übrigens steht der uint32_t Cast genau vor der Konstanten F_CPU.
Dieser Cast endet am Divisor-Operator. Wie gesagt, frage PC-Lint! Ich
habe diese Tool gehasst, aber leider hatte es immer wieder Recht.
Und wie man liest, scheint Joschi jetzt glücklich zu sein.
Frohes Schaffen noch ...