【BLE】CC2541之RSSI

本篇博文最后修改时间:2017年01月06日,11:06。


一、简介

本文以TI提供的SimpleBLECentral工程和SimpleBLEPeripheral工程为例,介绍SimpleBLECentral工程连接时读取RSSI、SimpleBLECentral工程不连接时读取RSSI、SimpleBLEPeripheral工程连接时读取RSSI的方法。


二、实验平台

协议栈版本:BLE-CC254x-1.4.0

编译软件:IAR 8.20.2

硬件平台:Smart RF(主芯片CC2541)


版权声明

博主:甜甜的大香瓜

声明:喝水不忘挖井人,转载请注明出处。

原文地址:http://blog.csdn.NET/feilusia

联系方式:897503845@qq.com

香瓜BLE之CC2541群:127442605

香瓜BLE之CC2640群:557278427

香瓜BLE之Android群:541462902

香瓜单片机之STM8/STM32群:164311667
甜甜的大香瓜的小店(淘宝店):https://shop217632629.taobao.com/?spm=2013.1.1000126.d21.hd2o8i

四、 实验前提
1、在进行本文步骤前,请先 阅读 以下博文:
暂无

2、在进行本文步骤前,请先 实现以下博文:
1)《CC2541之串口收发》:http://blog.csdn.net/feilusia/article/details/47431659


五、基础知识

1、什么是RSSI?

答:Received Signal Strength Indication,接收的信号强度指示。


2、RSSI有什么用?
答:可根据RSSI来测主从机之间的距离。


3、RSSI需不需要连接才能读取?

答:不需要。但需要不停地数据交互,才能更新结构体中得到的RSSI。


六、解析代码SimpleBLECentral工程中以连接方式读RSSI

注:该工程默认即是可读RSSI,下面只是解析代码。

1、添加RSSI回调函数

1)定义一个函数simpleBLECentralRssiCB(SimpleBLECentral.c中)

static void simpleBLECentralRssiCB( uint16 connHandle, int8 rssi )
{
    LCD_WRITE_STRING_VALUE( "RSSI -dB:", (uint8) (-rssi), 10, HAL_LCD_LINE_1 );
    
    //输出RSSI的值到串口
    NPI_PrintValue("RSSI:-", (uint8) (-rssi), 10);
    NPI_PrintString("dB\r\n");  
}


2)声明函数simpleBLECentralRssiCB(SimpleBLECentral.c中

static void simpleBLECentralRssiCB( uint16 connHandle, int8  rssi );


3)将回调函数与函数指针结构体挂钩SimpleBLECentral.c中

// GAP Role Callbacks
static const gapCentralRoleCB_t simpleBLERoleCB =
{
  simpleBLECentralRssiCB,       // RSSI callback
  simpleBLECentralEventCB       // Event callback
};


4)注册回调函数SimpleBLECentral.c中

  if ( events & START_DEVICE_EVT )
  {
    // Start the Device
    VOID GAPCentralRole_StartDevice( (gapCentralRoleCB_t *) &simpleBLERoleCB );

    // Register with bond manager after starting device
    GAPBondMgr_Register( (gapBondCBs_t *) &simpleBLEBondCB );

    return ( events ^ START_DEVICE_EVT );
  }

2、读取RSSI过程
1)按下“down”键,若此时处于“连接”、且“不读取RSSI”状态时,则调用RSSI开始读的周期函数SimpleBLECentral.c中

 if ( keys & HAL_KEY_DOWN )
  {
    // Start or cancel RSSI polling
    if ( simpleBLEState == BLE_STATE_CONNECTED )
    {
      if ( !simpleBLERssi )
      {
        simpleBLERssi = TRUE;
        GAPCentralRole_StartRssi( simpleBLEConnHandle, DEFAULT_RSSI_PERIOD );
      }
      else
      {
        simpleBLERssi = FALSE;
        GAPCentralRole_CancelRssi( simpleBLEConnHandle );
        
        LCD_WRITE_STRING( "RSSI Cancelled", HAL_LCD_LINE_1 );
      }
    }
  }


2)GAPCentralRole_StartRssi函数

bStatus_t GAPCentralRole_StartRssi( uint16 connHandle, uint16 period )
{
  gapCentralRoleRssi_t  *pRssi;

  // Verify link is up
  if (!linkDB_Up(connHandle))   //没连接则退出
  {
    return bleIncorrectMode;
  }

  // If already allocated
  if ((pRssi = gapCentralRole_RssiFind( connHandle )) != NULL)  //如果“RSSI的connHandle值”等于“主从机的connHandle”
  {
    // Stop timer
    osal_CbTimerStop( pRssi->timerId );
  }
  // Allocate structure
  else if ((pRssi = gapCentralRole_RssiAlloc( connHandle )) != NULL)//connHandle不相等,说明还没有给RSSI分配connHandle,则分配下
  {
    pRssi->period = period;
  }
  // Allocate failed
  else
  {
    return bleNoResources;
  }

  // Start timer
  osal_CbTimerStart( gapCentralRole_timerCB, (uint8 *) pRssi,    //这是一个带回调函数的定时器函数,到时即会调用回调函数gapCentralRole_timerCB
                     period, &pRssi->timerId );

  return SUCCESS;
}


3)回调定时器函数gapCentralRole_timerCB

static void gapCentralRole_timerCB( uint8 *pData )
{
  gapCentralRoleRssiEvent_t *pMsg;

  // Timer has expired so clear timer ID
  ((gapCentralRoleRssi_t *) pData)->timerId = INVALID_TIMER_ID;     //清除定时器ID

  // Send OSAL message
  pMsg = (gapCentralRoleRssiEvent_t *) osal_msg_allocate( sizeof(gapCentralRoleRssiEvent_t) );
  if ( pMsg )
  {
    pMsg->hdr.event = GAPCENTRALROLE_RSSI_MSG_EVT;
    pMsg->pRssi = (gapCentralRoleRssi_t *) pData;

    osal_msg_send ( gapCentralRoleTaskId, (uint8 *) pMsg );    //发送消息到gapCentralRoleTaskId任务的GAPCENTRALROLE_RSSI_MSG_EVT事件中
  }
}


4)GAPCENTRALROLE_RSSI_MSG_EVT事件

      case GAPCENTRALROLE_RSSI_MSG_EVT:
      {
        gapCentralRoleRssi_t *pRssi = ((gapCentralRoleRssiEvent_t *) pMsg)->pRssi;

        // If link is up and RSSI reads active
        if (pRssi->connHandle != GAP_CONNHANDLE_ALL &&
            linkDB_Up(pRssi->connHandle))
        {
          // Restart timer
          osal_CbTimerStart( gapCentralRole_timerCB, (uint8 *) pRssi,  //不停地定时地调用本事件,从而读取RSSI
                             pRssi->period, &pRssi->timerId );

          // Read RSSI
          VOID HCI_ReadRssiCmd( pRssi->connHandle );  //调用读取RSSI的函数,调用完后会进到回调函数simpleBLECentralRssiCB
        }
      }
      break;


3、实验结果


疑问:测试中发现多次读到-129dB,暂不知原因,有人知道的话麻烦告诉我一声~谢谢!

答:

感谢群友“崔氏小农”的答疑解惑:



七、实验步骤SimpleBLEPeripheral工程以连接方式读RSSI

1、定义并注册一个回调函数

1)定义一个函数SimpleBLEPeripheral.c中

/*********************************************************************
 * @fn      simpleBLEPeripheralRssiCB
 *
 * @brief   RSSI callback.
 *
 * @param   newRSSI - RSSI
 *
 * @return  none
 */
static void simpleBLEPeripheralRssiCB( int8 newRSSI )
{
    HalLcdWriteStringValue( "RSSI -dB:", (uint8) (-newRSSI), 10, HAL_LCD_LINE_1 );
    
  // 可以输出一个值,用10进制表示
    NPI_PrintValue("RSSI:-", (uint8) (-newRSSI), 10);
    NPI_PrintString("dB\r\n");
}

注:从机端的RssiCB会比主机端少一个connHandle参数。


2)函数声明SimpleBLEPeripheral.c中

