海思Hi3531 GPIO按键的长按、短按、连发——Linux驱动+应用程序

本文介绍了一种利用海思Hi3531平台的GPIO硬件中断进行按键检测的方法,通过Linux驱动程序实现按键的按下、抬起和长按事件的检测,避免了CPU的频繁轮询,提高了系统的效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转:https://blog.csdn.net/cfl927096306/article/details/88842398###

之前整理了一篇博文,是纯粹在应用层(用户空间)来轮询GPIO口的电平状态,来达到按键检测的目的。

https://blog.csdn.net/cfl927096306/article/details/88640930

显然这样就会一直不停的占用CPU,虽然每次轮询都delay了10毫秒,但这样的代码还是不够优秀。

本篇文章提供了另一种思路:

1. 由Linux驱动来完整按键的检测,借用Linux的输入子系统,再利用海思Hi3531的GPIO硬件中断来做

2. 应用层则使用系统调用read()函数来获取按键按下、抬起、长按的事件即可

Linux驱动程序如下:


 
  1. #include <linux/module.h>
  2. #include <linux/kernel.h>
  3. #include <linux/fs.h>
  4. #include <linux/init.h>
  5. #include <linux/delay.h>
  6. #include <linux/poll.h>
  7. #include <linux/sched.h>
  8. #include <linux/interrupt.h>
  9. #include <linux/irq.h>
  10. #include <linux/input.h>
  11. #include <linux/jiffies.h>
  12. #include <linux/platform_device.h>
  13. #include <linux/cdev.h>
  14. #include <linux/miscdevice.h>
  15. #include <linux/timer.h>
  16. #include <asm/irq.h>
  17. #include <asm/io.h>
  18. #include <asm/uaccess.h>
  19. #include <mach/hardware.h>
  20. //按键映射
  21. //KEY1 - GPIO6_1
  22. //KEY2 - GPIO5_7
  23. //KEY3 - GPIO5_5
  24. #define MY_KEY1 1
  25. #define MY_KEY2 2
  26. #define MY_KEY3 3
  27. #define WRITE_REG(Addr, Value) ((*(volatile unsigned int *)(Addr)) = (Value))
  28. #define READ_REG(Addr) (*(volatile unsigned int *)(Addr))
  29. //Hi3531复用寄存器基地址
  30. #define MUXCTRL_BASE_ADDR 0x200F0000
  31. //Hi3531 GPIO5基地址
  32. #define GPIO_5_BASE_ADDR 0x201A0000
  33. //Hi3531 GPIO6基地址
  34. #define GPIO_6_BASE_ADDR 0x201B0000
  35. //方向控制寄存器,配置输入或输出
  36. #define GPIO_DIR_OFFSET_ADDR 0x400
  37. //中断触发寄存器,配置边沿或电平触发
  38. #define GPIO_IS_OFFSET_ADDR 0x404
  39. //双沿触发中断寄存器,配置单边沿或双边沿触发方式
  40. #define GPIO_IBE_OFFSET_ADDR 0x408
  41. //触发中断条件寄存器,配置下降沿/低电平或上升沿/高电平触发
  42. #define GPIO_IEV_OFFSET_ADDR 0x40C
  43. //中断屏蔽寄存器,用来屏蔽或使能中断
  44. #define GPIO_IE_OFFSET_ADDR 0x410
  45. //原始中断状态寄存器,用来查询 GPIO 管脚是否发生中断(0:未发生,1:发生)
  46. #define GPIO_RIS_OFFSET_ADDR 0x414
  47. //屏蔽状态中断寄存器,用来查询 GPIO 管脚屏蔽后的中断是否有效
  48. #define GPIO_MIS_OFFSET_ADDR 0x418
  49. //中断清除寄存器,用来清除管脚产生的中断,同时清除GPIO_RIS和GPIO_MIS
  50. #define GPIO_IC_OFFSET_ADDR 0x41C
  51. unsigned int muxctrl_virtual_addr = 0;
  52. unsigned int gpio_5_virtual_addr = 0;
  53. unsigned int gpio_6_virtual_addr = 0;
  54. //定义一个结构体用来对输入按键进行描述
  55. struct my_buttons_desc {
  56. int gpio; // 表示对应的按键引脚
  57. int irq; // 表示对应的中断位
  58. char *name; // 表示对应的按键请求中断时的中断名
  59. int key_code; // 表示按键在输入子系统中对应的键值
  60. };
  61. //定义一个描述按键的数组
  62. //根据hisi SDK文档得知:GPIO6的中断号是111,GPIO5的中断号是110
  63. static struct my_buttons_desc buttons_desc[] = {
  64. {MY_KEY1, 111, "my_buttons_A", KEY_A},
  65. {MY_KEY2, 110, "my_buttons_B", KEY_B},
  66. {MY_KEY3, 110, "my_buttons_C", KEY_C},
  67. };
  68. //定义一个输入子系统的结构体指针变量
  69. static struct input_dev *buttons_dev;
  70. static struct my_buttons_desc *irq_buttons_desc = NULL;
  71. static struct timer_list buttons_timer;
  72. //地址映射
  73. static int hi3531_virtual_addr_map(void)
  74. {
  75. muxctrl_virtual_addr = ( unsigned int)ioremap_nocache(MUXCTRL_BASE_ADDR, 0x10000);
  76. if(!muxctrl_virtual_addr)
  77. {
  78. printk( "MUXCTRL_BASE_ADDR ioremap addr failed !\n");
  79. return -1;
  80. }
  81. gpio_5_virtual_addr = ( unsigned int)ioremap_nocache(GPIO_5_BASE_ADDR, 0x10000);
  82. if(!gpio_5_virtual_addr)
  83. {
  84. printk( "GPIO_5_BASE_ADDR ioremap addr failed !\n");
  85. return -1;
  86. }
  87. gpio_6_virtual_addr = ( unsigned int)ioremap_nocache(GPIO_6_BASE_ADDR, 0x10000);
  88. if(!gpio_6_virtual_addr)
  89. {
  90. printk( "GPIO_6_BASE_ADDR ioremap addr failed !\n");
  91. return -1;
  92. }
  93. return 0;
  94. }
  95. //取消地址映射
  96. static void hi3531_virtual_addr_unmap(void)
  97. {
  98. iounmap(( void*)muxctrl_virtual_addr);
  99. iounmap(( void*)gpio_5_virtual_addr);
  100. iounmap(( void*)gpio_6_virtual_addr);
  101. }
  102. //海思官方提供的中断操作
  103. //如果要产生中断,且避免假中断,则必须按照下面的初始化顺序:
  104. //1. 配置 GPIO_IS,选择边沿触发或电平触发。
  105. //2. 配置 GPIO_IEV,选择下降沿/上升沿触发和高电平/低电平触发。
  106. //3. 如果选择边沿触发,需配置 GPIO_IBE,选择单沿或双沿触发方式。
  107. //4. 保证 GPIO 数据线在以上操作过程中保持稳定。
  108. //5. 向寄存器 GPIO_IC 写 0xFF,清中断。
  109. //6. 配置 GPIO_IE 为 1,使能中断。
  110. static int hi3531_button_gpio_config(void)
  111. {
  112. unsigned int u32Reg = 0;
  113. //配置为gpio
  114. WRITE_REG(muxctrl_virtual_addr + 0xC4, 0x1); //KEY1 - GPIO6_1
  115. WRITE_REG(muxctrl_virtual_addr + 0xBC, 0x1); //KEY3 - GPIO5_7
  116. //配置为输入
  117. u32Reg = READ_REG(gpio_6_virtual_addr + GPIO_DIR_OFFSET_ADDR);
  118. u32Reg &= (~ 0x02);
  119. WRITE_REG(gpio_6_virtual_addr + GPIO_DIR_OFFSET_ADDR, u32Reg); //GPIO6_1
  120. u32Reg = READ_REG(gpio_5_virtual_addr + GPIO_DIR_OFFSET_ADDR);
  121. u32Reg &= (~ 0x80);
  122. WRITE_REG(gpio_5_virtual_addr + GPIO_DIR_OFFSET_ADDR, u32Reg); //GPIO5_7
  123. //配置中断
  124. u32Reg = READ_REG(gpio_6_virtual_addr + GPIO_IS_OFFSET_ADDR);
  125. u32Reg &= (~ 0x02);
  126. WRITE_REG(gpio_6_virtual_addr + GPIO_IS_OFFSET_ADDR, u32Reg); //GPIO6_1: 边沿触发中断
  127. u32Reg = READ_REG(gpio_6_virtual_addr + GPIO_IBE_OFFSET_ADDR);
  128. u32Reg |= ( 0x02);
  129. WRITE_REG(gpio_6_virtual_addr + GPIO_IBE_OFFSET_ADDR, u32Reg); //GPIO6_1: 双边沿触发中断
  130. WRITE_REG(gpio_6_virtual_addr + GPIO_IC_OFFSET_ADDR, 0xFF); //GPIO6: 清除中断
  131. u32Reg = READ_REG(gpio_6_virtual_addr + GPIO_IE_OFFSET_ADDR);
  132. u32Reg |= ( 0x02);
  133. WRITE_REG(gpio_6_virtual_addr + GPIO_IE_OFFSET_ADDR, u32Reg); //GPIO6_1: 使能中断
  134. u32Reg = READ_REG(gpio_5_virtual_addr + GPIO_IS_OFFSET_ADDR);
  135. u32Reg &= (~ 0xA0);
  136. WRITE_REG(gpio_5_virtual_addr + GPIO_IS_OFFSET_ADDR, u32Reg); //GPIO5_7,GPIO5_5: 边沿触发中断
  137. u32Reg = READ_REG(gpio_5_virtual_addr + GPIO_IBE_OFFSET_ADDR);
  138. u32Reg |= ( 0xA0);
  139. WRITE_REG(gpio_5_virtual_addr + GPIO_IBE_OFFSET_ADDR, u32Reg); //GPIO5_7,GPIO5_5: 双边沿触发中断
  140. WRITE_REG(gpio_5_virtual_addr + GPIO_IC_OFFSET_ADDR, 0xFF); //GPIO5: 清除中断
  141. u32Reg = READ_REG(gpio_5_virtual_addr + GPIO_IE_OFFSET_ADDR);
  142. u32Reg |= ( 0xA0);
  143. WRITE_REG(gpio_5_virtual_addr + GPIO_IE_OFFSET_ADDR, u32Reg); //GPIO5_7,GPIO5_5: 使能中断
  144. return 0;
  145. }
  146. //GPIO按键中断处理函数
  147. static irqreturn_t my_buttons_irq(int irq, void *dev_id)
  148. {
  149. unsigned int u32Reg = 0;
  150. struct my_buttons_desc *tmp_desc = (struct my_buttons_desc *)dev_id;
  151. //因为是一组GPIO(8个pin)共享一个中断号,所以这里一开始就要判断到底是哪个中断来了
  152. //通过读中断状态寄存器来判断
  153. if(tmp_desc->gpio == MY_KEY1)
  154. {
  155. u32Reg = READ_REG(gpio_6_virtual_addr + GPIO_RIS_OFFSET_ADDR);
  156. if(!(u32Reg & 0x02)) //GPIO6_1
  157. {
  158. //MY_KEY1 interrupt not happened
  159. return IRQ_HANDLED;
  160. }
  161. WRITE_REG(gpio_6_virtual_addr + GPIO_IC_OFFSET_ADDR, 0xFF); //GPIO6: 清除中断
  162. }
  163. else if(tmp_desc->gpio == MY_KEY2)
  164. {
  165. u32Reg = READ_REG(gpio_5_virtual_addr + GPIO_RIS_OFFSET_ADDR);
  166. if(!(u32Reg & 0x80)) //GPIO5_7
  167. {
  168. //MY_KEY2 interrupt not happened
  169. return IRQ_HANDLED;
  170. }
  171. WRITE_REG(gpio_5_virtual_addr + GPIO_IC_OFFSET_ADDR, 0xFF); //GPIO5: 清除中断
  172. }
  173. else if(tmp_desc->gpio == MY_KEY3)
  174. {
  175. u32Reg = READ_REG(gpio_5_virtual_addr + GPIO_RIS_OFFSET_ADDR);
  176. if(!(u32Reg & 0x20)) //GPIO5_5
  177. {
  178. //MY_KEY3 interrupt not happened
  179. return IRQ_HANDLED;
  180. }
  181. WRITE_REG(gpio_5_virtual_addr + GPIO_IC_OFFSET_ADDR, 0xFF); //GPIO5: 清除中断
  182. }
  183. //按键IO发生边沿中断时重新设置定时间隔,用于按键消抖
  184. //20ms之后触发定时器中断,执行my_buttons_timer_function(),并将buttons_timer.data传过去
  185. irq_buttons_desc = (struct my_buttons_desc *)dev_id;
  186. buttons_timer.data = irq_buttons_desc->gpio;
  187. mod_timer(&buttons_timer, jiffies+msecs_to_jiffies( 20));
  188. return IRQ_HANDLED;
  189. }
  190. static unsigned int my_buttons_read_gpio(unsigned int gpio)
  191. {
  192. unsigned int gpio_level = 0;
  193. switch(gpio)
  194. {
  195. case MY_KEY1:
  196. gpio_level = READ_REG(gpio_6_virtual_addr + ( 0x02 << 2)); //GPIO6_1
  197. gpio_level = gpio_level >> 1;
  198. break;
  199. case MY_KEY2:
  200. gpio_level = READ_REG(gpio_5_virtual_addr + ( 0x80 << 2)); //GPIO5_7
  201. gpio_level = gpio_level >> 7;
  202. break;
  203. case MY_KEY3:
  204. gpio_level = READ_REG(gpio_5_virtual_addr + ( 0x20 << 2)); //GPIO5_5
  205. gpio_level = gpio_level >> 5;
  206. break;
  207. default:
  208. break;
  209. }
  210. return gpio_level;
  211. }
  212. //定时器中断处理函数
  213. static void my_buttons_timer_function(unsigned long data)
  214. {
  215. unsigned int gpio_level;
  216. if (!irq_buttons_desc)
  217. {
  218. // 初始化定时器会走进该function一次
  219. printk( "irq_buttons_desc == NULL, return\n");
  220. return;
  221. }
  222. //获取按键IO状态
  223. gpio_level = my_buttons_read_gpio(( unsigned int)data);
  224. printk( "my_buttons_timer_function: gpio = %ld, gpio_level = %d\n", data, gpio_level);
  225. //根据按键IO状态上报按键事件
  226. if (gpio_level)
  227. {
  228. //上报按键弹起
  229. input_event(buttons_dev, EV_KEY, irq_buttons_desc->key_code, 0);
  230. input_sync(buttons_dev);
  231. }
  232. else
  233. {
  234. //上报按键按下
  235. input_event(buttons_dev, EV_KEY, irq_buttons_desc->key_code, 1);
  236. input_sync(buttons_dev);
  237. }
  238. }
  239. //入口函数
  240. static int __ init my_buttons_init(void)
  241. {
  242. int i = 0;
  243. int ret = 0;
  244. printk( "my_buttons_init start\n");
  245. //1、分配一个input_dev结构体
  246. buttons_dev = input_allocate_device();
  247. if(!buttons_dev)
  248. {
  249. printk( "input_allocate_device error!\n");
  250. return -ENOMEM;
  251. }
  252. //2、设置input_dev结构体
  253. //2.1、设置支持的事件类型
  254. set_bit(EV_KEY, buttons_dev->evbit);
  255. set_bit(EV_REP, buttons_dev->evbit); //支持长按
  256. //2.2、设置支持该类事件中的事件码
  257. for(i = 0; i < sizeof(buttons_desc)/ sizeof(buttons_desc[ 0]); i++)
  258. {
  259. set_bit(buttons_desc[i].key_code, buttons_dev->keybit);
  260. }
  261. //2.3、硬件相关的操作
  262. hi3531_virtual_addr_map();
  263. hi3531_button_gpio_config();
  264. //3、中断相关的操作
  265. //为每个按键申请一个中断,共用中断处理函数my_buttons_irq()
  266. //按键触发方式为双边沿触发
  267. for(i = 0; i < sizeof(buttons_desc)/ sizeof(buttons_desc[ 0]); i++)
  268. {
  269. //Hi3531的一组GPIO只有一个中断号,一组GPIO有8个pin,所以这里得是共享中断
  270. ret = request_irq(buttons_desc[i].irq, my_buttons_irq, IRQF_SHARED, buttons_desc[i].name, ( void*)&buttons_desc[i]);
  271. printk( "request_irq %s\n", ret== 0? "succeed": "failed");
  272. }
  273. //4、注册input_dev结构体
  274. input_register_device(buttons_dev);
  275. //初始化定时器,用于按键消抖
  276. init_timer(&buttons_timer);
  277. buttons_timer.function = my_buttons_timer_function;
  278. add_timer(&buttons_timer);
  279. printk( "my_buttons_init end\n");
  280. return 0;
  281. }
  282. //出口函数
  283. static void __ exit my_buttons_exit(void)
  284. {
  285. int i;
  286. printk( "my_buttons_exit start\n");
  287. hi3531_virtual_addr_unmap();
  288. //释放申请的按键中断
  289. for(i = 0; i < sizeof(buttons_desc)/ sizeof(buttons_desc[ 0]); i++)
  290. {
  291. free_irq(buttons_desc[i].irq, ( void*)&buttons_desc[i]);
  292. }
  293. //删除定时器
  294. del_timer(&buttons_timer);
  295. //注销输入设备
  296. input_unregister_device(buttons_dev);
  297. //释放输入设备内存空间
  298. input_free_device(buttons_dev);
  299. printk( "my_buttons_exit end\n");
  300. }
  301. module_init(my_buttons_init);
  302. module_exit(my_buttons_exit);
  303. 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

 

