在编写input相关驱动时(比如键盘驱动、触摸屏驱动),需要考虑到及时获取按键或屏幕触摸对相关Gpio的修改值情况。
常见的两种获取方式:
一. 通过触发中断号读取相关Gpio值信息;
二. 通过工作队列轮询遍历所有的Gpio值信息,并筛选出点击的按键值。
第一种方式对于单个按键或无共享Gpio时适用,对于防抖动处理有些不足;
第二种方式主要用于解决防抖动处理,并减少多余的开支。
一般键盘由一个或多个共享Gpio(引脚)和多个单用Gpio组成,比如一个八键键盘可能由一个引脚和三个Gpio组成,这样可以减少非必要Gpio使用数量,当然对于效率来说会有一定影响。市场上用到的键盘一般都在30-400ms的延时时间,这些时间主要使用在按键信号触发和防抖动处理以及修改状态消耗等。
一个八键键盘使用一个引脚和三个Gpio可以组成以下数据:
“1110”,
“0110”,
“1010”,
“0010”,
“1100”,
“0100”,
“1000”,
“0000”
这些数据可以表示为数字0-7,每个数字可以代表一个按键,明白这些原理后,我们开始参考工作队列用法。
首先定义工作队列:
struct delayed_work work;
1.1 初始化工作队列:
INIT_DELAYED_WORK(&work, timeout_work);
1.2 启动工作队列:
queue_delayed_work(15);//这个函数为自实现函数 (队列延时唤醒函数),参数毫秒
自实现函数:
//队列延时唤醒函数,参数毫秒
static void queue_delayed_work(unsigned long delay)
{
unsigned long delay_ = msecs_to_jiffies(delay);
if (delay_ >= HZ)
delay_ = round_jiffies_relative(delay_);
schedule_delayed_work(&work, delay_);
}
//工作队列触发函数
static void timeout_work(struct work_struct *work)
{
gpio_Queryvalue(); //这个函数可以根据需要自行编写,用来查询Gpio值并抖动处理后上报按键
queue_delayed_work(15); 再次调用 队列延时唤醒函数
}
1.3 释放工作队列:
cancel_delayed_work_sync(&work);
工作队列使用方式:
调用1.1和1.2开始工作队列循环唤醒使用,1.3用来停止和删除工作队列。
实际使用工作队列时,需要考虑防抖动因素,鉴于Gpio状态修改存在一些延时,可以设计为通过三次检测所有Gpio值相同为触发按键,每次检测的时间在12-20ms即可,这样即可避免Gpio造成的延时问题,也完成了防抖动处理。