之前整理了一篇博文,是纯粹在应用层(用户空间)来轮询GPIO口的电平状态,来达到按键检测的目的。
显然这样就会一直不停的占用CPU,虽然每次轮询都delay了10毫秒,但这样的代码还是不够优秀。
本篇文章提供了另一种思路:
1. 由Linux驱动来完整按键的检测,借用Linux的输入子系统,再利用海思Hi3531的GPIO硬件中断来做
2. 应用层则使用系统调用read()函数来获取按键按下、抬起、长按的事件即可
Linux驱动程序如下:
-
#include <linux/module.h>
-
#include <linux/kernel.h>
-
#include <linux/fs.h>
-
#include <linux/init.h>
-
#include <linux/delay.h>
-
#include <linux/poll.h>
-
#include <linux/sched.h>
-
#include <linux/interrupt.h>
-
#include <linux/irq.h>
-
#include <linux/input.h>
-
#include <linux/jiffies.h>
-
#include <linux/platform_device.h>
-
#include <linux/cdev.h>
-
#include <linux/miscdevice.h>
-
#include <linux/timer.h>
-
-
#include <asm/irq.h>
-
#include <asm/io.h>
-
#include <asm/uaccess.h>
-
-
#include <mach/hardware.h>
-
-
//按键映射
-
//KEY1 - GPIO6_1
-
//KEY2 - GPIO5_7
-
//KEY3 - GPIO5_5
-
-
#define MY_KEY1 1
-
#define MY_KEY2 2
-
#define MY_KEY3 3
-
-
#define WRITE_REG(Addr, Value) ((*(volatile unsigned int *)(Addr)) = (Value))
-
#define READ_REG(Addr) (*(volatile unsigned int *)(Addr))
-
-
//Hi3531复用寄存器基地址
-
#define MUXCTRL_BASE_ADDR 0x200F0000
-
//Hi3531 GPIO5基地址
-
#define GPIO_5_BASE_ADDR 0x201A0000
-
//Hi3531 GPIO6基地址
-
#define GPIO_6_BASE_ADDR 0x201B0000
-
-
//方向控制寄存器,配置输入或输出
-
#define GPIO_DIR_OFFSET_ADDR 0x400
-
//中断触发寄存器,配置边沿或电平触发
-
#define GPIO_IS_OFFSET_ADDR 0x404
-
//双沿触发中断寄存器,配置单边沿或双边沿触发方式
-
#define GPIO_IBE_OFFSET_ADDR 0x408
-
//触发中断条件寄存器,配置下降沿/低电平或上升沿/高电平触发
-
#define GPIO_IEV_OFFSET_ADDR 0x40C
-
//中断屏蔽寄存器,用来屏蔽或使能中断
-
#define GPIO_IE_OFFSET_ADDR 0x410
-
//原始中断状态寄存器,用来查询 GPIO 管脚是否发生中断(0:未发生,1:发生)
-
#define GPIO_RIS_OFFSET_ADDR 0x414
-
//屏蔽状态中断寄存器,用来查询 GPIO 管脚屏蔽后的中断是否有效
-
#define GPIO_MIS_OFFSET_ADDR 0x418
-
//中断清除寄存器,用来清除管脚产生的中断,同时清除GPIO_RIS和GPIO_MIS
-
#define GPIO_IC_OFFSET_ADDR 0x41C
-
-
unsigned
int muxctrl_virtual_addr =
0;
-
unsigned
int gpio_5_virtual_addr =
0;
-
unsigned
int gpio_6_virtual_addr =
0;
-
-
//定义一个结构体用来对输入按键进行描述
-
struct my_buttons_desc {
-
int gpio;
// 表示对应的按键引脚
-
int irq;
// 表示对应的中断位
-
char *name;
// 表示对应的按键请求中断时的中断名
-
int key_code;
// 表示按键在输入子系统中对应的键值
-
};
-
-
//定义一个描述按键的数组
-
//根据hisi SDK文档得知:GPIO6的中断号是111,GPIO5的中断号是110
-
static
struct my_buttons_desc buttons_desc[] = {
-
{MY_KEY1,
111,
"my_buttons_A", KEY_A},
-
{MY_KEY2,
110,
"my_buttons_B", KEY_B},
-
{MY_KEY3,
110,
"my_buttons_C", KEY_C},
-
};
-
-
//定义一个输入子系统的结构体指针变量
-
static
struct input_dev *buttons_dev;
-
static
struct my_buttons_desc *irq_buttons_desc = NULL;
-
static
struct timer_list buttons_timer;
-
-
-
//地址映射
-
static int hi3531_virtual_addr_map(void)
-
{
-
muxctrl_virtual_addr = (
unsigned
int)ioremap_nocache(MUXCTRL_BASE_ADDR,
0x10000);
-
if(!muxctrl_virtual_addr)
-
{
-
printk(
"MUXCTRL_BASE_ADDR ioremap addr failed !\n");
-
return
-1;
-
}
-
-
gpio_5_virtual_addr = (
unsigned
int)ioremap_nocache(GPIO_5_BASE_ADDR,
0x10000);
-
if(!gpio_5_virtual_addr)
-
{
-
printk(
"GPIO_5_BASE_ADDR ioremap addr failed !\n");
-
return
-1;
-
}
-
-
gpio_6_virtual_addr = (
unsigned
int)ioremap_nocache(GPIO_6_BASE_ADDR,
0x10000);
-
if(!gpio_6_virtual_addr)
-
{
-
printk(
"GPIO_6_BASE_ADDR ioremap addr failed !\n");
-
return
-1;
-
}
-
-
return
0;
-
}
-
-
//取消地址映射
-
static void hi3531_virtual_addr_unmap(void)
-
{
-
iounmap((
void*)muxctrl_virtual_addr);
-
iounmap((
void*)gpio_5_virtual_addr);
-
iounmap((
void*)gpio_6_virtual_addr);
-
}
-
-
//海思官方提供的中断操作
-
//如果要产生中断,且避免假中断,则必须按照下面的初始化顺序:
-
//1. 配置 GPIO_IS,选择边沿触发或电平触发。
-
//2. 配置 GPIO_IEV,选择下降沿/上升沿触发和高电平/低电平触发。
-
//3. 如果选择边沿触发,需配置 GPIO_IBE,选择单沿或双沿触发方式。
-
//4. 保证 GPIO 数据线在以上操作过程中保持稳定。
-
//5. 向寄存器 GPIO_IC 写 0xFF,清中断。
-
//6. 配置 GPIO_IE 为 1,使能中断。
-
static int hi3531_button_gpio_config(void)
-
{
-
unsigned
int u32Reg =
0;
-
-
//配置为gpio
-
WRITE_REG(muxctrl_virtual_addr +
0xC4,
0x1);
//KEY1 - GPIO6_1
-
WRITE_REG(muxctrl_virtual_addr +
0xBC,
0x1);
//KEY3 - GPIO5_7
-
-
//配置为输入
-
u32Reg = READ_REG(gpio_6_virtual_addr + GPIO_DIR_OFFSET_ADDR);
-
u32Reg &= (~
0x02);
-
WRITE_REG(gpio_6_virtual_addr + GPIO_DIR_OFFSET_ADDR, u32Reg);
//GPIO6_1
-
-
u32Reg = READ_REG(gpio_5_virtual_addr + GPIO_DIR_OFFSET_ADDR);
-
u32Reg &= (~
0x80);
-
WRITE_REG(gpio_5_virtual_addr + GPIO_DIR_OFFSET_ADDR, u32Reg);
//GPIO5_7
-
-
//配置中断
-
u32Reg = READ_REG(gpio_6_virtual_addr + GPIO_IS_OFFSET_ADDR);
-
u32Reg &= (~
0x02);
-
WRITE_REG(gpio_6_virtual_addr + GPIO_IS_OFFSET_ADDR, u32Reg);
//GPIO6_1: 边沿触发中断
-
-
u32Reg = READ_REG(gpio_6_virtual_addr + GPIO_IBE_OFFSET_ADDR);
-
u32Reg |= (
0x02);
-
WRITE_REG(gpio_6_virtual_addr + GPIO_IBE_OFFSET_ADDR, u32Reg);
//GPIO6_1: 双边沿触发中断
-
-
WRITE_REG(gpio_6_virtual_addr + GPIO_IC_OFFSET_ADDR,
0xFF);
//GPIO6: 清除中断
-
-
u32Reg = READ_REG(gpio_6_virtual_addr + GPIO_IE_OFFSET_ADDR);
-
u32Reg |= (
0x02);
-
WRITE_REG(gpio_6_virtual_addr + GPIO_IE_OFFSET_ADDR, u32Reg);
//GPIO6_1: 使能中断
-
-
-
u32Reg = READ_REG(gpio_5_virtual_addr + GPIO_IS_OFFSET_ADDR);
-
u32Reg &= (~
0xA0);
-
WRITE_REG(gpio_5_virtual_addr + GPIO_IS_OFFSET_ADDR, u32Reg);
//GPIO5_7,GPIO5_5: 边沿触发中断
-
-
u32Reg = READ_REG(gpio_5_virtual_addr + GPIO_IBE_OFFSET_ADDR);
-
u32Reg |= (
0xA0);
-
WRITE_REG(gpio_5_virtual_addr + GPIO_IBE_OFFSET_ADDR, u32Reg);
//GPIO5_7,GPIO5_5: 双边沿触发中断
-
-
WRITE_REG(gpio_5_virtual_addr + GPIO_IC_OFFSET_ADDR,
0xFF);
//GPIO5: 清除中断
-
-
u32Reg = READ_REG(gpio_5_virtual_addr + GPIO_IE_OFFSET_ADDR);
-
u32Reg |= (
0xA0);
-
WRITE_REG(gpio_5_virtual_addr + GPIO_IE_OFFSET_ADDR, u32Reg);
//GPIO5_7,GPIO5_5: 使能中断
-
-
return
0;
-
}
-
-
//GPIO按键中断处理函数
-
static irqreturn_t my_buttons_irq(int irq, void *dev_id)
-
{
-
unsigned
int u32Reg =
0;
-
struct my_buttons_desc *tmp_desc = (struct my_buttons_desc *)dev_id;
-
-
//因为是一组GPIO(8个pin)共享一个中断号,所以这里一开始就要判断到底是哪个中断来了
-
//通过读中断状态寄存器来判断
-
if(tmp_desc->gpio == MY_KEY1)
-
{
-
u32Reg = READ_REG(gpio_6_virtual_addr + GPIO_RIS_OFFSET_ADDR);
-
if(!(u32Reg &
0x02))
//GPIO6_1
-
{
-
//MY_KEY1 interrupt not happened
-
return IRQ_HANDLED;
-
}
-
WRITE_REG(gpio_6_virtual_addr + GPIO_IC_OFFSET_ADDR,
0xFF);
//GPIO6: 清除中断
-
}
-
else
if(tmp_desc->gpio == MY_KEY2)
-
{
-
u32Reg = READ_REG(gpio_5_virtual_addr + GPIO_RIS_OFFSET_ADDR);
-
if(!(u32Reg &
0x80))
//GPIO5_7
-
{
-
//MY_KEY2 interrupt not happened
-
return IRQ_HANDLED;
-
}
-
WRITE_REG(gpio_5_virtual_addr + GPIO_IC_OFFSET_ADDR,
0xFF);
//GPIO5: 清除中断
-
}
-
else
if(tmp_desc->gpio == MY_KEY3)
-
{
-
u32Reg = READ_REG(gpio_5_virtual_addr + GPIO_RIS_OFFSET_ADDR);
-
if(!(u32Reg &
0x20))
//GPIO5_5
-
{
-
//MY_KEY3 interrupt not happened
-
return IRQ_HANDLED;
-
}
-
WRITE_REG(gpio_5_virtual_addr + GPIO_IC_OFFSET_ADDR,
0xFF);
//GPIO5: 清除中断
-
}
-
-
//按键IO发生边沿中断时重新设置定时间隔,用于按键消抖
-
//20ms之后触发定时器中断,执行my_buttons_timer_function(),并将buttons_timer.data传过去
-
irq_buttons_desc = (struct my_buttons_desc *)dev_id;
-
buttons_timer.data = irq_buttons_desc->gpio;
-
mod_timer(&buttons_timer, jiffies+msecs_to_jiffies(
20));
-
-
return IRQ_HANDLED;
-
}
-
-
static unsigned int my_buttons_read_gpio(unsigned int gpio)
-
{
-
unsigned
int gpio_level =
0;
-
-
switch(gpio)
-
{
-
case MY_KEY1:
-
gpio_level = READ_REG(gpio_6_virtual_addr + (
0x02 <<
2));
//GPIO6_1
-
gpio_level = gpio_level >>
1;
-
break;
-
case MY_KEY2:
-
gpio_level = READ_REG(gpio_5_virtual_addr + (
0x80 <<
2));
//GPIO5_7
-
gpio_level = gpio_level >>
7;
-
break;
-
case MY_KEY3:
-
gpio_level = READ_REG(gpio_5_virtual_addr + (
0x20 <<
2));
//GPIO5_5
-
gpio_level = gpio_level >>
5;
-
break;
-
default:
-
break;
-
}
-
return gpio_level;
-
}
-
-
//定时器中断处理函数
-
static void my_buttons_timer_function(unsigned long data)
-
{
-
unsigned
int gpio_level;
-
-
if (!irq_buttons_desc)
-
{
-
// 初始化定时器会走进该function一次
-
printk(
"irq_buttons_desc == NULL, return\n");
-
return;
-
}
-
-
//获取按键IO状态
-
gpio_level = my_buttons_read_gpio((
unsigned
int)data);
-
printk(
"my_buttons_timer_function: gpio = %ld, gpio_level = %d\n", data, gpio_level);
-
-
//根据按键IO状态上报按键事件
-
if (gpio_level)
-
{
-
//上报按键弹起
-
input_event(buttons_dev, EV_KEY, irq_buttons_desc->key_code,
0);
-
input_sync(buttons_dev);
-
}
-
else
-
{
-
//上报按键按下
-
input_event(buttons_dev, EV_KEY, irq_buttons_desc->key_code,
1);
-
input_sync(buttons_dev);
-
}
-
}
-
-
//入口函数
-
static
int __
init my_buttons_init(void)
-
{
-
int i =
0;
-
int ret =
0;
-
-
printk(
"my_buttons_init start\n");
-
-
//1、分配一个input_dev结构体
-
buttons_dev = input_allocate_device();
-
if(!buttons_dev)
-
{
-
printk(
"input_allocate_device error!\n");
-
return -ENOMEM;
-
}
-
-
//2、设置input_dev结构体
-
//2.1、设置支持的事件类型
-
set_bit(EV_KEY, buttons_dev->evbit);
-
set_bit(EV_REP, buttons_dev->evbit);
//支持长按
-
-
//2.2、设置支持该类事件中的事件码
-
for(i =
0; i <
sizeof(buttons_desc)/
sizeof(buttons_desc[
0]); i++)
-
{
-
set_bit(buttons_desc[i].key_code, buttons_dev->keybit);
-
}
-
-
//2.3、硬件相关的操作
-
hi3531_virtual_addr_map();
-
hi3531_button_gpio_config();
-
-
//3、中断相关的操作
-
//为每个按键申请一个中断,共用中断处理函数my_buttons_irq()
-
//按键触发方式为双边沿触发
-
for(i =
0; i <
sizeof(buttons_desc)/
sizeof(buttons_desc[
0]); i++)
-
{
-
//Hi3531的一组GPIO只有一个中断号,一组GPIO有8个pin,所以这里得是共享中断
-
ret = request_irq(buttons_desc[i].irq, my_buttons_irq, IRQF_SHARED, buttons_desc[i].name, (
void*)&buttons_desc[i]);
-
printk(
"request_irq %s\n", ret==
0?
"succeed":
"failed");
-
}
-
-
//4、注册input_dev结构体
-
input_register_device(buttons_dev);
-
-
//初始化定时器,用于按键消抖
-
init_timer(&buttons_timer);
-
buttons_timer.function = my_buttons_timer_function;
-
add_timer(&buttons_timer);
-
-
printk(
"my_buttons_init end\n");
-
-
return
0;
-
}
-
-
//出口函数
-
static
void __
exit my_buttons_exit(void)
-
{
-
int i;
-
-
printk(
"my_buttons_exit start\n");
-
-
hi3531_virtual_addr_unmap();
-
-
//释放申请的按键中断
-
for(i =
0; i <
sizeof(buttons_desc)/
sizeof(buttons_desc[
0]); i++)
-
{
-
free_irq(buttons_desc[i].irq, (
void*)&buttons_desc[i]);
-
}
-
-
//删除定时器
-
del_timer(&buttons_timer);
-
-
//注销输入设备
-
input_unregister_device(buttons_dev);
-
-
//释放输入设备内存空间
-
input_free_device(buttons_dev);
-
-
printk(
"my_buttons_exit end\n");
-
}
-
-
module_init(my_buttons_init);
-
module_exit(my_buttons_exit);
-
MODULE_LICENSE(
"GPL");
将以上驱动程序编译成kernel模块,需事先完整编译一遍kernel代码,如:
该文件命名为xxx.c
在 linux-3.0.y/drivers/input/keyboard/Makefile 加一句
obj-m += xxx.o
把该文件放于 linux-3.0.y/drivers/input/keyboard 目录下
cd linux-3.0.y
make ARCH=arm CROSS_COMPILE=arm-hisiv200-linux- SUBDIRS=./drivers/input/keyboard modules
简单的应用程序如下:
-
#include <sys/types.h>
-
#include <sys/stat.h>
-
#include <fcntl.h>
-
#include <stdio.h>
-
#include <poll.h>
-
#include <signal.h>
-
#include <sys/types.h>
-
#include <unistd.h>
-
#include <fcntl.h>
-
-
#include <linux/input.h>
-
-
/*
-
struct input_event {
-
struct timeval time;
-
__u16 type; //EV_SYN=0x00,EV_KEY=0x01
-
__u16 code; //KEY_A,KEY_B,KEY_C
-
__s32 value;//抬起=0,按下=1,长按=2
-
};
-
*/
-
-
int main(int argc, char **argv)
-
{
-
int fd =
0;
-
struct input_event buttons_event;
-
unsigned
long cur_ms =
0;
-
-
//fd = open("/dev/event0", O_RDWR | O_NONBLOCK);
-
fd = open(
"/dev/event0", O_RDWR);
-
if (fd <
0)
-
{
-
printf(
"can't open!\n");
-
return
-1;
-
}
-
-
while (
1)
-
{
-
read(fd, &buttons_event,
sizeof(struct input_event));
-
-
if(buttons_event.type == EV_SYN)
-
continue;
-
-
cur_ms = (buttons_event.time.tv_sec *
1000) + (buttons_event.time.tv_usec/
1000);
-
-
//打印时间,事件类型,事件码,事件值
-
printf(
"cur_ms:%ld type:0x%x code:%d value:%d\n",
-
cur_ms,
-
buttons_event.type,
-
buttons_event.code,
-
buttons_event.value);
-
}
-
-
return
0;
-
}
安装驱动后(insmod xxx.ko),执行 cat /proc/interrupts 看一下中断相关情况,可见110这个中断号挂了两个gpio pin (上面的驱动代码就是这样写的)
运行应用程序,效果如下
以上应用程序平时没人按按键的话,就会阻塞在read()函数,不占用CPU资源,比轮询的优秀!
要想识别长按、短按、连发,还得加写逻辑判断和去掉应用程序消抖的动作(已在kernel驱动做了消抖了)。
代码如下:
-
#include <sys/types.h>
-
#include <sys/stat.h>
-
#include <fcntl.h>
-
#include <stdio.h>
-
#include <poll.h>
-
#include <signal.h>
-
#include <sys/types.h>
-
#include <unistd.h>
-
#include <fcntl.h>
-
-
#include <linux/input.h>
-
-
// 定义长按键的TICK数, 以及连发间隔的TICK数, 单位是毫秒ms
-
//#define KEY_DEBOUNCE_PERIOD 20 // 延时消抖已经在kernel驱动做了,应用层不需要做了
-
#define KEY_LONG_PERIOD 1000
-
#define KEY_CONTINUE_PERIOD 200
-
-
#define TRUE 1
-
#define FALSE 0
-
-
typedef
unsigned
int Bool;
-
typedef void (*pf)(void);
-
-
typedef
enum
-
{
-
APP_KEY1 =
0,
-
APP_KEY2,
-
APP_KEY3,
-
APP_KEY_MAX_NUM
-
} KEY_NUM_E;
-
-
typedef
enum {
-
APP_KEY_STATE_INIT =
0,
-
APP_KEY_STATE_WOBBLE,
-
APP_KEY_STATE_PRESS,
-
APP_KEY_STATE_LONG,
-
APP_KEY_STATE_CONTINUE,
-
APP_KEY_STATE_RELEASE
-
} KEY_STATE_E;
-
-
void key1DownAction(void)
-
{
-
printf(
"%s\n", __FUNCTION__);
-
}
-
-
void key1LongAction(void)
-
{
-
printf(
"%s\n", __FUNCTION__);
-
}
-
-
void key1ContinueAction(void)
-
{
-
printf(
"%s\n", __FUNCTION__);
-
}
-
-
void key1DownUpAction(void)
-
{
-
printf(
"%s\n", __FUNCTION__);
-
}
-
-
void key1LongUpAction(void)
-
{
-
printf(
"%s\n", __FUNCTION__);
-
}
-
-
void key2DownAction(void)
-
{
-
printf(
"%s\n", __FUNCTION__);
-
}
-
-
void key2LongAction(void)
-
{
-
printf(
"%s\n", __FUNCTION__);
-
}
-
-
void key2ContinueAction(void)
-
{
-
printf(
"%s\n", __FUNCTION__);
-
}
-
-
void key2DownUpAction(void)
-
{
-
printf(
"%s\n", __FUNCTION__);
-
}
-
-
void key2LongUpAction(void)
-
{
-
printf(
"%s\n", __FUNCTION__);
-
}
-
-
void key3DownAction(void)
-
{
-
printf(
"%s\n", __FUNCTION__);
-
}
-
-
void key3LongAction(void)
-
{
-
printf(
"%s\n", __FUNCTION__);
-
}
-
-
void key3ContinueAction(void)
-
{
-
printf(
"%s\n", __FUNCTION__);
-
}
-
-
void key3DownUpAction(void)
-
{
-
printf(
"%s\n", __FUNCTION__);
-
}
-
-
void key3LongUpAction(void)
-
{
-
printf(
"%s\n", __FUNCTION__);
-
}
-
-
-
typedef
struct
-
{
-
KEY_NUM_E eKeyId;
-
unsigned
int downTick;
-
unsigned
int upTick;
-
KEY_STATE_E eKeyCurState;
//key cur state(fsm)
-
Bool bStateChangedFlag;
//state changed flag
-
-
pf keyDownAction;
-
pf keyLongAction;
-
pf keyContinueAction;
-
pf keyDownUpAction;
-
pf keyLongUpAction;
-
} KEY_HANDLE_T;
-
-
-
KEY_HANDLE_T keyList[APP_KEY_MAX_NUM] =
-
{
-
{APP_KEY1,
0,
0, APP_KEY_STATE_INIT, FALSE, key1DownAction, key1LongAction, key1ContinueAction, key1DownUpAction, key1LongUpAction},
-
{APP_KEY2,
0,
0, APP_KEY_STATE_INIT, FALSE, key2DownAction, key2LongAction, key2ContinueAction, key2DownUpAction, key2LongUpAction},
-
{APP_KEY3,
0,
0, APP_KEY_STATE_INIT, FALSE, key3DownAction, key3LongAction, key3ContinueAction, key3DownUpAction, key3LongUpAction},
-
};
-
-
-
void keyScan(unsigned long cur_ms, int value, KEY_HANDLE_T *key)
-
{
-
if(key ==
NULL)
-
{
-
printf(
"key == NULL, return\n");
-
return;
-
}
-
-
switch(key->eKeyCurState)
-
{
-
case APP_KEY_STATE_INIT:
-
if(value ==
1)
-
{
-
key->downTick = cur_ms;
-
key->keyDownAction();
//短按
-
}
-
-
if(value)
-
{
-
if((cur_ms - key->downTick) >= KEY_LONG_PERIOD)
-
{
-
key->bStateChangedFlag = TRUE;
-
key->eKeyCurState = APP_KEY_STATE_LONG;
-
}
-
}
-
else
-
{
-
key->upTick = cur_ms;
-
key->bStateChangedFlag = TRUE;
-
key->eKeyCurState = APP_KEY_STATE_INIT;
-
key->keyDownUpAction();
//短按抬起
-
}
-
break;
-
-
case APP_KEY_STATE_LONG:
-
if(TRUE == key->bStateChangedFlag)
-
{
-
key->bStateChangedFlag = FALSE;
-
key->keyLongAction();
//长按
-
}
-
-
if(value)
-
{
-
if((cur_ms - key->downTick) >= (KEY_LONG_PERIOD + KEY_CONTINUE_PERIOD))
-
{
-
key->downTick = cur_ms;
-
key->bStateChangedFlag = TRUE;
-
key->eKeyCurState = APP_KEY_STATE_CONTINUE;
-
}
-
}
-
else
-
{
-
key->upTick = cur_ms;
-
key->bStateChangedFlag = TRUE;
-
key->eKeyCurState = APP_KEY_STATE_INIT;
-
key->keyLongUpAction();
//长按抬起
-
}
-
break;
-
-
case APP_KEY_STATE_CONTINUE:
-
if(TRUE == key->bStateChangedFlag)
-
{
-
key->bStateChangedFlag = FALSE;
-
key->keyContinueAction();
//连发
-
}
-
-
if(value)
-
{
-
if((cur_ms - key->downTick) >= KEY_CONTINUE_PERIOD)
-
{
-
key->downTick = cur_ms;
-
key->bStateChangedFlag = TRUE;
-
key->eKeyCurState = APP_KEY_STATE_CONTINUE;
-
}
-
}
-
else
-
{
-
key->upTick = cur_ms;
-
key->bStateChangedFlag = TRUE;
-
key->eKeyCurState = APP_KEY_STATE_INIT;
-
key->keyLongUpAction();
//长按抬起
-
}
-
break;
-
-
default:
-
break;
-
}
-
}
-
-
/*
-
struct input_event {
-
struct timeval time;
-
__u16 type; //EV_SYN=0x00,EV_KEY=0x01
-
__u16 code; //KEY_A,KEY_B,KEY_C
-
__s32 value;//抬起=0,按下=1,长按=2
-
};
-
*/
-
-
int main(int argc, char **argv)
-
{
-
int fd =
0;
-
struct input_event buttons_event;
-
KEY_HANDLE_T *curKey =
NULL;
-
unsigned
long cur_ms =
0;
-
-
//fd = open("/dev/event0", O_RDWR | O_NONBLOCK);
-
fd = open(
"/dev/event0", O_RDWR);
-
if (fd <
0)
-
{
-
printf(
"can't open!\n");
-
return
-1;
-
}
-
-
while (
1)
-
{
-
read(fd, &buttons_event,
sizeof(struct input_event));
-
-
if(buttons_event.type == EV_SYN)
-
continue;
-
-
cur_ms = (buttons_event.time.tv_sec *
1000) + (buttons_event.time.tv_usec/
1000);
-
-
//打印时间,事件类型,事件码,事件值
-
printf(
"cur_ms:%ld type:0x%x code:%d value:%d\n",
-
cur_ms,
-
buttons_event.type,
-
buttons_event.code,
-
buttons_event.value);
-
-
// match key struct
-
switch(buttons_event.code)
-
{
-
case KEY_A:
-
curKey = &keyList[APP_KEY1];
-
break;
-
case KEY_B:
-
curKey = &keyList[APP_KEY2];
-
break;
-
case KEY_C:
-
curKey = &keyList[APP_KEY3];
-
break;
-
default:
-
curKey =
NULL;
-
break;
-
}
-
-
keyScan(cur_ms, buttons_event.value, curKey);
-
}
-
-
return
0;
-
}
运行该应用程序
短按的情况:
长按的情况:
连发的情况: