LIST

  • 开发环境
  • 测试过程
    • 前言
    • 目标
    • 工程与代码
    • 结语
  • 官方资料

开发环境

MCU:STM8L151K4T6
蓝牙模块:WH-BLE103(文末附官方资料链接)
编译:IAR_STM8
烧录:STVP
开发平台:vscode
主要扩展:Embedded IDE、C\C++


测试过程

前言

最近想鼓捣鼓捣蓝牙,之前没有接触过蓝牙协议栈,感觉从现成的模块入手会更快一点。
选用的是WH-BLE103,支持透传以及AT指令组网。这里简单科普一下,透传是啥呢?其实就是把蓝牙模块当串口来用,你发过来的数据是什么,我接收到的就是什么。而AT指令,可以快速的设置蓝牙模块的各项参数。
对于WH-BLE103来说,只需要设定配对密码和改变模式就能自行组网。

目标

  • 实现十台设备的组网和信息通讯
  • 实现手机通过中继控制/查询网内节点设备信息(实验中使用LED亮暗表示信息)

工程与代码

  • 工程配置
    因为我希望组网是一个动态的过程(可以任意添加或删除设备),因此需要申请动态数组,看了下memory map,我在工程中申请了一个256字节的heap。
"linker": {"linker-config": "lnkstm8l151k4.icf","auto-search-runtime-lib": true,"use-C_SPY-debug-lib": true,"config-defines": ["_CSTACK_SIZE=0x0400","_HEAP_SIZE=0x0100"]}
  • MCU串口初始化
    AT指令可以设置蓝牙的串口通讯参数,本实验沿用了WH-BLE103的出厂参数,具体可看注释。
void bsp_uart_init(void)
{USART_DeInit(USART1);CLK_PeripheralClockConfig(CLK_Peripheral_USART1, ENABLE);//remappin//SYSCFG_REMAPPinConfig(REMAP_Pin_USART1TxRxPortC, ENABLE);/*** @param USART1 ,* @param BR: 57600, * @param WL: 8bit, * @param SB: 1 bit, * @param PR: no parity, * @param MODE: RX/TX mode */USART_Init(USART1, (uint32_t)57600, USART_WordLength_8b, USART_StopBits_1, USART_Parity_No, (USART_Mode_Tx | USART_Mode_Rx));USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);ITC_SetSoftwarePriority(USART1_RX_IRQn, ITC_PriorityLevel_2);//priority 2USART_Cmd(USART1, ENABLE);USART1_RX_STA = 0;bsp_tim3_init(1250);//Enter interrupt after 10ms
}
  • MCU串口数据处理程序
    用于处理蓝牙回传数据流和外部(如手机)数据流
    USART1_RX_STA的声明入下:
Bit [15] Bit [14:0]
0: waiting for receive, 1: received a set of data record the length of data

采用了10ms规则,即两次数据流的接收间隔必须大于10ms

void USART1_IRQHandler(void)
{uint8_t receive_data;if(USART_GetITStatus(USART1,USART_IT_RXNE) != RESET)        //Check whether the specified UART1 interrupt occurs.{receive_data = USART_ReceiveData8(USART1);if((USART1_RX_STA & (uint16_t)(1<<15)) == 0)                      {if(USART1_RX_STA < USART1_RX_MAX_LEN)               //Determine whether the byte overflows{TIM3_SetCounter(0);//recountif(0 == USART1_RX_STA)TIM3_Cmd(ENABLE);USART1_RX_buf[USART1_RX_STA++] = receive_data;// if(RELAY_DEV == DEVICE_ID)//     USART1_RELAY_buf[USART1_RX_STA++] = receive_data;}elseUSART1_RX_STA |= (uint16_t) 1<<15;//enforce finish receive}USART_ClearITPendingBit(USART1,USART_IT_RXNE);            //Clear UART1 pending flag}
}
  • AT指令发送
    基于蓝牙模块手册编写,根据蓝牙回传规则,AT指令发送成功时的返回数据尾为 “OK\r\n”,进入AT模式时返回的数据尾为 “ok\r\n
