www.mikrocontroller.net

C_TAST.C

C_TAST.C
/************************************************************************/
/*                                                                      */
/*                      Debouncing 8 Keys        */
/*      Sampling 4 Times        */
/*      With Repeat Function        */
/*                                                                      */
/*              Author: Peter Dannegger                                 */
/*                      danni@specs.de                                  */
/*                                                                      */
/************************************************************************/

#include <io.h>
#include <interrupt.h>
#include <signal.h>

typedef unsigned char  u8;
typedef signed short  s16;

#define  XTAL    1e6    // 1MHz

#define KEY_PIN    PINB
#define KEY0    0
#define KEY1    1
#define KEY2    2

#define LED_DDR    DDRA
#define LED_PORT  PORTA
#define LED0    0
#define LED1    1
#define LED2    2

#define REPEAT_MASK  (1<<KEY1^1<<KEY2)  // repeat: key1, key2
#define REPEAT_START  50    // after 500ms
#define REPEAT_NEXT  20    // every 200ms


u8 key_state;        // debounced and inverted key state:
          // bit = 1: key pressed
u8 key_press;        // key press detect

u8 key_rpt;        // key long press and repeat


SIGNAL (SIG_OVERFLOW0)      // every 10ms
{
  static u8 ct0, ct1, rpt;
  u8 i;

  TCNT0 = (u8)(s16)-(XTAL / 1024 * 10e-3 + 0.5);  // preload for 10ms

  i = key_state ^ ~KEY_PIN;    // key changed ?
  ct0 = ~( ct0 & i );      // reset or count ct0
  ct1 = ct0 ^ (ct1 & i);    // reset or count ct1
  i &= ct0 & ct1;      // count until roll over ?
  key_state ^= i;      // then toggle debounced state
  key_press |= key_state & i;    // 0->1: key press detect

  if( (key_state & REPEAT_MASK) == 0 )  // check repeat function
     rpt = REPEAT_START;    // start delay
  if( --rpt == 0 ){
    rpt = REPEAT_NEXT;      // repeat delay
    key_rpt |= key_state & REPEAT_MASK;
  }
}


u8 get_key_press( u8 key_mask )
{
  cli();          // read and clear atomic !
  key_mask &= key_press;                        // read key(s)
  key_press ^= key_mask;                        // clear key(s)
  sei();
  return key_mask;
}


u8 get_key_rpt( u8 key_mask )
{
  cli();          // read and clear atomic !
  key_mask &= key_rpt;                          // read key(s)
  key_rpt ^= key_mask;                          // clear key(s)
  sei();
  return key_mask;
}


u8 get_key_short( u8 key_mask )
{
  cli();      // read key state and key press atomic !
  return get_key_press( ~key_state & key_mask );
}


u8 get_key_long( u8 key_mask )
{
  return get_key_press( get_key_rpt( key_mask ));
}


int main( void )
{
  TCCR0 = 1<<CS02^1<<CS00;      // divide by 1024
  TIMSK = 1<<TOIE0;        // enable timer interrupt

  LED_PORT = 0xFF;
  LED_DDR = 0xFF;
  sei();

  for(;;){          // main loop
      // single press

    if( get_key_press( 1<<KEY0 ))
      LED_PORT ^= 1<<LED0;

      // release after short press: task 1
      // long press: task 2

    if( get_key_short( 1<<KEY1 ))
      LED_PORT ^= 1<<LED1;

    if( get_key_long( 1<<KEY1 ))
      LED_PORT ^= 1<<LED2;

      // single press and repeat

    if( get_key_press( 1<<KEY2 ) || get_key_rpt( 1<<KEY2 )){
      u8 i = LED_PORT;

      i = (i & 0x07) | ((i << 1) & 0xF0);
      if( i < 0xF0 )
        i |= 0x08;
      LED_PORT = i;      
    }
  }
}

webmaster@mikrocontroller.netImpressumWerbung auf Mikrocontroller.net