<蓝牙BLE>cc2540主机读RSSI值

转载 2015年11月17日 21:26:40

转自大香瓜的博客。


一、简介

本篇以TI提供的SimpleBLECentral工程和SimpleBLEPeripheral工程为例,介绍读取RSSI的方法。


二、实验平台

协议栈版本:BLE-CC254x-1.3.2

编译软件:IAR 8.20.2


三、关于RSSI

1、什么是RSSI?

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


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


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

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


四、解析SimpleBLECentral工程中读RSSI

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

1、添加RSSI回调函数

1)定义一个函数simpleBLECentralRssiCB(此处添加串口输出

  1. static void simpleBLECentralRssiCB( uint16 connHandle, int8 rssi )  
  2. {  
  3.     LCD_WRITE_STRING_VALUE( "RSSI -dB:", (uint8) (-rssi), 10, HAL_LCD_LINE_1 );  
  4.       
  5.     //输出RSSI的值到串口  
  6.     NPI_PrintValue("RSSI:-", (uint8) (-rssi), 10);  
  7.     NPI_PrintString("dB\r\n");    
  8. }  


2)声明函数

  1. static void simpleBLECentralRssiCB( uint16 connHandle, int8  rssi );  


3)将回调函数与函数指针结构体挂钩

  1. // GAP Role Callbacks  
  2. static const gapCentralRoleCB_t simpleBLERoleCB =  
  3. {  
  4.   simpleBLECentralRssiCB,       // RSSI callback  
  5.   simpleBLECentralEventCB       // Event callback  
  6. };  


4)注册回调函数

  1. if ( events & START_DEVICE_EVT )  
  2. {  
  3.   // Start the Device  
  4.   VOID GAPCentralRole_StartDevice( (gapCentralRoleCB_t *) &simpleBLERoleCB );  
  5.   
  6.   // Register with bond manager after starting device  
  7.   GAPBondMgr_Register( (gapBondCBs_t *) &simpleBLEBondCB );  
  8.   
  9.   return ( events ^ START_DEVICE_EVT );  
  10. }  

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

  1. if ( keys & HAL_KEY_DOWN )  
  2.  {  
  3.    // Start or cancel RSSI polling  
  4.    if ( simpleBLEState == BLE_STATE_CONNECTED )  
  5.    {  
  6.      if ( !simpleBLERssi )  
  7.      {  
  8.        simpleBLERssi = TRUE;  
  9.        GAPCentralRole_StartRssi( simpleBLEConnHandle, DEFAULT_RSSI_PERIOD );  
  10.      }  
  11.      else  
  12.      {  
  13.        simpleBLERssi = FALSE;  
  14.        GAPCentralRole_CancelRssi( simpleBLEConnHandle );  
  15.          
  16.        LCD_WRITE_STRING( "RSSI Cancelled", HAL_LCD_LINE_1 );  
  17.      }  
  18.    }  
  19.  }  


2)GAPCentralRole_StartRssi函数

  1. bStatus_t GAPCentralRole_StartRssi( uint16 connHandle, uint16 period )  
  2. {  
  3.   gapCentralRoleRssi_t  *pRssi;  
  4.   
  5.   // Verify link is up  
  6.   if (!linkDB_Up(connHandle))   //没连接则退出  
  7.   {  
  8.     return bleIncorrectMode;  
  9.   }  
  10.   
  11.   // If already allocated  
  12.   if ((pRssi = gapCentralRole_RssiFind( connHandle )) != NULL)  //如果“RSSI的connHandle值”等于“主从机的connHandle”  
  13.   {  
  14.     // Stop timer  
  15.     osal_CbTimerStop( pRssi->timerId );  
  16.   }  
  17.   // Allocate structure  
  18.   else if ((pRssi = gapCentralRole_RssiAlloc( connHandle )) != NULL)//connHandle不相等,说明还没有给RSSI分配connHandle,则分配下  
  19.   {  
  20.     pRssi->period = period;  
  21.   }  
  22.   // Allocate failed  
  23.   else  
  24.   {  
  25.     return bleNoResources;  
  26.   }  
  27.   
  28.   // Start timer  
  29.   osal_CbTimerStart( gapCentralRole_timerCB, (uint8 *) pRssi,    //这是一个带回调函数的定时器函数,到时即会调用回调函数gapCentralRole_timerCB  
  30.                      period, &pRssi->timerId );  
  31.   
  32.   return SUCCESS;  
  33. }  


