(配套源码、软件、开发板等资源,可移步博客同名QQ群/TB店铺:拿破仑940911)
本节将讲述如何实现基于系统时钟的多功能按键,主要是关于如何根据“按键时间持续的长短”来决定按键操作,实现单一按键的多功能化。从本节开始,所有的程序均在“ZStack-CC2530-2.5.1a-20170924_1020.zip”的基础往下进行!(详见“\ZigBee_CC2530\代码:完整工程”该网盘目录下的《程序版本说明20170924_1033.txt》)
一、应用举例(“华为荣耀xSport AM61运动蓝牙耳机”)
一般实际项目开发中,经常会使用多功能按键,比如我自己正在使用的“AM61蓝牙耳机”,如下图所示:
这个多功能按键确实功能非常丰富!我这里截取了京东的售货页面上关于这个多功能按键的部分说明:
通过本节的学习,我们自己也可以开发处类似的多功能按键!
二、Z-Stack中基于系统时钟实现多功能按键的原理
1、按键中断模式
在了解多功能按键的实现原理之前,建议大家先回顾一下《ZigBee CC2530 Z-Stack 15 按键驱动移植及使用1-轮询模式与中断模式》和《ZigBee CC2530 Z-Stack 16 按键驱动移植及使用2-驱动移植》这两节,尤其是其中关于按键中断模式的讲解。
2、系统时钟——osal_systemClock
在OSAL_Timers.c文件中,有一个名为osal_GetSystemClock()的函数,其定义如下:
/********************************************************************* * @fn osal_GetSystemClock() * * @brief Read the local system clock. * * @param none * * @return local clock in milliseconds */ uint32 osal_GetSystemClock( void ) { return ( osal_systemClock ); }可见函数中仅仅是直接返回osal_systemClock的值,该变量的定义也在同一个文件中:
// Milliseconds since last reboot static uint32 osal_systemClock;可见该变量的值的范围是毫秒,更多关于这个变量信息请自行查阅Z-Stack中相关代码。这里唯一需要说明的是,该值的范围是0~(2^32-1),系统一上电,该值就从0开始每毫秒增1。所以我们可以通过调用osal_GetSystemClock()函数直接获取系统时钟osal_systemClock的值,这是我们基于系统时钟的多功能按键实现的基本原理。
3、基于osal_systemClock的多功能按键
基于系统时钟的多功能按键,关键就是获取“按键时间持续的长短”,根据按键时间长短划分成不同的时间段,就实现了单一按键的多功能化。获取按键时间的基本思想为(以ZB502底板上的KEY1为例,下降沿触发):
(1)对KEY1做好基本IO初始化(上拉输入),以及相关中断初始化(下降沿触发);
(2)按下按键的一瞬间,会由于“下降沿”触发而第一次进入中断,此时获取当前系统时钟,存在我们定义的全局变量HAL_KEY_starting_time中:
HAL_KEY_starting_time = osal_GetSystemClock();退出中断前,将触发模式切换为“上升沿”触发:
PICTL ^= HAL_KEY_SW_1_EDGEBIT; //触发边沿<--取反(3)松开按键的一瞬间,会由于“上升沿”触发而第二次进入中断,此时获取当前系统时钟,与HAL_KEY_starting_time做差即可得到此次按键的持续时间——HAL_KEY_interval_time,仅当持续时间大于HAL_KEY_FILTER_TIME(20 ms)才会认为是有效(valid),否则则会被过滤掉:
HAL_KEY_interval_time = osal_GetSystemClock()-HAL_KEY_starting_time; if(HAL_KEY_interval_time > HAL_KEY_FILTER_TIME)//小于HAL_KEY_FILTER_TIME ms的电平变化都会被过滤掉 { isrKeys |= HAL_KEY_SW_1; valid = TRUE; }退出中断前,将触发模式还原为“下降沿”触发:
PICTL ^= HAL_KEY_SW_1_EDGEBIT; //触发边沿<--取反(4)如果本次按键有效,则会最终将按键的事件(KEY_CHANGE)发送至应用层任务(ProjectApp_TaskID):
if (valid) { osal_set_event(Hal_TaskID, HAL_KEY_EVENT); }(中间过程请回顾《ZigBee CC2530 Z-Stack 15 按键驱动移植及使用1-轮询模式与中断模式》)
OnBoard_KeyCallback()函数修改为如下:
void OnBoard_KeyCallback ( uint8 keys, uint8 state ) { uint8 shift; (void)state; if (HAL_KEY_interval_time < 5000) shift = HAL_KEY_00_05_S; else if(HAL_KEY_interval_time < 10000) shift = HAL_KEY_05_10_S; else if(HAL_KEY_interval_time < 15000) shift = HAL_KEY_10_15_S; else return; if ( OnBoard_SendKeys( keys, shift ) != ZSuccess ) { } }既然按键是有效的,那我们就可以根据此次按键的持续时间——HAL_KEY_interval_time,将按键时间划分为如上述代码中所示的多段,其中总共有3个有效的时间段,我们通过shift(state)的值,将时间段的标识传递到应用层任务,我们在应用层的处理对应代码如下:
case KEY_CHANGE : ProjectApp_HandleKeys(((keyChange_t *)MSGpkt)->state,((keyChange_t *)MSGpkt)->keys);break;static void ProjectApp_HandleKeys( uint8 shift, uint8 keys ) { if ( keys & HAL_KEY_SW_1 ) { switch(shift) { case HAL_KEY_00_05_S : break; case HAL_KEY_05_10_S : break; case HAL_KEY_10_15_S : break; } } uint16 ss = HAL_KEY_interval_time/1000; uint16 ms = HAL_KEY_interval_time%1000; printf("keys:%02X shift:%01d interval:%02d.%03ds\r\n", keys, shift, ss, ms); }在switch语句中的各个case分支下,我们可以根据自己的需求,分别去实现自己想要的不同功能;最后的printf()函数在这里只是临时debug使用的,可以方便大家清楚地知道精确的按键持续时间。上述描述已将多功能按键的原理分析完毕,如果有疑问或者想阅读完整工程代码的话,可以直接去本文最开始提供的百度网盘链接去下载~
三、实验验证
1、编译下载
本次实验验证只需要一个ZigBee设备即可完成,这里我们选择“CoordinatorEB”编译下载:
2、实验现象
下载成功之后,一开始ZigBee设备还是和以前一样会打印一些自己的网络状态变化信息,接下来,我们便开始验证我们的多功能按键:
按键时间在20ms~15000ms之间都会有串口输出,串口打印的信息非常容易理解,此处就不再赘述~此外,这里我们只实现了KEY1,大家如果想扩展其余按键的功能,按照前面讲述的原理,一样的操作即可~
(配套源码、软件、开发板等资源,可移步博客同名QQ群/TB店铺:拿破仑940911)