Hallo ihr Lieben, Folgendes Problem: Ich arbeite mit einem ATMega 2560, einen Atmel-Ice Debugger und Atmel Studio 6.2 auf Windows 10. Im Allgemeinen funktioniert die Arbeit auch. Allerdings kommt es scheinbar zufällig vor, dass die USART-Interrupts (Receive Complete) nicht mehr funktionieren. Das ist bisher nach kleinen Code-Änderungen vorgekommen (Bei vielen anderen ist nichts passiert). Nach Rückbau der Änderungen ändert sich aber nichts am Fehlverhalten. Die Änderungen haben nichts mit dem USART-Teil zu tun. Alle Interrupts sind enabled und das Flag wird gesetzt. Wenn ich im Debug Modus pausiere, kann ich das auch wunderbar im IO View einsehen. Faktisch wird aber das Interrupt nicht ausgelöst, während ein normales Timer-Interrupt noch funktioniert. Das Nichtauslösen der Interrupts mache ich an nicht ausgeführten Anzeigen und Breakpoints aus. (Beschränkt sich alles nicht auf den Debug Modus, abgesehen von den Breakpoints natürlich) Beim ersten Auftreten hat sich das Ganze scheinbar zufällig nach einiger Zeit und einigen Nerven von alleine gelöst. Jetzt ist das Problem allerdings wieder aufgetreten. Ich habe keine Ahnung woran es liegt. Hat schon mal jemand ähnliche Erfahrungen gemacht oder ansonsten eine Ahnung woran es liegen kann? Weitere Infos: Signal kommt am pin an, hab ich mit Oszi überprüft. Speicher ist noch lange nicht voll. uC hängt sich nicht auf, normale Routinen und Timer-Interrupts funktionieren weiterhin. Genutzte USART-Interrupts sind die Receive Complete Interrupts von USART0 und USART1. Beide sind betroffen.
Der Fehler liegt im nicht geposteten Programmcode. Du kannst bei Interesse auch mehrere C-Files anhängen...
Den Code habe ich bewusst weg gelassen, da es sich ja um Code unabhänige Probleme handelt. Wie beschrieben ändert ein Code Rückbau nichts an der Fehlfunktion. Falls hier dennoch begründeter Verdacht besteht, reiche ich das gerne nach, sehe ich aktuell aber nicht als zielführend. Außerdem ist das nicht sehr schön ;)
Meine Glaskugel sagt: Die gesendeten Daten sind Schrott. Bei Frame Errors werden keine Interrupts ausgelöst. ohne Gewähr
Florian H. schrieb: > Den Code habe ich bewusst weg gelassen, da es sich ja um Code unabhänige > Probleme handelt. Mit einiger Sicherheit nicht. Du hast einen Fehler im Programm, der dir vorher nicht aufgefallen ist.
Florian H. schrieb: > Beim ersten Auftreten hat sich das Ganze scheinbar zufällig nach einiger > Zeit und einigen Nerven von alleine gelöst. Programmfehler lösen sich nicht von alleine in Luft und Liebe auf. Ein Problem, welches scheinbar von alleine verschwindet ohne dass man den Hauch einer Idee hätte warum das so ist, das ist ein Alarmsignal und keineswegs etwas Beruhigendes. So etwas zu ignorieren, verschlimmert das Problem im Endeffekt meistens.
:
Bearbeitet durch User
Hab hier mal die main angehangen. Ist alles sehr unübersichtlich, da muss ausgemistet werden. Aber dann brauch man hier keine Glaskugeln mehr. Die Daten sind nicht schrott, im Normalfall funktioniert ja alles. Ist es denn so, dass beim Frame Error das Flag nicht gesetzt wird, oder das Interrupt zum Flag nicht ausgeführt wird? Das Data Receive Complete Flag wird nämlich gesetzt.
Ulrich F. schrieb: > Meine Glaskugel sagt: > Die gesendeten Daten sind Schrott. > Bei Frame Errors werden keine Interrupts ausgelöst. > *ohne Gewähr* mag sein, dass ich mich irre. Aber meiner Erinnerung noch, wird auch in so einem Fall ein Receive Complete Interrupt ausgelöst. Alles andere wäre auch dämlich.
Da hat sich ja jemand die finger wund getippt:
1 | void trans_stop(void) |
2 | {
|
3 | while(!(UCSR0A & (1<<UDRE0))); |
4 | UDR0 = 's'; |
5 | while(!(UCSR0A & (1<<UDRE0))); |
6 | UDR0 = 't'; |
7 | while(!(UCSR0A & (1<<UDRE0))); |
8 | UDR0 = 'o'; |
9 | while(!(UCSR0A & (1<<UDRE0))); |
10 | UDR0 = 'p'; |
11 | }
|
warum nicht einfach eine Funktion schreiben, die strings ausgibt. Dann könnte der Code sogar lesbar werden.
1 | void trans_stop(void) |
2 | {
|
3 | SendStr("stop"); |
4 | }
|
Peter II schrieb: > Da hat sich ja jemand die finger wund getippt: > >
1 | > void trans_stop(void) |
2 | > { |
3 | > while(!(UCSR0A & (1<<UDRE0))); |
4 | > UDR0 = 's'; |
5 | > while(!(UCSR0A & (1<<UDRE0))); |
6 | > UDR0 = 't'; |
7 | > while(!(UCSR0A & (1<<UDRE0))); |
8 | > UDR0 = 'o'; |
9 | > while(!(UCSR0A & (1<<UDRE0))); |
10 | > UDR0 = 'p'; |
11 | > } |
12 | >
|
> > warum nicht einfach eine Funktion schreiben, die strings ausgibt. Dann > könnte der Code sogar lesbar werden. > >
1 | > void trans_stop(void) |
2 | > { |
3 | > SendStr("stop"); |
4 | > } |
5 | >
|
Und genau deswegen wollte ich den Code nicht posten. Ich kommuniziere mit ner Matlab Gui, die funktion trans_stop soll einfach nur die vier chars senden. Wider besseren Wissens bin ich davon ausgegangen, dass die Funktion genau das tut was sie soll. Das ganze hat aber überhaupt nix mit der Fragestellung zu tun... Frame Error Flag wird übrigens nicht gesetzt. Nur Receive Complete und Data Register Empty. Also eigentlich alles paletti.
Eine offensichtliche Fehlerursache liegt darin, dass du aus der Interrupt-Service-Routine heraus "trans_val()" aufrufst, die ewig lange benötigt. Alle RXC-Interrupts, die in dieser Zeit auflaufen werden bis auf den letzten "vergessen".
Florian H. schrieb: > Ich kommuniziere mit ner Matlab Gui, die funktion trans_stop soll > einfach nur die vier chars senden. Wider besseren Wissens bin ich davon > ausgegangen, dass die Funktion genau das tut was sie soll. > Das ganze hat aber überhaupt nix mit der Fragestellung zu tun... war ja nur als netter Hinweis gemeint, je lesbarer ein Code ist, desto weniger können sich darin Fehler verstecken.
Florian H. schrieb: > Hab hier mal die main angehangen. Ist alles sehr unübersichtlich, da > muss ausgemistet werden. Dann mach das mal. Der ganze Code kann um einiges eingedampft werden. Die Übersichtlichkeit würde dadurch nicht leiden. Ganz im Gegenteil.
1 | ....
|
2 | else
|
3 | {
|
4 | samples[i]=buffer; |
5 | i++; |
6 | }
|
gefährlich, gefährlich. Bei einem Array der Länge 4. Und vor allen Dingen: so überflüssig wie ein Kropf. Warum setzt ihr denn die Zahl nicht gleich während des Empfangens zusammen? (d.h. wenn das empfangene Zeichen ein digit ist). Beim '.' wird dann nur noch entschieden, in welche Variable (je nach tf bzw. dem anderen Flag) die Zahl kommen muss. Dieses Zwischenspeichern in einem char Array braucht kein Mensch. Nur läuft ihr dann eben Gefahr, dass Array zu überlaufen, wenn der Input mal nicht so ist, wie ihr erwartet habt.
:
Bearbeitet durch User
@Peter: darum ist es ja in eine Funktion verpackt. Strings senden ist ansonsten nicht interessant für mich. @Rainer: Danke für den Hinweis. Es löst allerdings kein einziges Interrupt aus und ich komme gar nicht zu diesem Punkt. Im Normalfall funktioniert es aber auch mit diesem sehr unschönen Aufbau Fehlerlos.
Florian H. schrieb: > @Peter: > darum ist es ja in eine Funktion verpackt. Strings senden ist ansonsten > nicht interessant für mich. Statt dessen schreibst du lieber die Litanei da runter? Deine trans_val könnte so einfach sein
1 | void trans_val(void) |
2 | {
|
3 | char tmp[10]; |
4 | |
5 | sprintf( tmp, "%d\n", T ); |
6 | uart_puts( tmp ); |
7 | |
8 | sprintf( tmp, "%d\n", output ); |
9 | uart_puts( tmp ); |
10 | |
11 | sprintf( tmp, "%d\n", samp + 1); |
12 | uart_puts( tmp ); |
13 | }
|
(oder so ähnlich) > @Rainer: > Danke für den Hinweis. Die andere ISR hat ein ähnliches Problem, wenn ich den Funktionsnamen DISP_irgendwas richtig deute. Man macht in einer ISR keine Ausgaben! Ausser vielleicht wenn sie interrupt getrieben gebuffert sind. Ausgaben kommen in die Hauptschleife, die bei dir leer ist. > Es löst allerdings kein einziges Interrupt aus > und ich komme gar nicht zu diesem Punkt. Im Normalfall funktioniert es > aber auch mit diesem sehr unschönen Aufbau Fehlerlos. Bei diesem Aufbau weiss man doch gar nicht mehr, wo man mit der Fehlersuche anfangen soll.
:
Bearbeitet durch User
Karl H. schrieb: > gefährlich, gefährlich. Bei einem Array der Länge 4. > Und vor allen Dingen: so überflüssig wie ein Kropf. > > Warum setzt ihr denn die Zahl nicht gleich während des Empfangens > zusammen? (d.h. wenn das empfangene Zeichen ein digit ist). Beim '.' > wird dann nur noch entschieden, in welche Variable (je nach tf bzw. dem > anderen Flag) die Zahl kommen muss. Dieses Zwischenspeichern in einem > char Array braucht kein Mensch. Nur läuft ihr dann eben Gefahr, dass > Array zu überlaufen, wenn der Input mal nicht so ist, wie ihr erwartet > habt. Hast du vollkommen recht mit. Kommt auf die TODO-Liste. Allerdings ist der Anwendungsbereich auf die Kommunikation mit der Matlab-Gui beschränkt, welche ich ja entsprechend aufgebaut habe. Insofern in meinen Augen aktuell nicht so dringend. Weiterhin suche ich ja primär nach Ideen zu Gründen für das beschriebene Verhalten.
Zusätzlich zum bereits erwähnten "tans_val()": in einem Interrupt bedient man (oder zumindest ich) kein Display... Im Gegenteil: ich versuche so schnell wie irgend möglich den Interrupt wieder zu verlassen, damit ein anderer Interrupt nicht verschlampt wird. Denn es gibt nur 1 einziges Interruptflag, das anzeigt, ob etwas passiert ist. Wenn das "etwas" 4x passiert, dann habe ich 3x "verloren", weil das eine einzige Flag ja nur 1x merken kann...
Florian H. schrieb: > Hast du vollkommen recht mit. Kommt auf die TODO-Liste. Bei dir kommt immer alles auf die TODO Liste. Die Dinge, von denen die Profis wissen, dass sie vital sind, um blöde Fehler erst gar nicht zu machen, die sind bei dir auf der TODO Liste.
Um es klar zu sagen. Irgendwo in deinem Programm sitzt ein Fehler. Ich tippe mal auf einen Array-Überlauf. Aber dazu müsste man wissen, was über die UART reinkommt und vor allen Dingen müsste man erst mal das Programm komplett auseinandernehmen und vernünftig wieder neu zusammensetzen. Was du gerade lernst, das man mit Schlamperei bei kleinen Programmen noch durchkommt. Bei größeren Programmen geht das aber ins Auge. Und das so sicher, wie das Amen im Gebet.
:
Bearbeitet durch User
Ich hab doch gesagt, dass das sehr unschön, aber im Normalfall funktional ist. Diese unschöne Struktur ist durch den Entstehungsprozess bedingt, in dem in der Regel quick & dirty angesagt war. Fakt ist, ich weiß dass das ziemlich dirty ist aber eigentlich funktioniert. Die Interrupts fallen ca im Sekundentakt. Seid ihr denn ernsthaft der Meinung, dass das Problem damit zu tun hat?
Karl H. schrieb: > Florian H. schrieb: > >> Hast du vollkommen recht mit. Kommt auf die TODO-Liste. > > > Bei dir kommt immer alles auf die TODO Liste. > > Die Dinge, von denen die Profis wissen, dass sie vital sind, um blöde > Fehler erst gar nicht zu machen, die sind bei dir auf der TODO Liste. Ja danke, ich habe auch nie behauptet professionell zu sein. Wenn ihr der Meinung seid, dass deswegen keine Interrupts fallen, weil die zu lange zum ausführen brauchen, dann finde ich das interessant werde das aber so mitnehmen. Wieso interessiert eigentlich niemanden, dass es im Problemfall gar nicht dazu kommt dass ich zu lange in den Interrupts hänge...???
Wem nicht zu helfen ist .... Die UART ist es jedenfalls nicht. Millionen Programmierer haben absolut kein Problem mit der UART. Du währst gut beraten, die Schuld nicht bei der Hardware, beim Compiler etc zu suchen, sondern bei dir und deinem Programm! Natürlich gibt es in all diesen Bereichen Fehler. Aber in in mehr als 99% aller Fälle ist es der Programmierer, der die Sache verbockt hat.
Florian H. schrieb: > Wieso interessiert eigentlich niemanden, > dass es im Problemfall gar nicht dazu kommt dass ich zu lange in den > Interrupts hänge...??? Weil in deinem Programm soviele potentielle Fehlermöglichkeiten stecken, dass man nicht mit dem Finger auf eine davon zeigen kann und sagen kann, die ist es. In deinem Programm stimmt fast gar nichts. Das beginnt bereits beim globalen Programmdesign.
Ich versuche eure Kritik auf zu nehmen und entsprechend nach zu bessern. Bzw. im Neuanfang zu berücksichtigen. Die Frage war aber ernst gemeint. Kann die schlampige programmierung innerhalb der Interrupts dazu führen, dass die nicht ausgeführt werden? Ich kann leider nicht direkt alles verbessern war hier angemerkt wird, werde das aber jetzt in Angriff nehmen. Ich will nur ne Einschätzung haben, ob das realistisch ist, dass das die Ursache für die beschriebenen Fehler ist. Edit: Okay das scheint wohl so zu sein. Ich hoffe ihr habt recht, ansonsten melde ich mich dann wohl mit neuem Code zurück...
:
Bearbeitet durch User
Florian H. schrieb: > Regel quick & dirty angesagt war. Auch wenn man quick&dirty arbeitet, ist man in der Regel gut beraten, zwischendurch immer wieder mal den Code aufzuräumen, durch den Code zu scrollen und sich zu überlegen, wie man Dinge quick einigermassen bereinigen kann. Sonst bleibt nämlich am Ende nur noch "dirty" übrig. "Quick" spielt es dann nicht mehr.
Florian H. schrieb: > Kann die schlampige programmierung > innerhalb der Interrupts dazu führen, dass die nicht ausgeführt werden? klaro wenn am Anfang der IRQ if 1=2 steht gehts gleich wieder raus. Eigentlich wird sie ja ausgeführt, oder man kommt nie mehr raus while(1); Dauert die IRQ zu lange und bleiben die IRQ gesperrt kommen andere IRQ nie an die Reihe. Ich hatte mir angwöhnt ein Port am Anfang der IRQ zu setzen und am Ende zu löschen und mir gerne mal die Verweilzeit im IRQ anzusehen per Oszi, da wird manche "Fehlfunktion" klarer.
Florian H. schrieb: > Wieso interessiert eigentlich niemanden, > dass es im Problemfall gar nicht dazu kommt dass ich zu lange in den > Interrupts hänge...??? Diese Randbedingung als gesetzt hinzunehmen ist aufgrund der Asynchronität des Auftretens von Interrupts gefährlich. Nach meiner Erfahrung sind sich blockierende Interrupts häufige und sehr schwer zu lokalisierende Fehlerursache. > Kann die schlampige programmierung > innerhalb der Interrupts dazu führen, dass die nicht ausgeführt werden? Nur indirekt, wie oben angemerkt: Weil weitere Interrupts (auch von völlig anderen Interruptquellen) eintrudeln, während dein Programm noch in der Abarbeitung des ersten steckt.
Karl H. schrieb: > Florian H. schrieb: > >> Regel quick & dirty angesagt war. > > Auch wenn man quick&dirty arbeitet, ist man in der Regel gut beraten, > zwischendurch immer wieder mal den Code aufzuräumen, durch den Code zu > scrollen und sich zu überlegen, wie man Dinge quick einigermassen > bereinigen kann. > > Sonst bleibt nämlich am Ende nur noch "dirty" übrig. "Quick" spielt es > dann nicht mehr. Meiner zugegebenermaßen wenig professionellen Einschätzung nach lief es halt bis jetzt. Und all zu lange sitze ich auch nicht dran. Aber offensichtlich ist es mehr als Zeit auf zu räumen. Danke für die konstruktiven Kritiken und wer weiß vielleicht fällt einem ja noch eine andere Ursache ein.
Hallo Florian, um dir einen Weg auf zuzeigen, versuche mal einen anderen Ansatz. Implementiere für alle Sende- und Empfangsroutrinen einen "UART mit FIFO". So können alle eingehenden und ausgehenden Zeichen in einem "asynchronen" Puffer "eingeliefert" werden und entsprechend beim Senden auch aus einem weiteren "abgeholt" werden. Somit erfolgt dieser Aufgabe komplett transparent vom eigentlichen Hauptprogramm und man kann die Routinen auch immer wieder als Funktionsbibliothek einsetzen. In nutzte die Implementierung von Peter Dannegger (peda): # Beitrag "AVR-GCC: UART mit FIFO" Der kompakte Programmierstil von Peter muss ja nicht deiner sein, aber aus der Idee und deren Umsetzung könntest Du deinen eigenen Code implementieren.
:
Bearbeitet durch User
Florian H. schrieb: > Allerdings kommt es > scheinbar zufällig vor, dass die USART-Interrupts (Receive Complete) > nicht mehr funktionieren. Warum denkst Du das, d.h. wie genau hast Du das festgestellt? Florian H. schrieb: > Nach Rückbau der > Änderungen ändert sich aber nichts am Fehlverhalten. D.h. Du hast eine vorher laufende Version wieder aus der Versionsverwaltung ausgecheckt und sie verhält sich plötzlich anders? Das glaub ich Dir nicht. Florian H. schrieb: > Ich kommuniziere mit ner Matlab Gui Du must natürlich auch die dazugehörende Version des Matlab Programms mit auschecken.
Peter D. schrieb: > Florian H. schrieb: >> Allerdings kommt es >> scheinbar zufällig vor, dass die USART-Interrupts (Receive Complete) >> nicht mehr funktionieren. > > Warum denkst Du das, d.h. wie genau hast Du das festgestellt? > > Florian H. schrieb: >> Nach Rückbau der >> Änderungen ändert sich aber nichts am Fehlverhalten. > > D.h. Du hast eine vorher laufende Version wieder aus der > Versionsverwaltung ausgecheckt und sie verhält sich plötzlich anders? > Das glaub ich Dir nicht. > > Florian H. schrieb: >> Ich kommuniziere mit ner Matlab Gui > > Du must natürlich auch die dazugehörende Version des Matlab Programms > mit auschecken. Zu 1: Die ausgaben aus dem Interrupt passierten nicht mehr, im Debug Modus lösten die Routinen trotz Flags nicht aus Zu 2: Das kann ich gut verstehen, aber genau das ist so geschehen. Zu 3: Matlab Teil ist aktuell statisch. Ändere ungern mehrere Dinge gleichzeitig. Aktuell versuche ich den Code neu in besser zu schreiben. Edit: zu 2 noch: Falls das ganze wie hier bereits mehrfach angedeutet an den zu langen Interrupts liegt kann ich mir vorstellen, dass das zu scheinbar nicht deterministischen Abläufen führen könnte, aber ist eine reine Vermutung. Edit2: @Uwe: Danke für den Tipp. Werde ich mal rein schauen.
:
Bearbeitet durch User
Florian H. schrieb: > Die ausgaben aus dem Interrupt passierten nicht mehr, im Debug Modus > lösten die Routinen trotz Flags nicht aus Die Ausgaben sind kein zuverlässiger Beweis, sie können ja selber fehlschlagen. Setze direkt bei Eintritt eine LED (Portpin) und lösche sie bei Austritt aus dem Handler. Ist das Flag gesetzt und der Interrupt wird aber nicht betreten, gibt es folgende Ursachen: 1. der Interrupt ist disabled 2. die Interrupts sind global disabled 3. Du bist bereits im Interrupthandler oder einer von ihm aufgerufenen Funktion.
Ich hab immer Bauchweh beim benutzen eines Debuggers. Zu oft sehe ich Entwickler mitm Debugger rumhantieren und zu keinem Ziel kommen. Mit Logging - oder bei MC via Pin-Togglen - bin ich meist viel schneller und weiter gekommen. Wenn man jetzt mehrere Kanäle gleichzeitig aufnehmen kann, sieht man was genau passiert und kann damit argumentieren. Debugger - ohne den hier verwendeten jetzt genau zu kennen - zeigen nur selten was man sehen muss/will. Nämlich wie sich Werte im Zusammenhang mit anderen Werten verändern, insbes. zu welchem Zeitpunkt im Programm. Ich suche und finde Fehler schon seit ich mit Softwareentwicklung vor 15 Jahren anfing mit printf(). Selten haben mir Debugger wirklich geholfen. Gut, was geholfen hat war ein analytisches denken. Thesen aufstellen (was sollte ich gleich sehen? was für werte erwarte ich wo?), ein "Experiment" (Reproduktion des Bugs) und die Analyse des Ergebnisses (was habe ich gesehen? wurde meine These belegt oder wiederlegt? Fehlen noch informationen?). Hier ists im Grunde egal ob Debugger oder printf(). Aber ein Logfile (sei es jetzt auf der Festplatte oder im Speicher-Oszi) beinhaltet meist noch weitere Kontext-Infos von vorherigen "Experimenten". Und das hilft meist beim progressiven Arbeiten. Kurz: Machs wie Peter Dannegger vorschlägt :-)
Florian H. schrieb: > Aktuell versuche ich den Code neu in besser zu schreiben. Und ich hoffe, du fängst erst mal mit der UART, UND NUR mit der UART an (und noch die Anzeige mit dazu, damit du dir ausgeben lassen kannst, was über die UART rein kommt). Nicht zu viel auf einmal. Immer in Schritten arbeiten. Jeden Schritt ausgiebig testen, eher der nächste Teilschritt dazu kommt. Und wenn dir einem Teilschritt etwas unhandlich oder schlecht zu benutzen vorkommt, dann ändere das gleich. Es ist absolut normal, dass man während der Entwicklung drauf kommt, dass manche Dinge sich in der Praxis als weit weniger elegant darstellen als man ürsprünglich dachte. Es ist nicht schlimm seine Entscheidungen zu revidieren. Schlimm ist nur, mit dem selben Krampf wieder besseren Wissens immer weiter zu machen. Und ja, spätestens wenn du 'denselben' Code dem Prinzip nach immer wieder kopierst um nur ein paar Konstanten zu ändern, dann ist es Zeit dafür ein Funktion zu machen. Gerade für UART Funktionen hab ich überhaupt kein Verständnis dafür, warum man sich selbst das Leben schwer machen muss, indem man sich selbst keinerlei Hilsfunktionen schreibt. Die nächsten 3 Funktionen
1 | void uart_putc( char c ) |
2 | {
|
3 | while(!(UCSR0A & (1<<UDRE0))); |
4 | UDR0 = c; |
5 | }
|
6 | |
7 | void uart_puts( const char* s ) |
8 | {
|
9 | while( *s ) |
10 | uart_putc( *s++ ); |
11 | }
|
12 | |
13 | void uart_puti( int i ) |
14 | {
|
15 | char tmp[7]; |
16 | |
17 | itoa( i, tmp, 10 ); |
18 | uart_puts( tmp ); |
19 | }
|
sind das absolute Minimum, das jeder in seinem Vorrat an UART Hilfsfunktionen haben sollte. Das zum Beispiel
1 | uint8_t S[4]; |
2 | sprintf(Temp, "%d", T); |
3 | sprintf(Out, "%d", output); |
4 | sprintf(S, "%d", samp+1); |
5 | while(!(UCSR0A & (1<<UDRE0))); |
6 | UDR0 = 2; //start of text |
7 | while(!(UCSR0A & (1<<UDRE0))); |
8 | UDR0 = 'z'; |
9 | while(!(UCSR0A & (1<<UDRE0))); |
10 | UDR0 = S[0]; |
11 | while(!(UCSR0A & (1<<UDRE0))); |
12 | UDR0 = S[1]; |
13 | while(!(UCSR0A & (1<<UDRE0))); |
14 | UDR0 = S[2]; |
15 | while(!(UCSR0A & (1<<UDRE0))); |
16 | UDR0 = S[3]; |
woher weisst du eigentlich, dass in S[3] irgendwas sinnvolles steht? weisst du doch gar nicht. Solche Dinge sind extrem mühsam zu debuggen, auch wenn die jetzt wahrscheinlich nichts mit deinem Problem zu tun haben. Aber: Du sendest höchst wahrscheinlich etwas an dein Matlab Programm, was da eigentlich nichts zu suchen hat. Wie das Matlab Programm darauf reagiert, das steht in den Sternen. Der springende Punkt ist: solche Dinge musst man suchen und wie die Auswirkungen sind, ist gar nicht so leicht vorherzusagen. Selbst wenn ich kein sprintf verwende (verwenden will), ist ein
1 | uart_putc( STX ); |
2 | |
3 | uart_putc( 'z' ); |
4 | uart_puti( samp + 1 ); |
schon wesentlich leichter zu überblicken und zu verfolgen, als deine ganze UART Orgie. Und vor allen Dingen: Die Mechanik dahinter ist korrekt. Und in der UART-ISR ungeprüft in ein Array schreiben, das ist sowieso ein NoGo. Wenn du dir den Speicher erst mal mit einem Array Überlauf zerschossen hast, werden keine Wetten mehr angenommen, was dein Programm eigentlich noch so alles macht bzw. nicht macht.
:
Bearbeitet durch User
Karl H. schrieb: > Und ich hoffe, du fängst erst mal mit der UART, UND NUR mit der UART an > (und noch die Anzeige mit dazu, damit du dir ausgeben lassen kannst, was > über die UART rein kommt). Eine erste Version könnte zb so aussehen
1 | #define F_CPU 16000000UL
|
2 | |
3 | |
4 | #define BAUD2 38400L
|
5 | #define UBRR_VAL2 ((F_CPU+BAUD2*8)/(BAUD2*16)-1)
|
6 | #define BAUD_REAL2 (F_CPU/(16*(UBRR_VAL2+1)))
|
7 | #define BAUD_ERROR2 ((BAUD_REAL2*1000)/BAUD2)
|
8 | #if ((BAUD_ERROR2<990) || (BAUD_ERROR2>1010))
|
9 | #error Baudratenfehler zu gross! (2)
|
10 | #endif
|
11 | |
12 | #include <stdlib.h> |
13 | #include <ctype.h> |
14 | #include <avr/io.h> |
15 | #include <avr/interrupt.h> |
16 | #include <util/delay.h> |
17 | |
18 | #include "Anzeige.c" |
19 | |
20 | volatile uint16_t samp=0; |
21 | volatile int16_t temp_soll = 10000; |
22 | |
23 | #define CMD_NONE 0
|
24 | #define CMD_NEW_VALUE 1
|
25 | #define CMD_READ 2
|
26 | volatile uint8_t command = CMD_NONE; |
27 | |
28 | #define STX 2
|
29 | #define ETX 3
|
30 | |
31 | void init(void) |
32 | {
|
33 | //setting baud rate
|
34 | UBRR0H = UBRR_VAL2 >> 8; |
35 | UBRR0L = UBRR_VAL2 & 0xFF; |
36 | //enable receive and interrupt
|
37 | UCSR0B |= (1 << RXCIE0) | (1 << RXEN0) | (1<<TXEN0); |
38 | }
|
39 | |
40 | void uart_putc( char c ) |
41 | {
|
42 | while(!(UCSR0A & (1<<UDRE0))); |
43 | UDR0 = c; |
44 | }
|
45 | |
46 | void uart_puts( const char* s ) |
47 | {
|
48 | while( *s ) |
49 | uart_putc( *s++ ); |
50 | }
|
51 | |
52 | void uart_puti( int i ) |
53 | {
|
54 | char tmp[7]; |
55 | |
56 | itoa( i, tmp, 10 ); |
57 | uart_puts( tmp ); |
58 | }
|
59 | |
60 | int main(void) |
61 | {
|
62 | init(); |
63 | |
64 | sei(); |
65 | while(1) |
66 | {
|
67 | if( command == CMD_NEW_VALUE ) |
68 | {
|
69 | command = CMD_NONE; |
70 | .... temp_soll und samp auf der Anzeige ausgeben |
71 | }
|
72 | |
73 | else if( command == CMD_READ ) |
74 | {
|
75 | command = CMD_NONE; |
76 | |
77 | uart_putc( STX ); |
78 | |
79 | uart_putc( 'z' ); |
80 | uart_puti( samp + 1 ); |
81 | |
82 | uart_putc( ETX ); |
83 | }
|
84 | }
|
85 | }
|
86 | |
87 | ISR(USART0_RX_vect) |
88 | {
|
89 | static uint8_t target; |
90 | static uint16_t number = 0; |
91 | uint8_t c; |
92 | |
93 | c = UDR0; |
94 | |
95 | if( c == 't' ) |
96 | {
|
97 | number = 0; |
98 | target = 't'; |
99 | }
|
100 | |
101 | else if( c == 's' ) |
102 | {
|
103 | number = 0; |
104 | target = 's'; |
105 | }
|
106 | |
107 | else if( isdigit(c) ) |
108 | number = 10*number + ( c - '0' ); |
109 | |
110 | else if( c == '.' ) |
111 | {
|
112 | if( target == 't' ) |
113 | temp_soll = number; |
114 | else if( target == 's' ) |
115 | samp = number; |
116 | |
117 | number = 0; |
118 | command = CMD_NEW_VALUE; |
119 | }
|
120 | |
121 | else if( c == 'r' ) |
122 | command = CMD_READ; |
123 | |
124 | else if( c == 'x' ) |
125 | {
|
126 | temp_soll = 0; |
127 | samp = 0; |
128 | command = CMD_NEW_VALUE; |
129 | }
|
130 | }
|
das ist sicherlich noch nicht der Weisheit letzter Schluss und schon da gibt es Alternativen und Dinge, die man anders machen könnte. Aber es ist ein Anfang. Damit kannst du dein UART mal im Dauerbetrieb testen und es zeigt auch, wie eine sinnvolle Arbeitsteilung zwischen ISR und Hauptschleife aussehen könnte. Die ISR macht die Dinge die einfach gehen und die keine nennenswerte Zeit benötigen, wie zb das Zusammensetzen von Digits zu kompletten Zahlen. Für alles weitere hinterlässt sie in einer globalen Variablen einen Code, der dann von der Hauptschleife ausgewertet wird und der dann länger andauernde Aktionen anstösst.
:
Bearbeitet durch User
@Peter: Dritteres ist/war wohl der Fall. @Robin: Ist jetzt auch nicht das erste Mal, dass ich was am uC mache, allerdings das erste Mal in größerem Umfang. Die genannten Methoden sind aber bekannt. Trotzdem danke. @Karl Heinz: Genau da habe ich angefangen. UART habe ich die Basis Funktionen rein gepackt und es ist wesentlich einfacher und übersichtlicher. Die nicht voll geschriebenen Arrays habe ich übrigens Matlabseitig abgefangen, Überläufe empfangsseitig genau so. Bin aber dabei die ganzen Vorschläge aus dem Thread ein zu bauen. Stand bis jetzt ist, dass alle größeren Dinge, vor allem die Sendegeschichten nicht mehr in den Interrupts stehen. Ich habe jetzt wieder ein paar andere Dinge die nicht laufen aber da werde ich erst mal selber ein wenig testen bevor ich deswegen ein Fass auf mache. Eindruck bis jetzt ist jedenfalls, dass die These mit den zugemüllten Interrupts als Quelle für das Fehlverhalten Stand jetzt schwer zu widerlegen sein wird ;) Danke an alle Konstruktiven Beiträge und entschuldigung für den unschönen Code den ich euch aufgetischt habe.
Robin R. schrieb: > Selten haben mir Debugger wirklich geholfen. Kommt darauf an. Bei Fehlern in Berechnungen oder der Logik an sich hilft ein Debugger immens, bei Laufzeitproblemen wie konkurrierende IRQs hilft er nicht. > Gut, was geholfen hat war ein analytisches denken. Das unterschreibe ich zu 100% > Thesen aufstellen (was sollte ich gleich sehen? was für werte erwarte > ich wo?), ein "Experiment" (Reproduktion des Bugs) und die Analyse des > Ergebnisses (was habe ich gesehen? wurde meine These belegt oder > wiederlegt? Ich hatte hier schon mehrere Male die Situation wo ich ein dokumentiertes Verhalten im Trace nicht verstanden habe / nicht nachvollziehen konnte. Da man nicht immer grenzenlos Zeit hat wurde der eigentliche Fehler gefixt, aber fast jedes Mal hat sich das "seltsame" Verhalten als weiterer Fehler oder als Teil des Fehlers herausgestellt und man nusste später noch mal ran.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.