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.
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 ;)
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.
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.
>> warum nicht einfach eine Funktion schreiben, die strings ausgibt. Dann> könnte der Code sogar lesbar werden.>>
1
>voidtrans_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.
@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
voidtrans_val(void)
2
{
3
chartmp[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.
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.
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...
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.
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.
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
voiduart_putc(charc)
2
{
3
while(!(UCSR0A&(1<<UDRE0)));
4
UDR0=c;
5
}
6
7
voiduart_puts(constchar*s)
8
{
9
while(*s)
10
uart_putc(*s++);
11
}
12
13
voiduart_puti(inti)
14
{
15
chartmp[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_tS[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.
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
volatileuint16_tsamp=0;
21
volatileint16_ttemp_soll=10000;
22
23
#define CMD_NONE 0
24
#define CMD_NEW_VALUE 1
25
#define CMD_READ 2
26
volatileuint8_tcommand=CMD_NONE;
27
28
#define STX 2
29
#define ETX 3
30
31
voidinit(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
voiduart_putc(charc)
41
{
42
while(!(UCSR0A&(1<<UDRE0)));
43
UDR0=c;
44
}
45
46
voiduart_puts(constchar*s)
47
{
48
while(*s)
49
uart_putc(*s++);
50
}
51
52
voiduart_puti(inti)
53
{
54
chartmp[7];
55
56
itoa(i,tmp,10);
57
uart_puts(tmp);
58
}
59
60
intmain(void)
61
{
62
init();
63
64
sei();
65
while(1)
66
{
67
if(command==CMD_NEW_VALUE)
68
{
69
command=CMD_NONE;
70
....temp_sollundsampaufderAnzeigeausgeben
71
}
72
73
elseif(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
staticuint8_ttarget;
90
staticuint16_tnumber=0;
91
uint8_tc;
92
93
c=UDR0;
94
95
if(c=='t')
96
{
97
number=0;
98
target='t';
99
}
100
101
elseif(c=='s')
102
{
103
number=0;
104
target='s';
105
}
106
107
elseif(isdigit(c))
108
number=10*number+(c-'0');
109
110
elseif(c=='.')
111
{
112
if(target=='t')
113
temp_soll=number;
114
elseif(target=='s')
115
samp=number;
116
117
number=0;
118
command=CMD_NEW_VALUE;
119
}
120
121
elseif(c=='r')
122
command=CMD_READ;
123
124
elseif(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.
@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.