简单的应用程序如下:


 
  1. #include <sys/types.h>
  2. #include <sys/stat.h>
  3. #include <fcntl.h>
  4. #include <stdio.h>
  5. #include <poll.h>
  6. #include <signal.h>
  7. #include <sys/types.h>
  8. #include <unistd.h>
  9. #include <fcntl.h>
  10. #include <linux/input.h>
  11. /*
  12. struct input_event {
  13. struct timeval time;
  14. __u16 type; //EV_SYN=0x00,EV_KEY=0x01
  15. __u16 code; //KEY_A,KEY_B,KEY_C
  16. __s32 value;//抬起=0,按下=1,长按=2
  17. };
  18. */
  19. int main(int argc, char **argv)
  20. {
  21. int fd = 0;
  22. struct input_event buttons_event;
  23. unsigned long cur_ms = 0;
  24. //fd = open("/dev/event0", O_RDWR | O_NONBLOCK);
  25. fd = open( "/dev/event0", O_RDWR);
  26. if (fd < 0)
  27. {
  28. printf( "can't open!\n");
  29. return -1;
  30. }
  31. while ( 1)
  32. {
  33. read(fd, &buttons_event, sizeof(struct input_event));
  34. if(buttons_event.type == EV_SYN)
  35. continue;
  36. cur_ms = (buttons_event.time.tv_sec * 1000) + (buttons_event.time.tv_usec/ 1000);
  37. //打印时间,事件类型,事件码,事件值
  38. printf( "cur_ms:%ld type:0x%x code:%d value:%d\n",
  39. cur_ms,
  40. buttons_event.type,
  41. buttons_event.code,
  42. buttons_event.value);
  43. }
  44. return 0;
  45. }