uint8_t AT_Send(uint8_t *atcmd)
{uint16_t tag = 1;uint8_t t;// uint16_t k;USART1_RX_STA = 0;memset(USART1_RX_buf, 0, sizeof(USART1_RX_buf));uint8_t retry = 10;//number of AT command sending attemptswhile (retry--){USART1_SendWord(atcmd);delay_ms_1(10);for (t = 0; t < 10; t++){if(USART1_RX_STA & 0x8000)break;delay_ms_1(5);// k = TIM3_GetCounter();}if ((USART1_RX_STA & 0x8000))//receive the data{tag = USART1_RX_STA & 0x7FFF;//get the length of dataUSART1_RX_STA = 0;//clear the state flagif ((('O' == USART1_RX_buf[tag-4]) &&('K' == USART1_RX_buf[tag-3])) ||(('o' == USART1_RX_buf[tag-4]) &&('k' == USART1_RX_buf[tag-3]))){tag = 0;//enter succeedbreak;}}}//clear the rx bufferUSART1_RX_STA = 0;memset(USART1_RX_buf, 0, sizeof(USART1_RX_buf));if(0 == retry)tag = 1;//enter failedreturn tag;
}
  • MESH组网命令
    有了前面的铺垫,写一个函数来一键组网就轻而易举啦!
    这里值得注意的是,进入组网后,蓝牙模块会重启!但至于重启的时间,比较玄学,我也不清楚。这里偷懒了,因为有10台设备,干脆写了10条AT指令,代码比较不优雅。:)
