PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : UART stoppt nach einiger Zeit



surfer
26.01.2005, 16:23
Ich hoffe ihr könnt mir bei meinem Problem helfen...
Ich habe ein UART Beispiel nach der Anleitung vom Mikrokontroller.net-Tutorial geschrieben. Senden vom uC zum PC funktioniert ohne Probleme.... aber komischerweise bricht mir die Verbindung beim senden vom PC zum uC nach ca. 5s ab. Ich habe es so geschrieben, dass ich über das Terminal die LED's mit der Taste "a" einschalten kann und mit der Taste "s" wieder ausschalten kann. Funktioniert in den ersten 5 sekunden, danach tut sich jedoch nichts mehr.

Ich hoffe ihr könnt mir helfen. Anbei das Beispielprogramm mit Interrupts...


#include <io.h>#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/signal.h>

#define F_CPU 4000000 // 4Mhz-Quarz
#define UART_BAUD_RATE 9600 // 9600 Baud


volatile char Daten;

SIGNAL(SIG_UART_RECV)
{
Daten = UDR;
}


int main(void)
{
UCR = (1<<TXEN) |(1<<RXEN)|( 1<<RXCIE) ;
UBRR= F_CPU/(UART_BAUD_RATE * 16L)-1;
outp(0xff,DDRC);
sei();
while(1)
{
if(Daten=='a')
{
Daten = 0;
outp(0xFF,PORTC);
}
if(Daten == 's')
{
Daten = 0;
outp(0x00,PORTC);
}
}

} [/quote]

muraad
26.01.2005, 18:18
Erstmal wieso deklariest du Daten als volatile, braucht man doch da garnicht.
Und mach sie zu ner unsigned das sie sonst von -127 - +127 geht und nicht den vollen ASCII Code darstellen kann.
Und noch was schau mal wieder zu www.mikrocontroller.net
es hat sich bei C einiges geändert, eigentlich gibt es outp() nicht mehr
statt dessen DDRC = 0xff;
Ich glaub nicht das es was aus macht aber erst machst du =='a' also ' ' bedeutet das Zeichen s und dann nur ==0 wobei jetzt hier die Zahl 0 gemeint was glaub ich was anderes ist wie '0', hier ist nämlich glaub ich das Zeichen 0 gemeint.
Gruß Muraad

surfer
26.01.2005, 18:24
Soviel ich weiss, muss man das volatile voransetzen, damit die Variabel auch für die Interrupts gültig ist, oder...?
Und das mit dem outp() ist eigentlich auch nicht so meine Weise... hab diesen Code nur mal zum testen geladen. Habs auch schon selber geschrieben -- ohne Erfolg.
Ich glaube kaum, dass es etwas mit dem == zu tun haben kann, da es ja für eine Zeit TipTop funktioniert. Könnte womöglich auch der Quarz oder Port defekt sein? Hatte nämlich auch schon mal das Problem beim LCD, dass es erst nach ca. 5s initialisiert wurde....

Hätte jemand noch eine Idee?

Danke

Thorsten
26.01.2005, 19:59
@muraad
Ich würd sie auch als volatile deklarieren, schließlich wird Daten im Interrupt
verwendet. Ohne volatile kann es doch sein, dass er sich in der main
Routine den Inhalt aus dem (veralteten) Register hohlt und nicht neu aus
dem Speicher ließt?
Oder steh ich aufm Schlauch?


if(foo) == 0 vergleicht mit dem Wert 0 also 0x00,
ff(bar) == '0' vergleicht mit dem ASCII Wert von 0 also 0x48.

Aber wieso er abstürzt weiß ich auch nicht, am üblichen Verdächtigen,
dem Watchdog kann es ja eigentlich nicht liegen.

surfer
26.01.2005, 21:22
Ich werd mir mal einen neuen Controller und Quarz kaufen.... könnte gut sein, dass irgendwo mal was kaputtgegangen ist. Hatte schon andere Probleme.... kostet ja zum Glück nicht die Welt :-)

mirki
26.01.2005, 22:31
Also die volatile deklaration ist notwendig, wenn man die variable auch ausserhalb des interrupt event handles verwendet. Dann ansonsten wird sie vom complier weg optimiert

mirki
26.01.2005, 22:33
nimm mal anstelle
UCR = (1<<TXEN) |(1<<RXEN)|( 1<<RXCIE) ;

das hier
UCR = (1<<RXEN)|( 1<<RXCIE) ;

surfer
27.01.2005, 08:03
Da hat leider auch nichts gebracht.... Habe auch schon den Controller gewechselt -- ohne Erfolg...
Könnte es was mit dem Overflow vom UART zu tun haben?

