BLE 协议栈 之"消息传递""事件触发"谁与争锋

Posted xiaoleiacm

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BLE 协议栈 之"消息传递""事件触发"谁与争锋相关的知识,希望对你有一定的参考价值。


BLE 协议栈中对于触发任务事件大可分为三种方式:

1 通过设置一个“软件定时器”,当其溢出时触发事件。osal_start_timerEx()—osalTimerUpdate()— osal_set_event() ;

2 通过调用系统消息传递机制触发事件。osal_msg_send()—osal_set_event() 

3 直接调用osal_set_event()触发事件。


自定义消息的发送与接收

这三种划分方式算是前人之鉴吧,自己看的时候值分出了前两种,不过最终归到事件触发上都调用了osal_set_event()函数

看了两天的消息触发事件,终于看出头了 下面是发送消息的一个例子!

***************** 自定义 消息的发送 ****************************************/
#define king_come 0xFC  // 定义消息标志位

注意 自定义消息的标志位的值只能是0xE0  到 0xFC 之间
static int right_come=0; 
typedef struct

  osal_event_hdr_t hdr;
  uint8 mark;

myUartMsg_t;       // 定义消息的结构体
void xy_come(void)    // 配置消息参数

    myUartMsg_t *myUartMsg;
    myUartMsg=(myUartMsg_t*)osal_msg_allocate(sizeof(myUartMsg_t));
    
    myUartMsg->hdr.event=king_come;
    myUartMsg->mark=right_come;
    osal_msg_send(simpleBLETaskId,(uint8 *)myUartMsg);

 

消息的发送是通过置位SYS_EVENT_MSG来实现的(在 osal_msg_send中使用osal_set_event( destination_task, SYS_EVENT_MSG );置位)

在这个例子中将xy_come()放在了串口的回调函数中,这样一但受到了数据,就会发送一条消息给osal ,并被osal_msg_receive接收


/**************************** 消息的接收 *************************************/
在系统下一次轮询的时候,会进入SimpleBLECentral_ProcessEvent事件
并被 if ( events & SYS_EVENT_MSG )响应
通过osal_msg_receive( simpleBLETaskId )接收消息
uint16 SimpleBLECentral_ProcessEvent( uint8 task_id, uint16 events )

  
  VOID task_id; // OSAL required parameter that isn't used in this function
  
  if ( events & SYS_EVENT_MSG )
  
    uint8 *pMsg;

    if ( (pMsg = osal_msg_receive( simpleBLETaskId )) != NULL )//接收到消息
    
      simpleBLECentral_ProcessOSALMsg( (osal_event_hdr_t *)pMsg ); // 处理函数
      VOID osal_msg_deallocate( pMsg );  // 注意这里已经删除消息
        
    return (events ^ SYS_EVENT_MSG);
  
消息处理:

进入 simpleBLECentral_ProcessOSALMsg中进行消息处理
 case king_come:
        /* do something */
       LCD_WRITE_STRING( "AAA", HAL_LCD_LINE_1 );// 消息处理
    break;

按键事件的流程

 对于按键来说可以分为三个部分:按键的硬件配置,按键消息的配置,以及按键触发事件的配置.

按键的硬件配置:

/*********************** 按键功能的 初始化 *******************************/
第一步 : 定义按键状态
#if defined ( CC2540_MINIDK )
/* SW_1 is at P0.0 */
#define HAL_KEY_SW_1_PORT   P0
#define HAL_KEY_SW_1_BIT    BV(0)
#define HAL_KEY_SW_1_SEL    P0SEL
#define HAL_KEY_SW_1_DIR    P0DIR

第二步: 初始化按键
HAL_KEY_SW_1_SEL &= ~(HAL_KEY_SW_1_BIT);    /* Set pin function to GPIO */
  HAL_KEY_SW_1_DIR &= ~(HAL_KEY_SW_1_BIT);    /* Set pin direction to Input */

第三步: 按键中断配置
 PICTL |= HAL_KEY_SW_1_EDGEBIT;   /* Set the edge bit to set falling edge to give int */
 HAL_KEY_SW_1_ICTL |= HAL_KEY_SW_1_ICTLBIT; /* enable interrupt generation at port */
HAL_KEY_SW_1_IEN |= HAL_KEY_SW_1_IENBIT;   /* enable CPU interrupt */   HAL_KEY_SW_1_PXIFG = ~(HAL_KEY_SW_1_BIT); /* Clear any pending interrupt */
第四步: 清除中断标志位
 HAL_KEY_SW_1_ICTL &= ~(HAL_KEY_SW_1_ICTLBIT); /* don't generate interrupt */
 HAL_KEY_SW_1_IEN &= ~(HAL_KEY_SW_1_IENBIT);   /* Clear interrupt enable bit */
 

