Guten Tag liebe Community,
das ist das erste mal dass ich hier etwas poste, ich hoffe ich mach das
richtig. Ich sitze gerade an meiner Studienarbeit und hab ein Problem
...
Ich sende mit einem ATmega2560 über UART an einen ATmega32A. Gesendet
wird mit 8n2. Durch eine LED die ich aktiviere sobald der 32A in den
Interrupt springt seh ich dass er etwas empfängt. Aber er empfängt
einfach nicht was ich schicke.
Daten vom ATmega2560 per UART mit Terminal ausgelesen (ASCII):
r108yg109yb42yr107yg108yb41yr106yg107yb40yr105yg106yb39yr104yg105yb38yr1
03yg
Code vom 32A der diesen Daten auswerten soll:
........................................................................
.
########################################################################
#include <avr/io.h>
#include <inttypes.h>
#include <avr/delay.h>
#include <avr/interrupt.h>
#define F_CPU 8000000UL
#define BAUD 115200UL
#define UBRR_BAUD ((F_CPU/(16UL*BAUD))-1)
#define intervall10 "set intervall 10"
#define streamon "set stream 1"
#define streamoff "set stream 0"
void timer2_init() //PWM Rot
{
TCCR2 |= (1 << COM21)|(1 << WGM20)|(1 << CS22);
OCR2 = 230;
}
void timer1_init() //PWM Grün, Blau
{
TCCR1A |= (1 << COM1A1)|(1 << COM1B1) |(1<<WGM10);
TCCR1B |= (1 << CS11)|(1 << CS10);
TCNT1 = 0;
OCR1A = 230;
OCR1B = 230;
}
// USART initialisieren
void uart_init(void){
UBRRH = (unsigned char)(UBRR_BAUD >> 8);
UBRRL = UBRR_BAUD;
UCSRA = (1 << UDRE); //Puffer-leer bit setzen
UCSRB |= (1<<RXEN)|(1<<RXCIE); //Senden
aktivieren
UCSRC |= (1<<UCSZ1)|(1<<UCSZ0)|(1<<USBS); //Anzahl Datenbits
und Stopbits wählen
do
{
UDR;
}
while (UCSRA & (1 << RXC));
}
#define UART_MAXSTRLEN 100
char uart_string[UART_MAXSTRLEN + 1] = "";
volatile uint8_t uart_str_complete = 0;
volatile uint8_t uart_str_count = 0;
int Gruen; //Farbwert gelb 0-255
int Blau; //Farbwert blau 0-255
int Rot; //Farbwert rot 0-255
int testcounter = 0;
int main(void)
{
// USART + timer initialisieren
uart_init();
timer1_init();
timer2_init();
DDRA |= 0xFFF;
DDRD |= (1<<PD6);
DDRD |= (1<<PD4); //OC1B
DDRD |= (1<<PD5); //OC1A
DDRD |= (1<<PD7); //OC2
sei();
do{
if(uart_str_complete == 1){
if(uart_string[0] == 'r'){
memmove(uart_string, uart_string+1, strlen(uart_string));
Rot = atoi(uart_string);
OCR2 = Rot;
if(Rot > 50){
PORTA |= (1<<PA4);
}
else{
PORTA &= ~(1<<PA4);
}
}
if(uart_string[0] == 'g'){
memmove(uart_string, uart_string+1, strlen(uart_string));
Gruen = atoi(uart_string);
OCR1A = Gruen;
if(Gruen > 50){
PORTA |= (1<<PA5);
}
else{
PORTA &= ~(1<<PA5);
}
}
if(uart_string[0] == 'b'){
memmove(uart_string, uart_string+1, strlen(uart_string));
Blau = atoi(uart_string);
OCR1B = Blau;
if(Blau > 50){
PORTA |= (1<<PA6);
}
else{
PORTA &= ~(1<<PA6);
}
}
if(uart_string[0] == 'c'){
if(uart_string[1] == '1'){
PORTA |= (1<<PA7);
}
else{
PORTA &= ~ (1<<PA7);
}
}
if(uart_string[0] == 'O'){
if(uart_string[1] == '1'){
PORTA |= (1<<PA2);
PORTA |= (1<<PA3);
}
else{
PORTA &= ~ (1<<PA2);
PORTA &= ~ (1<<PA3);
}
}
uart_str_complete = 0;
}
} while (1);
}
ISR(USART_RXC_vect) // Interrupt
{
unsigned char nextChar;
nextChar = UDR;
if( uart_str_complete == 0 )
{
if((nextChar != 'y'))
{
uart_string[uart_str_count] = nextChar;
uart_str_count++;
uart_string[uart_str_count] = '\0';
}
else
{
uart_string[uart_str_count] = '\0';
uart_str_count = 0;
uart_str_complete = 1;
}
}
}
.......................................................................
#####################################################################
Leider klappt das mit der formatierung nicht so ganz hier im kleinen
Fenster, viel verschoben ist ja nicht.
Mein Problem ist.... ich sehe im Terminal dass ich die Daten richtig
schicke. Aber mein Interrupt erkennt das 'y' einfach nicht. Ich saß nun
schon 12 Stunden an diesem Probelm und finde einfach den Fehler nicht.
Ich hoffe hier im Forum kann mir jemand helfen.
Vielen Dank im voraus!!!!
MfG Martin
Oszi habe ich mir sogar extra eins ausgeliehen und hier. Aber ich muss
zugeben ich habe keine Ahnung wie man so etwas erkennt.
Noch zur Info ... der ATmega32A läuft auf einem STK500 momentan
Sprich den Mega32 doch auch mal über ein Terminal an und schick ihm
deine Zeichenketten. Zur Fehlersuche kann er dann ein Echo zurück
schicken und noch ein Hinweis, in welcher Schleife er gerade ist.
UART Studienarbeit schrieb:> Oszi habe ich mir sogar extra eins ausgeliehen und hier. Aber ich muss> zugeben ich habe keine Ahnung wie man so etwas erkennt.
Viele "UUUUUU" senden.
Und Timing messen.
Moderne haben eingebaute Werkzeuge, bei älteren kann auch ein Lineal und
Taschenrechner helfen.
UART Studienarbeit schrieb:> Oszi habe ich mir sogar extra eins ausgeliehen und hier. Aber ich muss> zugeben ich habe keine Ahnung wie man so etwas erkennt.
Um die Baudrate mit dem Oszi zu "messen", sendest du fortlaufend 0x55
oder 0xAA mit einem Stopbit. Damit erhältst du eine Rechteckspannung an
Tx von 57,6KHz bzw. 28,8KHz.
Wenn ich es durch ein echo nicht herausfinde werde ich das mit dem oszi
probieren. Vielen Dank für die ganzen Antworten. Ich bin völlig baff wie
schnell man hier Hilfe bekommt!
8MHz und 115200Baud ist nicht möglich für nen AVR.
Und deshalb glaub ich dir auch nicht, dass du das mit nem Terminal
korrekt empfangen konntest. Selbst im double-speed-mode sind das fast 4%
Fehler.
Wenn du allerdings auf beiden Seiten mit demselben Fehler arbeitest,
funktioniert es schon, aber dann eben nicht mit Standardbaudraten
(Terminal).
der ATmega2560 sitzt mit einem externen 7,3Mhz Quarz auf einer kleinen
Platine. die Platine hab ich von einem Prof bekommen um damit zu
arbeiten. Ich habe ebenfalls ein Programm von ihm bekommen und habe
seine UART-init übernommen.
Mhm ich muss zugeben das war nie mein Lieblingsfach... daher bin ich bei
dem ganzen Thema noch nicht so bewandert, ich versuche mein Bestes.
Thema Echo:
ISR(USART_RXC_vect) // Interrupt
{
unsigned char nextChar;
nextChar = UDR;
if( uart_str_complete == 0 )
{
if((nextChar != 'y'))
{
uart_string[uart_str_count] = nextChar;
uart_str_count++;
uart_string[uart_str_count] = '\0';
while (!(UCSRA & (1<<UDRE)));
UDR = nextChar;
}
else
{
uart_string[uart_str_count] = '\0';
uart_str_count = 0;
uart_str_complete = 1;
}
}
}
Ich weiss nicht ob ich das so einfach machen darf... also ein echo
direkt im interrupt für jedes einzelne char.
Sobald ich dem mega32 einen Befehl sende bekommen ich dieses Zeichen
zurück das Null-Zeichen zurück <\0>.
Entschuldigt meine Rechtschreibung, ich versuche immer so schnell es
geht zu Antworten bevor jemand von Ihnen schlafen geht. Da hacke ich
einfach auf meine Tastatur ein.
Du könntest es auch ohne Hardware UART lösen was etwas mehr
Programmieraufwand bedeuten würde, aber letztendlich viel
unproblematischer im Taktverhalten ist. Nicht das du später irgend einen
Vorführeffekt hast.
Das Byte einfach bitweise mit einem Taktsignal über einen 2ten Pin
rausschieben. Das Taktsignal löst beim Empänger einen Interrupt aus und
er schiebt das Bit in ein Byte rein.
Durch die Taktleitung hat man keinerlei Probleme wenn die Takte der µC
nicht synchron sind und einander weglaufen, da jedes Bit neu
synchronisiert wird.
UART Studienarbeit schrieb:> Ich weiss nicht ob ich das so einfach machen darf... also ein echo> direkt im interrupt für jedes einzelne char.
sollte funktionieren, die while() davor brauchst du eigentlich nicht
vielleicht setzt du zum Testen die Baudrate herunter, wenns funzt,
kannst du sie ja wieder hochsetzen
UART Studienarbeit schrieb:> also ich kann den mega32 nicht mit dem internen 8Mhz und> 115200baud> laufen lassen?
Und nochmal:
Schaue dir das Timing an.
Von beiden!
Vergleiche!
Und dann findest du deine eigene Antwort.
Oder Rechne es aus. Das bringt das gleiche Ergebnis, wenn du es richtig
machst.
Teiler, Fuses, ist ja alles offen.
Ok ich werde es versuchen.
Nur noch eins was mit gerade klar wird. der jetztige mega32 ist nur ein
testµC. Ich bekomme in einer woche meine Finale Platine. Und dann wird
der mega32 ebenfalls mit einem externen 7,3Mhz Quarz betrieben.
Wenn das nun wirklich am Timing liegt sollte sich das doch eigentlich
erledigen wenn ich den mega32 mit dem selben Quarz laufen lasse wie der
2560.
oder?
UART Studienarbeit schrieb:> Wenn das nun wirklich am Timing liegt sollte sich das doch eigentlich> erledigen wenn ich den mega32 mit dem selben Quarz laufen lasse wie der> 2560.> oder?
Ja
... bevor du eine Woche wartest, kannst du natürlich auch mit einer
geringeren Baudrate arbeiten, z.B. 38400, da beträgt der Baudratenfehler
nur 0,2% bei 8MHz, beim 7.3728MHz-Quarz ist der Fehler 0%.
UART Studienarbeit schrieb:> bin echt begeistert von dem forum!!!
Wenn da nicht immer die Freitags Trolle wären :-) Ah Ah Ah 00:16h es ist
schon wieder Freitag ....
Gute Nacht :-)
Émile Baudot schrieb:> ... bevor du eine Woche wartest, kannst du natürlich auch mit> einer> geringeren Baudrate arbeiten, z.B. 38400, da beträgt der Baudratenfehler> nur 0,2% bei 8MHz, beim 7.3728MHz-Quarz ist der Fehler 0%.
Nee, sorry, vergiss es, du nimmst ja den internen RC-Oszillator, hab ich
gerade erst gesehen. Der ist wahrscheinlich zu ungenau. Das mit der
niedrigeren BR wird auch nur dann funktionieren, wenn du an den mega32
einen ext. Quarz dranklemmst. Vllt nochmal in ein paar Schubladen
wühlen...
Guten Abend zusammen,
und vielen Dank an alle die mir hier geholfen haben. Ich wollte den
Thread natürlich noch auflösen und aufklären wo mein Fehler lag. Die
Platine die ich von der Hochschule gestellt bekommen habe, auf der sich
der mega2560 befindet, hat einen RS485 Baustein mit dem die UART nach
aussen geführt wird. Das STK500 auf dem der mega32A installiert war
kommuniziert jedoch mittels RS232. Daher konnte eine Kommunikation
garnicht zustande kommen.
Trotzdem nochmals vielen Dank an alle die sich hier die Mühe gemacht
haben und versuchten mit zu helfen!!!!!
Mit freundlichen Grüssen Martin