3)回调定时器函数gapCentralRole_timerCB

  1. static void gapCentralRole_timerCB( uint8 *pData )  
  2. {  
  3.   gapCentralRoleRssiEvent_t *pMsg;  
  4.   
  5.   // Timer has expired so clear timer ID  
  6.   ((gapCentralRoleRssi_t *) pData)->timerId = INVALID_TIMER_ID;     //清除定时器ID  
  7.   
  8.   // Send OSAL message  
  9.   pMsg = (gapCentralRoleRssiEvent_t *) osal_msg_allocate( sizeof(gapCentralRoleRssiEvent_t) );  
  10.   if ( pMsg )  
  11.   {  
  12.     pMsg->hdr.event = GAPCENTRALROLE_RSSI_MSG_EVT;  
  13.     pMsg->pRssi = (gapCentralRoleRssi_t *) pData;  
  14.   
  15.     osal_msg_send ( gapCentralRoleTaskId, (uint8 *) pMsg );    //发送消息到gapCentralRoleTaskId任务的GAPCENTRALROLE_RSSI_MSG_EVT事件中  
  16.   }  
  17. }  


4)GAPCENTRALROLE_RSSI_MSG_EVT事件

  1. case GAPCENTRALROLE_RSSI_MSG_EVT:  
  2. {  
  3.   gapCentralRoleRssi_t *pRssi = ((gapCentralRoleRssiEvent_t *) pMsg)->pRssi;  
  4.   
  5.   // If link is up and RSSI reads active  
  6.   if (pRssi->connHandle != GAP_CONNHANDLE_ALL &&  
  7.       linkDB_Up(pRssi->connHandle))  
  8.   {  
  9.     // Restart timer  
  10.     osal_CbTimerStart( gapCentralRole_timerCB, (uint8 *) pRssi,  //不停地定时地调用本事件,从而读取RSSI  
  11.                        pRssi->period, &pRssi->timerId );  
  12.   
  13.     // Read RSSI  
  14.     VOID HCI_ReadRssiCmd( pRssi->connHandle );  //调用读取RSSI的函数,调用完后会进到回调函数simpleBLECentralRssiCB  
  15.   }  
  16. }  
  17. break;  


实验结果:


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

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



五、SimpleBLEPeripheral工程中读RSSI

1、定义并注册一个回调函数(SimpleBLEPeripheral.c中)

1)定义一个函数

  1. /********************************************************************* 
  2.  * @fn      simpleBLEPeripheralRssiCB 
  3.  * 
  4.  * @brief   RSSI callback. 
  5.  * 
  6.  * @param   newRSSI - RSSI 
  7.  * 
  8.  * @return  none 
  9.  */  
  10. static void simpleBLEPeripheralRssiCB( int8 newRSSI )  
  11. {  
  12.     HalLcdWriteStringValue( "RSSI -dB:", (uint8) (-newRSSI), 10, HAL_LCD_LINE_1 );  
  13.       
  14.   // 可以输出一个值,用10进制表示  
  15.     NPI_PrintValue("RSSI:-", (uint8) (-newRSSI), 10);  
  16.     NPI_PrintString("dB\r\n");  
  17. }  

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


2)函数声明

  1. static void simpleBLEPeripheralRssiCB( int8 newRSSI );  


3)将回调函数与函数指针结构体挂钩

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

4)注册回调函数

  1. if ( events & SBP_START_DEVICE_EVT )  
  2. {  
  3.   // Start the Device  
  4.   VOID GAPRole_StartDevice( &simpleBLEPeripheral_PeripheralCBs );  
  5.   
  6.   // Start Bond Manager  
  7.   VOID GAPBondMgr_Register( &simpleBLEPeripheral_BondMgrCBs );  
  8.   
  9.   // Set timer for first periodic event  
  10.   osal_start_timerEx( simpleBLEPeripheral_TaskID, SBP_PERIODIC_EVT, SBP_PERIODIC_EVT_PERIOD );  
  11.   
  12.   return ( events ^ SBP_START_DEVICE_EVT );  
  13. }  


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

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


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


