SWITCH DEBOUNCE AND USER INPUT
Here's a way to deal with debounce and timing the switches linked to microcontroller port. it is mostly a re-write in C of the Mutable instrument UI interface. The key in here is to do stuff upon the release of the button and to time how long the button has been pressed. This code runs into a 1Khz interrupt to deal with user inputs.
#define DEBOUNCE 50
#define SW_EVENT 0
#define ADC_EVENT 1
#define MAX_BUTTON 6
// store button state, 0 or 1
uint8_t state[MAX_BUTTON];
//debounce counter
uint16_t press_timer[MAX_BUTTON];
//store the time
uint16_t press_time[MAX_BUTTON];
// if the button aren't linked to consecutive pins, used masks
uint16_t gpio_mask[4];
1Khz_interupt
{
for(uint8_t i=0; i<7; i++)
{
// are we in 0 state
if(!state[i])
{
//first we read if the button is pressed, is it pressed ?
// otherwise, there's a bounce so 0 it out.
if(!(GPIOB->IDR & gpio_mask[i]))
{
//increment debounce counter
press_timer[i]++;
//are we above the threshold ? we are !
if(press_timer[i] >= DEBOUNCE_SW)
{
//becomes one
state[i]++;
//reset debounce_counter
press_timer[i] = 0;
//store time for next comparasion
press_time[i] = ms;
}
}
// bounce or nothing, reset
else press_timer[i] = 0;
}
// have we recorded a valid pressed ?
else if(state[i])
{
//has the button been released ? (pin high)
if(GPIOB->IDR & gpio_mask[i])
{
//same principle for the debounce, switches bounce in the both way.
press_timer[i]++;
if(press_timer[i] >= DEBOUNCE_SW)
{
//record the change, state = 0
state[i]--;
//create a struct to store the data for
//next processing, here we label it as a switch
event.type = SW_EVENT;
//which switch ?
event.id = i;
// the time it has been down
event.data = ms - press_time[i];
//stock into the circular buffer
push_user_event(&event);
//reset debounce timer
press_timer[i] = 0;
}
}
//still pressed, ignore and reset
else press_timer[i] = 0;
}
}
}
the input data is stored into a ciurcular buffer containing struct data type
#define MAX_EVENT_FIFO 16
typedef struct{
uint8_t type; //pot or switch
uint8_t id; //which one
uint16_t data; //value for adc
}USER_EVENT;
uint8_t ptr_event_read, ptr_event_write, event_fifo_counter;
USER_EVENT event_fifo[MAX_EVENT_FIFO_SIZE];
//retrieve data from the buffer
void get_user_event(USER_EVENT *event)
{
if(event_fifo_counter >0)
{
event->type = event_fifo[ptr_event_read].type;
event->id = event_fifo[ptr_event_read].id;
event->data = event_fifo[ptr_event_read].data;
ptr_event_read++;
if(ptr_event_read >= MAX_EVENT_FIFO_SIZE) ptr_event_read = 0;
event_fifo_counter--;
}
}
//stock data to the buffer
void push_user_event(USER_EVENT *event)
{
if(event_fifo_counter < MAX_EVENT_FIFO_SIZE)
{
event_fifo[ptr_event_write].type = event->type;
event_fifo[ptr_event_write].id = event->id;
event_fifo[ptr_event_write].data = event->data;
ptr_event_write++;
if(ptr_event_write >= MAX_EVENT_FIFO_SIZE) ptr_event_write = 0;
event_fifo_counter++;
}
}
the processing is dealt with in the main loop
void user_event_do(void)
{
static USER_EVENT event;
// is there some event to process ?
if(event_fifo_counter)
{
// copy struct into local one
get_user_event(&event);
switch(event.type)
{
case SW_EVENT:
//which switch ?
switch(event.id)
{
case 0:
//long press
if(event.data >= PRESS_LONG_DURATION) action_1();
//short press
else action_2();
break;
case 1:
if(event.data >= PRESS_LONG_DURATION) action_3();
else action_4();
break;
default:break;
}
break;
case ADC_EVENT:
switch(event.id)
{
case 0:
break;
case 1:
break;
default:break;
}
break;
}
}
}