嵌入式——按键原理和消抖方式
一. 按键原理
如下图是一个4X3的按键原理图,左边KR是行,上面的KC是列。
这里以下降沿触发为例子来讲讲按键的原理和处理流程。所谓下降沿触发,就是从高电平到低电平即可触发,反之就是上升沿触发。
原理: 将列的输出电平拉高,然后依次拉低列,读取行的输入电平是否为低电平,若为低电平,则表示该按键被按下。
1. 按键配置
- 根据原理图配置对应的GPIO口。
- 将列(col)配置为输出口(OUTPUT),并设置成漏极开路(Open Drain)即高阻状态,使用外部上拉电阻即可产生高电平。
- 将行(row)配置为输入口(INPUT),因为行默认是高电平,所以将GPIO模式设置成上拉模式(Pull up)。
- 将按键设置为下降沿触发
2.按键扫描流程
1.禁用中断,防止扫描过程被干扰。
2.利用列的外部上拉电阻将所有列拉高为高电平,然后开始循环扫描按键是否被按下
3.循环扫描的流程
①将第一列拉低,然后扫描所有的行,一旦检测到行也是低电平,即表示按键被按下,如果行 没有低电平,则第一列扫描结束,将第一列拉高。
②然后拉低第二列,继续扫描所有行,依次扫描,直到扫描全部按键。
4.将所有列都拉低,为了防止下一次按键扫描无法将列一起拉高。
5.打开中断,将被按下的按键的行列数据拿出来。
static void key_scan_row(void)
{
uint32_t col, col_mask, col_index;
uint32_t row, row_mask, row_index, row_value;
bool pressed = false;
key_scan_data_t data = {0};
uint32_t row_pin_mask = key_scan_env.config.row_pin_mask;
uint32_t col_pin_mask = key_scan_env.config.col_pin_mask;
// Disable IRQ
gpio_set_interrupt(row_pin_mask, GPIO_TRIGGER_DISABLE);
// All colume to HIGH
pmu_pin_mode_set(col_pin_mask, PMU_PIN_MODE_PU);
gpio_write(col_pin_mask, GPIO_HIGH);
co_delay_us(KEY_SCAN_COL_OUTPUT_KEEP_TIME);
pmu_pin_mode_set(col_pin_mask, PMU_PIN_MODE_OD);
// Scan
col_index = 0;
for(col=0; col<KEY_SCAN_PIN_NUM_MAX; ++col)
{
col_mask = 1u << col;
if(col_pin_mask & col_mask)
{
// Only current colume output LOW
gpio_write(col_mask, GPIO_LOW);
co_delay_us(KEY_SCAN_COL_OUTPUT_KEEP_TIME);
// Read value
row_value = (~gpio_read(row_pin_mask)) & row_pin_mask;
// Current colume to HIGH
pmu_pin_mode_set(col_pin_mask, PMU_PIN_MODE_PU);
gpio_write(col_pin_mask, GPIO_HIGH);
// Check ROW
row_index = 0;
for(row=0; row<KEY_SCAN_PIN_NUM_MAX; ++row)
{
row_mask = 1u << row;
if(row_pin_mask & row_mask)
{
if(row_value & row_mask)
{
data.num++;
data.val[col_index] |= 1u << row_index;
}
++row_index;
if(row_index >= KEY_ROW_NUM)
break;
}
}
if(data.val[col_index])
pressed = true;
// restore OD
pmu_pin_mode_set(col_pin_mask, PMU_PIN_MODE_OD);
++col_index;
if(col_index >= KEY_COL_NUM)
break;
}
}
// All colume to LOW
gpio_write(col_pin_mask, GPIO_LOW);
co_delay_us(KEY_SCAN_COL_OUTPUT_KEEP_TIME+50);
// Enable IRQ
gpio_set_interrupt(row_pin_mask, GPIO_BOTH_EDGE);
if(pressed)
key_pressed(data);
}
二. 按键抖动以及消抖方式
抖动原理
由于机械触点的弹性作用,按键在按下和松开的一瞬间都会伴随一阵抖动,一般是5~10ms左右,为了避免抖动带来的按下一次按键处理多次的问题,我们需要对按键进行消抖处理。
消抖的方式
大家可以参考一下这篇文章按键消抖及原理(硬件和软件方法详解)
对于硬件消抖一般适用于按键较少的情况下,因为按键消抖增加了电路的复杂性,增加了成本和体积,我们一般用软件消抖。