一、简介
本文以SimpleBLECentral工程为例,介绍串口控制蓝牙。
过程:
扫描从机 - 根据从机号连接指定从机 - 获取RSSI值(信号强度) - 向char1写入特征值 - 断开连接
二、实验平台
协议栈版本:BLE-CC254x-1.3.2
编译软件: IAR 8.20.2
硬件平台: Smart RF开发板(主芯片CC2541)、USB Dongle
PC: 友善串口调试助手
三、版权声明
声明:转载请注明出处。
四、实验前提
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;
卫朋
人人都是产品经理受邀专栏作家,CSDN 嵌入式领域新星创作者、资深技术博主。2020 年 8 月开始写产品相关内容,截至目前,人人都是产品经理单渠道阅读 56 万+,鸟哥笔记单渠道阅读200 万+,CSDN 单渠道阅读 210 万+,51CTO单渠道阅读 180 万+。
卫朋入围2021/2022年人人都是产品经理平台年度作者,光环国际学习社区首批原创者、知识合作伙伴,商业新知 2021 年度产品十佳创作者,腾讯调研云2022年达人榜第三名。
文章被人人都是产品经理、CSDN、华为云、运营派、产品壹佰、鸟哥笔记、光环国际、商业新知、腾讯调研云等头部垂直类媒体转载。文章见仁见智,各位看官可策略性选择对于自己有用的部分。