背景
今年上半年一直在负责基于CC2640R2F挂锁项目的开发,项目目前基本完成,分享下2640各个外设的开发。
实现功能
短按进入NB模式,长按3s左右进入BLE模式,长按5s关机。
实现步骤
首先按键作为一个输入设备,我们应该把IO口设置成输入上拉模式,其次还涉及到消抖处理,防止误触发。由于该按键需实现长短按,于是把IO口设置成双边沿触发中断,具体实现如下:
//配置IO位输入上拉模式
PIN_Config keyPinsCfg[] =
{
Board_WakeUpKey | PIN_GPIO_OUTPUT_DIS | PIN_INPUT_EN | PIN_PULLUP,
PIN_TERMINATE
};
//注册按键回调函数
Board_initKeys(SimpleBLEPeripheral_keyChangeHandler);
//按键初始化
void Board_initKeys(keysPressedCB_t appKeyCB)
{
// Initialize KEY pins. Enable int after callback registered
KeyHandle = PIN_open(&KeyState, keyPinsCfg);
PIN_registerIntCb(KeyHandle, Board_keyCallback); //注册中断,中断触发进入Board_keyCallback函数
//定义中断触发条件
PIN_setConfig(KeyHandle, PIN_BM_IRQ, Board_WakeUpKey | PIN_IRQ_BOTHEDGES); //电源按键
#ifdef POWER_SAVING //低功耗状态唤醒
//Enable wakeup
PIN_setConfig(KeyHandle, PINCC26XX_BM_WAKEUP, Board_WakeUpKey | PINCC26XX_WAKEUP_NEGEDGE);
#endif //POWER_SAVING
// Setup keycallback for keys 消抖
Util_constructClock(&keyChangeClock, Board_keyChangeHandler,
KEY_DEBOUNCE_TIMEOUT, 0, false, 0); //手动定时器
// Set the application callback
//appKeyCB 入队列的函数指针
appKeyChangeHandler = appKeyCB; //通知APP层,有按键触发
}
具体思路
1 //按键消抖,延时16ms处理
static void Board_keyCallback(PIN_Handle hPin, PIN_Id pinId)
{
Util_restartClock(&keyChangeClock, 16); //启动定时器,延时消抖
PIN_clrPendInterrupt(hPin, pinId); //清中断
}
//按键消抖后,长短按键处理
static void Board_keyChangeHandler(UArg a0)
{
uint8_t key_pressed = 0;
2 //检测到下降沿触发,打开定时器
if (!PIN_getInputValue(Board_WakeUpKey))
{
Util_startClock(&keyTime_periodicClock); //启动定时器,判断长短按键
key_time = 0;
}
else
{
4 //按键上升沿触发,关闭定时器,事件入队列
Util_stopClock(&keyTime_periodicClock);
if (appKeyChangeHandler != NULL)
{
if (key_time <= 2)
{
key_pressed |= KEY_SHORT;
}
else if ((key_time > 2) && (key_time <= 5))
{
key_pressed |= KEY_LONG;
}
else
{
key_pressed |= KEY_TOO_LONG;
}
}
// Notify the application 入队列
(*appKeyChangeHandler)(key_pressed);
}
}
3 //APP任务中处理定时器,设定为1s定时器,定时到则key_time++,指示灯亮则松手触发按键的上升沿中断
case SBP_KEY_TIME_EVT:
events &= ~SBP_KEY_TIME_EVT; //清事件ID
key_time++;
if (key_time == 3)
{
HwGPIOSet(Board_GLED, 1); //绿LED指示3s到
Util_startClock(&one_second);
}
else if (key_time == 6)
{
HwGPIOSet(Board_RLED, 1); //红LED指示6s到
Util_startClock(&one_second);
}
else
{
//do nothing
}
break;
5 //按键回调函数,入队列
void SimpleBLEPeripheral_keyChangeHandler(uint8 keys)
{
SimpleBLEPeripheral_enqueueMsg(SBP_KEY_CHANGE_EVT, keys);
}
//入队列函数
static void SimpleBLEPeripheral_enqueueMsg(uint8_t event, uint8_t state)
{
sbpEvt_t *pMsg;
// Create dynamic pointer to message.
if ((pMsg = ICall_malloc(sizeof(sbpEvt_t))))
{
pMsg->hdr.event = event;
pMsg->hdr.state = state;
// Enqueue the message.
Util_enqueueMsg(appMsgQueue, syncEvent, (uint8*)pMsg);
}
}
6 //出队列
case SBP_QUEUE_EVT:
events &= ~SBP_QUEUE_EVT;
while (!Queue_empty(appMsgQueue))
{
sbpEvt_t *pMsg = (sbpEvt_t *)Util_dequeueMsg(appMsgQueue);
if (pMsg)
{
// Process message.
SimpleBLEPeripheral_processAppMsg(pMsg);
// Free the space from the message.
ICall_free(pMsg);
}
}
static void SimpleBLEPeripheral_processAppMsg(sbpEvt_t *pMsg)
{
switch (pMsg->hdr.event)
{
case SBP_STATE_CHANGE_EVT:
SimpleBLEPeripheral_processStateChangeEvt((gaprole_States_t)pMsg->
hdr.state);
break;
case SBP_CHAR_CHANGE_EVT:
SimpleBLEPeripheral_processCharValueChangeEvt(pMsg->hdr.state);
break;
case SBP_KEY_CHANGE_EVT: //按键处理
SimpleBLEPeripheral_handleKeys(pMsg->hdr.state);
break;
default:
break;
}
}
7 //APP处理不同的按键事件
static void SimpleBLEPeripheral_handleKeys(uint8_t keys)
{
switch (keys)
{
case KEY_SHORT:
break;
//打开蓝牙
case KEY_LONG:
break;
//断电,切换管理员
case KEY_TOO_LONG:
break;
思路总结
当按键按下,检测到下降沿中断触发,消抖后,打开定时器,计时,3s时间到绿灯亮或则6时间到红灯亮,松手,检测到上升沿中断触发,消抖后,关闭定时器,将对应事件加入队列中,唤醒APP任务,出队列,进行相应的事件处理。