一、简介


本文以SimpleBLECentral工程为例,介绍串口控制蓝牙。
过程:
扫描从机 - 根据从机号连接指定从机 - 获取RSSI值(信号强度) - 向char1写入特征值 - 断开连接

二、实验平台


协议栈版本:BLE-CC254x-1.3.2
编译软件: IAR 8.20.2
硬件平台: Smart RF开发板(主芯片CC2541)、USB Dongle
PC: 友善串口调试助手


三、版权声明


声明:转载请注明出处。
原文地址:http://blog.csdn.net/liwei16611/article/category/7000460

四、实验前提


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

五、基础知识


1、为什么要通过串口控制蓝牙?
答:
可以为后续实现串口蓝牙透传做准备,比较适合低成本低功耗的短距离小数据传输;
封装AT指令,通过串口来控制蓝牙的相关操作。


六、实验步骤


1、在串口回调函数内添加AT指令处理(SerialApp.c)

// uart接收回调函数,当我们通过PC串口调试助手向开发板发送数据时,会调用该函数来接收
void sbpSerialAppCallback(uint8 port, uint8 event)
{
  uint8  pktBuffer[SBP_UART_RX_BUF_SIZE];
  (void)event;
  //返回可读的字节
  if ( (numBytes = Hal_UART_RxBufLen(port)) > 0 ){
  //读取全部有效的数据,这里可以一个一个读取,以解析特定的命令
(void)HalUARTRead (port, pktBuffer, numBytes);
   // AT指令处理函数
        CommondHandle(pktBuffer, numBytes);
  }
  


2、AT指令处理函数CommondHandle:验证串口(simpleBLECentral.c)

使用串口调试助手发送 AT

AT指令处理函数返回OK给PC:


  // AT占用两个字节
  if(length<2)
    return ;
  if(pBuffer[0]!='A' && pBuffer[1]!='T')
    return ;
  if(length <=4) {
    SerialPrintString("OK\r\n");
    return ;
  }

注:指令

  AT                  串口测试,返回OK
  AT+ROLE?            获取当前角色
  AT+SCAN             扫描从机
  AT+CON[x]           连接指定的从机,x为搜索到的从机序号
  AT+RSSI             获取rssi值
  AT+DISCON           断开连接
  AT+WRITE[0xXX]      向char1写入特征值

3、AT指令处理函数CommondHandle:BLE主机设备初始化完成(simpleBLECentral.c 的 simpleBLECentralEventCB 函数)

注册回调函数:

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

初始化成功会直接调用回调函数的 GAP_DEVICE_INIT_DONE_EVENT 事件:

  case GAP_DEVICE_INIT_DONE_EVENT:  
  {
        SerialPrintString("BLE Central: ");
// 将 BLE 主机设备地址通过串口发送给PC
        SerialPrintString((uint8*)bdAddr2Str( pEvent->initDone.devAddr ));SerialPrintString("\r\n");
  }
  break;

4、AT指令处理函数CommondHandle:BLE主机扫描从机(simpleBLECentral.c 的 CommondHandle 和 simpleBLECentralEventCB 函数)

1) 接收PC端AT指令:AT+SCAN

  if(length>=7 && str_cmp(pBuffer+3,"SCAN",4) == 0)
  {
      simpleBLEScanning = TRUE;
      simpleBLEScanRes = 0;
      
      SerialPrintString("Discovering...\r\n");
      
 // 开始扫描从机设备 - 需要开启蓝牙从机设备
      GAPCentralRole_StartDiscovery( DEFAULT_DISCOVERY_MODE,
                                     DEFAULT_DISCOVERY_ACTIVE_SCAN,
                                     DEFAULT_DISCOVERY_WHITE_LIST ); 
      return ;
  }

2) 扫描到从机,调用回调函数处理

  case GAP_DEVICE_DISCOVERY_EVENT:
  {
    simpleBLEScanning = FALSE;
    
    // if not filtering device discovery results based on service UUID
    if ( DEFAULT_DEV_DISC_BY_SVC_UUID == FALSE )
    {
      // Copy results
      simpleBLEScanRes = pEvent->discCmpl.numDevs;
      osal_memcpy( simpleBLEDevList, pEvent->discCmpl.pDevList,
                   (sizeof( gapDevRec_t ) * pEvent->discCmpl.numDevs) );
    }
    
// 将扫描的从机个数通过串口输出到PC
    SerialPrintValue("Devices Found", simpleBLEScanRes, 10);
    SerialPrintString("\r\n");
    
    if ( simpleBLEScanRes > 0 )
    {
      SerialPrintString("<- To Select\r\n");
    }
    
    // initialize scan index to last device
    simpleBLEScanIdx = simpleBLEScanRes; 
   }
   break;
   
5、AT指令处理函数CommondHandle:BLE连接扫描到的从机(simpleBLECentral.c 的 CommondHandle 和 simpleBLECentralEventCB 函数)

1) 接收PC端AT指令:AT+CON1    1表示从机序列号,即连接从机1

  if(length>=7 && str_cmp(pBuffer+3,"CON",3) == 0)
  {
      // 连接参数CON后面跟的数值大于等于1,意思是连接第一个从机 第二个从机等
      uint8 tmp=pBuffer[5]-48-1;
      if ( simpleBLEState == BLE_STATE_IDLE ){
        // if there is a scan result
        if ( simpleBLEScanRes > 0 )
        {
          uint8 addrType;
          uint8 *peerAddr;
          // connect to current device in scan result
          peerAddr = simpleBLEDevList[tmp].addr;
          addrType = simpleBLEDevList[tmp].addrType;
        
          simpleBLEState = BLE_STATE_CONNECTING;
          
 // 开始建立连接
          GAPCentralRole_EstablishLink( DEFAULT_LINK_HIGH_DUTY_CYCLE,
                                        DEFAULT_LINK_WHITE_LIST,
                                        addrType, peerAddr );
    
          SerialPrintString("Connecting:");
          SerialPrintString((uint8*)bdAddr2Str( peerAddr));SerialPrintString("\r\n");
        }
      }
      return ;
  }