第5 步: 设置中断处理 
halProcessKeyInterrupt() 中断处理函数中,清除标志位,并更新key事件的定时器,25ms进行去抖延时
if( HAL_KEY_SW_1_PXIFG & HAL_KEY_SW_1_BIT) /* Interrupt Flag has been set by SW1 */
  
    HAL_KEY_SW_1_PXIFG = ~(HAL_KEY_SW_1_BIT); /* Clear Interrupt Flag */
    valid = TRUE;
  


 

并在中断处理函数 HAL_ISR_FUNCTION( halKeyPort0Isr, P0INT_VECTOR )中调用,清除标志位。(编程时可直接写中断处理函数)

Central 工程的中断函数中只做了清除中断标志位以及按键去抖的操作,并没有发送消息给osal

这一步其实很简单,只需要像普通8051编程一样,定义好按键的状态以及中断即可。


按键消息的配置:


按键消息的标志位定义在comdef.h

#define KEY_CHANGE                0xC0    // Key Events

Note : 消息标志位(一共16bit)并不是事件标志位(32bit

例如事件标志:#define SYS_EVENT_MSG               0x8000 

 

按键的消息传递定义放在了 OnBoard.h

typedef struct

  osal_event_hdr_t hdr;
  uint8             state; // shift
  uint8             keys;  // keys
 keyChange_t;

消息的配置和发送放在了OnBoard.c

InitBoard函数中

HalKeyConfig( OnboardKeyIntEnable, OnBoard_KeyCallback);

OnBoard_KeyCallback函数的OnBoard_SendKeys函数中。

uint8 OnBoard_SendKeys( uint8 keys, uint8 state )

  keyChange_t *msgPtr;
  if ( registeredKeysTaskID != NO_TASK_ID )
  
    msgPtr = (keyChange_t *)osal_msg_allocate( sizeof(keyChange_t) );
    if ( msgPtr )
    
      msgPtr->hdr.event = KEY_CHANGE;
      msgPtr->state = state;
      msgPtr->keys = keys;
      osal_msg_send( registeredKeysTaskID, (uint8 *)msgPtr );
  //在OnBoard_KeyCallback中使用osal_msg_send向simpleBLETaskId发送消息

    
    return ( SUCCESS );
  
  else
    return ( FAILURE );

HalKeyConfig中还加入了事件处理回调函数: 

pHalKeyProcessFunction =  cback;

HalKeyConfig中把OnBoard_KeyCallback赋值给了pHalKeyProcessFunction

并且在HalKeyConfig的最后调用osal_set_event(Hal_TaskID, HAL_KEY_EVENT); 开启事件 


按键触发事件的配置:

按键状态的监测是使用的一个定时器 

按键事件是 Hal_ProcessEvent函数进行监测和处理的


事件的标志定义在hal_drivers.h

#define  HAL_KEY_EVENT  0x0010 // key事件的定时器标志

事件的处理是在Hal_ProcessEvent

  if (events & HAL_KEY_EVENT)  // 100ms 监测一次按键状态
     
    HalKeyPoll();
    if (!Hal_KeyIntEnable)
    
      osal_start_timerEx( Hal_TaskID, HAL_KEY_EVENT, 100);
    
    return events ^ HAL_KEY_EVENT;
  

HalKeyPoll里监测key的状态,并且调用

pHalKeyProcessFunction (keys, HAL_KEY_STATE_NORMAL);(在HalKeyPoll函数中) 做出相应的处理(例如监测到了按键按下,给osal发送消息处理)



/按键监测流程图:

                                                       第一次事件的标志的注册在InitBoard

HalKeyConfig->

osal_set_event(Hal_TaskID, HAL_KEY_EVENT); 

                                                      之后循环在定时器中:

Hal_ProcessEven->

HalKeyPoll->

pHalKeyProcessFunction当前值=OnBoard_KeyCallback->

HalKeyConfig->

osal_set_event(Hal_TaskID, HAL_KEY_EVENT); 











以上是关于BLE 协议栈 之"消息传递""事件触发"谁与争锋的主要内容,如果未能解决你的问题,请参考以下文章

BLE 蓝牙协议栈开发

IoTBLE 协议栈和数据报文解析

蓝牙4.0BLE协议栈

蓝牙BLE协议栈基础知识

蓝牙协议分析_BLE协议栈介绍

TI BLE协议栈软件框架分析