Hi
I am using the keyboard interrupt and was intending to use the RTC timer interrupt for debounce counting. ( MCU is S08QE128)
Further to this, I may also need to measure the length of time that the key is being held down in certain parts of the code.
The problem is of course that during the servicing of the key board interrupt, the RTC interrupt does not get serviced - and my debounce counter does not count - so the routine hangs in one place.
As I understand that nesting interrupts is not advisable (i.e. don't enabe the global interrupt enable within the keyboard ISR)
So what might a better approach be?
I have though of the following:
When the Keyboard ISR gets called :
1. Set a flag (e.g. key_x_pressed)
2 Immediately exit the Keyboard ISR
3 Disable the keyboard interrupt
4. Use the RTC to wait for a debounce period having used the flag that was set above to indicate that a debounce is required
OR if my code requires - wait while the key is held down such as:
While(key_down_count)
{
// key_down_count is a volatile variable decremented in the RTC ISR.
}
Any comments out there?
thanks
Russell
已解决! 转到解答。
Hello Russell,
Russell Sher wrote:
The problem is of course that during the servicing of the key board interrupt, the RTC interrupt does not get serviced - and my debounce counter does not count - so the routine hangs in one place.
As I understand that nesting interrupts is not advisable (i.e. don't enabe the global interrupt enable within the keyboard ISR)
I assume that you are not exiting the KBI ISR, whilst waiting for RTC timeout. This should be avoided at all cost - ISR's should not incorporate any extra delay or wait loop, but should exit as quickly as possible. This is to allow other interrupts, from other sources, to be processed in a timely manner. Nested interrupts, with their significant additional complexity, should be unnecessary.
For debounce and keypress timing purposes I would provide a periodic interrupt at a fixed "tick" interval. A period of 10ms should be suitable for key switch operation, and is feasible using the RTC module. All timing is then accomplished by counting the number of ticks that occur.
To allow for the presence of more than one key switch, when a particular switch becomes active it must be disengaged as a KBI interrupt source, so that any other switch closures can be detected whilst the key remains active. This is done within the KBI ISR code. The switch can only be re-enabled after it becomes inactive, and an additional debounce period has expired. The debounce period is actually associated with the turn-off process.
For each key, two separate counters will be required, a decrementing one for debounce timing, and an incrementing one for the keypress duration.
The following code snippet attempts to demonstrate the process, for a quantity of four switches -
.
/*
Polling of kpcount[n] for non-zero value determines that a keypress has
occurred, and may still be active. When dbcount[n] becomes zero, the key has
been released, and kpcount[n] containes its final value.
*/
// RTC module used to generate tick timeout period of 10 ms
#define DEBOUNCE 5 // Debounce period 40-50 ms
#define keyport PTAD
// Global variables:
word kpcount[4];
byte dbcount[4];
const byte keymask[4] = { 0x01, 0x02, 0x04, 0x08 };
//*****************************************************************************
// Polling for keypress events
void key_poll( void)
{
byte i;
for (i = 0; i < 4; i++) {
if (kpcount[i]) { // Keypress has occurred
if (dbcount[i]) { // Key not yet released
switch( i) {
case 0: // Key 0 closure processing
break;
case 1: // Key 1 closure processing
break;
case 2: // Key 2 closure processing
break;
case 3: // Key 3 closure processing
break;
} // End of switch
}
else { // Key now released
switch( i) {
case 0: // Key 0 release processing
break;
case 1: // Key 1 release processing
break;
case 2: // Key 2 release processing
break;
case 3: // Key 3 release processing
break;
} // End of switch
kpcount[i] = 0; // Ready for next keypress event
}
}
}
}
//*****************************************************************************
__interrupt VectorNumber_Vkeyboard
void KB_ISR( void)
{
byte keytemp;
byte i;
keytemp = keyport; // Read current key status
for (i = 0; i < 4; i++) { // Test all keys
if (kpcount[i] == 0) { // Previous keypress has been processed
if ((keytemp & keymask[i]) == 0) { // Keypress active
KBI1PE &= ~keymask[i]; // Disable KBI interrupt for this key
dbcount[i] = DEBOUNCE; // Set debounce period
}
}
}
KBI1SC = 0x06; // Clear flag - edge interrupts enabled
}
//*****************************************************************************
// Tick timing ISR - 10 ms period
__interrupt VectorNumber_Vrtc
void RTC_ISR( void)
{
byte i;
// Other tick timing code here
for (i = 0; i < 4; i++) { // Test all keys
if (dbcount[i]) {
kbcount[i]++; // Increment keypress timer
if ((keyport & keymask[i]) == 0) // Keypress still active
dbcount[i] = DEBOUNCE; // Re-start debounce period
else { // Key is inactive
dbcount[i]--;
if (dbcount[i] == 0) // Debounce timeout occurred
KBI1PE |= keymask[i]; // Re-enable KBI interrupt for key
}
}
}
RTCSC_RTIF = 1; // Clear flag
}
.
Regards,
Mac
Hello Russell,
Russell Sher wrote:
The problem is of course that during the servicing of the key board interrupt, the RTC interrupt does not get serviced - and my debounce counter does not count - so the routine hangs in one place.
As I understand that nesting interrupts is not advisable (i.e. don't enabe the global interrupt enable within the keyboard ISR)
I assume that you are not exiting the KBI ISR, whilst waiting for RTC timeout. This should be avoided at all cost - ISR's should not incorporate any extra delay or wait loop, but should exit as quickly as possible. This is to allow other interrupts, from other sources, to be processed in a timely manner. Nested interrupts, with their significant additional complexity, should be unnecessary.
For debounce and keypress timing purposes I would provide a periodic interrupt at a fixed "tick" interval. A period of 10ms should be suitable for key switch operation, and is feasible using the RTC module. All timing is then accomplished by counting the number of ticks that occur.
To allow for the presence of more than one key switch, when a particular switch becomes active it must be disengaged as a KBI interrupt source, so that any other switch closures can be detected whilst the key remains active. This is done within the KBI ISR code. The switch can only be re-enabled after it becomes inactive, and an additional debounce period has expired. The debounce period is actually associated with the turn-off process.
For each key, two separate counters will be required, a decrementing one for debounce timing, and an incrementing one for the keypress duration.
The following code snippet attempts to demonstrate the process, for a quantity of four switches -
.
/*
Polling of kpcount[n] for non-zero value determines that a keypress has
occurred, and may still be active. When dbcount[n] becomes zero, the key has
been released, and kpcount[n] containes its final value.
*/
// RTC module used to generate tick timeout period of 10 ms
#define DEBOUNCE 5 // Debounce period 40-50 ms
#define keyport PTAD
// Global variables:
word kpcount[4];
byte dbcount[4];
const byte keymask[4] = { 0x01, 0x02, 0x04, 0x08 };
//*****************************************************************************
// Polling for keypress events
void key_poll( void)
{
byte i;
for (i = 0; i < 4; i++) {
if (kpcount[i]) { // Keypress has occurred
if (dbcount[i]) { // Key not yet released
switch( i) {
case 0: // Key 0 closure processing
break;
case 1: // Key 1 closure processing
break;
case 2: // Key 2 closure processing
break;
case 3: // Key 3 closure processing
break;
} // End of switch
}
else { // Key now released
switch( i) {
case 0: // Key 0 release processing
break;
case 1: // Key 1 release processing
break;
case 2: // Key 2 release processing
break;
case 3: // Key 3 release processing
break;
} // End of switch
kpcount[i] = 0; // Ready for next keypress event
}
}
}
}
//*****************************************************************************
__interrupt VectorNumber_Vkeyboard
void KB_ISR( void)
{
byte keytemp;
byte i;
keytemp = keyport; // Read current key status
for (i = 0; i < 4; i++) { // Test all keys
if (kpcount[i] == 0) { // Previous keypress has been processed
if ((keytemp & keymask[i]) == 0) { // Keypress active
KBI1PE &= ~keymask[i]; // Disable KBI interrupt for this key
dbcount[i] = DEBOUNCE; // Set debounce period
}
}
}
KBI1SC = 0x06; // Clear flag - edge interrupts enabled
}
//*****************************************************************************
// Tick timing ISR - 10 ms period
__interrupt VectorNumber_Vrtc
void RTC_ISR( void)
{
byte i;
// Other tick timing code here
for (i = 0; i < 4; i++) { // Test all keys
if (dbcount[i]) {
kbcount[i]++; // Increment keypress timer
if ((keyport & keymask[i]) == 0) // Keypress still active
dbcount[i] = DEBOUNCE; // Re-start debounce period
else { // Key is inactive
dbcount[i]--;
if (dbcount[i] == 0) // Debounce timeout occurred
KBI1PE |= keymask[i]; // Re-enable KBI interrupt for key
}
}
}
RTCSC_RTIF = 1; // Clear flag
}
.
Regards,
Mac
Hi and thanks
Yes, that was obviously my problem. I was calling a routine to process this from the keyboard ISR instead of setting a value as you did and doing a quick exit. I'll go through your code and look at the method.
Thanks for the help
Russell
Hello Russell,
Something that I overlooked in the previous code snippet!
You will need an additionsl static flag for each key switch, to indicate that a closure event has already been processed within the key_poll() function. This is to prevent the closure code from executing multiple times whilst waiting for release of the key.
Regards,
Mac