Liebes Forum,
ich hänge hier fest und weiß einfach nicht warum:
Ich nutze einen Atmega88P mit einem MAX232 um Daten per UART an meine
RS232 Schnittstelle an den PC zu senden. Ich habe ein kleines
Fertigbauteil aus China, auf dem mein MAX232 sitzt, und mit dem ich
früher schon prima arbeiten konnte, in Assembler, nun will ich in C
arbeiten es will aber einfach nicht klappen. Auf dem Fertigbauteil (so
ne Platine) gibt es auch LEDs die blinken, wenn Daten übertragen werden
(RXD und TXD).
Zum Ablesen der eingehenden Daten benutze ich HTerm.
Das ist mein Code:
#define BAUD_ERROR ((BAUD_REAL*1000)/BAUD) // Fehler in Promille, 1000 = kein Fehler.
12
13
#if ((BAUD_ERROR<990) || (BAUD_ERROR>1010))
14
#error Systematischer Fehler der Baudrate grösser 1% und damit zu hoch!
15
#endif
16
17
void uart_init(void)
18
{
19
UBRR0H = (unsigned char)(UBRR_VAL >> 8);
20
UBRR0L = (unsigned char)(UBRR_VAL & 0xFF);
21
22
UCSR0B |= (1<<TXEN0); // UART TX einschalten
23
UCSR0C = (1<<USBS0)|(3<<UCSZ00);
24
}
25
26
int uart_putc(unsigned char c)
27
{
28
while (!(UCSR0A & (1<<UDRE0))) /* warten bis Senden moeglich */
29
{
30
}
31
32
UDR0 = c; /* sende Zeichen */
33
return 0;
34
}
35
36
37
38
int main (void)
39
{
40
char c;
41
42
uart_init();
43
44
while (1)
45
{
46
for (uint8_t i=0; i<=255; ++i)
47
{
48
c = i;
49
uart_putc( c );
50
// verkuerzt: uart_putc( i + '0' );
51
}
52
}
53
54
return 0; // never reached
55
56
}
In meinem Terminalprogramm kommt nix an, das RXD Lämpchen auf meiner
Platine blinkt fleißig, also dachte ich, wie wärs wenn du das RXD Kabel
des Bauteils an den TXD des Atmegas dran machst und das TXD Kabel des
Bauteils an den RXD des Atmegas: Dann kommt was in meinem Terminal an,
was aber immer abwechselnd "000" bzw. "128" ist. Ich hab geguckt, aber
in meinem HTerm habe ich alle Einstellungen so gelassen wie Sie sind
außer die Baudrate auf 9600 zu setzen.
Kann mir jemand sagen, was ich falsch mache?
Danke,
m.f.G.: K.R.
Klemme den AVR erstmal ab und verbinde am China Modul RxD mit TxD. Dann
schau mit Hterm, ob das, was du sendest auch wieder zurück kommt. Wenn
nicht, könnte dieses teil defekt sein.
Ansonsten stimmt vielleicht die Übertragungsrate nicht. Schwingt der
Quarz wirklich 8Mhz? hast Du vieleicht versehentlich die Fuse CLKDIV8
gesetzt.
Dan kann man mit einer blinkenden LED leicht testen:
1
while (1) {
2
led an machen;
3
_sleep_ms(1000);
4
led aus machen;
5
_sleep_ms(1000);
6
}
Die LED muss immer abwechselnd eine Sekunde an und aus sein. Wenn nicht,
stimmt etwas mit dem Taktgeber nicht.
1. Wenn ich RX mit TX vom Chinamodul verbinde, kommt das am PC an was
ich absende, daran liegts nicht.
2. Ja, das war in der Tat gesetzt, ich habs weggemacht
3. Ich habe keinen externen oszillator sondern der internen, und mein
avr studio sowie ein test mit den leds bestätigt, 8 Mhz
Seitdem ich den Fuse verändert habe kommt in Hterm mal "000" mal "192"
an, aber wie gesagt nichts sinnvolles.
Danke für deine hilfe, würde dir noch was einfallen woran es liegen
könnte?
2 Stopbits ? ist das gewollt?
> Ich hab geguckt, aber> in meinem HTerm habe ich alle Einstellungen so gelassen wie Sie sind> außer die Baudrate auf 9600 zu setzen.
HTerm ist per Default auf einem Stopbit.
Ich weiß zwar nicht ob das schon weiterhilft, aber das fiel mir nur
gerade spontan auf.
Du hast recht, ich habe jetzt hterm auf 2 umgestellt, hat nicht
geklappt,
Dann habe ich hterm wieder auf 1 stopbit umgestellt und es mit folgender
ersatzzeile versucht:
1
UCSR0C = (1<<UMSEL01)|(1<<UCSZ01)|(1<<UCSZ00);
Klappt aber auch nicht :?
Noch jemand eine Idee?
Danke für eure Hilfe,
m.f.G.: K.R.
Bernhard F. schrieb:> Ich weiß zwar nicht ob das schon weiterhilft
Mehr Stopbits zu senden, als der Empfänger erwartet, ist nie ein
Problem.
@ K. R.:
Mach mal eine Pause (1ms) nach dem uart_init().
K. R. schrieb:> Dann habe ich hterm wieder auf 1 stopbit umgestellt und es mit folgender> ersatzzeile versucht:> UCSR0C = (1<<UMSEL01)|(1<<UCSZ01)|(1<<UCSZ00);> Klappt aber auch nicht :?
Und auch das sollst du nicht tun. ATMEL sagt, dass UMSEL01=1 und
UMSEL00=0 RESERVED ist.
Nein, die Fuse ist nicht gesetzt, war, jetzt nicht mehr.
Das ist mein aktueller Code, ich warte jetzt 2 ms nach dem
Initialisieren,
und weiß ehrlich gesagt net was ich ganz konkret im UART Control
Register denn sonst einstellen soll:
O.K. habe mal deinen Code ins Studio geworfen und durchlaufen lassen.
Ergebnis: 4 Warnings mit entsprechenden Messages.
alle sagen "int overflow in Expression" bzw. "in expansion of Macro"
Dazu kommt noch: Wenn irgendwelche undefinierten Zeichen ankommen ist es
meist die Baudrate.
Im Register steht auch eine 0x0162, was ja wohl vollkommen daneben ist.
Versuch mal bitte statt
1
UBRR0H=(unsignedchar)(UBRR_VAL>>8);
2
UBRR0L=(unsignedchar)(UBRR_VAL&0xFF);
einfach
1
UBRRO=51;
und dazu eventuell noch den vorgeschlagenen Delay nach der
Initialisierung.
Was ergibt das ?
K. R. schrieb:> Wie ich darauf komme?>> http://www.atmel.com/images/doc2553.pdf> Seite 8 Tabelle unten.
Da steht nichts davon, dass URSEL nun UMSEL00 heisst. Da steht nur, dass
die alte Position für URSEL mittlerweile für andere Zwecke genutzt wird.
1. Der Code von Frank M funktioniert direkt.
2. Wenn ich UBRR0 = 51 setze klappt es auch.
Erstmal danke für die Antworten, jetzt klappts wuhu! :)
Aber: Warum? Habe ich in das Baudraten register die Baudrate falsch
eingetragen?
Gerade den Beitrag von Frank M. gesehen.
Wer mag mal erkären:
- warum dort die Baudrate als 9600_l_ definiert ist?
- Was das damit zu tun hat, dass 9600 x 16 größer als 65535 ist ?
- Was "int overflow" in diesem Zusammenhang dem Anwender sagen sollte?
Bernhard F. schrieb:> O.K. habe mal deinen Code ins Studio geworfen und durchlaufen lassen.>> Ergebnis: 4 Warnings mit entsprechenden Messages.
In der Tat, da fehlt ein L an der Baudrate.
K. R. schrieb:> 1. Der Code von Frank M funktioniert direkt.
Freut mich. Das Schöne daran ist, dass der nicht nur auf dem ATmega88
funktioniert.
> Aber: Warum? Habe ich in das Baudraten register die Baudrate falsch> eingetragen?
Dann stimmte wohl tatsächlich etwas mit dem Baudratenregister nicht. Ja,
das L fehlte :-)
Deine Methode zur Berechnung ist auch veraltet. Aktuell sollte man
besser die Preprocessor-Konstante BAUD setzen und das Include
<util/setbaud.h> benutzen. Durch Unterstützung von U2X werden dann auch
die Werte benutzt, die am besten zu Deiner F_CPU passen.
Bernhard F. schrieb:> Wer mag mal erkären:> - warum dort die Baudrate als 9600_l_ definiert ist?> - Was das damit zu tun hat, dass 9600 x 16 größer als 65535 ist ?> - Was "int overflow" in diesem Zusammenhang dem Anwender sagen sollte?
Gerechnet wird mit 16-Bit-Integer.
16-Bit-Integer geht von -32768 bis 32767. Alles, was über diesen
Zahlenraum hinausgeht, bedingt einen Overflow.
9600 * 16 ist, ob im Kopf oder auf dem Taschenrechner, 153600.
In 16-Bit-Integer jedoch 22528.
Netterweise gibt es dann besagte Warnung. Ignoriert man die,
funktioniert es nicht.
Macht man in der Berechung einen Faktor long, wird alles mit long
gerechnet. Also von -2147483684 bis 2147483683.
9600L * 16 = 153600. Dann passt das.
mfg.