完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
|
|
相关推荐
1个回答
|
|
最近看了很多按键扫描的文章,发现各有长处,后来自己花了一点时间做了一个单片机独立按键扫描的模块,此模块优点颇多,支持短按,长按,连发功能,只要配置相关结构体就可以实现这些功能,唯一的缺点是不支持多按键同时按下功能(后续有时间加上)
先简单介绍下整体思路,首先在Key_Scan.h里面定义一个按键结构体KeyInitStruct,里面包含按键的一些设置 #define Key_Num 5 //定义按键的个数 //按键连按结构体 typedef struct { uint8_t const Key_Continuous_flg; //按键是否支持连按功能,0-无连按,1-连按 uint16_t const Key_down_TimeSet; //连按时间设置 uint16_t const Key_down_frequency; //连按频率设置 }Key_DownTypeStruct; //按键长按结构体 typedef struct { uint8_t const Key_Longdown_flg; //按键是否支持长按功能,0-无长按,1-长按 uint16_t const Key_L_down_TimeSet; //长按时间设置 void(*Key_longdown_Dut)(void); //长按函数指针 }Key_LongDownStruct; //按键设置结构体 typedef struct { GPIO_TypeDef* GPIO_X; //GPIO口 uint16_t GPIO_PIN; //GPIO引脚 uint8_t Key_Value; //按键不按时引脚电平 uint8_t Key_Down; //按键防抖处理后按下标志 0-没按下,1-按下 Key_LongDownStruct Key_LongDown; //按键长按结构体 Key_DownTypeStruct Key_DownType; //按键连按结构体 void(*Key_shortdown_Dut)(void); //短按函数指针 }KeyInitStruct ; 然后在Key_Scan.c定义一个Key的结构体数组 KeyInitStruct Key[Key_Num]={ {GPIOC,GPIO_Pin_7,1,0,{1,100,KeySet_Longdown_Dut},{1,75,10},KeySet_shortdown_Dut}, //SET按键 {GPIOC,GPIO_Pin_9,1,0,{0,500},{1,75,5},KeyOPEN_shortdown_Dut}, //OPEN按键 {GPIOC,GPIO_Pin_8,1,0,{0,500},{0,50,5},KeySTOP_shortdown_Dut}, //STOP按键 {GPIOC,GPIO_Pin_6,1,0,{0,500},{1,75,5},KeyCLOSE_shortdown_Dut}, //CLOSE按键 {GPIOC,GPIO_Pin_14,1,0,{1,400,KeyLearn_Longdown_Dut},{0,50,5},KeyLearn_shortdown_Dut}, //LEARN按键 }; 在Key_Scan.c放入按键功能函数,将此函数放在20ms定时器里面,该函数一般不用更改(假如用户要在按键松开实现功能,可把对应函数移动到程序松开位置) /****************************************************************************** Function :void Key_Scan(void) ------------------------------------------------------------------------------ Description :按键扫描函数 ----------------------------------------------------------------------------- Returnvalue : ----------------------------------------------------------------------------- Parameters : ----------------------------------------------------------------------------- Date : ----------------------------------------------------------------------------- Remarks : ******************************************************************************/ void Key_Scan(void) { uint8_t i; for(i=0;i if(Key.Key_Value ==1) //硬件电路是否上拉 Key.Key_Down = 1-GPIO_ReadInputDataBit(Key.GPIO_X,Key.GPIO_PIN); //硬件电路上拉,按键按下则为0 else Key.Key_Down = GPIO_ReadInputDataBit(Key.GPIO_X,Key.GPIO_PIN); } } /****************************************************************************** Function :void Key_Function(void) ------------------------------------------------------------------------------ Description :按键功能函数,放在20ms定时器 ----------------------------------------------------------------------------- Returnvalue : ----------------------------------------------------------------------------- Parameters : ----------------------------------------------------------------------------- Date : ----------------------------------------------------------------------------- Remarks : ******************************************************************************/ void Key_Function(void) { uint8_t i; static uint8_t Pre_Key_St[Key_Num] = {0}; //定义一个按键上次状态的变量 static uint16_t Key_St_cnt[Key_Num]={0}; //按键按下计数变量 Key_Scan(); for(i=0;i if( Key.Key_LongDown.Key_Longdown_flg==0 ) //无长按功能 { if( Key.Key_DownType.Key_Continuous_flg==0 )//无连按功能 { if( Pre_Key_St ^ Key.Key_Down ) //按键上一次与现在状态不一致,说明按键要么按下,要么松开 { Pre_Key_St = Key.Key_Down; //这条语句很关键,自己体会,无法言语 if(Key.Key_Down) //按键按下 { Key.Key_shortdown_Dut(); } else //按键松开 { //可以在此添加按键松开的函数 } } else { Pre_Key_St = Key.Key_Down;; } } else //连按功能 { if( Pre_Key_St ^ Key.Key_Down ) //按键上一次与现在状态不一致,说明按键要么按下,要么松开 { Pre_Key_St = Key.Key_Down; //这条语句很关键,自己体会,无法言语 if(Key.Key_Down) //按键按下 { Key.Key_shortdown_Dut(); } else //按键松开 { //可以在此添加按键松开的函数 } } else { Pre_Key_St = Key.Key_Down; } if(Key.Key_Down) { Key_St_cnt++; //按键按下开始计数 } else { Key_St_cnt = 0; //松开计数清零 } if(Key_St_cnt>Key.Key_DownType.Key_down_TimeSet) //按键按下时间大于连按时间设置 { if((Key_St_cnt-Key.Key_DownType.Key_down_TimeSet)%Key.Key_DownType.Key_down_frequency==0) //进入函数的频率 { Key.Key_shortdown_Dut(); } } } } else //有长按功能 { if(Key.Key_Down) { Key_St_cnt++; } if(Key_St_cnt>0 && Key_St_cnt { if(Key.Key_Down == 0) //短按松开 { Key.Key_shortdown_Dut(); Key_St_cnt = 0; } } else if(Key_St_cnt>=Key.Key_LongDown.Key_L_down_TimeSet) { if( Pre_Key_St ^ Key.Key_Down ) //按键上一次与现在状态不一致,说明按键要么按下,要么松开 { Pre_Key_St = Key.Key_Down; //这条语句很关键,自己体会,无法言语 if(Key.Key_Down) //按键按下 { Key.Key_LongDown.Key_longdown_Dut(); } else //按键长按松开 { Key_St_cnt = 0; //按键长按松开计数清零 } } else { Pre_Key_St = Key.Key_Down; } } } } } 最后是按键对应的功能函数,用户只要在此更改自己所要实现的功能就行 void KeySet_shortdown_Dut(void) { //在此添加按键所对应的功能 } void KeyOPEN_shortdown_Dut(void) { //在此添加按键所对应的功能 } void KeySTOP_shortdown_Dut(void) { //在此添加按键所对应的功能 } void KeyCLOSE_shortdown_Dut(void) { //在此添加按键所对应的功能 } void KeyLearn_shortdown_Dut(void) { //在此添加按键所对应的功能 } void KeySet_Longdown_Dut(void) { //在此添加按键所对应的功能 } void KeyLearn_Longdown_Dut(void) { //在此添加按键所对应的功能 } 总结:用户只要配置按键结构体函数,定义按键个数Key_Num ,以及更改对应函数的功能。就可以实现所想要的功能,非常灵活,移植度高。下次有时间在做个按键与数码管二三级菜单设置模块。 |
|
|
|
只有小组成员才能发言,加入小组>>
3124 浏览 9 评论
2820 浏览 16 评论
3333 浏览 1 评论
8704 浏览 16 评论
3922 浏览 18 评论
9542浏览 3评论
876浏览 3评论
446浏览 2评论
const uint16_t Tab[10]={0}; const uint16_t *p; p = Tab;//报错是怎么回事?
450浏览 2评论
用NUC131单片机UART3作为打印口,但printf没有输出东西是什么原因?
2173浏览 2评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-8-16 09:50 , Processed in 0.622208 second(s), Total 76, Slave 58 queries .
Powered by 电子发烧友网
© 2015 www.ws-dc.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号