2010-08-11 10:32 AM
Simple and accurate delay inside an Interrupt
2011-05-17 05:01 AM
2011-05-17 05:01 AM
I would NOT recommend using interrupts for switch inputs. Instead I'd poll them via a timer ISR say every 1mS or 10mS depending on your requirements. I use the SysTick for this purpose as Ron suggested.
Port pin interrupts are edge triggered and since switches etc bounce you'll end up with multiple interrupts. That can be problematic. An advantage of polling via an ISR is that you already have a periodic interrupt so the debouncing can be done with counters inside the ISR. There's very little overhead doing this (i.e. interrupt processing is very fast). Delaying/looping inside ISR's is bad practice IMO.2011-05-17 05:01 AM
Stuart is right. An easy way to debounce keys is to read the GPIO state periodically with an interrupt and store the value in a short FIFO array. Then you can scan the array for a continuous keydown state (eg 5 contiguous keydowns) and set a flag ''KeyPressed'' (one for each key) which the main program can sense and clear in its own time. This method lends itself to both click and double click sensing and although it sounds a bit overcomplex actually makes handling the keypad very easy.
Interrupts should always complete and return as quickly as possible.2011-05-17 05:01 AM
''Im relatively new to STM32 land.''
Would it be a fair guess that you're also new to embedded microcontrollers in general? As already noted, delays inside interrupt handlers are generally a (very) Bad Thing! And high-level language (HLL) loops are never good for accurate delays - see:
2011-05-17 05:01 AM
2011-05-17 05:01 AM
John
just so I can check my new polling code. Do you have C code handy that uses your technique. Thanks Denis ________________________ http://www.CentronSolutions.com2011-05-17 05:01 AM
Hi Denis,
You're going to have to tease out the useful bits of this ... but as a guide :- #define ENTER (1<<17) //keys are sensed on P0.17..20 as zero when pressed #define UP (1<<18) #define DOWN (1<<19) #define MENU (1<<20) #define ANY (ENTER | UP | DOWN | MENU) #define NKEYSAMPLES 10 //Periodically in the timer interrupt service routine static unsigned int KeySamples[NKEYSAMPLES]; static unsigned int Index; //values maintained between calls unsigned int Sample; //general access index to KeySamples[] if(TickCount == 0) //periodically eg every 5 millisecs) { //read in keypad lines and sense and store keystates and keypresses //for keypad debounce, new data replaces old in circular store, keep index in range if(Index >= NKEYSAMPLES) Index = 0; KeySamples[Index] = FIO0PIN; //read port 0 KeySamples[Index] = ~KeySamples[Index]; //keys pressed stored as 1 PreviousKeys = CurrentKeys; //save current key values CurrentKeys = KeySamples[Index++]; //fetch modified port values just read //then look for bits set in all the KeySamples array for(Sample=0; Sample<NKEYSAMPLES; Sample++) CurrentKeys = CurrentKeys & KeySamples[Sample]; //bits will be set in CurrentKeys if they are present in all keysamples //set a bit in KeysPressed if a key has transitioned from unpressed to pressed //the programmer must clear Keypressed bits once actioned KeysPressed = KeysPressed | (CurrentKeys & ~PreviousKeys); } //in the main program //these functions return keystates unsigned int KeyDown(unsigned int KeyMask) { return (CurrentKeys & KeyMask); } unsigned int KeyPressed(unsigned int KeyMask) { return (KeysPressed & KeyMask); } void KeyClear(unsigned int KeyMask) { KeysPressed = KeysPressed & ~KeyMask; //clear the flag for argument KeyMask } //typically used as if (KeyPressed(UP)) { KeyClear(UP); //do something } //or KeyClear(ANY); //or while(!KeyPressed(ENTER)); //wait until user presses ''enter'' key Hope that helps.2011-05-17 05:01 AM
Never put a delay loop in an ISR.
Use 2 bytes/key. Byte 0: state of key for publication. I.e. use this byte in the rest of your program and not the GPIO state of the key. Byte 1: Millisecond timer. One kHz ISR: If timer byte != 0 decrement the byte. (Don’t look at GPIO key state.) Else... If GPIO state != byte 0 then toggle its state and set the timer = 35 or the timeout of your choosing. Simpler ISR: only decrement timer byte if it’s non-zero. Mainline only looks at GPIO key state when timer byte is zero. Update byte 0 when GPIO state != byte 0 and set timer byte. Either way it’s a simple digital filter. Key changes are reported immediately except for some number of milliseconds after a state change. Or even simpler, only look at your keys every 50 milliseconds.