void MESH_cmd(FunctionalState NewState)
{assert_param(IS_FUNCTIONAL_STATE(NewState));uint8_t i = 0;if (ENABLE == NewState){if (0 == AT_Send("+++a"))//Enter AT Mode{// delay_ms_1(100);
#if (1 == DEVICE_ID)AT_Send("AT+NAME=N1\r\n");//NODE 1 in MESH// delay_ms_1(100);
#endif
#if (2 == DEVICE_ID)AT_Send("AT+NAME=N2\r\n");//NODE 2 in MESH// delay_ms_1(100);
#endif
#if (3 == DEVICE_ID)AT_Send("AT+NAME=N3\r\n");//NODE 3 in MESH// delay_ms_1(100);
#endif
#if (4 == DEVICE_ID)AT_Send("AT+NAME=N4\r\n");//NODE 4 in MESH// delay_ms_1(100);
#endif
#if (5 == DEVICE_ID)AT_Send("AT+NAME=N5\r\n");//NODE 5 in MESH// delay_ms_1(100);
#endif
#if (6 == DEVICE_ID)AT_Send("AT+NAME=N6\r\n");//NODE 6 in MESH// delay_ms_1(100);
#endif
#if (7 == DEVICE_ID)AT_Send("AT+NAME=N7\r\n");//NODE 7 in MESH// delay_ms_1(100);
#endif
#if (8 == DEVICE_ID)AT_Send("AT+NAME=N8\r\n");//NODE 8 in MESH// delay_ms_1(100);
#endif
#if (9 == DEVICE_ID)AT_Send("AT+NAME=N9\r\n");//NODE 9 in MESH// delay_ms_1(100);
#endif
#if (10 == DEVICE_ID)AT_Send("AT+NAME=N10\r\n");//NODE 10 in MESH// delay_ms_1(100);
#endifAT_Send("AT+PASS=111111\r\n");//Set matching password: 111111// delay_ms_1(100);while(0 != AT_Send("AT+MODE=F\r\n"))//Enter AT Mode{if ((i++) >= 5){i = 0;USART1_SendWord("Enter MESH error...\r\n");beep_play(E_BEEP_MODE_ERR);memset(USART1_RX_buf, 0, sizeof(USART1_RX_buf));return;}    }USART1_SendWord("Enter MESH successfully...\r\n");beep_play(E_BEEP_MODE_SUCCESS);memset(USART1_RX_buf, 0, sizeof(USART1_RX_buf));}else{USART1_SendWord("MESH ERROR...\r\n");}    }if (DISABLE == NewState)    {   if (0 == AT_Send("+++a"))//Enter AT Mode{
#if (1 == DEVICE_ID)AT_Send("AT+NAME=D1\r\n");//DEVICE 1 out MESH
#endif
#if (2 == DEVICE_ID)AT_Send("AT+NAME=D2\r\n");//DEVICE 2 out MESH
#endif
#if (3 == DEVICE_ID)AT_Send("AT+NAME=D3\r\n");//DEVICE 3 out MESH
#endif
#if (4 == DEVICE_ID)AT_Send("AT+NAME=D4\r\n");//DEVICE 4 out MESH
#endif
#if (5 == DEVICE_ID)AT_Send("AT+NAME=D5\r\n");//DEVICE 5 out MESH
#endif
#if (6 == DEVICE_ID)AT_Send("AT+NAME=D6\r\n");//DEVICE 6 out MESH
#endif
#if (7 == DEVICE_ID)AT_Send("AT+NAME=D7\r\n");//DEVICE 7 out MESH
#endif
#if (8 == DEVICE_ID)AT_Send("AT+NAME=D8\r\n");//DEVICE 8 out MESH
#endif
#if (9 == DEVICE_ID)AT_Send("AT+NAME=D9\r\n");//DEVICE 9 out MESH
#endif
#if (10 == DEVICE_ID)AT_Send("AT+NAME=D10\r\n");//DEVICE 10 out MESH
#endifAT_Send("AT+MODE=S\r\n");//mode:SlaveAT_Send("AT+UARTTM=2\r\n");//data packing time: 20mswhile(AT_Send("AT+ENTM\r\n"))//Exit AT Mode{if ((i++) >= 5){i = 0;USART1_SendWord("Exit MESH error...\r\n");beep_play(E_BEEP_MODE_ERR);return;}}USART1_SendWord("Exit MESH successfully...\r\n");beep_play(E_BEEP_MODE_SUCCESS);}elseUSART1_SendWord("NON-MESH ERROR...\r\n");}}
  • 手机通过中继控制网络
    实际上官方文档中并没有提供蓝牙组网后的中继功能,所以本实验采用的是模式切换的方法。(在组网模式和从设备模式之间反复横跳)
    volatile uint8_t ctrl_string[] = "::000000000";//used to control LED group
/**Non-MESH modeNAME: Dx >>>Device x (x=1, 2, 3,...)LED MODE: Flashing LEDG in freq 1000msKEY MODE: Enter MESH Mode through short press(<3s)LINK PROC: Flashing LEDR in freq 100ms(NU)LINK OK: The LEDR(G) flash alternately for 1.5s with beep playLINK ERR: The buzzer beeps for 2s and the LEDR is onMESH modeNAME: Nx >>>Node x (x=1, 2, 3,...)LED MODE: Flashing LEDR in freq 1000msKEY MODE: Exit MESH Mode through long press(>3s)DISLINK PROC: Flashing LEDG in freq 100ms(NU)DISLINK OK: The LEDR(G) flash alternately for 1.5s with beep playDISLINK ERR: The buzzer beeps for 2s and the LEDG is on
**/
#if (RELAY_DEV == DEVICE_ID)if(0 == BLE_STA_flag)//process msg when enter mesh mode{delay_ms_1(100);//initmemset(USART1_RX_buf, 0, sizeof(USART1_RX_buf));USART1_RX_STA = 0;//processuint8_t *temp_string;//intermediate variablestemp_string = (uint8_t *)ctrl_string;USART1_SendWord(temp_string);delay_ms_1(500);MESH_cmd(DISABLE);BLE_status_it();}if((USART1_RX_STA & (uint16_t)(1<<15)) == 0)//No messagereturn;    if(('0' != USART1_RX_buf[1]) && ('1' != USART1_RX_buf[1]))//non-phone message{memset(USART1_RX_buf, 0, sizeof(USART1_RX_buf));USART1_RX_STA = 0;return;}if((USART1_RX_STA & (uint16_t)(1<<15)) == 0x8000)//Get phone message{if (0 != (USART1_RX_STA & 0X0001))//invaild cmd{USART1_SendWord("Invaild message...");memset(USART1_RX_buf, 0, sizeof(USART1_RX_buf));USART1_RX_STA = 0;return;}uint8_t id;//get the iduint8_t sta;//get the statusuint16_t i = 0;while (i < (USART1_RX_STA & 0x7fff)){id = USART1_RX_buf[i];sta = USART1_RX_buf[i+1];id -= 48;//ascii code offset compasationctrl_string[id+1] = sta;i += 2;}memset(USART1_RX_buf, 0, sizeof(USART1_RX_buf));USART1_RX_STA = 0;AT_Send("+++a");AT_Send("AT+DISCONN\r\n");AT_Send("AT+ENTM\r\n");delay_ms_1(100);MESH_cmd(ENABLE);BLE_status_it();}#endif
  • 手机查询节点信息
void node_info_query(void)
{uint8_t *temp_string;//intermediate variables// uint8_t *node_info_string = "N2: 0\r\nN3: 0\r\nN4: 0\r\nN5: 0\r\nN6: 0\r\nN7: 0\r\nN8: 0\r\nN9: 0\r\n";//record the status of nodeuint8_t k = 4, j = 0;temp_string = (uint8_t *)ctrl_string;temp_string += 3;uint8_t i =strlen(temp_string);i *= 7;uint8_t *node_info_string = (uint8_t *)malloc(i+1);//record the status of nodememset(node_info_string, 0, sizeof(node_info_string));for (i = 0; i < (strlen(temp_string) * 7); i+=7){node_info_string[i] = 'N';node_info_string[i+1] = '2' + j;node_info_string[i+2] = ':';node_info_string[i+3] = ' ';node_info_string[i+4] = '0';node_info_string[i+5] = '\r';node_info_string[i+6] = '\n';j++;}node_info_string+=4;*node_info_string = *temp_string;temp_string++;   while (*temp_string){node_info_string+=7;*node_info_string = *temp_string;k+=7;temp_string++;}node_info_string-=k;data_packet_process(node_info_string);free(node_info_string);//release the romnode_info_string = NULL;
}

结语

模块简单易上手,但是也存在许多坑。组网模式下的蓝牙机制资料过少,在处理大字节包时重传机制可能会造成丢包,追尾。蓝牙模式的转换需要预留时间,否则无法正常发包。


官方资料

WH-BLE103软件手册
WH-BLE103 MESH官方案例
STM8L151K4数据手册
EIDE手册

WH-BLE103蓝牙芯片组网测试相关推荐

  1. 网络设备集成测试/组网测试拓扑/组网自适应自动化配置脚本示例

    思路: 本文是网络设备集成测试/组网测试自动化配置脚本的示例. 主要诉求是能够自适应拓扑变化和组网方式变化. 例中使用的是cisco模拟器,IOS版本是12.4. 本例中演示了域内MPLS/BGP V ...

  2. 红米5+plus+信号显示无服务器,我的瞎折腾,红米AX5路由器MESH组网测试

    我的瞎折腾,红米AX5路由器MESH组网测试 2020-08-23 10:42:04 77点赞 443收藏 110评论 创作立场声明:路由器自己买的,我这不是客观测评,纯属主观瞎BB,我写的就是我使用 ...

  3. 西门子消防主机FC18配套CAN光端机进行光纤冗余环网组网测试

    项目背景: 1.三台西门子消防主机FC18组成光纤冗余环网: 2.单台设备或一段线路出现故障时,不影响网络内其它设备正常工作. 组网和测试方案025-68250795: 1.西门子消防主机FC18通过 ...

  4. 蓝牙芯片测试,蓝牙双模芯片协议栈测试认证,如何完成蓝牙芯片的测试认证,蓝牙芯片协议栈是什么?

    蓝牙芯片作为蓝牙产业链上游关键性元器件,直接关系着下游使用厂家蓝牙之间的互操作性和一致性,SIG组织有专门的测试标准和规范定义了这些测试. 下面以深光标准技术的蓝牙双模芯片项目为例,总体上有两部分的内 ...

  5. 杰理之mesh组网测试demo【篇】

    蓝牙Mesh网络是用于建立多对多(many:many)设备通信的低能耗蓝牙(Bluetooth Low Energy,也称为Bluetooth LE)的网络拓扑,网络中包含的蓝牙设备之间可以相互进行信 ...

  6. lte接口流程图_请画出LTE系统的组网图及标注接口。

    匿名用户 1级 2017-03-20 回答 摘要 快速发展的数据业务对于无线网络的数据传输能力要求越来越高,LTE技术在这种需求下应运而生.反映数据下载能力的下行流量是衡量LTE系统性能的一个极其重要 ...

  7. 测试软件jm,JM3818无线静态应变测试分析系统

    JM3818无线静态应变测试分析系统每台仪器8点,可无限扩展.特别适合测点分布相对分散的工程测试场合. 系统支持有线和无线组网测试方式.有线方式支持单台USB接口直接联机测试:多台之间通过总线级联组网 ...

  8. 【转】全屋WiFi覆盖无死角,Mesh组网是最佳选择!领势MR9000X组网实测

    很多游戏爱好者都会被WiFi网络所困扰.市面上的很多低端路由器,在信号覆盖和延迟上往往不尽如人意. 晚上下班回家,兴冲冲地想来盘王者.结果排队的时候就被卡掉线了.玩到一半起身去趟wc,走到一半遇到Wi ...

  9. SRv6测试技术简介

    什么是SRv6? SRv6技术就是采用现有的IPv6转发技术,通过扩展IPv6报文的头域,实现类似标签转发的处理.SRv6将一些IPv6地址定义成实例化的SID(Segment ID),每个SID有着 ...

最新文章

  1. linux规则及别名设置
  2. 45. GameProject9+输入检测
  3. pyscripter与python的关系_【转】PyScripter启动出错:Python could not be properly initialized. We must quit....
  4. JS保留4位小数(合集)
  5. linux eth_p_ip,linux数据链路访问之ETH_P_ALL等等
  6. delphi formshow 刷新_OPPO K7x部分配置和外观公布90Hz刷新率11·4发布
  7. Linux运维基础入门(二):网络基础知识梳理02
  8. 用代码理解ObjC中的发送消息和消息转发
  9. 零基础学启发式算法(4)-模拟退火 (Simulated Annealing)
  10. 网易云音乐云盘存歌曲加歌词
  11. HTTP代理socks5哪个快
  12. Qt实现全局键盘事件监听器-Windows
  13. Egret引擎的EUI基础使用教程
  14. 按日查看项目的预算成本和实际成本
  15. RollPitchYaw傻傻分不清
  16. 最强nba体验服显示服务器正在停机,最强nba体验服安装包
  17. Glyphs App Essential Training Glyphs App基础教程 Lynda课程中文字幕
  18. 51单片机外部中断的C51编程
  19. 你知道怎么查看 IP 地址吗?
  20. 解决 ffmpeg yasm not found, use --disable-yasm for a crippled build

热门文章

  1. 成人高考考试有技巧?看完如考神附体
  2. java飞机大战流程图_JAVA课程设计——飞机大战(团队)
  3. Dell Crowbar用途
  4. LVS基本概念及要诀(优化)
  5. Tomcat 9 下载与安装【个人总结】
  6. iOS开发高级分享 - App间账号共享与SDK封装
  7. 大厂面试官告诉你,这些问题,你最好别在面试时候问
  8. 最新官方有道翻译接口破解调用(详)
  9. Linux实战教学笔记36:PHP服务缓存加速深度优化实践
  10. 亲子沟通技巧学前教育培训.pptx