key debouncer

This commit is contained in:
Jeff Wang 2019-03-21 21:01:17 -04:00
parent c92decd204
commit b3f0f12c32
5 changed files with 251 additions and 20 deletions

2
src/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
a.out

177
src/key.c
View File

@ -4,12 +4,58 @@
* Created on: Mar 20, 2019
*/
#include <stdint.h>
#include "utils.h"
#ifndef DESKTOP
#include "stc15.h"
#endif
static uint8_t keys[5];
#define TOTAL_ROWS 5
#define M_COLS 4
static uint8_t keys[TOTAL_ROWS]; //only bottom nibbles get set
static uint32_t new_keys_pressed; //bottom 20 bits get set
static uint8_t last_state[TOTAL_ROWS]; //all used, 2 bits per key
static int8_t last_count[TOTAL_ROWS][M_COLS]; //all used
static uint8_t unexpected_count; //count of unexpected transitions
static const int8_t COUNT_LIM_LOW = -30;
static const int8_t COUNT_LIM_HIGH = 30;
static const int8_t THRESH_STEADY = 2;
static const int8_t THRESH_TRANS = 2;
//2-bit state:
#define STEADY_LOW 0
#define TRANS_LOW_HIGH 1
#define STEADY_HIGH 2
#define TRANS_HIGH_LOW 3
#ifdef DESKTOP
//test functions
void KeyInit(void){}
static void raw_scan(void){
static uint8_t i = 0;
static const uint8_t data[] = {
0,0,0,0,0,0,0,0,0,0,0,0,
0,2,0,2,0,2,0,2,0,2,0,2,
2,2,0,2,2,0,2,2,0,2,2,0,
2,2,2,2,2,2,2,2,2,2,2,2,
0,2,0,2,0,2,0,2,0,2,0,2,
0,0,2,0,0,2,0,0,2,0,0,2,
0,0,0,0,0,0,0,0,0,0,0,0
};
keys[1] = data[i];
i++;
if (i >= (sizeof(data)/sizeof(data[0]))){
i = 0;
}
}
#else
void KeyInit(void){
//set column drivers bits 7:4 to quasi-bidirectional w/ pullup M[1:0]=b00
//and row inputs bits 3:0 to quasi-bidirectional w/ pullup M[1:0]=b00
@ -29,11 +75,9 @@ void KeyInit(void){
P5 |= 0x30; //pull up
}
void KeyScan(void){
static void raw_scan(void){
//top row not part of matrix
static const uint8_t M_ROWS = 4;
static const uint8_t M_COLS = 4;
uint8_t i, j;
//scan top row
@ -62,8 +106,131 @@ void KeyScan(void){
}
}
}
#endif
uint8_t* GetKeys(void){
//based on quick draw/integrator hybrid debounce algorithm from
//https://summivox.wordpress.com/2016/06/03/keyboard-matrix-scanning-and-debouncing/
static void debounce(void){
uint8_t i, j;
new_keys_pressed = 0; //initially
for (i = 0; i < TOTAL_ROWS; i++){
for (j = 0; j < M_COLS; j++){
int8_t new_count;
uint8_t new_state;
int8_t curr_count = last_count[i][j];
uint8_t curr_state = last_state[i] & (0x3 << (j*2));
curr_state >>= j*2;
new_count = curr_count;
new_state = curr_state;
//update count
if (keys[i] & (1 << j)){
if (curr_count < COUNT_LIM_HIGH){
new_count = curr_count + 1;
}
} else {
if (curr_count > COUNT_LIM_LOW){
new_count = curr_count - 1;
}
}
//update state
switch(curr_state){
////////
case STEADY_LOW: {
if (new_count >= COUNT_LIM_LOW + THRESH_TRANS){
new_count = 0;
new_state = TRANS_LOW_HIGH;
}
break;
}
////////
case TRANS_LOW_HIGH: {
if (new_count >= THRESH_STEADY){
new_state = STEADY_HIGH;
new_count = COUNT_LIM_HIGH;
} else if (new_count <= -THRESH_STEADY){
new_state = STEADY_LOW;
new_count = COUNT_LIM_LOW;
unexpected_count++;
}
break;
}
////////
case STEADY_HIGH: {
if (new_count <= COUNT_LIM_HIGH - THRESH_TRANS){
new_count = 0;
new_state = TRANS_HIGH_LOW;
}
break;
}
////////
case TRANS_HIGH_LOW: {
if (new_count <= -THRESH_STEADY){
new_state = STEADY_LOW;
new_count = COUNT_LIM_LOW;
} else if (new_count >= THRESH_STEADY){
new_state = STEADY_HIGH;
new_count = COUNT_LIM_HIGH;
unexpected_count++;
}
break;
}
////////
default:
new_state = STEADY_LOW;
new_count = COUNT_LIM_LOW;
unexpected_count++;
} //switch(curr_state)
//track new keys down
if (curr_state != TRANS_LOW_HIGH && new_state == TRANS_LOW_HIGH){
new_keys_pressed |= ((uint32_t) 1 << (i*M_COLS + j));
}
//write back new count
last_count[i][j] = new_count;
//write back new state
last_state[i] = (last_state[i] & ~(0x3 << (j*2))) | (new_state << (j*2));
} //for cols
} //for rows
}
void KeyScan(void){
raw_scan();
debounce();
}
const uint8_t* DebugGetKeys(void){
return keys;
}
const uint32_t GetNewKeys(void){
return new_keys_pressed;
}
#ifdef DESKTOP
#include <stdio.h>
const char state_names[4][32] = {
"STEADY_LOW" ,
"TRANS_LOW_HIGH",
"STEADY_HIGH" ,
"TRANS_HIGH_LOW"
};
int main(void){
for (int iii = 0; iii < 100; iii++){
KeyScan();
const uint8_t* keys = DebugGetKeys();
static const uint8_t i = 1, j = 1;
uint8_t curr_count = last_count[i][j/2] & (0xf << ((j&1)*4));
uint8_t curr_state = last_state[i] & (0x3 << (j*2));
curr_count >>= (j&1)*4;
curr_state >>= j*2;
printf("%3d: %x, %14s, %2u, %2lx\n",
iii, keys[1], state_names[curr_state], curr_count, (unsigned long) GetNewKeys());
}
return 0;
}
#endif

View File

@ -9,7 +9,8 @@
void KeyInit(void);
void KeyScan(void);
uint8_t* GetKeys(void);
const uint8_t* DebugGetKeys(void);
const uint32_t GetNewKeys(void);
#endif /* SRC_KEY_H_ */

View File

@ -10,11 +10,42 @@
#define FOSC 11059200
// clear wdt
#define WDT_CLEAR() (WDT_CONTR |= 1 << 4)
static const char KEY_MAP[20] = {
'c', '<', 'r', 'm',
'/', '9', '8', '7',
'*', '6', '5', '4',
'-', '3', '2', '1',
'+', '=', '.', '0'
};
uint32_t NewKeyBuf[4];
volatile uint8_t new_key_write_i;
volatile uint8_t new_key_read_i;
volatile uint8_t new_key_empty;
#define INCR_NEW_KEY_I(i) i = (i + 1) & 3
volatile uint8_t SecCount;
void timer0_isr() __interrupt 1 __using 1
{
// P3_1 ^= 1;
static uint8_t count = 0;
static uint8_t min_count = 0, hour_count = 0;
uint32_t new_keys;
//scan keyboard
KeyScan();
new_keys = GetNewKeys();
if (new_keys != 0){
if (!new_key_empty && (new_key_write_i == new_key_read_i)){
//do not overwrite keymap currently being processed
INCR_NEW_KEY_I(new_key_write_i);
}
NewKeyBuf[new_key_write_i] = new_keys;
INCR_NEW_KEY_I(new_key_write_i);
new_key_empty = 0;
}
}
@ -41,34 +72,56 @@ char buf[17];
int main()
{
uint32_t i;
uint8_t* keys;
uint8_t j;
const uint8_t* keys;
uint8_t key_i;
Timer0Init(); // display refresh & switch read
LCD_Open();
KeyInit();
P3_4 = 0; //turn on led backlight
LCD_OutString("Hello world !!!!");
LCD_GoTo(1,0);
LCD_OutString(".......");
i = 0;
j = 0;
// LOOP
while (1)
{
LCD_GoTo(0,0);
//scan keyboard
KeyScan();
keys = GetKeys();
//keyboard debug
keys = DebugGetKeys();
for (key_i = 0; key_i < 5; key_i++){
LCD_OutNibble(keys[key_i]);
}
TERMIO_PutChar(',');
//counter
LCD_GoTo(1,7);
LCD_OutString(u32str(i, buf, 10));
i++;
if (SecCount == 0){
LCD_OutString(" ");
} else if (SecCount < 10){
TERMIO_PutChar(' ');
LCD_OutString(u32str(SecCount, buf, 10));
} else {
LCD_OutString(u32str(SecCount, buf, 10));
}
WDT_CLEAR();
///new keys
if (!new_key_empty){
uint8_t i_key;
uint32_t new_keys = NewKeyBuf[new_key_read_i];
INCR_NEW_KEY_I(new_key_read_i);
if (new_key_read_i == new_key_write_i){
new_key_empty = 1;
}
LCD_GoTo(1,j);
for (i_key = 0; i_key < 20; i_key++){
if (new_keys & ((uint32_t) 1 << i_key)){
TERMIO_PutChar(KEY_MAP[i_key]);
j++;
j &= 0x0f;
break;
}
}
}
}
}
/* ------------------------------------------------------------------------- */

View File

@ -17,5 +17,13 @@ void _delay_ms(uint8_t ms);
char* u32str(uint32_t x, char* buf, uint8_t base);
#ifdef __linux__
#define DESKTOP
#elif _WIN32
#define DESKTOP
#elif __APPLE__
#define DESKTOP
#endif
#endif /* SRC_UTILS_H_ */