Upload
others
View
16
Download
0
Embed Size (px)
Citation preview
串口透传
前言:
有了上面的基础,接下来就可以打造无线串口功能了。
实现平台:WeBee CC2540 模块及功能底板
图 3.117 网蜂 CC2540 模块及功能底板
实验现象:
两台 PC 通过串口连接 CC2540,通过设置好串口调试助手,就可以相互收发
信息。也可在一台 PC 利用两个串口实现这个功能。
实验讲解:
整个实验用到两个模块,一个作为服务器、一个作为客户端,重点为下面两
个方向:
1、客户端接收串口数据并写入特征值
2、服务器接收串口数据并写入特征值,再通知主机
1
本实验需要用到两个特征值,两个特征值的属性各不相同,我们同样在
SimpleGATTProfile 中新建即可,接下来就开始吧。
新建特征值表:
表 3.3 串口透传特征值属性
长度
(byte)
属性 UUID 功能
SIMPLEPROFILE_CHA
R6
15 可读可写 FFF6 服务器接收客户端的串口
数据
SIMPLEPROFILE_CHA
R7
15 不能直接读写,
通过通知发送
FFF7 客户端接收服务器的串口
数据
1.1.1 客户端接收串口数据并写入特征值
如何新建特征值我们上一节讲得很清楚了,SIMPLEPROFILE_CHAR6 可以直接
利用上一节中新建的特征值,这里把字长改为 15 即可,并在 static void
simpleProfileChangeCB( uint8 paramID )函数中添加 CHAR6 改变的处理函数,
这里是串口输出,我们的格式是:串口数据的长度(1 Byte) + 数据( 14 Byte)
1. case SIMPLEPROFILE_CHAR6: //串口透传 Profile
2. char newchar[15];
3. SimpleProfile_GetParameter( SIMPLEPROFILE_CHAR6, newchar);
4. if( newchar[0] >= 15 )
5. {
6. HalUARTWrite(0,&newchar[1],14);
7. HalUARTWrite(0,"...\n",4 );
8. }
9. else
10. {
2
11. HalUARTWrite(0,&newchar[1],newchar[0]);
12. }
13. break;
图 3.118 CHAR6接收
接下来是 simpleBLECentral 的写入:
在对 CHAR1 的写入代码中
1. // Do a write
2. attWriteReq_t req;
3.
4. req.handle = simpleBLECharHdl; //这个是在哪里得到的?
5. req.len = 1;
6. req.value[0] = 0x00;
7. req.sig = 0;
8. req.cmd = 0;
9. GATT_WriteCharValue( simpleBLEConnHandle, &req,
simpleBLETaskId );
3
进入 static void simpleBLEGATTDiscoveryEvent( gattMsgEvent_t *pMsg )函
数
图 3.119 读取 Handle
图 3.120 已获取 CHAR1 handle
4
这里我们就可以明白 simpleBLECharHd1 何来了,把这段改为我们需要的读取
CHAR6 的 Handle 然后调用
GATT_ReadUsingCharUUID( simpleBLEConnHandle, &req,
simpleBLETaskId );
就可以获取到该特征值的属性。
图 3.121 读取 CHAR6 Handle值
下一步就是串口的接收与 CHAR6 的写入,直接来分析代码
1. uint8 gStatus;
2. static void simpleBLEPeripheral_HandleSerial(mtOSALSerialData_t
*cmdMsg)
3. {
4. uint8 i,len,*str=NULL; //len 有用数据长度
5. uint8 CMD;
6. str=cmdMsg->msg; //指向数据开头
7. len=*str; //msg 里的第 1个字节代表后面的数据长度
8.
5
9. if ( ( simpleBLEState == BLE_STATE_CONNECTED ) &&
( simpleBLECharHd6 != 0 ) ) //写 char6
10. {
11. uint8 ValueBuf[SIMPLEPROFILE_CHAR6_LEN];
12.
13. if ( len >= SIMPLEPROFILE_CHAR6_LEN ) len =
SIMPLEPROFILE_CHAR6_LEN;
14. else len += 1;
15. for(i=0;i<=len;i++)
16. ValueBuf[i] = str[i];
17.
18. gattPrepareWriteReq_t req;
19.
20. req.handle = simpleBLECharHd6;
21. req.len = SIMPLEPROFILE_CHAR6_LEN;
22. req.offset = 0;
23. req.pValue = osal_msg_allocate(SIMPLEPROFILE_CHAR6_LEN);
24. osal_memcpy(req.pValue,ValueBuf,SIMPLEPROFILE_CHAR6_LEN);
25. GATT_WriteLongCharValue(simpleBLEConnHandle, &req,
simpleBLETaskId );
26.
27. }
28. else
29. {
30. HalUARTWrite(0,"Not Connect\n", 12 );
31. }
32.
33. }
6
第 9行:判断是否处于连接状态并且以获取 CHAR6 的 handle 值
第 18-23 行:设置对应的参数
第 24 行:将串口的数据赋给发送数组中
第 25 行:调用 GATT 层中的 API 写入特征值
下载连接后,在simpleBLECentral模块中通过串口发送小于15字节的数据,
就可以在 SimpleBLEPeripheral 的串口输出中看到对应的数据,到这里就实现
了第一个方向的传输。
图 3.122 单方向透传测试
可在 SimpleBLEPeripheral 中看到的串口输出:
7
图 3.123 接收成功
8
1.1.2 服务器接收串口数据并写入特征值,再通知主机
下面主要注意一下第二个特征值的添加,特别是其属性,他的属性与 CHAR4
的一样,这里可以参考一下。
下面主要看一下和之前的差别之处:
图 3.124 CHAR7属性
bStatus_t SimpleProfile_SetParameter( uint8 param, uint8 len, void
*value )函数中
9
图 3.125 CHAR7通知
具体代码
1. else if ( ( pMsg->method == ATT_HANDLE_VALUE_NOTI ) ) //通知
2. {
3. //CHAR7 的通知 串口打印
4. if( pMsg->msg.handleValueNoti.handle == 0x0038) {
5. if(pMsg->msg.handleValueNoti.value[0]>=15)
6. {
7. HalUARTWrite(0,&pMsg->msg.handleValueNoti.value[1],14 );
8. HalUARTWrite(0,"...\n",4 );
9. }
10. else
11. {
12. HalUARTWrite(0,&pMsg->msg.handleValueNoti.value[1],
13. pMsg->msg.handleValueNoti.value[0] );
14. }
15. }
10
16. }
第 1 行:判断是否为通知事件
第 4行:判断是否为 CHAR7 写入事件
第 5-9 行:如果串口接收的数据大于 15,则只能显示部分数据
第 9-14 行:显示串口接收到的全部数据
这两处就是最大的区别,当服务器端自己把数据改变时,客户端并不会自己主动
来读取数据的变化,这里就有一个通知机制,服务器要接收到 CHAR7 是否改变,
就需要打开对 CHAR7 的通知,就是在 CHAR7 的 Handle+1 写入 0x0001。
下面就进入 SimpleBLECentral 工程中,我们利用按键 S1 来使能这个通知
图 3.126 使能 CHAR7通知
具体代码:
1. if ( keys & HAL_KEY_SW_1 )
2. {
3. /* 使能通知 Char7 */
11
4. uint8 ValueBuf[2];
5. gattPrepareWriteReq_t req;
6.
7. req.handle = 0x0039;
8. req.len = 2;
9. ValueBuf[0] = 0x01;
10. ValueBuf[1] = 0x00;
11. req.offset = 0;
12. req.pValue = osal_msg_allocate(2);
13. osal_memcpy(req.pValue,ValueBuf,2);
14. GATT_WriteLongCharValue( simpleBLEConnHandle,
15. &req, simpleBLETaskId );
16.
17. HalUARTWrite(0,"Enable Notice\n", 14 );
18. }
第 7 行:选择要打开通知的特征值 handle
第 9-10 行:赋给对应的命令,这里是打开通知,即 0x0001
第 14 行:调用 API 使能 CHAR7 的通知
使能通知后,当服务器端有数据更新的通知会在哪里得到,这就要找到
static void simpleBLECentralProcessGATTMsg( gattMsgEvent_t *pMsg )函数,
这个函数式对 GATT 的事件进行处理的,包括通知。在函数中添加如下:
12
图 3.127 CHAR7接收
这里就完成 SimpleBLECentral 端的数据接收处理。最后一步就是 SimpleBLECentral 工程
的串口接收了。
具体代码:
1. static void simpleBLEPeripheral_HandleSerial(mtOSALSerialData_t
*cmdMsg)
2. {
3. uint8 i,len,*str=NULL; //len 有用数据长度
4. str=cmdMsg->msg; //指向数据开头
5. len=*str; //msg 里的第 1个字节代表后面的数据长度
6.
7. //串口透传 设置 char7 参数
8. {
9. uint8 charValue7[SIMPLEPROFILE_CHAR7_LEN];
10.
13
11. if ( len >= SIMPLEPROFILE_CHAR7_LEN ) len =
SIMPLEPROFILE_CHAR7_LEN;
12. else len += 1;
13. for(i=0;i<=len;i++)
14. charValue7[i] = str[i];
15.
16. SimpleProfile_SetParameter( SIMPLEPROFILE_CHAR7,
17. SIMPLEPROFILE_CHAR7_LEN, charValue7 );
18. }
19.
20. }
第 16 行:将接收到的数据写入特征值
接收到串口数据后马上更新 CHAR7 的数据,这时就会调用到刚才的函数通知客户
端 。
图 3.128 CHAR7通知
14
至此第二个方向就完成了。下载后等待连接完成,按下客户端的 S1 按键,
就可在simpleBLECentral端或SimpleBLEPeripheral 端中通过串口发送小于15
字节的数据,并可从对方的串口输出中看到对应的数据。
图 3.129 按键使能通知
simpleBLECentral 端
15
图 3.130 simpleBLECentral 端透传测试
SimpleBLEPeripheral 端
图 3.131 SimpleBLEPeripheral 端透传测试
到这里就完成两个方向的传输,相应的我们的串口透传已完成测试。