Ach und nur so nebenbei:
MAX232 sollte auch in Ordnung sein, da ich, wenn ich das Signal auf den PC Rückführe saubere Daten bekomme, keine Fehler, nichts. Also muss es etwas mit dem ATMEL zu tun haben....

NEUHAUS
27.01.2005, 11:10
Du koenntest auch ein Problem mit dem Baudratenfehler haben.
Bei 9600 Baud und einem 4MHz Takt hast du einen Fehler von 0.2%.
Stell mal 3.6864MHz ein, oder nimm den entsprechenden Quarz und probier es damit noch mal.

surfer
27.01.2005, 11:16
Das mit den 9600 Baud und 4MHz passt schon.
Wie gesagt. Senden an den PC funktioniert einwandfrei und mit einer Toleranz, die ich noch niee bemerkt habe ;-)
Auch sollte das Empfange theoretisch funktionieren, da es in den ersten 5s ohne Probleme läuft....
Was könnte da noch falsch sein????????

PicNick
27.01.2005, 12:00
Hi, Surfer ! Ohne sicher zu sein, daß das der Hänger-Grund ist, ist die Methode auf jeden Fall nicht sauber und du wirst irgendwann Zeichen verlieren.
Vergiß nicht, daß Interrupt und Normal völlig unsynchron ablaufen, d.h. sie hauen sich "Daten" gegenseitig nieder.
der interrupt fährt dir ja u.U. genau zwischen
if (daten == 'a')
und
daten = 0
rein, und dann ist dieses Zeichen schon mal weg.
Wie gesagt, weiß nicht, ob's der Grund ist, aber bäh ist es sicher.
mfg robert

surfer
27.01.2005, 12:03
Das könnte wirklich ne fehlerquelle sein.
Wie muss ich dann die Daten speichern ohne Interrupts?

27.01.2005, 14:00
Hi,
unter der Annahme, daß dein programm schnell genug ist, was dzt. wohl so ist (sonst müßtest du buffern)



static char daten = 0;
static char flag1 = 0; // flag is immer gut

SIGNAL(...)
{
flag |= 1; // es is was da
}

main()
....
...

while (1)
{
flag <<= 1; //
if (flag & 2)
{
flag &= ~2; // löschen
daten = UDR; // holen
......... // verwursteln if then else und überhaupt
}
}


Der Shift ist EIN Cpu-Befehl, der nicht unterbrochen werden kann. dadurch ist der Flag vom Interrupt entweder vorher drin, dann haben wir ihn ja, oder nachher, dann kriegen wir ihn halt beim nächsten mal
mfg robert

PicNick
27.01.2005, 14:04
Hopperla, so schön war's auch wieder nicht.
tut mir leid, unterm H... ausgeloggt.
](*,)

surfer
27.01.2005, 15:02
Tja. Ich habs jetzt nochmals ganz normal probiert (nachdem deine Methode auch nicht wirklich funktioniert hat). Hab jetzt herausgefunden, dass es nicht nur in den ersten 5s geht sondern eigentlich immer, das Problem ist nur, dass es nur in gewissen Zuständen funktioniert. Hab zwar keine Ahnung warum, aber wenn ich immer ein bisschen auf der Tastatur "rumhämmere", kommt das Signal manchmal durch....
Gibt es vielleicht einen Buffer? Wo die Daten gespeichert und abgerufen werden können, oder ist das nur das UDR?

PicNick
27.01.2005, 16:07
Tscha, opfere mal 2 LED für die doch möglichen Errors
die sind im UCSRA und heißen FE und DOR (Framing & Overflow)
die mußt Du abfragen VOR daten = UDR
ist einer "1" laß eine LED leuchten

Nächster Vorschlag (einfacher, also zuerst probieren
Pfeif auf die LED und mach einfach echo und sonst nix.
SIGNAL(..)
{
UDR = UDR // (TXEN nicht vergessen)
}

PS Buffer gibt's schon, aber der ist gewissermassen transparent (nicht sichtbar) Kopf hoch, das ist ja lächerlich mfg robert

surfer
28.01.2005, 09:04
Also ich hab mal die Register-Error-Bits anzeigen lassen.
Ich arbeite nicht viel mit diesen Registerbefehlen (ich siehe einfach im Datenblatt nach, welche Bits gesetzt werden müssen und dann schreibe ich den Wert z.B. 0x04 in das Register...) also weiss ich gar nicht ob dieses Programm stimmt... Auf jeden Fall leuchten die beiden Fehler-LED's.
Das mit dem UDR=UDR funktioniert für ein einziges Zeichen, dann ist Schluss, ausser manchmal geht es per Zufall....

Huiuiuiui


SIGNAL(SIG_UART_RECV)
{
if((USR<<FE))
sbi(PORTC,2);
if((USR<<DOR))
sbi(PORTC,3);

switch(inp(UDR))
{
case 'a': sbi(PORTC,0); cbi(PORTC,1); break;
case 's': sbi(PORTC,1); cbi(PORTC,0); break;
default: break;
}
}

surfer
30.01.2005, 18:51
Hat vielleicht noch jemand eine Lösungsidee?
Sonst könnt ihr mir mal einen Beispielcode geben, der bei euch läuft.
Wenn er bei mir nicht funzt, wechsle ich mal den Quarz (+ andere Frequenz...). Ich habe jetzt 4MHz. Was benutzt ihr so? Welches sind gute Werte? Danke

PicNick
30.01.2005, 19:18
Ich stell ein Programm rein, das tut zwar im Detail was anderes, aber es funzt und gibt antwort.
Ein Leidenskollege hatte USART-Probleme, er wird nicht böse sein, wenn ich dir den Code gebe.
Deine sbi und cbi mußt du natürlich noch einbauen.

Wie gesagt ES FUNZT , also wenn probleme, liegt's woanders.
mfg robert

surfer
31.01.2005, 08:38
Danke für das Programm... Hab jetzt dadurch etwas weiteres herausgefunden... Immer dann, wenn das Zeichen erkannt wird, ist alles OK (manchmal wird es eben erkannt und es läuft alles). Aber in den meisten Fällen wird bei Eingabe ein RESET durchgeführt..... Denn ich glaube nicht, dass dein Programm bei jeder Eingabe den Titel nochmals neu schreibt...

An was könnte das liegen?

Ach und so nebenbei... am Quarz liegts wohl kaum, da ich im Datenblatt gesehen habe, dass bei 4MHz und 9600BAUD die Fehlerquote nur 0.2% beträgt..... Aber wieso ein RESET???????

surfer
31.01.2005, 09:41
HOPPLA!!!!!! Apropos RESET!!!!!!!!!!!!!!!!!!

Wenn der RESET-PIN nicht auf Vcc liegt, gibts durch Eingang vom UART einen RESET!!!!!!!! Das wars!!!!!!!!!!!!!!!!!!!!!!!!!!!

Jetzt funktioniert alles!! Supper!!!
So ne riesen Diskussion, nur weil ich den RESET-Pin vergessen habe.... ](*,) ](*,) HEHE

Aber man lernt immer was.....

Danke jedenfalls für eure Antworten!!!!

PicNick
31.01.2005, 09:42
Würde annehmen, da is was elektrisches im Busch.
Irgendeine Reset-fähige Leitung schnackelt
Wackelige Stromversorgung, Peaks / Drops /Brownout
etc.
Beim Reset sind je nach Reset-Grund verschieden Flags gesetzt
Lies dich da mal rein und mach sie sichtbar bei Titel-Display
Wie gesagt, am Programm per se kann's nicht liegen, tät ich sagen.
Was Besseres hab' ich im Moment nicht zu bieten, sorry mfg robert

surfer
31.01.2005, 09:49
Eben! Es funktioniert jetzt...... Es lag am RESET-PIN, der anstatt an Vcc an "nichts" angeschlossen war....

PicNick
31.01.2005, 09:54
*seufz* *stöhn* *ächz*

surfer
31.01.2005, 10:23
*seufz* *stöhn* *ächz*

GENAU!!! ](*,) ](*,) ](*,) ](*,)

dark emporer
20.07.2005, 16:58
Das Programm hat mir schon sehr geholfen =D> Danke PicNick!

Jetzt würde ich gerne noch wissen wie ich Enter erkennen kann?

PicNick
20.07.2005, 17:14
Na ja,
Enter ist 0x0D oder d'13'

a = udr
if ( a == 13) then enter-gedrückt

SprinterSB
21.07.2005, 12:34
hmmm also ENTER ist doch ein '\n', oder?
Und das ist 10.

13 ist '\r' wobei Windows wahrscheinlich beides sendet?

Also
if (a == '\n') // Linux oder Win
if (a == '\r') // Win oder Mac

PicNick
21.07.2005, 12:59
Mit diesen beiden Zeichen ist es leider ein babylonischer Wahnsinn. Manche Terminal-emulatoren senden, wenn man "\r" <ENTER> drückt, auch ein "\n" <LF> automatisch hinten nach. Das "\r" kommt aber sicher (zuerst) und ist für dich das Kennzeichen, daß er Enter gedrückt hat
Wenn du C schreibst, wirst du ja schon gemerkt haben, daß, je nach Terminal-Einstellung , durch "\n" alleine NUR eine Zeile weitergeschoben
wird.
Erst durch "Hello\r\n" ist er am Anfang der nächsten Zeile.
Schau mal, ein bißchen was habe ich zusammengeschrieben.
https://www.roboternetz.de/wiki/pmwiki.php?n=Main.TermHyper