如何用单片机高效处理矩阵按键?
创作时间:
作者:
@小白创作中心
如何用单片机高效处理矩阵按键?
引用
1
来源
1.
https://cloud.tencent.com/developer/article/2505596
矩阵按键是一种常见的输入设备,广泛应用于嵌入式系统中,如工业控制、消费电子和智能家居等领域。其核心思想是利用行列扫描技术,通过较少的I/O口实现对大量按键的检测。本文将详细介绍如何使用单片机高效处理矩阵按键,包括基本扫描方法、低功耗优化、按键去抖动策略以及进一步优化方案。
假设有一个4×4的矩阵按键,它由4行(Row)和4列(Column)组成,共16个按键。通常,行连接到单片机的GPIO输出端,列连接到GPIO输入端,且列端口通常需要上拉电阻来保持默认高电平。
硬件连接示例:
矩阵按键的基本扫描方法
依次拉低每一行的电平,并读取列信号,判断是否有按键按下。
实现步骤:
- 设定所有行(Row)为高电平,所有列(Column)为输入模式,并上拉。
- 依次将每一行拉低(低电平),然后读取所有列的状态。
- 如果某列检测到低电平,说明该行与该列的交点处按键被按下。
- 记录按键位置,并等待去抖动处理。
- 继续扫描下一行,直到所有行扫描完毕。
示例代码(基于C语言):
#define ROWS 4
#define COLS 4
const uint8_t row_pins[ROWS] = {ROW1, ROW2, ROW3, ROW4};
const uint8_t col_pins[COLS] = {COL1, COL2, COL3, COL4};
void scan_matrix_keypad() {
for (int i = 0; i < ROWS; i++) {
// 设定当前行为低电平
gpio_write(row_pins[i], LOW);
delay_us(5); // 确保稳定
// 读取列状态
for (int j = 0; j < COLS; j++) {
if (gpio_read(col_pins[j]) == LOW) {
printf("按键[%d,%d]被按下\n", i, j);
}
}
// 恢复当前行为高电平
gpio_write(row_pins[i], HIGH);
}
}
低功耗优化
如果单片机支持外部中断,可以利用外部中断检测按键按下,降低CPU负载。
方法如下:
- 初始状态:所有行设为高电平,所有列配置为带上拉输入,并开启中断。
- 进入低功耗模式,等待外部中断。
- 当按键按下时,列引脚的电平变化触发中断。
- 进入中断后,采用行列扫描法识别具体按键。
- 处理按键逻辑后,恢复低功耗状态。
示例代码(基于C语言):
void EXTI_Handler() {
for (int j = 0; j < COLS; j++) {
if (gpio_read(col_pins[j]) == LOW) {
scan_matrix_keypad(); // 仅在有按键按下时扫描
break;
}
}
}
void setup() {
for (int i = 0; i < ROWS; i++) {
gpio_mode(row_pins[i], OUTPUT);
gpio_write(row_pins[i], HIGH);
}
for (int j = 0; j < COLS; j++) {
gpio_mode(col_pins[j], INPUT_PULLUP);
attach_interrupt(col_pins[j], EXTI_Handler, FALLING);
}
}
按键去抖动策略
按键在机械接触时会出现抖动,可能会误触发多次按键事件,因此需要去抖动处理。
软去抖动
通过软件延迟来过滤抖动信号,例如检测到按键按下后,延迟20ms再次检测是否仍然按下。
bool is_key_pressed(uint8_t row, uint8_t col) {
if (gpio_read(col_pins[col]) == LOW) {
delay_ms(20); // 20ms去抖
if (gpio_read(col_pins[col]) == LOW) {
return true;
}
}
return false;
}
硬件去抖动
可在矩阵按键电路中增加一个小电容(如0.1uF)或者使用施密特触发器来稳定按键信号。在资源受限的嵌入式系统中,如果单片机没有足够的外部中断资源,可以使用定时器进行周期性扫描矩阵按键,以减少CPU占用。同时,为了避免主循环(while(1))中阻塞等待按键事件,使用FIFO(First In, First Out)队列存储按键事件,以提高系统响应速度。
进一步优化
基本原理:
- 定时器周期性触发扫描,间隔通常设为10~20ms,以确保能及时捕获按键事件,同时避免过于频繁地占用CPU资源。
- 在定时器中断函数内,执行一次完整的行列扫描,如果检测到按键按下,则将其加入FIFO队列。
以下是基于STM32的定时器中断方式进行按键扫描的示例代码:
#define ROWS 4
#define COLS 4
const uint8_t row_pins[ROWS] = {ROW1, ROW2, ROW3, ROW4};
const uint8_t col_pins[COLS] = {COL1, COL2, COL3, COL4};
// FIFO 队列结构体
#define KEY_FIFO_SIZE 10
typedef struct {
uint8_t keys[KEY_FIFO_SIZE]; // 按键事件队列
uint8_t head; // 队列头
uint8_t tail; // 队列尾
} KeyFIFO;
KeyFIFO key_fifo = {{0}, 0, 0};
// 按键事件入队
void key_fifo_enqueue(uint8_t key) {
uint8_t next = (key_fifo.tail + 1) % KEY_FIFO_SIZE;
if (next != key_fifo.head) { // 队列未满
key_fifo.keys[key_fifo.tail] = key;
key_fifo.tail = next;
}
}
// 读取FIFO队列中的按键
uint8_t key_fifo_dequeue() {
if (key_fifo.head == key_fifo.tail) {
return 0; // 队列为空
}
uint8_t key = key_fifo.keys[key_fifo.head];
key_fifo.head = (key_fifo.head + 1) % KEY_FIFO_SIZE;
return key;
}
// 定时器中断回调函数,每10ms扫描按键
void TIM2_IRQHandler() {
for (int i = 0; i < ROWS; i++) {
gpio_write(row_pins[i], LOW);
delay_us(5); // 确保稳定
for (int j = 0; j < COLS; j++) {
if (gpio_read(col_pins[j]) == LOW) {
uint8_t key_id = (i * COLS) + j + 1;
key_fifo_enqueue(key_id);
}
}
gpio_write(row_pins[i], HIGH);
}
TIM_ClearITPendingBit(TIM2, TIM_IT_Update); // 清除定时器中断标志
}
// 定时器初始化
void timer2_init() {
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
TIM_TimeBaseStructure.TIM_Period = 10000 - 1; // 10ms定时
TIM_TimeBaseStructure.TIM_Prescaler = 72 - 1; // 1MHz时钟
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
TIM_Cmd(TIM2, ENABLE);
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
这样,我们就能在低资源占用和高响应速度之间取得良好平衡,构建更高效的单片机矩阵按键控制系统。
热门推荐
满满行李箱 暖暖团圆意(新春走基层)
国学经典《了凡四训》,到底讲的是什么?很有名,却很少人知晓
DHX36介导的G-四联体解绕对小鼠卵母细胞和早期胚胎发育至关重要
弦理论:宇宙大爆炸的物理解释与维度之谜
《易经》乾卦的含义
女生适合投资哪些领域?这些领域的投资前景如何?
一亩地种多少艾草
洗牙会不会伤牙?洗牙的8大传言,你信了多少?
贴这么搞笑的对联,是想笑晕路过的邻居吗?
青藏高原铜矿资源开发:机遇与挑战并存
慢性中耳炎护理评估指南
如何在黄金市场中把握操作时机?这些时机如何根据市场趋势来确定?
巴特勒转会勇士、AI技术竞争与贸易战:透视马太效应加剧的社会变革
软路由低功耗CPU天梯图2024年详细解析与选购指南
国家统计局如何统计各省教师工资的?
怪物猎人世界怪物实力排行及生态位特点解析
如何申请香港个人签证:全面指南
延胡索:传统中药材的现代应用
精细化管理电梯维保记录,确保乘梯安全无忧
2025年买电动车,满足“4+3”要求,4种车型随便骑,3种车型禁行
国家公祭鼎的原型!这件战国青铜大鼎重达400公斤
逆光拍摄注意这5点!轻松拍出唯美大片(干货分享)
高考数学选择题高效答题技巧分享
早上跑步和晚上跑步各有利弊,到底哪个更适合你呢?
全国哪里大米最好吃?经评比:这些大米最出名,有你的家乡吗?
感冒了可以喝白茶吗?专家解读白茶功效与饮用注意事项
民商法学:跨学科研究的重要领域
汽车发动机润滑油选购攻略:避开误区,选对机油
黄金ETF投资策略:如何在不同市场条件下实现资产增值?
炸带鱼时,有人蘸面糊,有人直接炸!大厨:都错了,教你正确做法