Hallo, ich musste für die FH einen Datenlogger für 10 Solarzellen bauen. Es sollte die Spannung, der Strom, der Kurzschlussstrom und zwei Temperaturen auf SD Karte aufgezeichnet werden. Das funktioniert auch soweit, nur macht mir der Controller jedes mal nach 32 - 34 Messzyklen (á 10Sek) einen reset. Ich habe schon das MCUCSR Register mit aufgezeichnet und nach dem RESET auf LCD ausgegeben. Das Register ist auch nach dem Reset 0. Ich teste jetzt schon seit Tagen und finde den Fehler einfach nicht. Ich vermute, es ist ein Stack overflow, der mir den reset verursacht (Sprung auf 0 da die Rückspungadresse nicht geladen werden kann). Ich habe den Schaltplan und die Software mal angehängt. Vielleicht kann mir da ja jemand helfen. Vielen Dank schon im Voraus!
Gast
#2076608
MAKE.EXE: *** No rule to make target `main.o', needed by `main.elf'. Stop.
Hi, schreib dir doch eine Testfunktion für den Stack. Bevor deine Vars ins SRAM kopiert werden, schreibst du von RAM_END an eine Anzahl von Bytes mit irgend ein Pattern ins RAM. (zb. 0xFFFF -> 0xFF00 = 0xA5) In der Main oder wenn du deine Werte Logs schreibst du die Anzahl der Bytes die verändert wurden mit weg. So kannst du schnell prüfen wie weit dein Stack anwächst. Beispiel: (kein CODE!!!!)
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
Vielleicht hilft es dir. Stephan
Gast
#2076687
Wo ist die main.c ?
Danke Stefan für die Info. Werd ich mir ansehen, wie das am einfachsten möglich ist. Kurti schrieb: > Wo ist die main.c ? sorry, wollte nicht mit in das zip. Kurz zur Erklärung: Im Prinzip wird alle 10 Sekunden die ISR von Timer1 ausgeführt welche die funktion "measure_and_save() aufruft.
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
19 | |
20 | |
21 | |
22 | |
23 | |
24 | |
25 | |
26 | |
27 | |
28 | |
29 | |
30 | |
31 | |
32 | |
33 | |
34 | |
35 | |
36 | |
37 | |
38 | |
39 | |
40 | |
41 | |
42 | |
43 | |
44 | |
45 | |
46 | |
47 | |
48 | |
49 | |
50 | |
51 | |
52 | |
53 | |
54 | |
55 | |
56 | |
57 | |
58 | |
59 | |
60 | |
61 | |
62 | |
63 | |
64 | |
65 | |
66 | |
67 | |
68 | |
69 | |
70 | |
71 | |
72 | |
73 | |
74 | |
75 | |
76 | |
77 | |
78 | |
79 | |
80 | |
81 | |
82 | |
83 | |
84 | |
85 | |
86 | |
87 | |
88 | |
89 | |
90 | |
91 | |
92 | |
93 | |
94 | |
95 | |
96 | |
97 | |
98 | |
99 | |
100 | |
101 | |
102 | |
103 | |
104 | |
105 | |
106 | |
107 | |
108 | |
109 | |
110 | |
111 | |
112 | |
113 | |
114 | |
115 | |
116 | |
117 | |
118 | |
119 | |
120 | |
121 | |
122 | |
123 | |
124 | |
125 | |
126 | |
127 | |
128 | |
Roman Dissauer schrieb: > Im Prinzip wird alle 10 Sekunden die ISR von Timer1 ausgeführt welche > die funktion "measure_and_save() aufruft. Schlechter Programmierstil. Eine ISR macht man kurz und flink. Die sollte nur ein Flag setzen, und die main loop wertet dieses Flag aus und triggert die weiteren Aktionen. Ist allerdings in deinem Falle möglicherweise nicht ernstlich relevant, da du ja nur einen Interrupt hast. > ISR (TIMER1_OVF_vect) > { > cli(); // disable interrupts Du solltest mit dem Studium des Controller-Handbuchs beginnen. Während einer ISR sind weitere Interrupts gesperrt ... > TCNT1 = 0x676A; // preload timer for timebase 10s Dafür nimmt man den CTC-Modus, statt hier manuell mit dem Timerwert rumzufummeln. > sei(); Sowas mancht man in einer ISR nur, wenn man sich wirklich sicher ist, was man tut. Andernfalls riskiert man einen rekursiven Interruptaufruf, und genau das könnte dein Problem sein. Falls es deine Funktion measure_and_save() nämlich nicht schafft, zwischen zwei Interrupts fertig zu werden, ist der Teufel los. Die oben genannte Variante mit einem Flag und der Auswertung in der main loop hat dieses Risiko nicht; die würde dann nur eine Messung verpassen, aber nicht in die (möglicherweise unendliche) Rekursion laufen.
Gast
#2078048
sprintf(str, "%u$1;1;%d%d.%d%d.%d%d%d%d %d%d:%d%d:%d%d;",
MCUCSR, rtc.date[0], rtc.date[1], rtc.date[3], rtc.date[4],
rtc.date[6], rtc.date[7], rtc.date[8], rtc.date[9],
rtc.time[0], rtc.time[1], rtc.time[3], rtc.time[4], rtc.time[6],
rtc.time[7]);
Bist du sicher das dieser Rattenschwanz in das hier passt?
unsigned char str[30];
Da kommt möglicherweise dein Stacküberlauf her.
Verwende besser snprintf(str, 30, "..",..);
Dann gibts keinen Arrayüberlauf.
Danke Jörg für deine Kommentare! Jetzt läuft es schon über 40min! Zuvor gab es alle 5min einen reset. Jörg Wunsch schrieb: > Roman Dissauer schrieb: >> Im Prinzip wird alle 10 Sekunden die ISR von Timer1 ausgeführt welche >> die funktion "measure_and_save() aufruft. > > Schlechter Programmierstil. Eine ISR macht man kurz und flink. > Die sollte nur ein Flag setzen, und die main loop wertet dieses > Flag aus und triggert die weiteren Aktionen. Dass mein Programmierstil nicht der beste ist kann ich mir gut vorstellen. Ist mein erstes uC Projekt. :) > Während einer ISR sind weitere Interrupts gesperrt ... Wenn doch während einer ISR alle weiteren Interrupts gesperrt sind, muss doch egal sein, wie lange diese ausgeführt wird. Bei mir ist der Interrupt alle 10sek gekommen und das Ausführen der ISR dauerte keine 100ms. Ich hab den Code jetzt mal im ersten Schritt folgendermaßen geändert:
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
19 | |
20 | |
21 | |
22 | |
23 | |
24 | |
25 | |
26 | |
27 | |
28 | |
29 | |
30 | |
31 | |
32 | |
33 | |
34 | |
Wie gesagt, ich versteh das zwar nicht ganz warum es jetzt funktioniert, aber ich werds mir merken, dass ISR kurz und bündig gemacht werden müssen. >> TCNT1 = 0x676A; // preload timer for timebase 10s > > Dafür nimmt man den CTC-Modus, statt hier manuell mit dem Timerwert > rumzufummeln. Danke für die Info, werd ich auch noch ändern. > Sowas mancht man in einer ISR nur, wenn man sich wirklich sicher > ist, was man tut. Andernfalls riskiert man einen rekursiven > Interruptaufruf, und genau das könnte dein Problem sein. Falls > es deine Funktion measure_and_save() nämlich nicht schafft, zwischen > zwei Interrupts fertig zu werden, ist der Teufel los. Wie schon gesagt, meine ISR hat ca. 100ms zum ausführen gebraucht und der Interrupt ist alle 10 sek gekommen. Da es jetzt funktioniert, wird es wohl daran gelegen sein, aber verstanden hab ich es nicht ganz. Eine Sache, die ich auch noch nicht ganz verstanden hab: wenn ich in der Endlosschleife das
1 | |
2 | |
3 | |
weglasse, wird die funktion measure_and_save() nie ausgeführt!
holger schrieb: > Bist du sicher das dieser Rattenschwanz in das hier passt? > > unsigned char str[30]; ja, da war schon viel mehr drin! :) Ich hatte im Anfangsstadium der Software die komplette Zeile aus measure_and_save() in einem Array unsigned char str[256]; Nachdem ich Verdacht auf einen Stack overflow hatte, hab ich das dann in einzelne kleine abschnitte unterteilt und zum Schluss erst \n\r gemacht. > Verwende besser snprintf(str, 30, "..",..); vielen Dank für den Input, ich werd das auch noch aufnehmen.
Roman Dissauer schrieb: > weglasse, wird die funktion measure_and_save() nie ausgeführt! Hast du "measure" mittlerweile als volatile deklariert? Diese Variable änderst du in der ISR, das muss der Compiler wissen, damit er den Check beim if() keinesfalls wegoptimiert.
Tom M. schrieb: > Hast du "measure" mittlerweile als volatile deklariert? nachdem ich das gemacht hab, hat es auch ohne else{ nop(); } funktioniert. Vielen Dank! Ich hab nun auch den Timer auf CTC umgestellt, funktioniert alles blendend! Ich lass das ding mal über Nacht laufen, mal schauen was passiert. Vielen Dank allen nochmal für die schnelle Hilfe!
Roman Dissauer schrieb: >> Während einer ISR sind weitere Interrupts gesperrt ... > Wenn doch während einer ISR alle weiteren Interrupts gesperrt sind, muss > doch egal sein, wie lange diese ausgeführt wird. Jein. Bei dir wäre es in der Tat egal, allerdings hast du ja gleich am Anfang selbst die Interrupts freigegeben. Wenn man mehr als einen Interrupt hat, dann führt eine lang laufende ISR jedoch zu riesigen (und schwankenden) Latenzen in der Interruptannahme, daher vermeidet man das.
Gast
#2078711
Roman Dissauer schrieb: >> Während einer ISR sind weitere Interrupts gesperrt ... > Wenn doch während einer ISR alle weiteren Interrupts gesperrt sind, muss > doch egal sein, wie lange diese ausgeführt wird. Bei mir ist der > Interrupt alle 10sek gekommen und das Ausführen der ISR dauerte keine > 100ms. Naja, während die ISR läuft, ist halt alles andere blockiert. Jörg Wunsch schrieb: > Wenn man mehr als einen Interrupt hat, dann führt eine lang > laufende ISR jedoch zu riesigen (und schwankenden) Latenzen > in der Interruptannahme, daher vermeidet man das. Wenn während der Zeit ein anderer Interrupt mehrmals ankommt, verliert man auch welche. Wenn du z.B. beschließt, noch für irgendeine Zeitstempelung einen weiteren Timer im Millisekunden-Takt laufen zu lassen und dort einen Counter zu inkrementieren, dann verlierst du während deiner 100 ms halt 99 von den Inkrementierungen.
Antwort schreiben
Bitte melde dich an, um einen Beitrag zu schreiben.