2) 连接成功,调用回调函数处理

  case GAP_LINK_ESTABLISHED_EVENT:
  {
    if ( pEvent->gap.hdr.status == SUCCESS )
    {          
      simpleBLEState = BLE_STATE_CONNECTED;
      simpleBLEConnHandle = pEvent->linkCmpl.connectionHandle;
      simpleBLEProcedureInProgress = TRUE;    
    
      // If service discovery not performed initiate service discovery
      if ( simpleBLECharHdl == 0 )
      {
        osal_start_timerEx( simpleBLETaskId, START_DISCOVERY_EVT, DEFAULT_SVC_DISCOVERY_DELAY );
      }
                
      SerialPrintString("Connected: ");
      SerialPrintString((uint8*) bdAddr2Str( pEvent->linkCmpl.devAddr ));SerialPrintString("\r\n");   
    }
    else
    {
      simpleBLEState = BLE_STATE_IDLE;
      simpleBLEConnHandle = GAP_CONNHANDLE_INIT;
      simpleBLERssi = FALSE;
      simpleBLEDiscState = BLE_DISC_STATE_IDLE;
      
      SerialPrintString("Connect Failed: ");
      SerialPrintValue("Reason:",  pEvent->gap.hdr.status,10);
    }
  }
  
6、AT指令处理函数CommondHandle:BLE获取信号强度RSSI的值(simpleBLECentral.c 的 CommondHandle 和 simpleBLECentralEventCB 函数)

1) 接收PC端AT指令:AT+RSSI    

  if(length>=7 && str_cmp(pBuffer+3,"RSSI",4) == 0)
  {
    // Start or cancel RSSI polling
    if ( simpleBLEState == BLE_STATE_CONNECTED )
    {
      if ( !simpleBLERssi )
      {
        simpleBLERssi = TRUE;

// 开启获取RSSI值
        GAPCentralRole_StartRssi( simpleBLEConnHandle, DEFAULT_RSSI_PERIOD );
      }
      else
      {
        simpleBLERssi = FALSE;
        GAPCentralRole_CancelRssi( simpleBLEConnHandle );
        
        LCD_WRITE_STRING( "RSSI Cancelled", HAL_LCD_LINE_1 );
        SerialPrintString("RSSI Cancelled\r\n");
      }
    }
    return ;
  }

2) RSSI获取成功,调用回调函数处理

  static void simpleBLECentralRssiCB( uint16 connHandle, int8 rssi )
  { 
    // RSSI 值通过串口发送给 PC
    SerialPrintValue("RSSI -dB:", (uint8) (-rssi), 10);SerialPrintString("\r\n");
  }
  
7、AT指令处理函数CommondHandle:BLE主机向char1写入特征值(simpleBLECentral.c 的 CommondHandle 和 simpleBLECentralEventCB 函数)
  
1) 接收PC端AT指令:AT+WRITE0x5A

  //AT+WRITE0xXX
  if(length>=10 && str_cmp(pBuffer+3,"WRITE0x",7) == 0)
  {
    //uint8 val=0;
    simpleBLECharVal=str2hex(pBuffer+10);
    if ( simpleBLEState == BLE_STATE_CONNECTED &&
              simpleBLECharHdl != 0 &&
              simpleBLEProcedureInProgress == FALSE )
    {
      uint8 status;

      // Do a write
      attWriteReq_t req;
      
      req.handle = simpleBLECharHdl;
      req.len = 1;
      req.value[0] = simpleBLECharVal;
      req.sig = 0;
      req.cmd = 0;
 
 // 写入特征值
      status = GATT_WriteCharValue( simpleBLEConnHandle, &req, simpleBLETaskId );         
      
      if ( status == SUCCESS )
      {
        simpleBLEProcedureInProgress = TRUE;
      }
    } 
    return ;
  }
  
8、AT指令处理函数CommondHandle:BLE主机断开连接(simpleBLECentral.c 的 CommondHandle 和 simpleBLECentralEventCB 函数)

1) 接收PC端AT指令:AT+DISCON

  if(length>=10 && str_cmp(pBuffer+3,"DISCON",6) == 0)
  {
    if ( simpleBLEState == BLE_STATE_CONNECTING ||
              simpleBLEState == BLE_STATE_CONNECTED )
    {
      // disconnect
      simpleBLEState = BLE_STATE_DISCONNECTING;
      
      // 断开连接
      gStatus = GAPCentralRole_TerminateLink( simpleBLEConnHandle );
      
      SerialPrintString("Disconnecting\r\n");
    }
  }

2) 断开连接成功,调用回调函数处理

  case GAP_LINK_TERMINATED_EVENT:
  {
    simpleBLEState = BLE_STATE_IDLE;
    simpleBLEConnHandle = GAP_CONNHANDLE_INIT;
    simpleBLERssi = FALSE;
    simpleBLEDiscState = BLE_DISC_STATE_IDLE;
    simpleBLECharHdl = 0;
    simpleBLEProcedureInProgress = FALSE;
      
    SerialPrintString("Disconnected: ");
    SerialPrintValue("Reason:",  pEvent->linkTerminate.reason,10);
  }
  break;