static void simpleBLEPeripheralRssiCB( int8 newRSSI );


3)将回调函数与函数指针结构体挂钩SimpleBLEPeripheral.c中

// GAP Role Callbacks
static gapRolesCBs_t simpleBLEPeripheral_PeripheralCBs =
{
  peripheralStateNotificationCB,  // Profile State Change Callbacks
  simpleBLEPeripheralRssiCB       // When a valid RSSI is read from controller (not used by application)
};

4)注册回调函数SimpleBLEPeripheral.c中

  if ( events & SBP_START_DEVICE_EVT )
  {
    // Start the Device
    VOID GAPRole_StartDevice( &simpleBLEPeripheral_PeripheralCBs );

    // Start Bond Manager
    VOID GAPBondMgr_Register( &simpleBLEPeripheral_BondMgrCBs );

    // Set timer for first periodic event
    osal_start_timerEx( simpleBLEPeripheral_TaskID, SBP_PERIODIC_EVT, SBP_PERIODIC_EVT_PERIOD );

    return ( events ^ SBP_START_DEVICE_EVT );
  }


2、设置RSSI扫描速率SimpleBLEPeripheral.c的SimpleBLEPeripheral_Init中

  //设置RSSI的读取速率,默认是0
  uint16 desired_rssi_rate = 1000;
  GAPRole_SetParameter(GAPROLE_RSSI_READ_RATE,sizeof(uint16),&desired_rssi_rate);


跟踪下代码看看这是在设置什么参数,如下:


再看看RSSI_READ_EVT事件在做什么:



3、实验结果


从机端读取的RSSI比较正常,不像主机端有异常的“-129dB”。


八、实验步骤SimpleBLECentral工程中以不连接的扫描方式读RSSI

1、修改代码SimpleBLECentral.c中

    case GAP_DEVICE_INFO_EVENT:
      {                
        // if filtering device discovery results based on service UUID
        if ( DEFAULT_DEV_DISC_BY_SVC_UUID == TRUE )
        {
          if ( simpleBLEFindSvcUuid( SIMPLEPROFILE_SERV_UUID,
                                     pEvent->deviceInfo.pEvtData,
                                     pEvent->deviceInfo.dataLen ) )
          {
            simpleBLEAddDeviceInfo( pEvent->deviceInfo.addr, pEvent->deviceInfo.addrType );
            
            NPI_PrintString("发现设备:");//打印地址 
            NPI_PrintString((uint8 *)bdAddr2Str(pEvent->deviceInfo.addr));        
            NPI_PrintString("\r\n");              
            NPI_PrintValue("rssi:-", (uint8)(-( pEvent->deviceInfo.rssi )), 10);//打印RSSI
            NPI_PrintString("dB\r\n");                                                          
          }
        }

      }
      break;

可通过不停地按“up”键扫描,不需要连接即可获取RSSI。

因为主机在扫描时获得的结构体数据,就已经有RSSI数据了:

/**
 * GAP_DEVICE_INFO_EVENT message format.  This message is sent to the
 * app during a Device Discovery Request, when a new advertisement or scan
 * response is received.
 */
typedef struct
{
  osal_event_hdr_t  hdr;    //!< GAP_MSG_EVENT and status
  uint8 opcode;             //!< GAP_DEVICE_INFO_EVENT
  uint8 eventType;          //!< Advertisement Type: @ref GAP_ADVERTISEMENT_TYPE_DEFINES
  uint8 addrType;           //!< address type: @ref GAP_ADDR_TYPE_DEFINES
  uint8 addr[B_ADDR_LEN];   //!< Address of the advertisement or SCAN_RSP
  int8 rssi;                //!< Advertisement or SCAN_RSP RSSI
  uint8 dataLen;            //!< Length (in bytes) of the data field (evtData)
  uint8 *pEvtData;          //!< Data field of advertisement or SCAN_RSP
} gapDeviceInfoEvent_t;

2、实验结果



至此,SimpleBLECentral工程连接时读取RSSI、SimpleBLECentral工程不连接时读取RSSI、SimpleBLEPeripheral工程连接时读取RSSI的三种方法都成功了。

因此,实验成功。


评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值