16
串口透传 前言: 有了上面的基础,接下来就可以打造无线串口功能了。 实现平台WeBee CC2540 模块及功能底板 3.117 网蜂 CC2540 模块及功能底板 实验现象: 两台 PC 通过串口连接 CC2540,通过设置好串口调试助手,就可以相互收发 信息。也可在一台 PC 利用两个串口实现这个功能。 实验讲解: 整个实验用到两个模块,一个作为服务器、一个作为客户端,重点为下面两 个方向: 1、客户端接收串口数据并写入特征值 2、服务器接收串口数据并写入特征值,再通知主机

串口透传 - upload.semidata.info · 实现平台:webee cc2540 模块及功能底板 图 3.117 网蜂 cc2540 模块及功能底板 实验现象: 两台 pc 通过串口连接

  • Upload
    others

  • View
    16

  • Download
    0

Embed Size (px)

Citation preview

Page 1: 串口透传 - upload.semidata.info · 实现平台:webee cc2540 模块及功能底板 图 3.117 网蜂 cc2540 模块及功能底板 实验现象: 两台 pc 通过串口连接

串口透传

前言:

有了上面的基础,接下来就可以打造无线串口功能了。

实现平台:WeBee CC2540 模块及功能底板

图 3.117 网蜂 CC2540 模块及功能底板

实验现象:

两台 PC 通过串口连接 CC2540,通过设置好串口调试助手,就可以相互收发

信息。也可在一台 PC 利用两个串口实现这个功能。

实验讲解:

整个实验用到两个模块,一个作为服务器、一个作为客户端,重点为下面两

个方向:

1、客户端接收串口数据并写入特征值

2、服务器接收串口数据并写入特征值,再通知主机

Page 2: 串口透传 - upload.semidata.info · 实现平台:webee cc2540 模块及功能底板 图 3.117 网蜂 cc2540 模块及功能底板 实验现象: 两台 pc 通过串口连接

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. {

Page 3: 串口透传 - upload.semidata.info · 实现平台:webee cc2540 模块及功能底板 图 3.117 网蜂 cc2540 模块及功能底板 实验现象: 两台 pc 通过串口连接

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 );

Page 4: 串口透传 - upload.semidata.info · 实现平台:webee cc2540 模块及功能底板 图 3.117 网蜂 cc2540 模块及功能底板 实验现象: 两台 pc 通过串口连接

3

进入 static void simpleBLEGATTDiscoveryEvent( gattMsgEvent_t *pMsg )函

图 3.119 读取 Handle

图 3.120 已获取 CHAR1 handle

Page 5: 串口透传 - upload.semidata.info · 实现平台:webee cc2540 模块及功能底板 图 3.117 网蜂 cc2540 模块及功能底板 实验现象: 两台 pc 通过串口连接

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.

Page 6: 串口透传 - upload.semidata.info · 实现平台:webee cc2540 模块及功能底板 图 3.117 网蜂 cc2540 模块及功能底板 实验现象: 两台 pc 通过串口连接

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. }

Page 7: 串口透传 - upload.semidata.info · 实现平台:webee cc2540 模块及功能底板 图 3.117 网蜂 cc2540 模块及功能底板 实验现象: 两台 pc 通过串口连接

6

第 9行:判断是否处于连接状态并且以获取 CHAR6 的 handle 值

第 18-23 行:设置对应的参数

第 24 行:将串口的数据赋给发送数组中

第 25 行:调用 GATT 层中的 API 写入特征值

下载连接后,在simpleBLECentral模块中通过串口发送小于15字节的数据,

就可以在 SimpleBLEPeripheral 的串口输出中看到对应的数据,到这里就实现

了第一个方向的传输。

图 3.122 单方向透传测试

可在 SimpleBLEPeripheral 中看到的串口输出:

Page 8: 串口透传 - upload.semidata.info · 实现平台:webee cc2540 模块及功能底板 图 3.117 网蜂 cc2540 模块及功能底板 实验现象: 两台 pc 通过串口连接

7

图 3.123 接收成功

Page 9: 串口透传 - upload.semidata.info · 实现平台:webee cc2540 模块及功能底板 图 3.117 网蜂 cc2540 模块及功能底板 实验现象: 两台 pc 通过串口连接

8

1.1.2 服务器接收串口数据并写入特征值,再通知主机

下面主要注意一下第二个特征值的添加,特别是其属性,他的属性与 CHAR4

的一样,这里可以参考一下。

下面主要看一下和之前的差别之处:

图 3.124 CHAR7属性

bStatus_t SimpleProfile_SetParameter( uint8 param, uint8 len, void

*value )函数中

Page 10: 串口透传 - upload.semidata.info · 实现平台:webee cc2540 模块及功能底板 图 3.117 网蜂 cc2540 模块及功能底板 实验现象: 两台 pc 通过串口连接

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. }

Page 11: 串口透传 - upload.semidata.info · 实现平台:webee cc2540 模块及功能底板 图 3.117 网蜂 cc2540 模块及功能底板 实验现象: 两台 pc 通过串口连接

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 */

Page 12: 串口透传 - upload.semidata.info · 实现平台:webee cc2540 模块及功能底板 图 3.117 网蜂 cc2540 模块及功能底板 实验现象: 两台 pc 通过串口连接

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 的事件进行处理的,包括通知。在函数中添加如下:

Page 13: 串口透传 - upload.semidata.info · 实现平台:webee cc2540 模块及功能底板 图 3.117 网蜂 cc2540 模块及功能底板 实验现象: 两台 pc 通过串口连接

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.

Page 14: 串口透传 - upload.semidata.info · 实现平台:webee cc2540 模块及功能底板 图 3.117 网蜂 cc2540 模块及功能底板 实验现象: 两台 pc 通过串口连接

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通知

Page 15: 串口透传 - upload.semidata.info · 实现平台:webee cc2540 模块及功能底板 图 3.117 网蜂 cc2540 模块及功能底板 实验现象: 两台 pc 通过串口连接

14

至此第二个方向就完成了。下载后等待连接完成,按下客户端的 S1 按键,

就可在simpleBLECentral端或SimpleBLEPeripheral 端中通过串口发送小于15

字节的数据,并可从对方的串口输出中看到对应的数据。

图 3.129 按键使能通知

simpleBLECentral 端

Page 16: 串口透传 - upload.semidata.info · 实现平台:webee cc2540 模块及功能底板 图 3.117 网蜂 cc2540 模块及功能底板 实验现象: 两台 pc 通过串口连接

15

图 3.130 simpleBLECentral 端透传测试

SimpleBLEPeripheral 端

图 3.131 SimpleBLEPeripheral 端透传测试

到这里就完成两个方向的传输,相应的我们的串口透传已完成测试。