Guten Abend, Ich habe hier eine Schaltung welche über SPI einen A/D Wandler liest und den Messwert auf einer 7-Segment Anzeige ausgibt. Zusätzlich habe ich noch 3 Taster angeschlossen mit PullUps auf high. Bei Tastendruck wird der PIN auf GND gelegt. Eine SET ein UP und eine DOWN Taste. Damit kann ein Wert eingestellt werden um ein Relais bei einem bestimmten erreichten Wert ein/aus schaltet. Timer1 wird verwendet um die Anzeige alle 20 ms zu aktualisieren. high priorit Interrupt. Timer0 wird verwendet um alle 500ms eine Messung zu triggern. low priority Interrupt. Das Program läuft super. Bis ich die Tasten verwenden möchte. Es funktioniert ein paar mal und dann bleibt das Programm stehen. Der Wert ändert sich nicht mehr und die Tasten haben auch keine Wirkung mehr. Habt ihr schon mal solche Erfahrungen gemacht? Danke Andreas
Gast
#3089471
>Timer1 wird verwendet um die Anzeige alle 20 ms zu aktualisieren. >Timer0 wird verwendet um alle 500ms eine Messung zu triggern. Zwei Timer? Warum leitest Du das 500 ms-Interval nicht einfach aus den 20 ms ab? >dann bleibt das Programm stehen Kann viel heißen. Ich würde als erstes prüfen, ob die Mainloop noch ausgeführt wird. Was das Problem mit den Tasten betrifft, kannst Du davon ausgehen, dass es nicht am Controller liegt, sondern an der Beschaltung oder am Code, wobei letzteres sehr viel wahrscheinlicher ist.
Ich verwende 2 Timer weil die Wandlung recht lange dauert. Damit meine Anzeige nicht flimmert wird der low priority Interrupt vom high Interrupt unterbrochen. Ich denke das alles stehen bleibt weil sich auch die Anzeige nicht mehr aktualisiert.
Gast
#3089540
Erfahrungen gesammelt - aber sicher doch! Irgendwie lässt sich das Problem immer mit einer LED finden. Ein paar Befehle zum Ein-Ausschalten einbauen und die Stelle wo es hängt einkreisen. Mit dem Pickit Debugger geht es aber 100 mal so schnell.
Gast
#3089635
>Ich verwende 2 Timer weil die Wandlung recht lange dauert. Damit meine >Anzeige nicht flimmert wird der low priority Interrupt vom high >Interrupt unterbrochen. nixversteh Wieso spielt es ne Rolle, wie lange die Wandlung dauert? Wartest Du die etwa mit ner blockierenden Schleife ab? Oh, mir schwant Übles, denn genau das käme gut als Grund in Betracht, warum Du die Interrupt-durch-Interrupt-Unterbrechungsgeschichte brauchst. Sonst hätte ich keine Erklärung dafür, denn 20 ms sind ne Ewigkeit. OK, da ich nicht weiß, was Du da gecodet hast, ist alles nur Spekulation. Davon will ich Dich lieber verschonen. Gute Nacht.
Hallo, Ich habe jetzt festgestellt das die Interrupts weiter laufen und die Hauptschleife den Geist aufgibt. Ich empfange am PC nach wie vor die Werte und das Display reagier auch immer noch. Hier ist noch mein Code:
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 | |
129 | |
130 | |
131 | |
132 | |
133 | |
134 | |
135 | |
136 | |
137 | |
138 | |
139 | |
140 | |
141 | |
142 | |
143 | |
144 | |
145 | |
146 | |
147 | |
148 | |
149 | |
150 | |
151 | |
152 | |
153 | |
154 | |
155 | |
156 | |
157 | |
158 | |
159 | |
160 | |
161 | |
162 | |
163 | |
164 | |
165 | |
166 | |
167 | |
168 | |
169 | |
170 | |
171 | |
172 | |
173 | |
174 | |
175 | |
176 | |
177 | |
178 | |
179 | |
180 | |
181 | |
182 | |
183 | |
184 | |
185 | |
186 | |
187 | |
188 | |
189 | |
190 | |
191 | |
192 | |
193 | |
194 | |
195 | |
196 | |
197 | |
198 | |
199 | |
200 | |
201 | |
202 | |
203 | |
204 | |
205 | |
206 | |
207 | |
208 | |
209 | |
210 | |
211 | |
212 | |
213 | |
214 | |
215 | |
216 | |
217 | |
218 | |
219 | |
220 | |
221 | |
222 | |
223 | |
224 | |
225 | |
226 | |
227 | |
228 | |
229 | |
230 | |
231 | |
232 | |
233 | |
234 | |
235 | |
236 | |
237 | |
238 | |
239 | |
240 | |
241 | |
242 | |
243 | |
244 | |
245 | |
246 | |
247 | |
248 | |
249 | |
250 | |
251 | |
252 | |
253 | |
254 | |
255 | |
256 | |
257 | |
258 | |
259 | |
260 | |
261 | |
262 | |
263 | |
264 | |
265 | |
266 | |
267 | |
268 | |
269 | |
270 | |
271 | |
272 | |
273 | |
274 | |
275 | |
276 | |
277 | |
278 | |
279 | |
280 | |
281 | |
282 | |
283 | |
284 | |
285 | |
286 | |
287 | |
288 | |
289 | |
290 | |
291 | |
292 | |
293 | |
294 | |
295 | |
296 | |
297 | |
298 | |
299 | |
300 | |
301 | |
302 | |
303 | |
304 | |
305 | |
306 | |
307 | |
308 | |
309 | |
310 | |
311 | |
312 | |
313 | |
314 | |
315 | |
316 | |
317 | |
318 | |
319 | |
320 | |
321 | |
322 | |
323 | |
324 | |
325 | |
326 | |
327 | |
328 | |
329 | |
330 | |
331 | |
332 | |
333 | |
334 | |
335 | |
336 | |
337 | |
338 | |
339 | |
340 | |
341 | |
342 | |
343 | |
344 | |
345 | |
346 | |
347 | |
348 | |
349 | |
350 | |
351 | |
352 | |
353 | |
354 | |
355 | |
356 | |
357 | |
358 | |
359 | |
360 | |
361 | |
362 | |
363 | |
364 | |
365 | |
366 | |
367 | |
368 | |
369 | |
370 | |
371 | |
372 | |
373 | |
374 | |
375 | |
376 | |
377 | |
378 | |
379 | |
380 | |
381 | |
382 | |
383 | |
384 | |
BG Andreas
Gast
#3090174
Delayschleifen (Delay1KTCYx) im ISR-Handler? Blockierendes Warten auf das Loslassen von Tasten? Dein Programm ist - sorry - ein Beispiel dafür, wie man's nicht machen sollte. Mein Rat: Tu Dir was Gutes und schreibs neu. Erzeuge Dir mit einem (Hardware-)Timer einen 5 ms-Interrupt (*). Der reicht für alles. Weitere (Hardware-)Timer brauchst Du nicht. Alle längeren Zeiten zählst Du einfach über Software-Counter ab. Keine Delayschleifen, keine Wartegeschichten; beides ist strikt verboten. Das entsprechende Konzept heißt kooperatives Multitasking. Wie das funktioniert, kannst Du z. B. hier nachlesen: http://www.mikrocontroller.net/articles/Multitasking#Kooperatives_Multitasking Wenn Du es schaffst, was nicht schwer ist, wenn Du das Prinzip verstanden hast, wirst Du am Schluss wahrscheinlich über das Ergebnis erstaunt sein: Obwohl in Deinem Programm nirgendwo mehr irgendein Delay etc. vorkommt, erfüllt es seine Aufgabe genau wie gewünscht - hundertprozent flimmerfreies Display inklusive ;-) Wegen seiner einfachen Struktur kannst Du sein Verhalten nachvollziehen und voraussagen, Du kannst etwaige Fehler im Code relativ schnell finden und korrigieren, und Du kannst es leicht ändern und erweitern. Alles sehr willkommene Eigenschaften, meinst Du? Stimmt. Besser gesagt: Ihr Wert kann gar nicht hoch genug geschätzt werden. Deshalb ziehen erfahrene Programmierer das kooperative Multitasking allen Alternativen vor, solange dem keine gewichtigen Gründe entgegenstehen. (*) Damit kommst Du bei drei Digits auf eine Display-Refreshrate von 1/(3*5 ms) = 66 Hz. Das ist ein brauchbarer Wert.
Andreas Riegebauer schrieb: > Das Program läuft super. Bis ich die Tasten verwenden möchte. Tastenpins direkt in Mainloop abfragen -> ganz schlecht. Tasten brauchen Entprellen + Flankenerkennung. Beides geht am besten mit einem Timerinterrupt.
Ich werde es versuchen das Programm umzuschreiben. Ich weiß allerdings nicht ganz wie. Ich habe mir den Artikel durchgelesen. Den Timer auf die 5 ms zu stellen ist kein Problem. Aber soll ich das so machen wie im Beispiel das ich die Hauptschleife jede ms ausführen lasse oder den Code auch in der Interrupt routine lassen? Bzw. was in den Interrupt stecken und was in der Hauptschleife lassen? Wieso ist das Abfragen der Tasten in der Hauptschleife schlecht? Wo sonst? BG Andreas
Eine Interrupt-Routine sollte so klein und so schnell wie möglich sein. Keine Delays, keine komplexen Berechnungen, keine großen Ausgaben, das alles gehört in die Main Loop. Am besten, denke ich, ist es du beginnst mit der Tastenentprellung, ohne irgendwas anderes. Dadurch musst du einen Timer richtig verwenden, und hast eine gute Basis um weiter aufzubauen. Funktioniert alles kannst du das Display hinzufügen. Ein Counter den du im Timer hochzählst gibt dir eine Zeitbasis nach der du dich in deiner Main Loop richten kannst. Überprüfe einfach den Counter und update das Display in der Main Loop wenn ein bestimmter Wert erreicht ist (setz den Counter jedes mal zurück, sodass er von vorne beginnt zu zählen) Dann implementiere den A/D Wandler in der Main Loop. Da er eine Weile zum Wandeln braucht musst du auf das Ergebnis warten. Aber nicht indem du das Programm, wie momentan, anhälst. Stattdessen starte die Wandlung, lass dein Programm weiter arbeiten und nach 100ms oder so liest du den Wert ein. Alles kannst du wieder mit dem Counter der im Timer inkrementiert wird bewerkstelligen. Somit solltest du kein einziges Delay verwendet haben. Professioneller geht es vermutlich durch einen externen Interrupt den der Wandler auslösen kann (RDY Pin) und dir signalisiert wann die Wandlung abgeschlossen ist. Das ist aber eine Erweiterung und kann später realisiert werden. Noch was: Du hast den AD7793 laut Code, der hat zwei Modi, Single Measurement und Continuous Measurement. Wenn du nicht Batteriebetrieben bist, d.h. Stromsparen musst, so kannst du doch auch einfach den Continous Modus (Standardmäßig aktiviert) benutzen. Dadurch musst du nicht die Wandlung starten, da er ständig eine Wandlung durchführt. D.h. du musst einfach nur alle 500ms den Wert auslesen, sonst nichts. Das macht dir das Leben einfacher.
Gast
#3090832
>Aber soll ich das so machen wie im Beispiel das ich die Hauptschleife jede >ms ausführen lasse oder den Code auch in der Interrupt routine lassen? Bzw. >was in den Interrupt stecken und was in der Hauptschleife lassen? Gut! Das Stellen dieser Frage zeigt, dass Du schon viel verstanden hast. Wenn Du nirgendwo mehr ein Delay hast, bleiben nur noch die "echten" Berechnungen übrig. Da das vermutlich nur wenige einfache sind, wird Dein µC damit unter allen Umständen (d. h. auch bei der umfangreichsten Berechnung, die jemals auftreten kann) sehr schnell fertig sein - wahrscheinlich innerhalb von Millisekundenbruchteilen. Wenn das zutrifft, kannst Du alles in der Main oder alles im Timerinterrupt laufen lassen, oder die Aufgaben nach gusto aufteilen - es spielt keine Rolle. Ich würde dann einfach alles in der Main erledigen, unter Verwendung eines passenden Sleep-Modus. Etwas anders siehts aus, wenn nicht garantiert ist, dass der µC die Berechnungen immer in 5 ms schafft. Dann gehört der Berechnungsteil in die Main, und in die Timer-ISR kommt alles, was die Ein-/Ausgabe des Programms betrifft, also das Einlesen der Tasten, und das Refreshen des Displays (aber nicht mehr!). Die Timer-ISR behält ihren 5 ms-Takt, aber die Main wird mit einem langsameren Takt versorgt, z. B. nur 40 ms, erzeugt durch softwaremäßige 1:8-Teilung des 5 ms-Taktes. Damit bekommst Du zwei Ausführungslevel in Deinem Programm: Einen "weichen", das ist die mit mäßiger Frequenz vor sich hintuckernde, timingUNkritische, unterbrechbare Mainloop für den Berechnungskram, und einen "harten", das ist die Timer-ISR für alle I/O-Angelegenheiten, die timingkritisch sind und/oder schnell laufen sollen (bei Dir der Refresh des LED-Displays). Der Timer-Interrupt kann und wird dann die Mainloop unterbrechen, wenn es erforderlich ist - das ist der Clou an der Sache. Buenas noches.
Andreas Riegebauer schrieb: > Wieso ist das Abfragen der Tasten in der Hauptschleife schlecht? Wo > sonst? Weil Du keine Kontrolle darüber hast, wann und wie oft die Mainloop den Pin abfragt. Dauert die Mainloop mal länger, geht der Tastendruck verloren. Dauert sie kurz, siehst Du mehrere Tastendrücke (Preller). Nur mit einem Timerinterrupt kannst Du definierte Entprellintervalle erzeugen. Und darin setzt Du dann ein Flag, daß ein Tastendruck erkannt wurde. Das Main kann nun dieses Flag lesen und löschen, wann es ihm paßt. Es kriegt nur genau ein Event je Druck und verliert keinen Druck.
Antwort schreiben
Bitte melde dich an, um einen Beitrag zu schreiben.