安装驱动后(insmod xxx.ko),执行  cat /proc/interrupts  看一下中断相关情况,可见110这个中断号挂了两个gpio pin (上面的驱动代码就是这样写的)

运行应用程序,效果如下

以上应用程序平时没人按按键的话,就会阻塞在read()函数,不占用CPU资源,比轮询的优秀!

要想识别长按、短按、连发,还得加写逻辑判断和去掉应用程序消抖的动作(已在kernel驱动做了消抖了)。

代码如下:

 


 
  1. #include <sys/types.h>
  2. #include <sys/stat.h>
  3. #include <fcntl.h>
  4. #include <stdio.h>
  5. #include <poll.h>
  6. #include <signal.h>
  7. #include <sys/types.h>
  8. #include <unistd.h>
  9. #include <fcntl.h>
  10. #include <linux/input.h>
  11. // 定义长按键的TICK数, 以及连发间隔的TICK数, 单位是毫秒ms
  12. //#define KEY_DEBOUNCE_PERIOD 20 // 延时消抖已经在kernel驱动做了,应用层不需要做了
  13. #define KEY_LONG_PERIOD 1000
  14. #define KEY_CONTINUE_PERIOD 200
  15. #define TRUE 1
  16. #define FALSE 0
  17. typedef unsigned int Bool;
  18. typedef void (*pf)(void);
  19. typedef enum
  20. {
  21. APP_KEY1 = 0,
  22. APP_KEY2,
  23. APP_KEY3,
  24. APP_KEY_MAX_NUM
  25. } KEY_NUM_E;
  26. typedef enum {
  27. APP_KEY_STATE_INIT = 0,
  28. APP_KEY_STATE_WOBBLE,
  29. APP_KEY_STATE_PRESS,
  30. APP_KEY_STATE_LONG,
  31. APP_KEY_STATE_CONTINUE,
  32. APP_KEY_STATE_RELEASE
  33. } KEY_STATE_E;
  34. void key1DownAction(void)
  35. {
  36. printf( "%s\n", __FUNCTION__);
  37. }
  38. void key1LongAction(void)
  39. {
  40. printf( "%s\n", __FUNCTION__);
  41. }
  42. void key1ContinueAction(void)
  43. {
  44. printf( "%s\n", __FUNCTION__);
  45. }
  46. void key1DownUpAction(void)
  47. {
  48. printf( "%s\n", __FUNCTION__);
  49. }
  50. void key1LongUpAction(void)
  51. {
  52. printf( "%s\n", __FUNCTION__);
  53. }
  54. void key2DownAction(void)
  55. {
  56. printf( "%s\n", __FUNCTION__);
  57. }
  58. void key2LongAction(void)
  59. {
  60. printf( "%s\n", __FUNCTION__);
  61. }
  62. void key2ContinueAction(void)
  63. {
  64. printf( "%s\n", __FUNCTION__);
  65. }
  66. void key2DownUpAction(void)
  67. {
  68. printf( "%s\n", __FUNCTION__);
  69. }
  70. void key2LongUpAction(void)
  71. {
  72. printf( "%s\n", __FUNCTION__);
  73. }
  74. void key3DownAction(void)
  75. {
  76. printf( "%s\n", __FUNCTION__);
  77. }
  78. void key3LongAction(void)
  79. {
  80. printf( "%s\n", __FUNCTION__);
  81. }
  82. void key3ContinueAction(void)
  83. {
  84. printf( "%s\n", __FUNCTION__);
  85. }
  86. void key3DownUpAction(void)
  87. {
  88. printf( "%s\n", __FUNCTION__);
  89. }
  90. void key3LongUpAction(void)
  91. {
  92. printf( "%s\n", __FUNCTION__);
  93. }
  94. typedef struct
  95. {
  96. KEY_NUM_E eKeyId;
  97. unsigned int downTick;
  98. unsigned int upTick;
  99. KEY_STATE_E eKeyCurState; //key cur state(fsm)
  100. Bool bStateChangedFlag; //state changed flag
  101. pf keyDownAction;
  102. pf keyLongAction;
  103. pf keyContinueAction;
  104. pf keyDownUpAction;
  105. pf keyLongUpAction;
  106. } KEY_HANDLE_T;
  107. KEY_HANDLE_T keyList[APP_KEY_MAX_NUM] =
  108. {
  109. {APP_KEY1, 0, 0, APP_KEY_STATE_INIT, FALSE, key1DownAction, key1LongAction, key1ContinueAction, key1DownUpAction, key1LongUpAction},
  110. {APP_KEY2, 0, 0, APP_KEY_STATE_INIT, FALSE, key2DownAction, key2LongAction, key2ContinueAction, key2DownUpAction, key2LongUpAction},
  111. {APP_KEY3, 0, 0, APP_KEY_STATE_INIT, FALSE, key3DownAction, key3LongAction, key3ContinueAction, key3DownUpAction, key3LongUpAction},
  112. };
  113. void keyScan(unsigned long cur_ms, int value, KEY_HANDLE_T *key)
  114. {
  115. if(key == NULL)
  116. {
  117. printf( "key == NULL, return\n");
  118. return;
  119. }
  120. switch(key->eKeyCurState)
  121. {
  122. case APP_KEY_STATE_INIT:
  123. if(value == 1)
  124. {
  125. key->downTick = cur_ms;
  126. key->keyDownAction(); //短按
  127. }
  128. if(value)
  129. {
  130. if((cur_ms - key->downTick) >= KEY_LONG_PERIOD)
  131. {
  132. key->bStateChangedFlag = TRUE;
  133. key->eKeyCurState = APP_KEY_STATE_LONG;
  134. }
  135. }
  136. else
  137. {
  138. key->upTick = cur_ms;
  139. key->bStateChangedFlag = TRUE;
  140. key->eKeyCurState = APP_KEY_STATE_INIT;
  141. key->keyDownUpAction(); //短按抬起
  142. }
  143. break;
  144. case APP_KEY_STATE_LONG:
  145. if(TRUE == key->bStateChangedFlag)
  146. {
  147. key->bStateChangedFlag = FALSE;
  148. key->keyLongAction(); //长按
  149. }
  150. if(value)
  151. {
  152. if((cur_ms - key->downTick) >= (KEY_LONG_PERIOD + KEY_CONTINUE_PERIOD))
  153. {
  154. key->downTick = cur_ms;
  155. key->bStateChangedFlag = TRUE;
  156. key->eKeyCurState = APP_KEY_STATE_CONTINUE;
  157. }
  158. }
  159. else
  160. {
  161. key->upTick = cur_ms;
  162. key->bStateChangedFlag = TRUE;
  163. key->eKeyCurState = APP_KEY_STATE_INIT;
  164. key->keyLongUpAction(); //长按抬起
  165. }
  166. break;
  167. case APP_KEY_STATE_CONTINUE:
  168. if(TRUE == key->bStateChangedFlag)
  169. {
  170. key->bStateChangedFlag = FALSE;
  171. key->keyContinueAction(); //连发
  172. }
  173. if(value)
  174. {
  175. if((cur_ms - key->downTick) >= KEY_CONTINUE_PERIOD)
  176. {
  177. key->downTick = cur_ms;
  178. key->bStateChangedFlag = TRUE;
  179. key->eKeyCurState = APP_KEY_STATE_CONTINUE;
  180. }
  181. }
  182. else
  183. {
  184. key->upTick = cur_ms;
  185. key->bStateChangedFlag = TRUE;
  186. key->eKeyCurState = APP_KEY_STATE_INIT;
  187. key->keyLongUpAction(); //长按抬起
  188. }
  189. break;
  190. default:
  191. break;
  192. }
  193. }
  194. /*
  195. struct input_event {
  196. struct timeval time;
  197. __u16 type; //EV_SYN=0x00,EV_KEY=0x01
  198. __u16 code; //KEY_A,KEY_B,KEY_C
  199. __s32 value;//抬起=0,按下=1,长按=2
  200. };
  201. */
  202. int main(int argc, char **argv)
  203. {
  204. int fd = 0;
  205. struct input_event buttons_event;
  206. KEY_HANDLE_T *curKey = NULL;
  207. unsigned long cur_ms = 0;
  208. //fd = open("/dev/event0", O_RDWR | O_NONBLOCK);
  209. fd = open( "/dev/event0", O_RDWR);
  210. if (fd < 0)
  211. {
  212. printf( "can't open!\n");
  213. return -1;
  214. }
  215. while ( 1)
  216. {
  217. read(fd, &buttons_event, sizeof(struct input_event));
  218. if(buttons_event.type == EV_SYN)
  219. continue;
  220. cur_ms = (buttons_event.time.tv_sec * 1000) + (buttons_event.time.tv_usec/ 1000);
  221. //打印时间,事件类型,事件码,事件值
  222. printf( "cur_ms:%ld type:0x%x code:%d value:%d\n",
  223. cur_ms,
  224. buttons_event.type,
  225. buttons_event.code,
  226. buttons_event.value);
  227. // match key struct
  228. switch(buttons_event.code)
  229. {
  230. case KEY_A:
  231. curKey = &keyList[APP_KEY1];
  232. break;
  233. case KEY_B:
  234. curKey = &keyList[APP_KEY2];
  235. break;
  236. case KEY_C:
  237. curKey = &keyList[APP_KEY3];
  238. break;
  239. default:
  240. curKey = NULL;
  241. break;
  242. }
  243. keyScan(cur_ms, buttons_event.value, curKey);
  244. }
  245. return 0;
  246. }

运行该应用程序

短按的情况:

长按的情况:

连发的情况:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值