Hallo,
ich bin dabei die Kommunikation über RS232 über den Standard mit
Baudrate=9600 und 8N1 aufzubauen.
Alle Daten, die ich vom µC aus sende kann ich in HTerm am PC empfangen.
Sende ich jedoch vom PC aus etwas an den µC, so kommt dort nichts an.
Ich habe festgestellt, dass der Pegel von RXD am Atmega8 dauerhaft bei
3,53V liegt (mit Digital-Multimeter), egal ob ich was sende oder nicht
(das verwirrt mich)
Meine Schaltung habe ich wie im Tutorial aufgebaut:
http://www.mikrocontroller.net/wikifiles/e/ee/AVR-RS232.png
1
// Definition Taktfrequenz CPU
2
#ifndef F_CPU
3
#warning "F_CPU war noch nicht definiert, wird nun mit 3686400 definiert"
while(!(UCSRA&(1<<UDRE)))/* warten bis Senden moeglich */
53
{
54
}
55
56
UDR=c;/* sende Zeichen */
57
return0;
58
}
59
60
61
/* puts ist unabhaengig vom Controllertyp */
62
voiduart_puts(char*s)
63
{
64
while(*s)
65
{/* so lange *s != '\0' also ungleich dem "String-Endezeichen" */
66
uart_putc(*s);
67
s++;
68
}
69
}
70
71
72
/* Zeichen empfangen */
73
uint8_tuart_getc(void)
74
{
75
while(!(UCSRA&(1<<RXC)))// warten bis Zeichen verfuegbar
76
{
77
PORTB^=(1<<PB0);
78
UDR=UCSRA;
79
_delay_ms(500);
80
}
81
PORTB^=(1<<PB1);
82
UDR=UCSRA;
83
_delay_ms(1000);
84
returnUDR;// Zeichen aus UDR an Aufrufer zurueckgeben
85
}
86
87
voiduart_gets(char*Buffer,uint8_tMaxLen)
88
{
89
uint8_tNextChar;
90
uint8_tStringLen=0;
91
92
NextChar=uart_getc();// Warte auf und empfange das nächste Zeichen
93
94
// Sammle solange Zeichen, bis:
95
// * entweder das String Ende Zeichen kam
96
// * oder das aufnehmende Array voll ist
97
while(NextChar!='\n'&&StringLen<MaxLen-1){
98
*Buffer++=NextChar;
99
StringLen++;
100
NextChar=uart_getc();
101
}
102
103
// Noch ein '\0' anhängen um einen Standard
104
// C-String daraus zu machen
105
*Buffer='\0';
106
}
107
108
109
110
// #######################
111
// #### MAIN-FUNCTION ####
112
// #######################
113
intmain(void)
114
{
115
DDRB=0xFF;
116
PORTB|=(1<<PB0);
117
uart_init();
118
sei();
119
120
while(1)
121
{
122
if(uart_str_complete)
123
{
124
PORTB^=(1<<PB0);
125
}
126
else
127
{
128
PORTB^=(1<<PB1);
129
uart_putc(UCSRA);
130
}
131
uart_str_complete=0;
132
}
133
134
return0;
135
}
Ich verwende einen Quarz mit 3,6864MHz und bin nun schon langsam
verzweifelt, da ich schon seit 4 Tagen an dem Problem sitze und nicht
voran komme.
Ein Loop durch Brücken der Receive- und Transferpins auf der 5V Seite
des MAX232 funktioniert, sodass die Zeichen, die ich vom PC aus sende
auch direkt wieder zurückkommen.
GND vom RS232-USB-Wandler an Pin 5 ist mit dem GND der
Spannungsversorgung für den ATmega8 und dem MAX232 verbunden.
Hi
>und bügelst damit über den PORT B. Wolltest du nicht auch empfangen?
PortB hat nichts mit der UART zu tun. Und selbst wenn, die UART
überbügelt die Porteinstellungen.
MfG Spess
Naja aber die Datenrichtung am Port ist schon entscheidend und ein
Ausgangsport ist nunmal ein Ausgangsport. Woher kommen denn sonst die
3,5xxx Volt am Ausgang? Das hört sich für mich wie logisch high an.
Hi
>Naja aber die Datenrichtung am Port ist schon entscheidend und ein>Ausgangsport ist nunmal ein Ausgangsport. Woher kommen denn sonst die>3,5xxx Volt am Ausgang? Das hört sich für mich wie logisch high an.
Sieh dir mal 'Alternate Port Functions' im Datenblatt an.
MfG Spess
Hi
Ja ich weiß das die alternative Funktion die Portfunktion überschreibt.
An welchem Port liegt der UART? Dachte jetzt das es der B Port ist, naja
trotzdem würde ich die Datenrichtung festlegen.
Versuch macht kluch.
Grüße
Der UART liegt beim ATmega8 am Port D an. Da ich TXEN und RXEN
einschalte im Register, muss ich doch dort keine Datenrichtung angeben,
da diese beiden Pins dann für den UART "reserviert" sind und nicht mehr
als digitale Ports genutzt werden können.
Hallo Jörg,
1. Die Define Berechnungen sind schick. Aber trage doch erst einmal 17
hex in das UBBRL und UBBRH 0hex ein. Das sind die harten Werte lt.
Datenblatt. Damit schließt Du aus, dass die Formel keinen Fehler hat.
Ansonsten hätte ich gesagt, Debugger dran und Register prüfen . Das geht
aber bei mega8 nicht. Er hat kein OCDS.
2. Laß eine LED ggf. eine weitere blitzen, wenn der Interrupt aufgerufen
wird. Dann weißt Du, dass zumindest der Empfang funktioniert.
3. Welche Sinn macht das Warten von 500 ms und weiteren 1000 ms in der
uart_putc(). Ist das eine Debugging-Verzweifelungstat?
4. in uart_putc() fragst Du in "while (!(UCSRA & (1<<RXC)))". Der
Empfangsinterupt setzt RXC automatisch zurück. Es wäre dann sinnvoller
hier auf uart_str_complete zu testen.
ISR(USART_RXC_vect)
{
receive_char = UDR;
uart_str_complete = 1; <- möglicherweise eine Semaphore, obwohl hier
kein End of Line Test (0x0D, 0x0A)
}
wobei ich glaube, dass Du damit einen anderen Zweck verfolgt hast.
Versuche doch mal
if(ptr < UART_MAXSTRLEN +1)
uart_string[ptr++];
in der Interruptroutine und lass diese uart_str_complete da weg. Die
würde dort nur anzeigen, dass ein Byte empfangen wurde. Also so etwas
wie ein RXC-Flag-Ersatz.
In get_char checkst Du nur noch, ob sich der "ptr" gegebenüber dem
letzten Aufruf verändert hat.
if(last_ptr != ptr)
{
"Mach was mit dem uart_string[ptr-1]" -> ptr wäre in der ISR bereits
inkrementiert und zeigt auf nächsten beschreibbaren "leeren"
Charakterplatz.
/* Lastpointer updaten*/
last_ptr = ptr; // wichtig, damit nur ein neuer Empfang berücksichtigt
wird
}
5.
Die 3,5 Volt sind merkwürdig. Mach folgendes: zieh den RS232-stecker aus
der Buchse, entferne den mega8 -wenn möglich oder unterbreche die
Leitung zum MAX- und gebe auf den RX-Input vom MAX 0V drauf und miß am
Ausgang. Der muß dann ca 4,5 Volt haben. Dann gebe 5Volt auf den
RX-Input und der Ausgang muß ca. 0 Volt haben. Andernfalls ist der
Schaltung etwas nicht in Ordnung. Dieser merkwürdige Wert kommt meist zu
stande wenn der mega8 als Ausgang geschaltet ist und ein anderer Chip
auch im Ausgangsmode ist. Wenn beide dann gegensätzlichen Pegel haben,
kommt aufgrund der Strombegrenzung meist so ein merkwürdiges Ergebnis
dabei heraus.
Eventuell ist der mega hin.
6.
DDRB = 0xFF sollte den Port D, an dem die UART hängt, nicht
beeinflussen.
Vielleicht ist ja was dabei.
Viel Erfolg
Ich hab eine seltsame Feststellung gemacht, nachdem ich nun immer mehr
davon ausgehe, dass das Problem auf der elektrischen Seite liegt.
Wenn ich die ISR's für RXD und TXD einprogrammiere und am Ausgang des
PortB entsprechend die Pins 0 und 1 toggeln lasse, um mir die Aktivität
anzuzeigen, dann funktioniert dies für ein Zeichen dass ich beim
Mikrocontroller auf sich selbst sende (dabei sind RXD und TXD am µC
gebrückt).
1
ISR(USART_TXC_vect)
2
{
3
PORTB^=(1<<PB1);
4
_delay_ms(500);
5
}
6
7
ISR(USART_RXC_vect)
8
{
9
unsignedcharnextChar;
10
11
// Daten aus dem Puffer lesen
12
nextChar=UDR;
13
PORTB^=(1<<PB0);
14
_delay_ms(500);
15
}
16
17
intmain(void)
18
{
19
DDRB=0xFF;// Port B = Ausgang
20
PORTB|=(1<<PB0);// Pin B0 aktivieren
21
uart_init();// UART initialisieren
22
charLine[40];// String mit maximal 39 zeichen
23
charz[5]={"A\n"};
24
sei();
25
while(1)
26
{
27
28
uart_put_string(z);
29
//_delay_ms(500);
30
//uart_gets(Line,sizeof(Line));
31
}
32
33
return0;
34
}
Wenn ich nun RXD und TXD über den MAX232 schicke und RXD und TXD an der
RS232-Seite des MAX232 brücke (in meinem fall die Pins 13 und 14), dann
kommt keine Kommunikation im µC zustande (LEDs blinken nicht).
Folgenden Aufbau habe ich mit einem MAX232CPE
RXD vom µC -> an Pin 12 des MAX232 (R1OUT)
TXD vom µC -> an Pin 11 des MAX232 (T1IN)
Pin 13 (R1IN) und 14 (T1OUT) am MAX232 sind kurzgeschlossen/gebrückt
Habe ich einen Denkfehler? Meiner Meinung nach ist es nichts anderes als
das direkte Brücken am µC, nur dass ich hier eine Wandlung des
gesendeten Signals auf RS232-Pegel bringe und dieses anschließend hinter
der Brücke wieder auf TTL-Pegel wandle und es auf den Empfangs-Pin des
µC gebe.
Ich habe bereits 3 MAX232CPE vom gleichen Typ ausprobiert, um ein
defektes Bauteil auszuschließen. Ebenfalls habe ich auch einen anderen
ATmega8-µC in die Schaltung gesteckt.
Die Funktion des MAX232CPE habe ich auch mal zwischen 2 PCs getestet.
Dabei bin ich bei der Kommunikation zwischen den beiden PCs über die
RS232-TTL-Wanldung und TTL-RS232-Wandlung gegangen. Dies hat alles ohne
Probleme funktioniert.
Hab auch gerade den Eingang R1IN getestet und geschaut was an dessen
Ausgang R1OUT ansteht.
0V rein (R1IN) -> 5V raus (R1OUT)
5V rein (R1IN)-> 0V raus (R1OUT)
Passt also alles, so wie es soll.
Andersrum ebenfalls.
0V rein (T1IN) -> 9V raus (T1OUT)
5V rein (T1IN) -> -9V raus (T1OUT)
Moin Jörg,
sag Du hast immer noch diese Delay-Funktionen drin! Warum?
Schickst Du VOM Terminal Einzelzeichen?
Du toggelst doch die LEDs, eine Zeitverzögerung macht da wirklich keinen
Sinn.
Woher weiß Deine Funktion
void uart_puts (char *s)
{
while (*s)
{ /* so lange *s != '\0' also ungleich dem "String-Endezeichen" */
uart_putc(*s);
s++;
}
}
das der String zu ende ist? In uart_putc wird nicht auf auf *c == '\0'
geprüft.
Nur falls Du Dich wunderst, dass im HT kein A - neue Zeile erscheint.
Warum weist Du in uart_getc UDR=UCSRA; dem Datenregister das
Statusregister A zu? Da wird keine Zeichen im HT zu lesen sein, weil es
u. U. ein Steuerzeichen sein kann.
Hast Du nur ein Multimeter? Kein Oszilloskop? Kannst Du Dir keins
ausleihen? Messtechnik muß sein. Ansonsten wirst Du weiterhin im Nebel
stochern.
cskulkw schrieb:> Moin Jörg,>> sag Du hast immer noch diese Delay-Funktionen drin! Warum?
Die Delay ist dort drin, um bei HTerm noch mitverfolgen zu können, wann
sich das Statusregister UCSRA ändert. Das ist auch der Grund, weshalb
ich mir mit UDR=UCSRA das Statusregister ausgeben lasse, um es in HTerm
zu sehen.
>> Schickst Du VOM Terminal Einzelzeichen?
ja das tue ich, da ich überprüfen möchte, wie sich das Statusregister A
verändert. Es scheint so, als ob kein gesendetes Zeichen beim µC
ankommt.
>> Du toggelst doch die LEDs, eine Zeitverzögerung macht da wirklich keinen> Sinn.
Doch, da die LEDs sonst so schnell Ein- und Ausschalten, dass ich davon
an der LED nichts sehe, die diese dauerhaft leuchten würde. So kann ich
das E/A der LED sehen.
>> Woher weiß Deine Funktion>> void uart_puts (char *s)> {> while (*s)> { /* so lange *s != '\0' also ungleich dem "String-Endezeichen" */> uart_putc(*s);> s++;> }> }>> das der String zu ende ist? In uart_putc wird nicht auf auf *c == '\0'> geprüft.
Die WHILE-Schleife ist solange erfüllt, solange die Bedingung (*s) nicht
NULL wird. Das Zeichen NULL entspricht ja 0x00 bzw. dem
Stringe-Ende-Zeichen \0
>> Nur falls Du Dich wunderst, dass im HT kein A - neue Zeile erscheint.
In HTerm kann ich einstellen, dass bei der binären Null der Cursor in
die neue Zeile gesetzt wird.
>> Warum weist Du in uart_getc UDR=UCSRA; dem Datenregister das> Statusregister A zu? Da wird keine Zeichen im HT zu lesen sein, weil es> u. U. ein Steuerzeichen sein kann.
Das stimmt. Wenn ich mir das empfangene Zeichen jedoch binär darstellen
lasse, dann sehe ich den Inhalt des UCSRA
>> Hast Du nur ein Multimeter? Kein Oszilloskop? Kannst Du Dir keins> ausleihen? Messtechnik muß sein. Ansonsten wirst Du weiterhin im Nebel> stochern.
Das ist leider nicht so einfach. Ich besitze zwar ein altes Oszi,
allerdings ohne Triggerfunktion
Nun, aber faktisch hast Du Dein Ziel immer noch nicht erreicht, oder?
Als ich vor Jahren mit der UART beim C51 angefangen hatte, gab es noch
kein OnChip Debugging. Also habe ich ein Zeichen permanent gesendet und
dann mit dem Skope nachgemessen. Dann braucht man nur auf eine steigende
oder fallende Flanke triggern. Das sollte jedes noch so alte Oszilloskop
können. Ansonsten wäre es nutzlos.
So, jetzt zu Deinem Problem.
Was kannst Du machen. Schließe 8 LED in der Reihenfolge an, dass man
damit die Bits 0 bis 7 ablesen kann. Klemme sie zunächst an den Port B
und schalte den auf Ausgang. Dann weist Du den Inhalt des
UDR-Empfangsregister dem Port zu.
PortB = nextChar;
Möglicherweise kann der SPI mit gesetzter Fuse (weil über den
programmiert wird) dazwischen funken.
Dann machst Du folgendes:
DDRC = 0x3F;
DDRD |= 0xC0;
PORTC = nextChar; (Bits 0 bis 5 UDR)
PORTD = (nextChar & 0xC0); (Bits 6 und 7 des UDR)
Jetzt hättest Du die Möglichkeit die Registerinhalte in Kombination mit
der Warteschleife zu überprüfen.
Prinzipiell kannst Du Dir daraus auch eine Funktion basteln und dann
damit auch das UDSRA anguggen.
Ich habe mir eine Schaltbox gebaut, die über RS232 ein Relais ein und
ausschaltet. Dabei sollte sich der mega8 wie ein Töllner-Netzteil
verhalten. Auch mich hatte das Ding Stunden gekostet, weil man nichts
sieht. Die Fehler habe ich letztlich auf einem mega16 mit Debugger
gefunden. Erst als es da funktionierte, übertrug ich den Code.
Du hast Dir einen kostengünstigen aber steinigen Weg ausgesucht.
Das ist genau das Problem, das ich habe. Ich sehe bei dem ATmega8 gar
nichts.
Gibt es denn Chips, bei denen ich ein On-Chip-Debugging machen kann?
Was würdest du mir als Einsteiger dabei empfehlen?
Ich verballere hier inzwischen schon Tage und komme nicht voran.
Hi
>Gibt es denn Chips, bei denen ich ein On-Chip-Debugging machen kann?>Was würdest du mir als Einsteiger dabei empfehlen?
Ja. ATMega88. Dazu einen AVR-Dragon.
MfG Spess
Hallo Jörg,
einfach bei Ebay den Begriff "JTAGICE" eingeben. Dann findest Du jede
Menge Nachbauten für 20 - 30 Euro. Ich habe auch mit so einem Dongle
angefangen. Die sind nicht schnell, aber wirksam. Du kannst das Teil
dann aus dem AVR-Studio heraus bedienen.
Der AVRDragon kostet neu zw. 50 - 60 Euro. Kann aber auch mehr.
Das AVR JTAGICE mkII ist so die Mittelklasse. Der kostet aber auch schon
260 - 300 Euro. Der wird wohl eher nicht für Dich in Frage kommen.
Wenn Du mit dem ATmega16 kein Problem hast, dann nimm doch den.
Gruß
cskulkw
Hallo,
ich hab eingentlich genau dasselbe Problem wie oben beschrieben, nur
nutze ich einen ATmega32 und möchte per UART-Interrupt Daten empfangen.
Mit normaler if((UCSRA & (1<<RXC)))-Abfrage in meiner main.c klappt das
alles prima.
Für den Interruptbetrieb habe ich die Routine genommen, die im
AVR-gcc-Totorial hier steht.
Allerdings springt mein Programm nicht in die UART-ISR,wenn ich über
HTerm ein zeichen sende.
Weiß aber grad nicht warum! RXCIE-Bit in UCSRB habe ich gesetzt.