Keyboard interrupts and timer interrupt used as debounce - question

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Keyboard interrupts and timer interrupt used as debounce - question

Jump to solution
2,562 Views
russellsher
Contributor III

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

Labels (1)
0 Kudos
1 Solution
1,140 Views
bigmac
Specialist III

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

View solution in original post

0 Kudos
5 Replies
1,141 Views
bigmac
Specialist III

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

0 Kudos
1,140 Views
admin
Specialist II

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

0 Kudos
1,140 Views
bigmac
Specialist III

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

1,140 Views
admin
Specialist II

Hi Mac

In your routine

__interrupt VectorNumber_Vrtc

void RTC_ISR( void)

You have  a line that reads:   kbcount++

should this be:   kpcount[i]++ 

Russell

0 Kudos
1,140 Views
bigmac
Specialist III

Hello Russell,

Yes, you are correct - I though I had already made that correction, but obviously not within the code posted.

Regards,

Mac


0 Kudos