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
>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.
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.
>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 | #include <p18f46k20.h> |
2 | #include <usart.h> |
3 | #include <delays.h> |
4 | #include <spi.h> |
5 | #include <stdlib.h> |
6 | #include <AD7793.h> |
7 | #include <Communication.h> |
8 | #include <timers.h> |
9 | |
10 | // CONFIG1H |
11 | #pragma config FOSC = HS // Oscillator Selection bits (HS oscillator) |
12 | #pragma config FCMEN = OFF // Fail-Safe Clock Monitor Enable bit (Fail-Safe Clock Monitor disabled) |
13 | #pragma config IESO = OFF // Internal/External Oscillator Switchover bit (Oscillator Switchover mode disabled) |
14 | |
15 | // CONFIG2L |
16 | #pragma config PWRT = ON // Power-up Timer Enable bit (PWRT enabled) |
17 | #pragma config BOREN = OFF // Brown-out Reset Enable bits (Brown-out Reset disabled in hardware and software) |
18 | #pragma config BORV = 30 // Brown Out Reset Voltage bits (VBOR set to 3.0 V nominal) |
19 | |
20 | // CONFIG2H |
21 | #pragma config WDTEN = OFF // Watchdog Timer Enable bit (WDT is controlled by SWDTEN bit of the WDTCON register) |
22 | #pragma config WDTPS = 32768 // Watchdog Timer Postscale Select bits (1:32768) |
23 | |
24 | // CONFIG3H |
25 | #pragma config CCP2MX = PORTC // CCP2 MUX bit (CCP2 input/output is multiplexed with RC1) |
26 | #pragma config PBADEN = OFF // PORTB A/D Enable bit (PORTB<4:0> pins are configured as digital I/O on Reset) |
27 | #pragma config LPT1OSC = OFF // Low-Power Timer1 Oscillator Enable bit (Timer1 configured for higher power operation) |
28 | #pragma config HFOFST = OFF // HFINTOSC Fast Start-up (The system clock is held off until the HFINTOSC is stable.) |
29 | #pragma config MCLRE = ON // MCLR Pin Enable bit (MCLR pin enabled; RE3 input pin disabled) |
30 | |
31 | // CONFIG4L |
32 | #pragma config STVREN = ON // Stack Full/Underflow Reset Enable bit (Stack full/underflow will cause Reset) |
33 | #pragma config LVP = OFF // Single-Supply ICSP Enable bit (Single-Supply ICSP enabled) |
34 | #pragma config XINST = OFF // Extended Instruction Set Enable bit (Instruction set extension and Indexed Addressing mode disabled (Legacy mode)) |
35 | |
36 | // DEFINITIONS |
37 | #define DIGIT4 PORTBbits.RB4 |
38 | #define DIGIT3 PORTBbits.RB5 |
39 | #define DIGIT2 PORTAbits.RA2 |
40 | #define DIGIT1 PORTAbits.RA3 |
41 | |
42 | void high_isr(void); |
43 | void low_isr(void); |
44 | unsigned long GetRREF(void); |
45 | unsigned long GetRRTD(void); |
46 | unsigned long CalcTemp(void); |
47 | |
48 | unsigned int On_1 = 300; |
49 | unsigned int Off_1 = 310; |
50 | int menu = 0x00; |
51 | int counter = 0x00; |
52 | unsigned long Temperature = 0x00; |
53 | |
54 | unsigned long CodeRREF = 0x00, CodeRRTD = 0x00; |
55 | |
56 | /****************** Start Interrupt *********************/ |
57 | /* |
58 | * High interrupt vector |
59 | */ |
60 | #pragma code high_vector=0x08 |
61 | void high_vector_interrupt (void) |
62 | { |
63 | _asm |
64 | GOTO high_isr |
65 | _endasm |
66 | } |
67 | |
68 | /* |
69 | * Low interrupt vector |
70 | */ |
71 | #pragma code low_vector=0x18 |
72 | void low_vector_interrupt (void) |
73 | { |
74 | _asm |
75 | GOTO low_isr |
76 | _endasm |
77 | } |
78 | |
79 | #pragma code /* return to the default code section */ |
80 | /* |
81 | * High priority interrupt routine |
82 | */ |
83 | #pragma interrupt high_isr |
84 | void high_isr (void) |
85 | { |
86 | char buffer[20]; |
87 | unsigned int i; |
88 | |
89 | if ( PIR1bits.TMR1IF ) // check for TMR0 overflow |
90 | { |
91 | /* if menu is zero the temp is shown */ |
92 | if( menu == 0 ) |
93 | { |
94 | ultoa( Temperature, buffer ); |
95 | |
96 | i = (unsigned int)buffer[2]; |
97 | i -= 48; |
98 | PORTB = i; |
99 | DIGIT1 = 1; |
100 | Delay1KTCYx(10); |
101 | DIGIT1 = 0; |
102 | i = (unsigned int)buffer[1]; |
103 | i -= 48; |
104 | PORTB = i; |
105 | DIGIT2 = 1; |
106 | Delay1KTCYx(10); |
107 | DIGIT2 = 0; |
108 | i = (unsigned int)buffer[0]; |
109 | i -= 48; |
110 | PORTB = i; |
111 | DIGIT3 = 1; |
112 | Delay1KTCYx(10); |
113 | DIGIT3 = 0; |
114 | } |
115 | |
116 | /* if menu is 1 then the on temp is shown */ |
117 | if( menu == 1 ) |
118 | { |
119 | ultoa( On_1, buffer ); |
120 | |
121 | i = (unsigned int)buffer[2]; |
122 | i -= 48; |
123 | PORTB = i; |
124 | DIGIT1 = 1; |
125 | Delay1KTCYx(10); |
126 | DIGIT1 = 0; |
127 | i = (unsigned int)buffer[1]; |
128 | i -= 48; |
129 | PORTB = i; |
130 | DIGIT2 = 1; |
131 | Delay1KTCYx(10); |
132 | DIGIT2 = 0; |
133 | i = (unsigned int)buffer[0]; |
134 | i -= 48; |
135 | PORTB = i; |
136 | DIGIT3 = 1; |
137 | Delay1KTCYx(10); |
138 | DIGIT3 = 0; |
139 | } |
140 | |
141 | /* if menu is 2 then the off temp is shown */ |
142 | if( menu == 2 ) |
143 | { |
144 | ultoa( Off_1, buffer ); |
145 | |
146 | i = (unsigned int)buffer[2]; |
147 | i -= 48; |
148 | PORTB = i; |
149 | DIGIT1 = 1; |
150 | Delay1KTCYx(10); |
151 | DIGIT1 = 0; |
152 | i = (unsigned int)buffer[1]; |
153 | i -= 48; |
154 | PORTB = i; |
155 | DIGIT2 = 1; |
156 | Delay1KTCYx(10); |
157 | DIGIT2 = 0; |
158 | i = (unsigned int)buffer[0]; |
159 | i -= 48; |
160 | PORTB = i; |
161 | DIGIT3 = 1; |
162 | Delay1KTCYx(10); |
163 | DIGIT3 = 0; |
164 | } |
165 | |
166 | PIR1bits.TMR1IF = 0; // clear interrupt flag |
167 | WriteTimer1( 61785 ); // every 20 ms @12MHz a Interrupt |
168 | } // End TMR1IF |
169 | |
170 | |
171 | } |
172 | |
173 | #pragma code /* return to the default code section */ |
174 | /* |
175 | * |
176 | * low priority interrupt routine |
177 | * |
178 | * This starts the messure of the needed values |
179 | * |
180 | */ |
181 | #pragma interrupt low_isr |
182 | void low_isr (void) |
183 | { |
184 | char buffer[20]; |
185 | |
186 | if (INTCONbits.TMR0IF) // check for TMR0 overflow |
187 | { |
188 | CodeRRTD += GetRRTD(); // calc average |
189 | if( counter > 0 ) CodeRRTD /= 2; |
190 | CodeRREF += GetRREF(); // calc average |
191 | if( counter > 0 ) CodeRREF /= 2; |
192 | |
193 | counter++; |
194 | |
195 | if( counter == 4 ) |
196 | { |
197 | Temperature = CalcTemp(); |
198 | |
199 | ultoa( Temperature, buffer ); |
200 | putsUSART( buffer ); // send to PC |
201 | putrsUSART( "\r\n" ); |
202 | |
203 | /* Turn on or off the heating */ |
204 | if( Temperature < On_1 ) |
205 | { |
206 | PORTDbits.RD7 = 1; |
207 | } |
208 | if( Temperature > Off_1 ) |
209 | { |
210 | PORTDbits.RD7 = 0; |
211 | } |
212 | |
213 | CodeRREF = 0x00; |
214 | CodeRRTD = 0x00; |
215 | counter = 0x00; |
216 | } |
217 | } |
218 | INTCONbits.TMR0IF = 0; // clear interrupt flag |
219 | WriteTimer0( 18660 ); // every 500 ms a Interrupt |
220 | } |
221 | /****************** END Interrupt *********************/ |
222 | . |
223 | . |
224 | . |
225 | 3 Methoden fehlen |
226 | . |
227 | . |
228 | . |
229 | |
230 | /*********************************** |
231 | * |
232 | * main program |
233 | * |
234 | **********************************/ |
235 | void main( void ) |
236 | { |
237 | char buffer[20]; |
238 | |
239 | /* 9600, */ |
240 | OpenUSART(USART_TX_INT_OFF & |
241 | USART_RX_INT_OFF & |
242 | USART_ASYNCH_MODE & |
243 | USART_EIGHT_BIT & |
244 | USART_BRGH_HIGH, |
245 | 77); |
246 | |
247 | /* SPI idle is high, FOSC/64, */ |
248 | OpenSPI( SPI_FOSC_64, MODE_11, SMPMID ); |
249 | |
250 | /* Open Timer 0 */ |
251 | OpenTimer0( TIMER_INT_ON & |
252 | T0_16BIT & |
253 | T0_SOURCE_INT & |
254 | T0_PS_1_32 ); |
255 | |
256 | /* Open Timer 1 */ |
257 | OpenTimer1( TIMER_INT_ON & |
258 | T1_16BIT_RW & |
259 | T1_SOURCE_INT & |
260 | T1_PS_1_8 & |
261 | T1_OSC1EN_OFF & |
262 | T1_SYNC_EXT_OFF ); |
263 | |
264 | RCONbits.IPEN = 1; // Enable priority on interrupts |
265 | INTCONbits.GIEH = 1; // Enable high priority interrupt |
266 | INTCONbits.GIEL = 1; // Enable low priority interrupt |
267 | |
268 | INTCONbits.PEIE = 1; // Enable peripherial interrupts |
269 | |
270 | INTCONbits.TMR0IE = 1; // Enable TMR0 interrupt |
271 | INTCON2bits.TMR0IP = 0; // TMR0 interrupt low priority |
272 | |
273 | PIE1bits.TMR1IE = 1; // TMR1 interrupt enable |
274 | IPR1bits.TMR1IP = 1; // TMR1 interrupt high priority |
275 | |
276 | ANSEL = 0x00; // All Pins digital |
277 | ANSELH = 0x00; // All Pins digital |
278 | |
279 | TMR0H = 0x00; |
280 | TMR0L = 0x00; |
281 | |
282 | TMR1H = 0x00; |
283 | TMR1L = 0x00; |
284 | |
285 | TRISA = 0x00; // PortA output |
286 | TRISB = 0x00; // PortB output |
287 | TRISCbits.TRISC0 = 0; // RC0/CS - output |
288 | TRISCbits.TRISC4 = 1; // RC4/SDI - input |
289 | TRISCbits.TRISC5 = 0; // RC5/SDO - output |
290 | TRISCbits.TRISC3 = 0; // RC3/CLK - output |
291 | TRISDbits.TRISD0 = 1; // Taster - input |
292 | TRISDbits.TRISD1 = 1; // Taster - input |
293 | TRISDbits.TRISD2 = 1; // Taster - input |
294 | TRISDbits.TRISD3 = 1; // Taster - input |
295 | TRISDbits.TRISD6 = 0; // D6 - output (LED) |
296 | TRISDbits.TRISD7 = 0; // D7 - output (LED) |
297 | |
298 | AD7793_Reset(); |
299 | /* Set AD to idle mode */ |
300 | AD7793_SetRegisterValue(AD7793_REG_MODE, // MODE Reg |
301 | 0b0100000000000000, // Idle mode |
302 | 2, // 2 byte register |
303 | 1); // CS is modified by SPI read/write functions. |
304 | |
305 | DIGIT1 = 0; |
306 | DIGIT2 = 0; |
307 | DIGIT3 = 0; |
308 | DIGIT4 = 0; |
309 | |
310 | /* |
311 | * |
312 | * Start while |
313 | * |
314 | */ |
315 | while( 1 ) |
316 | { |
317 | /* up button */ |
318 | if( !PORTDbits.RD0 && ( menu > 0 ) ) |
319 | { |
320 | Delay1KTCYx(10); // Wake up time 1 ms |
321 | while( !PORTDbits.RD0 ); // wait till release |
322 | |
323 | /* plus On temp */ |
324 | if( menu == 1 ) |
325 | { |
326 | On_1++; |
327 | } |
328 | |
329 | /* plus Off temp */ |
330 | if( menu == 2 ) |
331 | { |
332 | Off_1++; |
333 | } |
334 | } |
335 | |
336 | /* set button */ |
337 | if( !PORTDbits.RD1 ) |
338 | { |
339 | Delay1KTCYx(10); // Wake up time 1 ms |
340 | while( !PORTDbits.RD1 ); // wait till release |
341 | |
342 | menu++; |
343 | |
344 | /* If in menu the Interrupt is disabled */ |
345 | if( menu > 0 ) |
346 | { |
347 | INTCONbits.TMR0IE = 0; // Enable TMR0 interrupt |
348 | } |
349 | if( menu > 2 ) |
350 | { |
351 | menu = 0; |
352 | INTCONbits.TMR0IE = 1; // Enable TMR0 interrupt |
353 | } |
354 | } |
355 | |
356 | /* down button */ |
357 | if( !PORTDbits.RD2 && ( menu > 0 ) ) |
358 | { |
359 | Delay1KTCYx(10); // Wake up time 1 ms |
360 | while( !PORTDbits.RD2 ); // wait till release |
361 | |
362 | /* minus ON temp */ |
363 | if( menu == 1 ) |
364 | { |
365 | On_1--; |
366 | } |
367 | |
368 | /* minus Off temp */ |
369 | if( menu == 2 ) |
370 | { |
371 | Off_1--; |
372 | } |
373 | } // END down button |
374 | |
375 | if( !PORTDbits.RD3 ) |
376 | { |
377 | Delay1KTCYx(10); // Wake up time 1 ms |
378 | while( !PORTDbits.RD3 ); // wait till release |
379 | |
380 | PORTDbits.RD6 ^= 1; |
381 | } |
382 | |
383 | } // END while( 1 ); |
384 | } |
BG Andreas
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.
>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.
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.