im6ull开发板——按键中断消抖处理注意事项及逻辑梳理
这个消抖要配合内核定时器一起使用,
1、首先在设备结构体中添加:
struct timer_list timer; /*定时器*/
2、在驱动初始化函数中添加:定时器初始化代码:
/*初始化并配置定时器*/
init_timer(&imx6uirq.timer);
imx6uirq.timer.function = timer_func;
注意:定时器在卸载函数中要删除定时器:del_timer_sync(&imx6uirq.timer);
3、这个时候要在按键中断函数中要添加:
dev->timer.data = (volatile unsigned long)dev_id;//dev_id就是&imx6uirq变量,这句代码很重要
mod_timer(&dev->timer,jiffies+msecs_to_jiffies(20));//20ms定时
此时激活定时器,定时器开始定时20ms后进入定时器处理函数:static void timer_func(unsigned long arg)
4、定时器处理函数如下:
/*定时器服务函数*/
static void timer_func(unsigned long arg)
{
int value = 0;
struct imx6uirq_dev *dev = (struct imx6uirq_dev*)arg;
printk("timer_function\r\n");
value = gpio_get_value(dev->irqkey[0].gpio);//得到引脚的输入值,也就是按下与否的电压值
if(value==0) /*按下*/
{
atomic_set(&dev->keyvalue,dev->irqkey[0].value);
printk("KEY0 Push\r\n");
}else if(value == 1) /*释放*/
{
atomic_set(&dev->keyvalue,0x80|(dev->irqkey[0].value));
atomic_set(&dev->releasekey,1);
printk("KEY0 release\r\n");
}
}
在定时器处理函数中,该按键值被赋到设备结构体中的变量里进行保存,此后将在read函数中被读到用户态中。
5、read函数中:
static ssize_t gpiokey_read(struct file *filp, char __user *buf, size_t count,
loff_t *offset)
{
int ret=0;
unsigned char keyvalue;
unsigned char releasekey;
struct imx6uirq_dev *dev = (struct imx6uirq_dev*)filp->private_data;
keyvalue = atomic_read(&dev->keyvalue);
releasekey = atomic_read(&dev->releasekey);//只有按键按下并松开时,releasekey才会置为1,否则为0
if(releasekey){/**有效按键**/
if(keyvalue&0x80){
keyvalue &= ~0x80;
ret = copy_to_user(buf,&keyvalue,sizeof(keyvalue));
}else{
goto data_error;
}
atomic_set(&dev->releasekey,0);
}
else{
goto data_error;
}
return ret;//如果按键按下松开读出keyvalue后,执行该语句,返回ret=0;应用那边接受用来判断是否按键按下并松开
data_error:
return -0xff;
}
6、应用程序内循环读取驱动程序内的值:
/*循环读取*/
while(1)
{
ret = read(fd, &data, sizeof(data));
if(ret < 0){
}else{
if(data)
{
printf("key value=%#x\r\n",data);
}
}
}