本文最后修改时间:2020年02月07日 19:32
一、本节简介
本文以SimpleBLEPeripheral工程为例,介绍如何使用AT指令来修改设备名称,且不需要重启设备,断开连接时即可看到广播中修改后的设备名称。
二、实验平台
1)CC2541平台
①协议栈版本:BLE-CC254x-1.4.0
②编译软件:IAR 8.20.2
③硬件平台:香瓜CC2541开发板
④仿真器:香瓜CC Debugger下载器
2)手机平台
①手机型号:小米8
②安卓版本:安卓8
③安卓app:TruthBlue
三、版权声明
1)作者:甜甜的大香瓜
2)声明:喝水不忘挖井人,转载请注明出处。
3)纠错/业务合作:897503845@qq.com
4)香瓜BLE之CC2541群:127442605
5)本文出处:原创连载资料《简单粗暴学蓝牙4.0(CC2541篇)》
6)完整开源资料下载地址(电脑端打开):
opengua.taobao.com
7)香瓜CC2541开发板套件购买:
opengua.taobao.com
四、实验前提
1、在进行本文步骤前,请先阅读以下章节:
1)《简单粗暴学蓝牙4.0(CC2541篇)》的“第一章至第三章”章节。
2)《简单粗暴学蓝牙4.0(CC2541篇)》的《CC2541之动态更新设备名》。
3)《简单粗暴学蓝牙4.0(CC2541篇)》的《CC2541之SNV》。
2、在进行本文步骤前,请先实现以下章节:
1)《简单粗暴学蓝牙4.0(CC2541篇)》的“第三章 软件的安装及使用”章节。
2)《简单粗暴学蓝牙4.0(CC2541篇)》的《CC2541之串口透传(20字节内任意长度)》。
五、基础知识
暂无
六、硬件原理
暂无
七、实验步骤
1、添加SNV头文件(SimpleBLEPeripheral.c中)
#include “osal_snv.h” |
2、添加设备名称所用的宏定义(SimpleBLEPeripheral.c中)
//GUA //SNV的设备名称使用 #define GUA_SNV_DEVICE_NAME_ID 0x80 #define GUA_SNV_DEVICE_NAME_READ 0x00 #define GUA_SNV_DEVICE_NAME_WRITE 0x01 //GUA |
3、添加SNV读写设备名称数据的函数
1)定义SNV读写设备名称数据的函数(SimpleBLEPeripheral.c中)
//****************************************************************************** //name: GUA_SNV_DeviceName //introduce: 从 SNV 读取或写入设备名称 //parameter: nGUA_WriteReadFlag:GUA_SNV_DEVICE_NAME_READ or GUA_SNV_DEVICE_NAME_WRITE // pGUA_DeviceName:设备名称结构体 //return: none //author: 甜甜的大香瓜 //email: 897503845@qq.com //QQ group: 香瓜 BLE 之 CC2541(127442605) //shop: opengua.taobao.com //changetime: 2020.01.18 //****************************************************************************** static void GUA_SNV_DeviceName(uint8 nGUA_WriteReadFlag, ST_GUA_DEVICE_NAME *pGUA_DeviceName) { uint8 nGUA_Ret; ST_GUA_DEVICE_NAME aGUA_Default_DeviceName = {7, “opengua”}; //从SNV读设备名称 if(nGUA_WriteReadFlag == GUA_SNV_DEVICE_NAME_READ) { nGUA_Ret = osal_snv_read(GUA_SNV_DEVICE_NAME_ID, sizeof(stGUA_Device_Name), pGUA_DeviceName);
//如果第一次读取失败,则说明没有写过,是出厂的设备。因此在这里设置为出厂设备名称。 If(nGUA_Ret == NV_OPER_FAILED) { //将出厂设备名称写入snv中 osal_snv_write(GUA_SNV_DEVICE_NAME_ID, sizeof(stGUA_Device_Name), &aGUA_Default_DeviceName); //读出设备名称 osal_snv_read(GUA_SNV_DEVICE_NAME_ID, sizeof(stGUA_Device_Name), pGUA_DeviceName); } } //写新的设备名称到SNV else if(nGUA_WriteReadFlag == GUA_SNV_DEVICE_NAME_WRITE) { //写进新的设备名称 osal_snv_write(GUA_SNV_DEVICE_NAME_ID, (pGUA_DeviceName->Len)+1, pGUA_DeviceName); //读出新的设备名称 nGUA_Ret = osal_snv_read(GUA_SNV_DEVICE_NAME_ID, (pGUA_DeviceName->Len)+1, pGUA_DeviceName); } } |
每次上电时会调用此函数,将设备名称的结构体数据从SNV中读出。第一次出厂名称为“opengua”。
2)声明SNV读写设备名称数据的函数(SimpleBLEPeripheral.c中)
//GUA static void GUA_SNV_DeviceName(uint8 nGUA_WriteReadFlag, ST_GUA_DEVICE_NAME *pGUA_DeviceName); //GUA |
4、添加设备名称结构体(SimpleBLEPeripheral.c中的最上方)
//GUA typedef struct{ uint8 Len; uint8 Name[GAP_DEVICE_NAME_LEN]; }ST_GUA_DEVICE_NAME; ST_GUA_DEVICE_NAME stGUA_Device_Name; //GUA |
之所以需要放在最上方,是因为声明函数中使用到此结构体,因此需要比声明函数位置更上方。
5、替换代码(SimpleBLEPeripheral.c中的SimpleBLEPeripheral_Init)
将
//GAPRole_SetParameter( GAPROLE_SCAN_RSP_DATA, sizeof ( scanRspData ), scanRspData ); |
替换成
//GUA uint8 aGUA_ScanRspData_Temp[B_MAX_ADV_LEN] = {0}; uint8 nGUA_I = 0;
//GAPRole_SetParameter( GAPROLE_SCAN_RSP_DATA, sizeof ( scanRspData ), scanRspData );
//从SNV中读出设备名称结构体 GUA_SNV_DeviceName(GUA_SNV_DEVICE_NAME_READ, &stGUA_Device_Name);
//保存名称数据字段 aGUA_ScanRspData_Temp[nGUA_I++] = 1 + stGUA_Device_Name.Len; //名称字段的长度=1(数据类型长度)+数据长度 aGUA_ScanRspData_Temp[nGUA_I++] = GAP_ADTYPE_LOCAL_NAME_COMPLETE; //名称字段的数据类型 osal_memcpy(&aGUA_ScanRspData_Temp[nGUA_I], stGUA_Device_Name.Name, stGUA_Device_Name.Len);//复制名称数据 //保存原来历程中的后续数据字段 nGUA_I += stGUA_Device_Name.Len; osal_memcpy(&aGUA_ScanRspData_Temp[nGUA_I], (scanRspData+21), 9); nGUA_I += 9;
//将扫描应答数据传给协议栈 GAPRole_SetParameter(GAPROLE_SCAN_RSP_DATA, nGUA_I, aGUA_ScanRspData_Temp); //GUA |
此处是在上电初始化时,将SNV的设备名称数据读出,并替换掉原来协议栈中的设备名称。但又保持原来扫描应答包的其他数据段。
6、替换香瓜profile的回调函数(SimpleBLEPeripheral.c中)
//****************************************************************************** //name: GUAProfileChangeCB //introduce: 主机写入时的回调函数 //parameter: paramID:特征值id //return: none //author: 甜甜的大香瓜 //email: 897503845@qq.com //QQ group: 香瓜 BLE 之 CC2541(127442605) //shop: opengua.taobao.com //changetime: 2020.01.19 //****************************************************************************** static void GUAProfileChangeCB( uint8 paramID ) { switch( paramID ) { case GUAPROFILE_CHAR1: { uint16 nGUA_NotifyHandle; uint8 aGUA_Buf[20] = {0}; uint8 aGUA_AT[3] = “AT+”; uint8 aGUA_AT_OK[5] = “AT+OK”; uint8 aGUA_ScanRspData_Temp[B_MAX_ADV_LEN] = {0}; uint8 nGUA_I = 0;
//获取句柄 GAPRole_GetParameter(GAPROLE_CONNHANDLE, &nGUA_NotifyHandle);
//获取主机发来的数据 GUAProfile_GetParameter(GUAPROFILE_CHAR1, aGUA_Buf);
//判断是否是AT指令,如果是AT指令,则是修改名称的指令,否则从串口透传出去 if(osal_memcmp(aGUA_Buf, aGUA_AT, 3) == TRUE) { //保存名称数据长度和名称数据到SNV stGUA_Device_Name.Len = gnGUA_len -3; osal_memcpy(stGUA_Device_Name.Name, (aGUA_Buf+3), stGUA_Device_Name.Len); GUA_SNV_DeviceName(GUA_SNV_DEVICE_NAME_WRITE, &stGUA_Device_Name); //保存名称数据字段到扫描应答包的缓冲区 aGUA_ScanRspData_Temp[nGUA_I++] = 1 + stGUA_Device_Name.Len; //名称字段的长度=1(数据类型长度)+数据长度 aGUA_ScanRspData_Temp[nGUA_I++] = GAP_ADTYPE_LOCAL_NAME_COMPLETE; //名称字段的数据类型 osal_memcpy(&aGUA_ScanRspData_Temp[nGUA_I], stGUA_Device_Name.Name, stGUA_Device_Name.Len);//复制名称数据
//保存原来历程中的后续数据字段到扫描应答包的缓冲区 nGUA_I += stGUA_Device_Name.Len; osal_memcpy(&aGUA_ScanRspData_Temp[nGUA_I], (scanRspData+21), 9); nGUA_I += 9;
//更新扫描应答包 GAP_UpdateAdvertisingData(simpleBLEPeripheral_TaskID, FALSE, nGUA_I, aGUA_ScanRspData_Temp);
//返回数据 GUAprofile_Notify(GUAPROFILE_CHAR1, nGUA_NotifyHandle, aGUA_AT_OK, sizeof(aGUA_AT_OK)); } else { //通过串口发送出去 NPI_WriteTransport(aGUA_Buf, gnGUA_len); } break; }
default:break; } } |
如果是AT指令,则为修改名称,香瓜在此添加了实时修改名称的代码处理。如果不是AT指令,则为串口透传。
八、注意事项
1、手机可能缓存了之前固件的数据(在更新过固件之后,都需要清除手机端的缓存!!!),因此要清除缓存,清除缓存的方法如下:
方法一:关闭app、关闭蓝牙总开关、打开蓝牙总开关、打开app。
方法二:手机重启。
九、实验结果
上述三张图,分别为默认设备名称、修改名称指令、修改后的设备名称。
香瓜实现的是不需要重启即可实现的修改设备名称。
因此,实验成功。