完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
本帖最后由 正点原子运营官 于 2020-3-14 16:12 编辑
1)实验平台:正点原子Linux开发板 2)摘自《正点原子I.MX6U嵌入式Linux驱动开发指南》关注官方微信号公众号,获取更多资料:正点原子 第十九章定时器按键消抖实验 在第十五章和第十七章实验中都用到了按键,用到按键就要处理因为机械结构带来的按键抖动问题,也就是按键消抖。前面的实验中都是直接使用了延时函数来实现消抖,因为简单,但是直接用延时函数来实现消抖会浪费CPU性能,因为在延时函数里面CPU什么都做不了。如果按键使用中断的话更不能在中断里面使用延时函数,因为中断服务函数要快进快出!本章我们学习如何使用定时器来实现按键消抖,使用定时器既可以实现按键消抖,而且也不会浪费CPU性能,这个也是Linux驱动里面按键消抖的做法。 19.1定时器按键消抖简介 按键消抖的原理在第十五章已经详细的讲解了,其实就是在按键按下以后延时一段时间再去读取按键值,如果此时按键值还有效那就表示这是一次有效的按键,中间的延时就是消抖的。但是这有一个缺点,就是延时函数会浪费CPU性能,因为延时函数就是空跑。如果按键是用中断方式实现的,那就更不能在中断服务函数里面使用延时函数,因为中断服务函数最基本的要求就是快进快出!上一章我们学习了EPIT定时器,定时器设置好定时时间,然后CPU就可以做其他事情去了,定时时间到了以后就会触发中断,然后在中断中做相应的处理即可。因此,我们可以借助定时器来实现消抖,按键采用中断驱动方式,当按键按下以后触发按键中断,在按键中断中开启一个定时器,定时周期为10ms,当定时时间到了以后就会触发定时器中断,最后在定时器中断处理函数中读取按键的值,如果按键值还是按下状态那就表示这是一次有效的按键。定时器按键消抖如图19.1.1所示: 图19.1.1定时器消抖示意图 在图19.1.1中t1~t3这一段时间就是按键抖动,是需要消除的。设置按键为下降沿触发,因此会在t1、t2和t3这三个时刻会触发按键中断,每次进入中断处理函数都会重新开器定时器中断,所以会在t1、t2和t3这三个时刻开器定时器中断。但是t1~t2和t2~t3这两个时间段是小于我们设置的定时器中断周期(也就是消抖时间,比如10ms),所以虽然t1开启了定时器,但是定时器定时时间还没到呢t2时刻就重置了定时器,最终只有t3时刻开启的定时器能完整的完成整个定时周期并触发中断,我们就可以在中断处理函数里面做按键处理了,这就是定时器实现按键防抖的原理,Linux里面的按键驱动用的就是这个原理! 关于定时器按键消抖的原理就介绍到这里,接下来讲解如何使用EPIT1来配合按键KEY来实现具体的消抖,步骤如下: 1、配置按键IO中断 配置按键所使用的IO,因为要使用到中断驱动按键,所以要配置IO的中断模式。 2、初始化消抖用的定时器 上面已经讲的很清楚了,消抖要用定时器来完成,所以需要初始化一个定时器,这里使用上一章讲解的EPIT1定时器,也算是对EPIT1定时器的一次巩固。定时器的定时周期为10ms,也可根据实际情况调整定时周期。 3、编写中断处理函数 需要编写两个中断处理函数:按键对应的GPIO中断处理函数和EPIT1定时器的中断处理函数。在按键的中断处理函数中主要用于开启EPIT1定时器,EPIT1的中断处理函数才是重点,按键要做的具体任务都是在定时器EPIT1的中断处理函数中完成的,比如控制蜂鸣器打开或关闭。 19.2 硬件原理分析本试验用到的资源如下: 、一个LED灯LED0。 、定时器EPti1。 、一个按键KEY。 、一个蜂鸣器。 本试验效果和第十五章的试验效果一样,按下KEY会打开蜂鸣器,再次按下KEY就会关闭蜂鸣器。LED0作为系统提示灯不断的闪烁。 19.3 试验程序编写 本实验对应的例程路径为:开发板光盘-> 1、裸机例程->11_key_filter。 本章实验在上一章例程的基础上完成,更改工程名字为“key_filter”,然后在bsp文件夹下创建名为“keyfilter”的文件夹,然后在bsp/keyfilter中新建bsp_keyfilter.c和bsp_keyfilter.h这两个文件。在bsp_keyfilter.h中输入如下内容: 示例代码19.3.1 bsp_keyfilter.h 文件代码 1 #ifndef _BSP_KEYFILTER_H 2 #define _BSP_KEYFILTER_H 3/*************************************************************** 4 Copyright © zuozhongkai Co., Ltd. 1998-2019. All rights reserved. 5文件名 : bsp_keyfilter.h 6作者 : 左忠凯 7版本 : V1.0 8描述 : 定时器按键消抖驱动头文件。 9其他 : 无 10论坛 : www.openedv.com 11日志 : 初版V1.0 2019/1/5 左忠凯创建 12 ***************************************************************/ 13 14/* 函数声明 */ 15void filterkey_init(void); 16void filtertimer_init(unsignedint value); 17void filtertimer_stop(void); 18void filtertimer_restart(unsignedint value); 19void filtertimer_irqhandler(void); 20void gpio1_16_31_irqhandler(void); 21 22 #endif bsp_keyfilter.h文件很简单,只是函数声明。在bsp_keyfilter.c中输入如下内容: 示例代码19.3.2 bsp_keyfilter.c 文件代码 /*************************************************************** Copyright © zuozhongkai Co., Ltd. 1998-2019. All rights reserved. 文件名 : bsp_keyfilter.c 作者 : 左忠凯 版本 : V1.0 描述 : 定时器按键消抖驱动。 其他 : 按键采用中断方式,按下按键触发按键中断,在按键中断里面 使能定时器定时中断。使用定时器定时中断来完成消抖延时, 定时器中断周期就是延时时间。如果定时器定时中断触发, 表示消抖完成(延时周期完成),即可执行按键处理函数。 论坛 : www.openedv.com 日志 : 初版V1.0 2019/1/5 左忠凯创建 ***************************************************************/ 1 #include "bsp_key.h" 2 #include "bsp_gpio.h" 3 #include "bsp_int.h" 4 #include "bsp_beep.h" 5 #include "bsp_keyfilter.h" 6 7/* 8 * @description : 按键初始化 9 * @param : 无 10 * @Return : 无 11 */ 12void filterkey_init(void) 13{ 14 gpio_pin_config_t key_config; 15 16/* 1、初始化IO */ 17 IOMUXC_SetPinMux(IOMUXC_UART1_CTS_B_GPIO1_IO18,0); 18 IOMUXC_SetPinConfig(IOMUXC_UART1_CTS_B_GPIO1_IO18,0xF080); 19 20/* 2、初始化GPIO为中断 */ 21 key_config.direction = kGPIO_DigitalInput; 22 key_config.interruptMode = kGPIO_IntFallingEdge; 23 key_config.outputLogic =1; 24 gpio_init(GPIO1,18,&key_config); 25 26/* 3、使能GPIO中断,并且注册中断处理函数 */ 27 GIC_EnableIRQ(GPIO1_Combined_16_31_IRQn); 28 system_register_irqhandler(GPIO1_Combined_16_31_IRQn, (system_irq_handler_t)gpio1_16_31_irqhandler, NULL); 29 30 gpio_enableint(GPIO1,18); /* 使能GPIO1_IO18的中断功能 */ 31 filtertimer_init(66000000/100); /* 初始化定时器,10ms */ 32} 33 34/* 35 * @description : 初始化用于消抖的定时器,默认关闭定时器 36 * @param - value : 定时器EPIT计数值 37 * @return : 无 38 */ 39void filtertimer_init(unsignedint value) 40{ 41 EPIT1->CR =0; /* 先清零 */ 42 EPIT1->CR =(1<<24|1<<3|1<<2|1<<1); 43 EPIT1->LR = value; /* 计数值 */ 44 EPIT1->CMPR =0; /* 比较寄存器为0 */ 45 46/* 使能EPIT1中断并注册中断处理函数*/ 47 GIC_EnableIRQ(EPIT1_IRQn); 48 system_register_irqhandler(EPIT1_IRQn, (system_irq_handler_t)filtertimer_irqhandler, NULL); 49} 50 51/* 52 * @description : 关闭定时器 53 * @param : 无 54 * @return : 无 55 */ 56void filtertimer_stop(void) 57{ 58 EPIT1->CR &=~(1<<0); /* 关闭定时器 */ 59} 60 61/* 62 * @description : 重启定时器 63 * @param – value : 定时器EPIT计数值 64 * @return : 无 65 */ 66void filtertimer_restart(unsignedint value) 67{ 68 EPIT1->CR &=~(1<<0); /* 先关闭定时器 */ 69 EPIT1->LR = value; /* 计数值 */ 70 EPIT1->CR |=(1<<0); /* 打开定时器 */ 71} 72 73/* 74 * @description : 定时器中断处理函数 75 * @param : 无 76 * @return : 无 77 */ 78void filtertimer_irqhandler(void) 79{ 80staticunsignedchar state = OFF; 81 82if(EPIT1->SR &(1<<0)) /* 判断比较事件是否发生 */ 83{ 84 filtertimer_stop(); /* 关闭定时器 */ 85if(gpio_pinread(GPIO1,18)==0)/* KEY0按下 */ 86{ 87 state =!state; 88 beep_switch(state); /* 反转蜂鸣器 */ 89} 90} 91 EPIT1->SR |=1<<0; /* 清除中断标志位 */ 92} 93 94/* 95 * @description : GPIO中断处理函数 96 * @param : 无 97 * @return : 无 98 */ 99void gpio1_16_31_irqhandler(void) 100{ 101 filtertimer_restart(66000000/100); /* 开启定时器 */ 102 gpio_clearintflags(GPIO1,18); /* 清除中断标志位 */ 103} 文件bsp_keyfilter.c一共有6个函数,这6个函数其实都很简单。filterkey_init是本试验的初始化函数,此函数首先初始化了KEY所使用的UART1_CTS这个IO,设置这个 IO的中断模式,并且注册中断处理函数,最后调用函数filtertimer_init初始化定时器EPIT1定时周期为10ms。函数filtertimer_init是定时器EPIT1的初始化函数,内容基本和上一章实验的EPIT1初始化函数一样。函数filtertimer_stop和filtertimer_restart分别是EPIT1的关闭和重启函数。filtertimer_irqhandler是EPTI1的中断处理函数,此函数里面就是按键要做的工作,在本例程里面就是开启或者关闭蜂鸣器。函数gpio1_16_31_irqhandler是GPIO1_IO18的中断处理函数,此函数只有一个工作,那就是重启定时器EPIT1。 bsp_keyfilter.c文件内容总体来说并不难,基本就是第十七章和第十八章实验的综合。最后在mian.c中输入如下所示代码: 示例代码19.3.3 main.c 文件代码 /************************************************************** Copyright © zuozhongkai Co., Ltd. 1998-2019. All rights reserved. 文件名 : mian.c 作者 : 左忠凯 版本 : V1.0 描述 : I.MX6U开发板裸机实验11 定时器实现按键消抖实验 其他 : 本实验主要学习如何使用定时器来实现按键消抖,以前的按键 消抖都是直接使用延时函数来完成的,这种做法效率不高,因为 延时函数完全是浪费CPU资源的。使用按键中断+定时器来实现按键 驱动效率是最好的,这也是Linux驱动所使用的方法! 论坛 : www.openedv.com 日志 : 初版V1.0 2019/1/5 左忠凯创建 **************************************************************/ 1 #include "bsp_clk.h" 2 #include "bsp_delay.h" 3 #include "bsp_led.h" 4 #include "bsp_beep.h" 5 #include "bsp_key.h" 6 #include "bsp_int.h" 7 #include "bsp_keyfilter.h" 8 9/* 10 * @description : main函数 11 * @param : 无 12 * @return : 无 13 */ 14int main(void) 15{ 16 unsignedchar state = OFF; 17 18 int_init(); /* 初始化中断(一定要最先调用!) */ 19 imx6u_clkinit(); /* 初始化系统时钟 */ 20 clk_enable(); /* 使能所有的时钟 */ 21 led_init(); /* 初始化led */ 22 beep_init(); /* 初始化beep */ 23 filterkey_init(); /* 带有消抖功能的按键 */ 24 25 while(1) 26 { 27 state =!state; 28 led_switch(LED0, state); 29 delay(500); 30 } 31 32 return0; 33} main.c文件只有一个main函数,在第23行调用函数filterkey_init来初始化带有消抖的按键,最后在while循环里面翻转LED0,周期大约为500ms。 19.4编译下载验证19.4.1编写Makefile和链接脚本 修改Makefile中的TARGET为keyfilter,在INCDIRS和SRCDIRS中加入“bsp/keyfilter”,修改后的Makefile如下: 示例代码19.4.1 Makefile代码 1 CROSS_COMPILE ?= arm-linux-gnueabihf- 2 TARGET ?=keyfilter 3 4/* 省略掉其它代码...... */ 5 6 INCDIRS := imx6ul 7 bsp/clk 8 bsp/led 9 bsp/delay 10 bsp/beep 11 bsp/gpio 12 bsp/key 13 bsp/exit 14 bsp/int 15 bsp/epittimer 16 bsp/keyfilter 17 18 SRCDIRS := project 19 bsp/clk 20 bsp/led 21 bsp/delay 22 bsp/beep 23 bsp/gpio 24 bsp/key 25 bsp/exit 26 bsp/int 27 bsp/epittimer 28 bsp/keyfilter 29 30 /* 省略掉其它代码...... */ 31 32 clean: 33 rm -rf $(TARGET).elf $(TARGET).dis $(TARGET).bin $(COBJS)$(SOBJS) 第2行修改变量TARGET为“keyfilter”,也就是目标名称为“keyfilter”。 第16行在变量INCDIRS中添加按键消抖驱动头文件(.h)路径。 第28行在变量SRCDIRS中添加按键消抖驱动文件(.c)路径。 链接脚本保持不变。 19.4.2编译下载 使用Make命令编译代码,编译成功以后使用软件imxdownload将编译完成的keyfilter.bin文件下载到SD卡中,命令如下: chmod 777 imxdownload //给予imxdownload可执行权限,一次即可 ./imxdownload keyfilter.bin /dev/sdd //烧写到SD卡中 烧写成功以后将SD卡插到开发板的SD卡槽中,然后复位开发板。本例程的效果和第十五章一样,按下KEY就会控制蜂鸣器的开关,并且LED0不断的闪烁,提示系统正在运行。 |
|
相关推荐
|
|
753 浏览 0 评论
AI模型部署边缘设备的奇妙之旅:如何在边缘端部署OpenCV
2714 浏览 0 评论
tms320280021 adc采样波形,为什么adc采样频率上来波形就不好了?
1368 浏览 0 评论
1955 浏览 0 评论
1523 浏览 0 评论
75000 浏览 21 评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-25 13:46 , Processed in 0.634362 second(s), Total 62, Slave 45 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号