Forum: Mikrocontroller und Digitale Elektronik PIC18F bleibt bei Tastendruck hängen


von Andreas R. (blackpuma)


Lesenswert?

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

von Vuvuzelatus (Gast)


Lesenswert?

>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.

von Andreas R. (blackpuma)


Lesenswert?

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.

von Kein Name (Gast)


Lesenswert?

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.

von Vuvuzelatus (Gast)


Lesenswert?

>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.

von Andreas R. (blackpuma)


Lesenswert?

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

von Vuvuzelatus (Gast)


Lesenswert?

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.

von Peter D. (peda)


Lesenswert?

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.

von Andreas R. (blackpuma)


Lesenswert?

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

von Frank M. (frank_m35)


Lesenswert?

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.

von Vuvuzelatus (Gast)


Lesenswert?

>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.

von Peter D. (peda)


Lesenswert?

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
Noch kein Account? Hier anmelden.