对于按键驱动修改不错的博文:https://wenku.baidu.com/view/12e61922aef8941ea66e05b9.html
https://blog.csdn.net/stone8761/article/details/79563594
此外,使用的TI BLE协议栈版本是1.3.2。
KEY服务API
KEY服务一共有7个API。分别是:
- HalKeyInit()
- HalKeyConfig()
- HalKeyRead()
- HalKeyEnterSleep()
- HalKeyExitSleep()
- HalKeyPoll()
- HalKeyPressed()
其中,HalKeyInit()、HalKeyConfig()、HalKeyRead()、HalKeyPoll()是我们需要关注的。
1.五向按键的硬件原理
五向按键的五个方向:上、下、左、右、垂直向下。原理是只要五向按键有按压动作,在JOY_MOVE引脚会产生中断,此时再去采集JOY_LEVEL的电压,根据电压范围来判断当前的五向按键的方向。原理还是很简单的,电路倒是有点复杂。
此外,开发板还有一个单独的按键S1。
2.KEY服务API源码分析
因为我使用的是开发板的例程,五向按键部分的电路和官方是不一样的,因此使用开发板提供的修改文件hal_key.c。
2.1 HalKeyInit()
-
-
-
-
-
-
-
-
-
-
-
-
-
-
halKeySavedKeys = HAL_KEY_CODE_NOKEY;
-
-
-
-
-
-
-
-
-
-
-
-
HAL_KEY_SW_6_SEL &= ~(HAL_KEY_SW_6_BIT);
-
HAL_KEY_SW_6_DIR &= ~(HAL_KEY_SW_6_BIT);
-
HAL_KEY_JOY_MOVE_SEL &= ~(HAL_KEY_JOY_MOVE_BIT);
-
HAL_KEY_JOY_MOVE_DIR &= ~(HAL_KEY_JOY_MOVE_BIT);
-
-
-
<span style="font-size:10px;">pHalKeyProcessFunction = NULL;</span>
-
-
-
HalKeyConfigured = FALSE;
-
-
<span style="font-size:10px;">halKeyTimerRunning = FALSE;</span>
-
-
这里主要是对两个引脚(一个用于触发中断,一个用于AD采样)进行设置,并设置相关文件域的全局变量,包括pHalKeyProcessFunction、HalKeyConfigured、halKeyTimerRunning。在使用KEY服务前必须要调用该函数,在TI的例程中只要开启相关宏定义即可,这时会在HalDriverInit()中进行初始化:
2.2 HalKeyConfig()
-
-
-
-
-
-
-
-
-
-
-
void HalKeyConfig (bool interruptEnable, halKeyCBack_t cback)
-
-
-
-
Hal_KeyIntEnable = interruptEnable;
-
-
-
pHalKeyProcessFunction = cback;
-
-
-
-
-
-
-
-
PICTL &= ~(HAL_KEY_SW_6_EDGEBIT);
-
-
PICTL &= ~(HAL_KEY_SW_6_EDGEBIT);
-
-
-
-
-
-
-
-
-
HAL_KEY_SW_6_ICTL |= HAL_KEY_SW_6_ICTLBIT;
-
HAL_KEY_SW_6_IEN |= HAL_KEY_SW_6_IENBIT;
-
HAL_KEY_SW_6_PXIFG = ~(HAL_KEY_SW_6_BIT);
-
-
-
-
-
-
HAL_KEY_JOY_MOVE_ICTL &= ~(HAL_KEY_JOY_MOVE_EDGEBIT);
-
-
-
HAL_KEY_JOY_MOVE_ICTL |= HAL_KEY_JOY_MOVE_EDGEBIT;
-
-
-
-
-
-
-
-
HAL_KEY_JOY_MOVE_ICTL |= HAL_KEY_JOY_MOVE_ICTLBIT;
-
HAL_KEY_JOY_MOVE_IEN |= HAL_KEY_JOY_MOVE_IENBIT;
-
HAL_KEY_JOY_MOVE_PXIFG = ~(HAL_KEY_JOY_MOVE_BIT);
-
-
-
-
if (HalKeyConfigured == TRUE)
-
-
osal_stop_timerEx( Hal_TaskID, HAL_KEY_EVENT);
-
-
-
-
-
HAL_KEY_SW_6_ICTL &= ~(HAL_KEY_SW_6_ICTLBIT);
-
HAL_KEY_SW_6_IEN &= ~(HAL_KEY_SW_6_IENBIT);
-
-
-
osal_start_timerEx (Hal_TaskID, HAL_KEY_EVENT, HAL_KEY_POLLING_VALUE);
-
-
-
-
-
-
该函数对KEY服务进行配置,形参有2个:interruptEnable, cback。
interruptEnable用来选择按键的扫描方式,KEY服务的按键扫描方式有两种,一种是循环扫描,另外一种是中断扫描。循环扫描和中断扫描的具体过程后面会介绍。cback就是应用层传给HAL KEY服务的回调函数,用于通知应用层相关按键的触发动作。回调函数的原型是:
typedef void (*halKeyCBack_t) (uint8 keys, uint8 state);
keys表示哪个按键被按下,state表示按键是怎么被按下的,TI的HAL进行如下定义:
state中HAL_KEY_STATE_SHIFT好像不怎么用得到,用HAL_KEY_STATE_NORMAL比较多。
2.3 HalKeyConfig()
-
-
-
-
-
-
-
-
-
-
uint8 HalKeyRead ( void )
-
-
-
-
-
if ((HAL_KEY_SW_6_PORT & HAL_KEY_SW_6_BIT))
-
-
-
-
-
if ((HAL_KEY_JOY_MOVE_PORT & HAL_KEY_JOY_MOVE_BIT))
-
-
keys |= halGetJoyKeyInput();
-
-
-
该函数不需要应用层调用,是有HAL层调用的,在开发板的例程中,因为硬件上只有一个按键和一个五向按键,所以该函数的前面部分是通过IO口电平判断按键现在的状态,后面部分则是具体检测五向按键的状态。首先要确定五向按键被操作了,之后再执行函数halGetJoyKeyInput()。
-
-
-
-
-
-
-
-
-
-
uint8 halGetJoyKeyInput(void)
-
-
-
-
-
-
-
-
-
-
-
-
-
-
adc = HalAdcRead (HAL_KEY_JOY_CHN, HAL_ADC_RESOLUTION_8);
-
-
if ((adc >= 2) && (adc <= 38))
-
-
-
-
else if ((adc >= 74) && (adc <= 88))
-
-
-
-
else if ((adc >= 60) && (adc <= 73))
-
-
-
-
else if ((adc >= 39) && (adc <= 59))
-
-
-
-
else if ((adc >= 89) && (adc <= 100))
-
-
ksave0 |= HAL_KEY_CENTER;
-
-
-
-
-
} while (ksave0 != ksave1);
-
-
-
2.4 HalKeyPoll()
-
-
-
-
-
-
-
-
-
-
#define GHOSTYU_CODE_NOKEY 0x00
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
if (keys == halKeySavedKeys)
-
-
-
-
-
-
-
-
(pHalKeyProcessFunction) (0, HAL_KEY_STATE_NORMAL);
-
-
-
-
if ((keys != 0 ) && Hal_KeyIntEnable &&
-
(pHalKeyProcessFunction))
-
-
-
-
-
(pHalKeyProcessFunction) (keys, HAL_KEY_STATE_NORMAL);
-
-
-
-
-
-
-
-
-
-
-
-
-
-
osal_start_timerEx(Hal_TaskID, HAL_KEY_EVENT, 50);
-
-
-
-
-
halKeyTimerRunning = FALSE;
-
-
-
-
-
-
该函数是对应开发板硬件修改的,它也是HAL层来执行,不需要应用层进行判断,主要功能是对按键的状态进行采集分析,并作回调。不过我看这个函数有些怪怪的,可以再优化下,增加可读性。另外,该函数和TI官方代码最大不同是,它增加了回调函数的一个功能,就是所有按键都释放时会有回调,此时state=0。下面贴一下官方的代码:
-
-
-
-
-
-
-
-
-
-
-
-
-
-
#if defined (CC2540_MINIDK)
-
if (!(HAL_KEY_SW_1_PORT & HAL_KEY_SW_1_BIT))
-
-
-
-
if (!(HAL_KEY_SW_2_PORT & HAL_KEY_SW_2_BIT))
-
-
-
-
-
if (!(HAL_KEY_SW_6_PORT & HAL_KEY_SW_6_BIT))
-
-
-
-
-
if ((HAL_KEY_JOY_MOVE_PORT & HAL_KEY_JOY_MOVE_BIT))
-
-
keys = halGetJoyKeyInput();
-
-
-
-
-
-
-
-
-
if (keys == halKeySavedKeys)
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
if (notify && (pHalKeyProcessFunction))
-
-
(pHalKeyProcessFunction) (keys, HAL_KEY_STATE_NORMAL);
-
-
-
不过,TI的代码好像也有问题:
-
-
if (!(HAL_KEY_SW_6_PORT & HAL_KEY_SW_6_BIT))
-
-
-
-
-
if ((HAL_KEY_JOY_MOVE_PORT & HAL_KEY_JOY_MOVE_BIT))
-
-
keys = halGetJoyKeyInput();
-
-
keys = halGetJoyKeyInput();
应该改为:
keys |= halGetJoyKeyInput();
剩下的3个API:HalKeyEnterSleep()和HalKeyExitSleep()是没有内容的,HalKeyPressed()只找到声明没找到定义,就不管了。
3.KEY服务的工作流程
前面已经大概介绍了几个API的主要功能,现在来说说他们是怎么被HAL层使用的。
首先,当按键服务宏定义被打开后,HalKeyInit()函数会被调用(前面有介绍),之后,一般在设备启动任务中对KEY服务进行配置。
这里就有两个分支了,一个是当KEY_INT_ENABLED时,使用的是中断扫描,否则使用循环扫描方式,他们再HAL层工作流程就不太一样。
3.1 循环扫描
当使用循环扫描时,HalKeyConfig()在最后会触发HAL_KEY_EVENT事件:
-
-
if (HalKeyConfigured == TRUE)
-
-
osal_stop_timerEx(Hal_TaskID, HAL_KEY_EVENT);
-
-
-
-
-
#if defined ( CC2540_MINIDK )
-
HAL_KEY_SW_1_ICTL &= ~(HAL_KEY_SW_1_ICTLBIT);
-
HAL_KEY_SW_1_IEN &= ~(HAL_KEY_SW_1_IENBIT);
-
HAL_KEY_SW_2_ICTL &= ~(HAL_KEY_SW_2_ICTLBIT);
-
HAL_KEY_SW_2_IEN &= ~(HAL_KEY_SW_2_IENBIT);
-
-
HAL_KEY_SW_6_ICTL &= ~(HAL_KEY_SW_6_ICTLBIT);
-
HAL_KEY_SW_6_IEN &= ~(HAL_KEY_SW_6_IENBIT);
-
-
-
osal_set_event(Hal_TaskID, HAL_KEY_EVENT);
-
而在HAL任务中,会进行如下工作:
-
if (events & HAL_KEY_EVENT)
-
-
#if (defined HAL_KEY) && (HAL_KEY == TRUE)
-
-
-
-
-
-
-
osal_start_timerEx( Hal_TaskID, HAL_KEY_EVENT, 100);
-
-
-
return events ^ HAL_KEY_EVENT;
-
这里我们可以注意到,当使用循环扫描时,扫描周期为100ms,每次处理该事件时调用的函数就是HalKeyPoll()。
3.2 中断扫描
和循环扫描所不同的是,它不会定时扫描,只有当中断触发时才会设置
HAL_KEY_EVENT事件。
在中断处理中,当检测到是相应开关触发的中断后,会调用函数halProcessKeyInterrupt():
-
-
-
-
-
-
-
-
-
-
-
void halProcessKeyInterrupt (void)
-
-
-
-
-
-
if (HAL_KEY_SW_6_PXIFG & HAL_KEY_SW_6_BIT)
-
-
HAL_KEY_SW_6_PXIFG = ~(HAL_KEY_SW_6_BIT);
-
-
-
-
if (HAL_KEY_JOY_MOVE_PXIFG & HAL_KEY_JOY_MOVE_BIT)
-
-
HAL_KEY_JOY_MOVE_PXIFG = ~(HAL_KEY_JOY_MOVE_BIT);
-
-
-
-
-
-
-
-
halKeyTimerRunning = TRUE;
-
-
osal_start_timerEx (Hal_TaskID, HAL_KEY_EVENT, HAL_KEY_DEBOUNCE_VALUE);
-
-
-
-