再看看RSSI_READ_EVT事件在做什么:



实验结果:


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


六、主机端扫描时获取RSSI的方法

  1. case GAP_DEVICE_INFO_EVENT:  
  2.   {                  
  3.     // if filtering device discovery results based on service UUID  
  4.     if ( DEFAULT_DEV_DISC_BY_SVC_UUID == TRUE )  
  5.     {  
  6.       if ( simpleBLEFindSvcUuid( SIMPLEPROFILE_SERV_UUID,  
  7.                                  pEvent->deviceInfo.pEvtData,  
  8.                                  pEvent->deviceInfo.dataLen ) )  
  9.       {  
  10.         simpleBLEAddDeviceInfo( pEvent->deviceInfo.addr, pEvent->deviceInfo.addrType );  
  11.           
  12.         NPI_PrintString("发现设备:");//打印地址   
  13.         NPI_PrintString((uint8 *)bdAddr2Str(pEvent->deviceInfo.addr));          
  14.         NPI_PrintString("\r\n");                
  15.         NPI_PrintValue("rssi:-", (uint8)(-( pEvent->deviceInfo.rssi )), 10);//打印RSSI  
  16.         NPI_PrintString("dB\r\n");                                                            
  17.       }  
  18.     }  
  19.   
  20.   }  
  21.   break;  

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

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

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

实验结果如下:

蓝牙RSSI计算距离

利用CoreLocation.framework很容易扫描获得周边蓝牙设备,苹果开源代码AirLocate有具体实现,下载地址: https://developer.apple.com/libr...
  • njchenyi
  • njchenyi
  • 2015年07月21日 09:54
  • 34778

Android——蓝牙利用RSSI进行距离测算

From:http://blog.csdn.net/lhc1105/article/details/54585632 算法: [java] view plain c...

<蓝牙BLE>如何调整cc2540的发射功率

一、背景介绍     根据TI的官方回复,cc2540只能调节四档发射功率,分别是(从大到小)4dBM、0dBM、-6dBM、-23dBM,而且不 能通过操作寄存器等方法对功率进行调整,如果需要更多级...

Android——蓝牙利用RSSI进行距离测算

算法:/** * 功能:根据rssi计算距离 * Created by liuhuichao on 2017/1/17. */ public class RssiUtil { //A和...

如何连续的测量蓝牙的RSSI

基于蓝牙的RSSI可以有很多应用,要获得蓝牙的RSSI无外乎两种方法,一种就是基于扫瞄的方法,优点是android本身支持,缺点是scan的时间比较长,并且中间过程不受控制,为了连续的测量,需要不断的...
  • Luohsh1
  • Luohsh1
  • 2014年02月09日 09:44
  • 2722

<蓝牙BLE>cc2540主机获取数据包

转自大香瓜的博客。 一、简介 本篇以SimpleBLECentral工程为例,介绍CC2541作为主机时是如何获取从机广播包数据的。 二、实验平台 协议栈版...

<BLE>CC2540主机获取各个从机广播

在蓝牙BLEcc2540的程序有一个函数用于记录周围正在发广播的蓝牙的地址,并且生成地址列表,以供后面的选择连接。我们可以对比着这个函数来写一个接受周围蓝牙从机发出的广播,并且生成相应的广播数据列表。...

关于TI CC2540 BLE协议栈中数据传输的几个函数实现(草稿)

在BLE协议栈站,关于数据传输可以范围下面两个方面,一是主机(Central)向从机(Peripheral)发送数据,二是从机(Peripheral)向主机(Central)发送数据。 1、...

android app与蓝牙设备之间连接与通讯

该文章主要用于手机蓝牙App界面的操作和通讯,保存到本地的通讯后数据txt文本文件 1.主要包括界面 2.AndroidManifest.xml中加入权限 uses-per...

Android实现一个apk连接两个ble设备

声明:代码基于网上某个小工程改的,如果涉及侵权,请联系本人,立马删除。 曾经做过一个小玩意,尝试把两个ble单片机设备都连在一个apk上,同时通信。网上可以找到类似的,但我找到的代码不够完整,还是自...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:<蓝牙BLE>cc2540主机读RSSI值
举报原因:
原因补充:

(最多只允许输入30个字)