-
目的
实现类似于windows消息映射的方式编程思想,将离散的逻辑调用整合成消息映射的方式,基于消息触发调用
-
实现步骤
step 1:
修改configPort.h中的内容
#ifndef __CONFIG_PORT__H
#define __CONFIG_PORT__H
#include "nrf_drv_gpiote.h"
#include "nrf_gpio.h"
#define __CONST
#define KEY_1_PIN_NO 7
#define KEY_2_PIN_NO 11
#define KEY_3_PIN_NO 14
#define KEY_4_PIN_NO 23
#define KEY_5_PIN_NO 24
#define KEY_6_PIN_NO 22
#define KEY_7_PIN_NO 13
#define KEY_8_PIN_NO 0xff
#define KEY_9_PIN_NO 0xff
#define KEY_10_PIN_NO 0xff
#define KEY_11_PIN_NO 0xff
#define KEY_12_PIN_NO 0xff
#define KEY_13_PIN_NO 0xff
#define KEY_14_PIN_NO 0xff
#define TOTAL_KEY_COUNT 7
#define BSP_GPIO_KEY {KEY_1_PIN_NO,KEY_2_PIN_NO,KEY_3_PIN_NO,KEY_4_PIN_NO,KEY_5_PIN_NO,KEY_6_PIN_NO,KEY_7_PIN_NO, \
KEY_8_PIN_NO,KEY_9_PIN_NO,KEY_10_PIN_NO,KEY_11_PIN_NO,KEY_12_PIN_NO,KEY_13_PIN_NO,KEY_14_PIN_NO}
#define BSP_key_init() \
do \
{ \
uint8_t list[] = BSP_GPIO_KEY; \
for(uint8_t i = 0; i < TOTAL_KEY_COUNT; i++) \
nrf_gpio_cfg_input(list[i], NRF_GPIO_PIN_PULLUP); \
}while(0)
#define BSP_key_DeInit() \
do \
{ \
uint8_t list[] = BSP_GPIO_KEY; \
for(uint8_t i = 0; i < TOTAL_KEY_COUNT; i++) \
{ \
nrf_gpio_pin_clear(list[i]); \
nrf_drv_gpiote_out_uninit(list[i]); \
} \
}while(0)
#define OSScanKey(temp) \
do \
{ \
uint8_t list[] = BSP_GPIO_KEY; \
uint16_t *p = &temp; \
*p = 0; \
for(uint8_t i = 0; i < TOTAL_KEY_COUNT; i++) \
{ \
if(nrf_gpio_pin_read(list[i])==0) \
*p |= 1<<i; \
} \
}while(0)
#endif
step 2:
baseCls.h中的内容如下:
#ifndef __BASECLASS_H
#define __BASECLASS_H
#include "configPort.h"
#ifndef __CONST
#define CONST code
#else
#define CONST const
#endif
#ifdef __TYPEDEF
#ifndef __TYPEDEF_ONCE
#define __TYPEDEF_ONCE
typedef unsigned char uint8_t;
typedef char int8_t;
typedef unsigned short uint16_t;
typedef short int16_t;
typedef unsigned long uint32_t;
typedef long int32_t;
#ifndef NULL
#define NULL (void*)0
#endif
#endif
#endif // __TYPEDEF end
#ifndef FALSE
#define FALSE (0)
#endif
#ifndef TRUE
#define TRUE (1)
#endif
typedef void (*AFX_PVVMSG)(volatile uint8_t *flag);
typedef void (*AFX_PMSG)(uint16_t * event);
typedef void (*AFX_VOID)(void);
typedef void (*AFX_PFN)( void *self);
typedef void (*AFX_PVMSG)( void*self,uint16_t event);
typedef void (*AFX_MSG)(uint16_t event);
typedef uint8_t (*PreFilterMsg)(uint16_t *msg);
/**********************************************************************/
typedef struct tagOnTime
{
uint16_t elapseTime;
uint8_t id;
}ONTIMER;
/************************************************************************/
enum AfxSig
{
AfxSig_vv=0, // void (void)
AfxSig_vpv, // void (void*)
AfxSig_vpvuc, // void (void*,uint16_t)
AfxSig_uc, //void (uint16_t)
AfxSig_puc, // void (uint16_t *)
AfxSig_pvv //带volatile uint8_t*参数
};
typedef union
{
AFX_VOID pfn; //不带参数
AFX_PFN pvfn; //带void*参数
AFX_PVMSG pvmfn; //带void*,unsigned short参数
AFX_MSG pucfn; //带unsigned short参数
AFX_PMSG ppucfn; // 带unsigned short*参数
AFX_PVVMSG pvvfn; //带volatile uint8_t*参数
}AFX_UNION_PFN;
typedef struct tagMSGMAP_ENTRY
{
uint16_t message;
uint8_t nSign;
AFX_VOID pfn;
}AFX_MSGMAP_ENTRY;
typedef struct tagCmdTarget
{
const AFX_MSGMAP_ENTRY *lpEn;
const PreFilterMsg preMsgHandler;
}cmdTarget;
/*################################################*/
//定义函数结果状态码
#define OK 1
#define ERROR 0
//定义循环队列空间大小
#define QUEUESIZE 16
//定义数据类型
typedef int ElemType;
//定义程序返回状态类型
typedef int State;
typedef struct tagSqMsg
{
void *lpMsgEn;
void *extraData;
uint16_t msg;
}QueueMsg;
//循环队列存储结构
typedef struct _CircleQueue
{
QueueMsg data_elem[QUEUESIZE];//存储队列元素
uint8_t front;//队列头指针
uint8_t rear;//队列尾指针
int count;//队列元素个数
}CircleQueue;
/*##################################################*/
#define initMsg(theClass)\
static CONST cmdTarget myTest = {&theClass[0]};
#define ON_EVENT_MESSAGE(message,pfn) {message,AfxSig_uc,(AFX_VOID)(AFX_MSG)&pfn},
#define ON_NSM_MESSAGE(message,pfn) {message,AfxSig_vv,pfn},
#define ON_SM_MESSAGE(message,pfn) {message,AfxSig_vpv,(AFX_VOID)(AFX_PFN)&pfn},
#define ON_NOTIFY_MESSAGE(message,pfn) {message,AfxSig_vpvuc,(AFX_VOID)(AFX_PVMSG)&pfn},
#define ON_KEY_LONG_EVENT_MESSAGE(message,pfn) {message,AfxSig_puc,(AFX_VOID)(AFX_PMSG)&pfn},
#define ON_TICK_MESSAGE(message,pfn) {message,AfxSig_pvv,(AFX_VOID)(AFX_PVVMSG)&pfn},
#define DECLARE_MESSAGE_MAP()\
const cmdTarget* lpEn;
#define BEGIN_MESSAGE_MAP(theClass)\
static CONST AFX_MSGMAP_ENTRY theClass[]={\
#define END_MESSAGE_MAP(lpDef) \
{0,AfxSig_vpv,(AFX_VOID)lpDef } \
};\
#define INIT_MSG_ENTRIES(theClass,cmdTargetName,preMsgHandler)\
CONST cmdTarget cmdTargetName = {theClass,preMsgHandler};
#define GET_MESSAGE_MAP(theClass, cmdTargetName) \
theClass.lpEn = &cmdTargetName;
#define DECLARE_cmdTarget(theClass) \
extern CONST cmdTarget theClass;
extern QueueMsg *lpGetMsg;
//void OnTime(uint8_t *count, AFX_VOID pfn);
void OnCmdMsg(uint16_t event, void *lpEn, void * extraData);
QueueMsg *GetMessage(void) ;
State PostMessage(uint16_t msg, void *self, void *extra);
void setKeyToneHandler(AFX_PMSG func);
void DisLongKeyContinueResponse(void);
void keyProcess(void*self,uint8_t *flag);
/************************************************************************/
#define KEY_LONG_ON 0X8000
#define KEY_OFF 0X4000
#define KEY_BLOCK_EVENT (KEY_LONG_ON|KEY_OFF) //阻塞长按键
/*############################################################*/
/* 短按按键事件ID */
/*################################################################*/
#define KEY_1_SHORT 0X01
#define KEY_2_SHORT 0X02
#define KEY_3_SHORT 0X04
#define KEY_4_SHORT 0X08
#define KEY_5_SHORT 0X10
#define KEY_6_SHORT 0X20
#define KEY_7_SHORT 0X40
#define KEY_8_SHORT 0X80
#define KEY_9_SHORT 0X100
#define KEY_10_SHORT 0X200
#define KEY_11_SHORT 0X400
#define KEY_12_SHORT 0X800
#define KEY_13_SHORT 0X1000
#define KEY_14_SHORT 0X2000
/*############################################################*/
/* 长按按键事件ID */
/*################################################################*/
#define KEY_1_LONG_ON (KEY_1_SHORT + KEY_LONG_ON)
#define KEY_2_LONG_ON (KEY_2_SHORT + KEY_LONG_ON)
#define KEY_3_LONG_ON (KEY_3_SHORT + KEY_LONG_ON)
#define KEY_4_LONG_ON (KEY_4_SHORT + KEY_LONG_ON)
#define KEY_5_LONG_ON (KEY_5_SHORT + KEY_LONG_ON)
#define KEY_6_LONG_ON (KEY_6_SHORT + KEY_LONG_ON)
#define KEY_7_LONG_ON (KEY_7_SHORT + KEY_LONG_ON)
#define KEY_8_LONG_ON (KEY_8_SHORT + KEY_LONG_ON)
#define KEY_9_LONG_ON (KEY_9_SHORT + KEY_LONG_ON)
#define KEY_10_LONG_ON (KEY_10_SHORT + KEY_LONG_ON)
#define KEY_11_LONG_ON (KEY_11_SHORT + KEY_LONG_ON)
#define KEY_12_LONG_ON (KEY_12_SHORT + KEY_LONG_ON)
#define KEY_13_LONG_ON (KEY_13_SHORT + KEY_LONG_ON)
#define KEY_14_LONG_ON (KEY_14_SHORT + KEY_LONG_ON)
/*############################################################*/
/* 短按松开按键事件ID */
/*################################################################*/
#define KEY_1_OFF (KEY_1_SHORT + KEY_OFF)
#define KEY_2_OFF (KEY_2_SHORT + KEY_OFF)
#define KEY_3_OFF (KEY_3_SHORT + KEY_OFF)
#define KEY_4_OFF (KEY_4_SHORT + KEY_OFF)
#define KEY_5_OFF (KEY_5_SHORT + KEY_OFF)
#define KEY_6_OFF (KEY_6_SHORT + KEY_OFF)
#define KEY_7_OFF (KEY_7_SHORT + KEY_OFF)
#define KEY_8_OFF (KEY_8_SHORT + KEY_OFF)
#define KEY_9_OFF (KEY_9_SHORT + KEY_OFF)
#define KEY_10_OFF (KEY_10_SHORT + KEY_OFF)
#define KEY_11_OFF (KEY_11_SHORT + KEY_OFF)
#define KEY_12_OFF (KEY_12_SHORT + KEY_OFF)
#define KEY_13_OFF (KEY_13_SHORT + KEY_OFF)
#define KEY_14_OFF (KEY_14_SHORT + KEY_OFF)
#define WAKEUP_FOR_32HZ 0X01
#define TICK_FOR_2HZ 0X08
#define TICK_FOR_1HZ 0X10
#define CLEAR_WAKEUP_FOR_32HZ (~WAKEUP_FOR_32HZ)
#define CLEAR_TICK_FOR_2HZ (~TICK_FOR_2HZ)
#define CLEAR_TICK_FOR_1HZ (~TICK_FOR_1HZ)
/*
32HZ中断调用
参数:tick_value---时间标识
*/
#define TICK_FOR_32HZ_INTERRUPT(tickTable) \
do \
{ \
static uint8_t cnt; \
static volatile uint8_t s_wakeup_flag; \
s_wakeup_flag |= WAKEUP_FOR_32HZ; \
if((++cnt & 0x07) == 0) s_wakeup_flag |= TICK_FOR_2HZ; \
if((cnt & 0x0f)==0) s_wakeup_flag |= TICK_FOR_1HZ; \
PostMessage(TICK_WAKEUP, (void*)&tickTable,(void*)&s_wakeup_flag); \
}while(0)
/****************************************************************
功能菜单数据结构
*****************************************************************/
typedef struct tagMenuKey
{
DECLARE_MESSAGE_MAP() //must be put it in first position
AFX_PMSG dispFunc;
uint16_t *ptrFlag;
}MENU_KEY;
#endif
step 3:
baseCls.c中的内容如下:
#include "baseCls.h"
/*#################################################################*/
CircleQueue sqMsg={0};
QueueMsg *lpGetMsg;
AFX_PMSG keyToneFunc = NULL;
//判断队列为空和满
//1、使用计数器count,队列为空和满时,front都等于rear
//2、少用一个元素的空间,约定队列满时:(rear+1)%QUEUESIZE=front,为空时front=rear
//rear指向队尾元素的下一个位置,始终为空;队列的长度为(rear-front+QUEUESIZE)%QUEUESIZE
/*************************************************
Function: EnQueue
Description: 入队
Input: 队列指针 CircleQueue *queue
数据元素 ElemType e
Output:
Return: 成功返回OK,失败返回ERROR
Others:
*************************************************/
State PostMessage(uint16_t msg, void *self, void *extra)
{
QueueMsg *pMsg = &sqMsg.data_elem[sqMsg.rear];
//验证队列是否已满
if(sqMsg.count == QUEUESIZE)
{
return ERROR;
}
//入队
pMsg->lpMsgEn= self;
pMsg->msg = msg;
pMsg->extraData = extra;
//对尾指针后移
sqMsg.rear = (sqMsg.rear + 1) % QUEUESIZE;
//更新队列长度
sqMsg.count++;
return OK;
}
/*************************************************
Function: DeQueue
Description: 出队
Input: 队列指针 CircleQueue *queue
Output:
Return: 成功返回数据元素,失败程序退出
Others:
*************************************************/
QueueMsg *GetMessage(void)
{
QueueMsg *e=NULL;
//判断队列是否为空
if(sqMsg.count != 0)
{
//保存返回值
e = &sqMsg.data_elem[sqMsg.front];
//更新队头指针
sqMsg.front = (sqMsg.front + 1) % QUEUESIZE;
//更新队列长度
sqMsg.count--;
}
return e;
}
/*####################################################################*/
/***********************************************************************
设置按键声通用处理函数
************************************************************************/
void setKeyToneHandler(AFX_PMSG func)
{
keyToneFunc = func;
}
/*##################################################################*/
/*
void OnTime(uint8_t *count, AFX_VOID pfn)
{
if((*count > 0) && (--*count ==0))
{
pfn();
}
}*/
/***********************************************************************************
Routine Name: OnCmdMsg
Form: void OnCmdMsg(uint8_t event, void *lpEn)
Parameters: uint8_t event---- pass key msg value into it
void *lpEn----point to own its msg object
Return Value: void
Description: according to event value to search msg in lpEn object msg map,then call associated function
with it
*************************************************************************************/
void OnCmdMsg(uint16_t event,void *lpEn, void * extraData)
{
// you are check up lpEn value whether is null point before call this function operating
if(lpEn != NULL)
{
// the lpEn pointer be converted cmdTarget object pointer
const cmdTarget *pCmd =(const cmdTarget*)(*(void **)lpEn);
// get msg map entries address
const AFX_MSGMAP_ENTRY *ptr = pCmd->lpEn;
// declare and define union function pointer-set object
AFX_UNION_PFN AllFunc ;
uint16_t msg = event;
// if no msg map entries address,then no any operate and direct return it
if(pCmd == NULL )
return;
// below be named msg prefilter,if the return value of the virtual function of own object is FALSE ,will skip below msg
if((pCmd->preMsgHandler != NULL) && (pCmd->preMsgHandler(&msg)==FALSE))
{ //可以用过滤函数传递消息
return;
}
// search msg map in class object
while((ptr->message != 0)&&(msg != ptr->message))
{
ptr++;
}
// if msg handler function is null,then skip below msg
AllFunc.pfn = ptr->pfn;
if(AllFunc.pfn == NULL)
return;
// if extraData is NULL,then lpEn will be passed into function by caller
if(extraData == NULL)
{
extraData = lpEn;
}
// acording to nSign value, to call belong to its function protype
switch(ptr->nSign)
{
case AfxSig_vpv:
AllFunc.pvfn(extraData);
break;
case AfxSig_vpvuc:
AllFunc.pvmfn(extraData,msg);
break;
case AfxSig_uc:
AllFunc.pucfn(msg);
break;
case AfxSig_puc:
AllFunc.ppucfn(&msg);
break;
case AfxSig_pvv:
AllFunc.pvvfn((volatile uint8_t*)extraData);
break;
default:
AllFunc.pfn();
break;
}
/**************************************************************************/
// 按键处理函数,如果要重写按键函数,必须调用SetKeyToneHandler
if(keyToneFunc != NULL)
{
keyToneFunc(&msg);
}
}
}
/************************************************************************************************/
/* key value generator function */
/************************************************************************************************/
#define LONG_ON_DITHERING_COUNTER 60 //定义长按按下确认需要的时间,如果是每1/32S调用一次OSReadKey(),则64意味着这个时间为2S
static uint8_t KeyEventCnt;
static uint8_t KeySampleCnt;
uint16_t KeyBuffer;
/*############################################################################*/
/*# Prototype #*/
/*############################################################################*/
/*############################################################################*/
/*# API #*/
/*############################################################################*/
/**********************************************
Routine Name: OSReadKey
Form: uint8_t OSReadKey(void)
Parameters: void
Return Value: uint8_t
0 : invalid key msg
else return key msg
Description: get key msg
***********************************************/
static uint16_t OSReadKey(void)
{
uint16_t KeyTemp;
OSScanKey(KeyTemp);
switch( (uint16_t)KeyEventCnt )
{
case 0:
if(KeyTemp != 0)
{
KeySampleCnt=0;
KeyBuffer=KeyTemp;
KeyEventCnt=1;
}
break;
case 1:
if(KeyTemp == KeyBuffer )
{
KeyBuffer |= KEY_OFF;
return KeyTemp ;//sure that key on,return KeyBuffer
}
else
{
if(KeyTemp == (KeyBuffer & ~KEY_OFF))
{
if(++KeySampleCnt>LONG_ON_DITHERING_COUNTER)
{
KeySampleCnt=LONG_ON_DITHERING_COUNTER-1;
return KeyTemp | KEY_LONG_ON ;
}
}
else
{
if((KeySampleCnt < 4)&&(KeyBuffer & KEY_LONG_ON)==0)
{
KeyEventCnt = 0;
}
if(KeyTemp ==0)
{
KeyEventCnt = 0;
return KeyBuffer ; //sure that key on turn off,return KeyBuffer | 0x40
}
}
}
break;
}
return 0;
}
/***************************************************************************
Routine Name: DisLongKeyContinueResponse
Form: void DisLongKeyContinueResponse(void)
Parameters: void
Return Value: void
Description: if call this function in the key process function,so it keep
continue long key msg to generate
****************************************************************************/
void DisLongKeyContinueResponse(void)
{
KeyBuffer |= KEY_BLOCK_EVENT; //prevent long key to continue response
}
/*****************************************************************
Routine Name: keyProcess
Form: void keyProcess(void*self,uint8_t *flag)
Parameters: const void*self
point to own its msg object
Return Value: void
Description: key msg dispatch in 1/16s timer function
******************************************************************/
void keyProcess(void*self,uint8_t *flag)
{
uint16_t keyEvent= OSReadKey();
if(keyEvent != 0)
{
*flag = 1;
// OnCmdMsg(keyEvent,self,NULL);
PostMessage(keyEvent,self,NULL);
}
}
step 4:
keyScan.h中的内容如下:
#ifndef __KEYSCAN_H__
#define __KEYSCAN_H__
#include "baseCls.h"
#define BLUETOOTH_DATA 0X02
#define TICK_WAKEUP 0X01
#define UPDATE_DISP_ONE_TIME 1
#define KEY_1_LED 15
#define KEY_2_LED 18
#define KEY_3_LED 19
#define KEY_4_LED 20
#define KEY_5_LED 28
#define KEY_6_LED 30
#define KEY_7_LED 31
#define BACKLIGHT_LED 5
#define TOTAL_LED_COUNT 8
#define BSP_GPIO_LED {KEY_1_LED,KEY_2_LED,KEY_3_LED,KEY_4_LED,KEY_5_LED,KEY_6_LED,KEY_7_LED,BACKLIGHT_LED}
typedef struct tagBleData
{
uint8_t *rxBuf;
uint8_t *txBuf;
uint8_t *flag;
uint8_t rxLen;
uint8_t txLen;
}BLE_DATA;
extern uint8_t s_update_display;
extern uint16_t menu_item;
extern CONST MENU_KEY op_mode_table[];
extern CONST MENU_KEY tick_table;
//void init_key_message_Map(void);
void dispFunc(const MENU_KEY* self,uint8_t *flag);
void BSP_led_init(void);
void BSP_led_DeInit(void);
#endif
step 5:
keyScan.c中的内容如下:
#include "keyScan.h"
static const uint8_t list[] = BSP_GPIO_LED;
uint16_t menu_item;
uint16_t menu_sub_item; //设置项数量
//MENU_KEY Function_mode;
/*#############################################################################*/
/*********************************************************************************/
static void Key1Handler(void);
static void Key2Handler(void);
static void Key3Handler(void);
static void Key4Handler(void);
static void Key5Handler(void);
static void Key6Handler(void);
static void Key7Handler(void);
/*********************************************************************************/
static unsigned char preMessageHandler(uint16_t *msg);
/*#################################################*/
/* Key Message Map */
/*################################################*/
/*-----MENU mode Key Message Map ---*/
BEGIN_MESSAGE_MAP(Menu_Function_ModeFuncEn)
ON_NSM_MESSAGE(KEY_1_SHORT,Key1Handler)
ON_NSM_MESSAGE(KEY_2_SHORT,Key2Handler)
ON_NSM_MESSAGE(KEY_3_SHORT,Key3Handler)
ON_NSM_MESSAGE(KEY_4_SHORT,Key4Handler)
ON_NSM_MESSAGE(KEY_5_SHORT,Key5Handler)
ON_NSM_MESSAGE(KEY_6_SHORT,Key6Handler)
ON_NSM_MESSAGE(KEY_7_SHORT,Key7Handler)
END_MESSAGE_MAP(NULL) /* if END_MESSAGE_MAP param is NULL,then msg isn't match,no default handler */
//0- msg map entries name, 1-cmdTarget object name,2-pre-process msg func
// 如果参数3为空,则没有预处理消息函数
INIT_MSG_ENTRIES(Menu_Function_ModeFuncEn,Menu_Function_cmd_func,preMessageHandler)
/*************************************************************************************
正常模式下,短按键功能
***************************************************************************************/
static void Key1Handler(void)
{
nrf_gpio_pin_toggle(list[0]);
}
static void Key2Handler(void)
{
nrf_gpio_pin_toggle(list[1]);
}
static void Key3Handler(void)
{
nrf_gpio_pin_toggle(list[2]);
}
static void Key4Handler(void)
{
nrf_gpio_pin_toggle(list[3]);
}
static void Key5Handler(void)
{
nrf_gpio_pin_toggle(list[4]);
}
static void Key6Handler(void)
{
nrf_gpio_pin_toggle(list[5]);
}
static void Key7Handler(void)
{
nrf_gpio_pin_toggle(list[6]);
}
/**********************************************************************
消息预处理,如果返回非0,则消息继续传递,返回非0则消息被
过滤,不去映射表内查找消息函数,改变msg值将会改变其消息路径
**********************************************************************/
static unsigned char preMessageHandler(uint16_t *msg)
{
return TRUE; // 返回TRUE,不过滤按键消息
}
/*
显示处理
*/
void updateDisplay(uint16_t *p)
{
printf("updateDisplay\n");
}
/*#############################################################################*/
/*********************************************************************************/
static void TickWakeup(volatile uint8_t *flag);
static void BluetoothDataHandler(void *data);
/*********************************************************************************/
uint8_t s_update_display;
/*#################################################*/
/* Message Map */
/*################################################*/
/*-----MENU mode Key Message Map ---*/
BEGIN_MESSAGE_MAP(Tick_Function_ModeFuncEn)
ON_TICK_MESSAGE(TICK_WAKEUP,TickWakeup)
ON_SM_MESSAGE(BLUETOOTH_DATA,BluetoothDataHandler)
END_MESSAGE_MAP(NULL) /* if END_MESSAGE_MAP param is NULL,then msg isn't match,no default handler */
//0- msg map entries name, 1-cmdTarget object name,2-pre-process msg func
// 如果参数3为空,则没有预处理消息函数
INIT_MSG_ENTRIES(Tick_Function_ModeFuncEn,Tick_Function_cmd_func,NULL)
/*蓝牙数据处理*/
static void BluetoothDataHandler(void *data)
{
//BLE_DATA *p = (BLE_DATA*)data;
}
/*32HZ,2HZ,1HZ处理*/
static void TickWakeup(volatile uint8_t *flag)
{
if((*flag & WAKEUP_FOR_32HZ) == 0) // 32Hz event handler
return;
*flag &= CLEAR_WAKEUP_FOR_32HZ;
keyProcess((void*)&op_mode_table[menu_item],&s_update_display); //按键消息投递
if((*flag & TICK_FOR_2HZ)==0) // 2Hz handler
return;
*flag &= CLEAR_TICK_FOR_2HZ;
s_update_display = 1;
if((*flag & TICK_FOR_1HZ) == 0) // 1Hz handler
return;
*flag &= CLEAR_TICK_FOR_1HZ;
}
/**********************************************************************************/
/*################################################################################*/
CONST MENU_KEY tick_table = {&Tick_Function_cmd_func,NULL,NULL};
/*#################################################################*/
/*********************************************************************
功能映射表,每一项对应一个功能对象,每一项有三个值,分别表示为
按键映射变量,显示操作,附加变量
**********************************************************************/
CONST MENU_KEY op_mode_table[]={
{&Menu_Function_cmd_func,updateDisplay,&menu_sub_item}, //正常模式
};
/*********************************************************************************
内存不使用const空间时,则动态初时化消息映射表变量
**********************************************************************************/
/*
void init_key_message_Map(void)
{
// GET_MESSAGE_MAP(Function_mode, Menu_Function_cmd_func);
}
*/
/*#######################################################################*/
/*************************************************************************
功能模式多态显示
*****************************************************************************/
void dispFunc(const MENU_KEY* self,uint8_t *flag)
{
if(*flag)
{
const MENU_KEY *cp = self;
*flag = 0;
if((cp!= 0) && (cp->dispFunc != 0))
{
cp->dispFunc(cp->ptrFlag);
}
}
}
void BSP_led_init(void)
{
for(uint8_t i = 0; i < TOTAL_LED_COUNT; ++i)
{
nrf_gpio_cfg_output(list[i]);
nrf_gpio_pin_clear(list[i]);
}
nrf_gpio_pin_set(5);
}
/**------------------------------------------------------------------------------------------------
* @brief : This is output deinit function
* @param : None
* @retval : None
*----------------------------------------------------------------------------------------------*/
void BSP_led_DeInit(void)
{
for(uint8_t i = 0; i < TOTAL_LED_COUNT; ++i)
{
nrf_gpio_pin_clear(list[i]);
nrf_drv_gpiote_out_uninit(list[i]);
}
}
step 6:
在32HZ事件回调函数中投递定时器消息
/**@brief Function for handling the Battery measurement timer timeout.
*
* @details This function will be called each time the battery level measurement timer expires.
*
* @param[in] p_context Pointer used for passing some arbitrary information (context) from the
* app_start_timer() call to the timeout handler.
*/
static void tick_32hz_timeout_handler(void * p_context)
{
UNUSED_PARAMETER(p_context);
TICK_FOR_32HZ_INTERRUPT(tick_table);
}
step 7:
在蓝牙数据接收中投递蓝牙数据处理消息
static void MIL_BTRX_HanderCallback(ble_nus_evt_t * p_evt)
{
if(p_evt->params.rx_data.length < BT_DATA_MIN)
return;
if(p_evt->params.rx_data.p_data[0] != BT_DATA_STR)
return;
uint8_t len = p_evt->params.rx_data.length-1;
uint8_t checksum = _Bluetooth_DataVerify(&p_evt->params.rx_data.p_data[0],len);
if(checksum != p_evt->params.rx_data.p_data[len])
return;
for(checksum = 0;checksum < len;checksum++)
{
ReceBuf[checksum] = p_evt->params.rx_data.p_data[checksum];
}
s_ble_data.rxBuf = &ReceBuf[2]; //从协议数据开始
s_ble_data.txBuf = SendBuf;
s_ble_data.rxLen = p_evt->params.rx_data.length-3;
s_ble_data.flag = &s_update_display;
PostMessage(BLUETOOTH_DATA, (void*)&tick_table,&s_ble_data);
}
step 8:
在main函数中取消息,翻译消息,执行消息
/**@brief Application main function.
*/
int main(void)
{
// Initialize.
uart_init(); timers_init();
power_management_init(); // Start execution.
printf("BLE UART central example started.\r\n");
// NRF_LOG_INFO("BLE UART central example started.");
ble_stack_init();
gap_params_init();
gatt_init();
conn_params_init();
services_init();
advertising_init();
advertising_start();
application_timers_start();
BSP_key_init();
BSP_led_init();
// Enter main loop.
for (;;)
{
if((lpGetMsg = GetMessage()) != NULL) //取出消息
{
OnCmdMsg(lpGetMsg->msg,lpGetMsg->lpMsgEn,lpGetMsg->extraData); //翻译执行消息
dispFunc(&op_mode_table[menu_item],&s_update_display); //功能显示处理
}
else
{
nrf_pwr_mgmt_run(); // enter idle mode
}
}
}
-
baseCls.h文件分析
- 不同类型消息的函数指针
typedef void (*AFX_PVVMSG)(volatile uint8_t *flag);
typedef void (*AFX_PMSG)(uint16_t * event);
typedef void (*AFX_VOID)(void);
typedef void (*AFX_PFN)( void *self);
typedef void (*AFX_PVMSG)( void*self,uint16_t event);
typedef void (*AFX_MSG)(uint16_t event);
typedef uint8_t (*PreFilterMsg)(uint16_t *msg);
2.不同类型的标志,转换成对应函数指针来实现不同的函数类型调用
enum AfxSig
{
AfxSig_vv=0, // void (void)
AfxSig_vpv, // void (void*)
AfxSig_vpvuc, // void (void*,uint16_t)
AfxSig_uc, //void (uint16_t)
AfxSig_puc, // void (uint16_t *)
AfxSig_pvv //带volatile uint8_t*参数
};
3.共用体数据类型,根据不同的AfxSig标记转成对应的函数指针去调用函数
typedef union
{
AFX_VOID pfn; //不带参数
AFX_PFN pvfn; //带void*参数
AFX_PVMSG pvmfn; //带void*,unsigned short参数
AFX_MSG pucfn; //带unsigned short参数
AFX_PMSG ppucfn; // 带unsigned short*参数
AFX_PVVMSG pvvfn; //带volatile uint8_t*参数
}AFX_UNION_PFN;
4.消息入口数据类型
typedef struct tagMSGMAP_ENTRY
{
uint16_t message;
uint8_t nSign;
AFX_VOID pfn;
}AFX_MSGMAP_ENTRY;
5.命令数据类型
typedef struct tagCmdTarget
{
const AFX_MSGMAP_ENTRY *lpEn;
const PreFilterMsg preMsgHandler;
}cmdTarget;
6.消息队列数据类型
typedef struct tagSqMsg
{
void *lpMsgEn;
void *extraData;
uint16_t msg;
}QueueMsg;
7.循环队列存储结构
typedef struct _CircleQueue
{
QueueMsg data_elem[QUEUESIZE];//存储队列元素
uint8_t front;//队列头指针
uint8_t rear;//队列尾指针
int count;//队列元素个数
}CircleQueue;
8.初时化消息对象宏
#define initMsg(theClass)\
static CONST cmdTarget myTest = {&theClass[0]};
9.消息映射宏
#define ON_EVENT_MESSAGE(message,pfn) {message,AfxSig_uc,(AFX_VOID)(AFX_MSG)&pfn},
#define ON_NSM_MESSAGE(message,pfn) {message,AfxSig_vv,pfn},
#define ON_SM_MESSAGE(message,pfn) {message,AfxSig_vpv,(AFX_VOID)(AFX_PFN)&pfn},
#define ON_NOTIFY_MESSAGE(message,pfn) {message,AfxSig_vpvuc,(AFX_VOID)(AFX_PVMSG)&pfn},
#define ON_KEY_LONG_EVENT_MESSAGE(message,pfn) {message,AfxSig_puc,(AFX_VOID)(AFX_PMSG)&pfn},
#define ON_TICK_MESSAGE(message,pfn) {message,AfxSig_pvv,(AFX_VOID)(AFX_PVVMSG)&pfn},
10.声明命令对象宏
#define DECLARE_MESSAGE_MAP()\
const cmdTarget* lpEn;
11.声明消息对象映射宏,在BEGIN_MESSAGE_MAP和END_MESSAGE_MAP之间添加要映射的消息映射宏
#define BEGIN_MESSAGE_MAP(theClass)\
static CONST AFX_MSGMAP_ENTRY theClass[]={\
#define END_MESSAGE_MAP(lpDef) \
{0,AfxSig_vpv,(AFX_VOID)lpDef } \
};\
12.初时化消息对象实例
#define INIT_MSG_ENTRIES(theClass,cmdTargetName,preMsgHandler)\
CONST cmdTarget cmdTargetName = {theClass,preMsgHandler};
13.获取命令对象实例
#define GET_MESSAGE_MAP(theClass, cmdTargetName) \
theClass.lpEn = &cmdTargetName;
14.声明命令对象
#define DECLARE_cmdTarget(theClass) \
extern CONST cmdTarget theClass;
15.接口函数及变量声明
extern QueueMsg *lpGetMsg;
//void OnTime(uint8_t *count, AFX_VOID pfn);
void OnCmdMsg(uint16_t event, void *lpEn, void * extraData);
QueueMsg *GetMessage(void) ;
State PostMessage(uint16_t msg, void *self, void *extra);
void setKeyToneHandler(AFX_PMSG func);
void DisLongKeyContinueResponse(void);
void keyProcess(void*self,uint8_t *flag);
-
baseCls.c文件分析
1.消息队列变量定义
CircleQueue sqMsg={0};
QueueMsg *lpGetMsg;
AFX_PMSG keyToneFunc = NULL;
2.往队列中添加消息对象
/*************************************************
Function: EnQueue
Description: 入队
Input: 队列指针 CircleQueue *queue
数据元素 ElemType e
Output:
Return: 成功返回OK,失败返回ERROR
Others:
*************************************************/
State PostMessage(uint16_t msg, void *self, void *extra)
{
QueueMsg *pMsg = &sqMsg.data_elem[sqMsg.rear];
//验证队列是否已满
if(sqMsg.count == QUEUESIZE)
{
return ERROR;
}
//入队
pMsg->lpMsgEn= self;
pMsg->msg = msg;
pMsg->extraData = extra;
//对尾指针后移
sqMsg.rear = (sqMsg.rear + 1) % QUEUESIZE;
//更新队列长度
sqMsg.count++;
return OK;
}
3.从队列里取出一个消息对象
/*************************************************
Function: DeQueue
Description: 出队
Input: 队列指针 CircleQueue *queue
Output:
Return: 成功返回数据元素,失败程序退出
Others:
*************************************************/
QueueMsg *GetMessage(void)
{
QueueMsg *e=NULL;
//判断队列是否为空
if(sqMsg.count != 0)
{
//保存返回值
e = &sqMsg.data_elem[sqMsg.front];
//更新队头指针
sqMsg.front = (sqMsg.front + 1) % QUEUESIZE;
//更新队列长度
sqMsg.count--;
}
return e;
}
4.设置按键音回调函数
/*####################################################################*/
/***********************************************************************
设置按键声通用处理函数
************************************************************************/
void setKeyToneHandler(AFX_PMSG func)
{
keyToneFunc = func;
}
5.按键相关变量定义
/************************************************************************************************/
/* key value generator function */
/************************************************************************************************/
#define LONG_ON_DITHERING_COUNTER 60 //定义长按按下确认需要的时间,如果是每1/32S调用一次OSReadKey(),则64意味着这个时间为2S
static uint8_t KeyEventCnt;
static uint8_t KeySampleCnt;
uint16_t KeyBuffer;
6.得到一个键值
/**********************************************
Routine Name: OSReadKey
Form: uint8_t OSReadKey(void)
Parameters: void
Return Value: uint8_t
0 : invalid key msg
else return key msg
Description: get key msg
***********************************************/
static uint16_t OSReadKey(void)
{
uint16_t KeyTemp;
OSScanKey(KeyTemp);
switch( (uint16_t)KeyEventCnt )
{
case 0:
if(KeyTemp != 0)
{
KeySampleCnt=0;
KeyBuffer=KeyTemp;
KeyEventCnt=1;
}
break;
case 1:
if(KeyTemp == KeyBuffer )
{
KeyBuffer |= KEY_OFF;
return KeyTemp ;//sure that key on,return KeyBuffer
}
else
{
if(KeyTemp == (KeyBuffer & ~KEY_OFF))
{
if(++KeySampleCnt>LONG_ON_DITHERING_COUNTER)
{
KeySampleCnt=LONG_ON_DITHERING_COUNTER-1;
return KeyTemp | KEY_LONG_ON ;
}
}
else
{
if((KeySampleCnt < 4)&&(KeyBuffer & KEY_LONG_ON)==0)
{
KeyEventCnt = 0;
}
if(KeyTemp ==0)
{
KeyEventCnt = 0;
return KeyBuffer ; //sure that key on turn off,return KeyBuffer | 0x40
}
}
}
break;
}
return 0;
}
7.阻止长按键不停地触发函数
/***************************************************************************
Routine Name: DisLongKeyContinueResponse
Form: void DisLongKeyContinueResponse(void)
Parameters: void
Return Value: void
Description: if call this function in the key process function,so it keep
continue long key msg to generate
****************************************************************************/
void DisLongKeyContinueResponse(void)
{
KeyBuffer |= KEY_BLOCK_EVENT; //prevent long key to continue response
}
8.按键消息投入函数
/*****************************************************************
Routine Name: keyProcess
Form: void keyProcess(void*self,uint8_t *flag)
Parameters: const void*self
point to own its msg object
Return Value: void
Description: key msg dispatch in 1/16s timer function
******************************************************************/
void keyProcess(void*self,uint8_t *flag)
{
uint16_t keyEvent= OSReadKey();
if(keyEvent != 0)
{
*flag = 1;
// OnCmdMsg(keyEvent,self,NULL);
PostMessage(keyEvent,self,NULL);
}
}
9.实现消息翻译的关键函数OnCmdMsg
/***********************************************************************************
Routine Name: OnCmdMsg
Form: void OnCmdMsg(uint8_t event, void *lpEn)
Parameters: uint8_t event---- pass key msg value into it
void *lpEn----point to own its msg object
Return Value: void
Description: according to event value to search msg in lpEn object msg map,then call associated function
with it
*************************************************************************************/
void OnCmdMsg(uint16_t event,void *lpEn, void * extraData)
{
// you are check up lpEn value whether is null point before call this function operating
if(lpEn != NULL) //对象表地址
{
// the lpEn pointer be converted cmdTarget object pointer
const cmdTarget *pCmd =(const cmdTarget*)(*(void **)lpEn); //得到命令对象指针
// get msg map entries address
const AFX_MSGMAP_ENTRY *ptr = pCmd->lpEn; //得到消息入口地址
// declare and define union function pointer-set object
AFX_UNION_PFN AllFunc ; //共用体变量
uint16_t msg = event; // 消息ID
// if no msg map entries address,then no any operate and direct return it
if(pCmd == NULL ) //命令对象为NULL,直接返回
return;
// below be named msg prefilter,if the return value of the virtual function of own object is FALSE ,will skip below msg
if((pCmd->preMsgHandler != NULL) && (pCmd->preMsgHandler(&msg)==FALSE))
{ //可以用过滤函数传递消息,过滤函数返回false将执行return返回
return;
}
// search msg map in class object
while((ptr->message != 0)&&(msg != ptr->message)) //根据消息ID,查找消息对象
{
ptr++;
}
// if msg handler function is null,then skip below msg
AllFunc.pfn = ptr->pfn; //共用体函数指针保存消息对象函数地址
if(AllFunc.pfn == NULL) //如果为NULL,没有消息处理函数
return;
// if extraData is NULL,then lpEn will be passed into function by caller
if(extraData == NULL) //如果extraData 为NULL,
{
extraData = lpEn; //将lpEn作附加数据参数
}
// acording to nSign value, to call belong to its function protype
switch(ptr->nSign) //根据nSign的值,共用体变量转换成对应的函数指针去调用函数
{
case AfxSig_vpv:
AllFunc.pvfn(extraData);
break;
case AfxSig_vpvuc:
AllFunc.pvmfn(extraData,msg);
break;
case AfxSig_uc:
AllFunc.pucfn(msg);
break;
case AfxSig_puc:
AllFunc.ppucfn(&msg);
break;
case AfxSig_pvv:
AllFunc.pvvfn((volatile uint8_t*)extraData);
break;
default:
AllFunc.pfn();
break;
}
/**************************************************************************/
// 按键处理函数,如果要重写按键函数,必须调用SetKeyToneHandler
if(keyToneFunc != NULL)
{
keyToneFunc(&msg); //按键音回调处理
}
}
}
-
keyScan.h文件分析
1.事件宏ID定义
#define BLUETOOTH_DATA 0X02
#define TICK_WAKEUP 0X01
#define UPDATE_DISP_ONE_TIME 1
2.LED IO引脚定义
#define KEY_1_LED 15
#define KEY_2_LED 18
#define KEY_3_LED 19
#define KEY_4_LED 20
#define KEY_5_LED 28
#define KEY_6_LED 30
#define KEY_7_LED 31
#define BACKLIGHT_LED 5
#define TOTAL_LED_COUNT 8
#define BSP_GPIO_LED {KEY_1_LED,KEY_2_LED,KEY_3_LED,KEY_4_LED,KEY_5_LED,KEY_6_LED,KEY_7_LED,BACKLIGHT_LED}
3.蓝牙数据结构
typedef struct tagBleData
{
uint8_t *rxBuf;
uint8_t *txBuf;
uint8_t *flag;
uint8_t rxLen;
uint8_t txLen;
}BLE_DATA;
4.接口函数及变量声明
extern uint8_t s_update_display;
extern uint16_t menu_item;
extern CONST MENU_KEY op_mode_table[];
extern CONST MENU_KEY tick_table;
//void init_key_message_Map(void);
void dispFunc(const MENU_KEY* self,uint8_t *flag);
void BSP_led_init(void);
void BSP_led_DeInit(void);
-
keyScan.c文件分析
1.变量定义
static const uint8_t list[] = BSP_GPIO_LED;
uint16_t menu_item;
uint16_t menu_sub_item; //设置项数量
2.按键函数声明,消息映射时会用到
static void Key1Handler(void);
static void Key2Handler(void);
static void Key3Handler(void);
static void Key4Handler(void);
static void Key5Handler(void);
static void Key6Handler(void);
static void Key7Handler(void);
3.按键消息过滤函数声明,消息映射时会用到
static unsigned char preMessageHandler(uint16_t *msg);
4.使用BEGIN_MESSAGE_MAP和END_MESSAGE_MAP宏实现消息映射,此只映射了短按键键值,其它键值也可以映射
/*#################################################*/
/* Key Message Map */
/*################################################*/
/*-----MENU mode Key Message Map ---*/
BEGIN_MESSAGE_MAP(Menu_Function_ModeFuncEn)
ON_NSM_MESSAGE(KEY_1_SHORT,Key1Handler)
ON_NSM_MESSAGE(KEY_2_SHORT,Key2Handler)
ON_NSM_MESSAGE(KEY_3_SHORT,Key3Handler)
ON_NSM_MESSAGE(KEY_4_SHORT,Key4Handler)
ON_NSM_MESSAGE(KEY_5_SHORT,Key5Handler)
ON_NSM_MESSAGE(KEY_6_SHORT,Key6Handler)
ON_NSM_MESSAGE(KEY_7_SHORT,Key7Handler)
END_MESSAGE_MAP(NULL) /* if END_MESSAGE_MAP param is NULL,then msg isn't match,no default handler */
5.使用INIT_MSG_ENTRIES宏初时化消息对象
//0- msg map entries name, 1-cmdTarget object name,2-pre-process msg func
// 如果参数3为空,则没有预处理消息函数
INIT_MSG_ENTRIES(Menu_Function_ModeFuncEn,Menu_Function_cmd_func,preMessageHandler)
6.短按键消息处理
static void Key1Handler(void)
{
nrf_gpio_pin_toggle(list[0]);
}
static void Key2Handler(void)
{
nrf_gpio_pin_toggle(list[1]);
}
static void Key3Handler(void)
{
nrf_gpio_pin_toggle(list[2]);
}
static void Key4Handler(void)
{
nrf_gpio_pin_toggle(list[3]);
}
static void Key5Handler(void)
{
nrf_gpio_pin_toggle(list[4]);
}
static void Key6Handler(void)
{
nrf_gpio_pin_toggle(list[5]);
}
static void Key7Handler(void)
{
nrf_gpio_pin_toggle(list[6]);
}
7.消息预处理函数,如果返回false,将会屏蔽上面的按键处理函数的调用,否则可以调用
/**********************************************************************
消息预处理,如果返回非0,则消息继续传递,返回非0则消息被
过滤,不去映射表内查找消息函数,改变msg值将会改变其消息路径
**********************************************************************/
static unsigned char preMessageHandler(uint16_t *msg)
{
return TRUE; // 返回TRUE,不过滤按键消息
}
8.显示处理函数
/*
显示处理
*/
void updateDisplay(uint16_t *p)
{
printf("updateDisplay\n");
}
9.按键功能表,此表只有一个模式,可以根据需要添加不同的模式,及显示函数,附加变量信息等
/*#################################################################*/
/*********************************************************************
功能映射表,每一项对应一个功能对象,每一项有三个值,分别表示为
按键映射变量,显示操作,附加变量
**********************************************************************/
CONST MENU_KEY op_mode_table[]={
{&Menu_Function_cmd_func,updateDisplay,&menu_sub_item}, //正常模式 0
};
10.变量定义
uint8_t s_update_display;
11.定时器函数和蓝牙数据处理函数声明,稍后消息映射会用到
static void TickWakeup(volatile uint8_t *flag);
static void BluetoothDataHandler(void *data);
12.BEGIN_MESSAGE_MAP和END_MESSAGE_MAP实现消息映射
/*#################################################*/
/* Message Map */
/*################################################*/
/*-----MENU mode Key Message Map ---*/
BEGIN_MESSAGE_MAP(Tick_Function_ModeFuncEn)
ON_TICK_MESSAGE(TICK_WAKEUP,TickWakeup)
ON_SM_MESSAGE(BLUETOOTH_DATA,BluetoothDataHandler)
END_MESSAGE_MAP(NULL) /* if END_MESSAGE_MAP param is NULL,then msg isn't match,no default handler */
13.初时化消息对象
//0- msg map entries name, 1-cmdTarget object name,2-pre-process msg func
// 如果参数3为空,则没有预处理消息函数
INIT_MSG_ENTRIES(Tick_Function_ModeFuncEn,Tick_Function_cmd_func,NULL)
14.定时器及蓝牙数据功能表
CONST MENU_KEY tick_table = {&Tick_Function_cmd_func,NULL,NULL};
15.蓝牙数据处理函数
/*蓝牙数据处理*/
static void BluetoothDataHandler(void *data)
{
BLE_DATA *p = (BLE_DATA*)data;
}
16.定时器函数处理
/*32HZ,2HZ,1HZ处理*/
static void TickWakeup(volatile uint8_t *flag)
{
if((*flag & WAKEUP_FOR_32HZ) == 0) // 32Hz event handler
return;
*flag &= CLEAR_WAKEUP_FOR_32HZ;
keyProcess((void*)&op_mode_table[menu_item],&s_update_display); //按键消息投递
if((*flag & TICK_FOR_2HZ)==0) // 2Hz handler
return;
*flag &= CLEAR_TICK_FOR_2HZ;
s_update_display = 1;
if((*flag & TICK_FOR_1HZ) == 0) // 1Hz handler
return;
*flag &= CLEAR_TICK_FOR_1HZ;
}
17.功能模式多态显示
/*#######################################################################*/
/*************************************************************************
功能模式多态显示
*****************************************************************************/
void dispFunc(const MENU_KEY* self,uint8_t *flag)
{
if(*flag)
{
const MENU_KEY *cp = self;
*flag = 0;
if((cp!= 0) && (cp->dispFunc != 0))
{
cp->dispFunc(cp->ptrFlag); //回调到表中显示函数
}
}
}
18.LED IO初时化
void BSP_led_init(void)
{
for(uint8_t i = 0; i < TOTAL_LED_COUNT; ++i)
{
nrf_gpio_cfg_output(list[i]);
nrf_gpio_pin_clear(list[i]);
}
nrf_gpio_pin_set(5);
}
19. LED IO反初时化
void BSP_led_DeInit(void)
{
for(uint8_t i = 0; i < TOTAL_LED_COUNT; ++i)
{
nrf_gpio_pin_clear(list[i]);
nrf_drv_gpiote_out_uninit(list[i]);
}
}
-
maic.c文件部分代码分析
1.蓝牙数据接收后,使用PostMessage将BLUETOOTH_DATA消息ID,对象表tick_table,附加数据s_ble_data加到消息
队列中
PostMessage(BLUETOOTH_DATA, (void*)&tick_table,&s_ble_data);
2.在32HZ定时器回调函数中,调用TICK_FOR_32HZ_INTERRUPT宏,实现定时器消息回调
TICK_FOR_32HZ_INTERRUPT(tick_table);
宏体内容如下,最终使用PostMessage将TICK_WAKEUP消息ID,对象表tickTable,附加数据s_wakeup_flag添加到消
息队列中:
#define TICK_FOR_32HZ_INTERRUPT(tickTable) \
do \
{ \
static uint8_t cnt; \
static volatile uint8_t s_wakeup_flag; \
s_wakeup_flag |= WAKEUP_FOR_32HZ; \
if((++cnt & 0x07) == 0) s_wakeup_flag |= TICK_FOR_2HZ; \
if((cnt & 0x0f)==0) s_wakeup_flag |= TICK_FOR_1HZ; \
PostMessage(TICK_WAKEUP, (void*)&tickTable,(void*)&s_wakeup_flag); \
}while(0)
3.消息处理
if((lpGetMsg = GetMessage()) != NULL) //取出消息
{
OnCmdMsg(lpGetMsg->msg,lpGetMsg->lpMsgEn,lpGetMsg->extraData); //翻译消息
dispFunc(&op_mode_table[menu_item],&s_update_display); //功能显示处理
}
else
{
nrf_pwr_mgmt_run(); // enter idle mode
}
如果lpGetMsg为NULL,则执行nrf_pwr_mgmt_run进入睡眠,如果不为NULL,执行OnCmdMsg函数将消息
翻译成对应的函数指针去回调消息对象中映射的函数,dispFunc多态调用表对象中函数
Demo下载地址:https://download.csdn.net/download/mygod2008ok/11180665