STM32F103C8T6蓝牙3.0模块 SPP透传 兼容HC-05/06从机 JDY-31的使用方法和代码驱动
STM32F103C8T6蓝牙3.0模块 SPP透传 兼容HC-05/06从机 JDY-31的使用方法和代码驱动
文档结尾有代码下载链接
🎯 实现效果
🌟 传感器用途
基于 “SPP 透传 + HC-05/06 兼容” 的特性,JDY-31 广泛应用于需要 “串口无线化” 的场景。
1.工业控制
- 传感器无线组网:将温湿度传感器、压力传感器、电流传感器的串口数据,通过 JDY-31 传输到 PLC 或上位机,替代传统的有线布线(尤其适合车间、仓库等大面积场景,减少布线成本和维护难度)。
- 备无线控制:通过手机 APP 或电脑,向连接 JDY-31 的 PLC、变频器发送控制指令(如启停、调速),实现 “远程操控”(如流水线设备的无线调试、无人车间的简易控制)。
2. 智能家居
- 家电控制:在 Arduino 或 51 单片机上连接 JDY-31,通过手机蓝牙 APP 发送指令(如 “开灯”“关窗帘”),控制继电器、电机等执行器,实现 “蓝牙智能家居”(无需 WiFi,适合小范围场景,如卧室、书房)。
- 数据反馈:将智能插座、加湿器的运行数据(如功率、湿度)通过 JDY-31 传输到手机,实时查看设备状态(如 “插座当前功率是否超标”“室内湿度是否达标”)。
3. 消费电子与 DIY 项目
- 蓝牙串口调试:替代传统的 USB-TTL 模块,用 JDY-31 连接单片机(如 STM32),通过手机或电脑的蓝牙串口助手查看调试信息(无需接线,适合移动场景调试,如机器人、无人机)。
- DIY 智能设备:在创客项目中(如蓝牙小车、蓝牙电子秤),用 JDY-31 作为从机,接收手机发送的控制指令(如 “前进”“后退”)或传输数据(如电子秤的重量数据),开发门槛低且成本可控。
4. 医疗与健康设备
- 便携医疗设备:在血压计、血糖仪等设备中集成 JDY-31,将测量数据(如血压值、血糖值)无线传输到手机 APP,方便用户记录历史数据(无需手动输入,适合老年人或医护人员使用)。
- 健康监测:在心率手环、睡眠监测仪中,用 JDY-31 传输低速率的生理数据(如心率、睡眠时长),无需复杂的 WiFi 模块,降低设备功耗和成本(适合民用级健康产品)。
🌟 传感器的介绍
蓝牙 3.0 是由蓝牙技术联盟(SIG)于 2009 年发布的经典蓝牙版本,核心定位是 “平衡传输速率与功耗”,为中低速数据交互场景提供稳定支持,其关键特性如下:
- 高速传输能力:支持EDR技术,理论最高传输速率可达 24Mbps,相比蓝牙 2.0 速率提升 3 倍以上,能快速传输串口设备的批量数据。
- 适中功耗表现:虽不具备蓝牙 4.0+BLE(低功耗蓝牙)的 “超低功耗” 特性,但蓝牙 3.0 的 “间歇通信” 机制(无数据时进入休眠),可满足多数民用 / 工业设备的续航需求(如电池供电的传感器,续航可达数天至数月,视通信频率而定)。
- 广泛兼容性:向下兼容蓝牙 2.0/2.1 版本,可与手机、平板、电脑(Windows/macOS)等主流设备的蓝牙功能直接配对,无需额外驱动。
1.关键技术
- SPP(Serial Port Profile,串行端口协议)是经典蓝牙的核心协议之一,其本质是 “在蓝牙链路中模拟一个物理串口(如 RS232/TTL)”。对用户而言,无需理解复杂的蓝牙底层协议(如 L2CAP、HCI),只需像操作传统有线串口一样,通过 “发送 / 接收串口数据” 实现无线通信。
- “透传” 即 “透明传输”——JDY-31 接收串口端(如单片机、传感器)发来的数据后,不进行任何解析或修改,直接通过蓝牙链路转发给配对设备(如手机、电脑);反之,蓝牙端接收的数据也会原封不动地通过串口发送给终端设备。
2.优势
- 开发门槛低:无需学习蓝牙协议栈,仅需掌握串口通信(如波特率、数据位、停止位配置)即可。
- 兼容性强:支持所有具备串口的设备(如 51 单片机、Arduino、PLC、传感器),且与主流操作系统(Windows、Android、iOS)的串口工具(如 SSCOM、蓝牙串口助手)无缝适配。
- 数据可靠:内置 CRC 校验、重传机制,确保数据在短距离(10-20 米空旷环境)传输中无丢失、无错码。
🎯 单片机连接硬件图
🌟 驱动思路
步骤 1:硬件初始化
- 配置串口:波特率为 9600bps,数据位设为 8 位,停止位 1 位,无校验位。
步骤 2:数据透传交互
- 完成初始化配置后,蓝牙模块进入透传模式(无需额外指令,直接透明转发串口数据),此时 STM32 需构建完整的双向数据交互机制:
- 发送数据:STM32 将需传输的信息(如传感器数据、设备状态)通过串口发送给蓝牙模块,模块自动无线转发给已配对的外部设备(如手机 APP);
- 接收与解析:外部设备(如手机)发送的指令(如控制命令)经蓝牙模块转发至 STM32,STM32 接收后解析指令(如识别 “开灯”“启动电机”),并执行对应操作(如控制 GPIO、驱动外设)。
🎯 单片机程序代码
main.c
#include "stm32f10x.h"
#include "string.h"
#include "stdio.h"
#include "delay.h"
#include "bsp_usart.h"
#include "oled.h"int cnt=0;
char OledBuff[52];
int flag=0;
int main(void)
{NVIC_PriorityGroupConfig (NVIC_PriorityGroup_2);SysTick_Init(72); //系统时钟初始化 usart1_init(115200);//串口1初始化printf("USART1 OK!\r\n");usart2_init(9600);//串口1初始化usart3_init(115200);//串口3初始化 OLED_Init();OLED_ShowString(36,0,"JDY-31");//:+CONNECTINGwhile(1){if(strstr(buf_uart2.buf,"CONNECTED")!=NULL){flag=1;OLED_ShowString(0,2," ");OLED_ShowString(0,2,"设备连接");printf("BLE设备连接\r\n");delay_ms(100);OLED_ShowString(0,2," ");Clear_Buffer_UART2();}if(strstr(buf_uart2.buf,"+DISC:SUCCESS")!=NULL){flag=0;OLED_ShowString(0,2," "); OLED_ShowString(0,2,"设备断开");printf("BLE设备断开\r\n");delay_ms(100);Clear_Buffer_UART2();}cnt++;if(cnt%100==1&&flag==1){USART2_Send("Send Data:123",sizeof("Send Data:123"));printf("Send Data:123\r\n");OLED_ShowString(0,2,"Send Data:123");}if(buf_uart2.rx_flag==1&&flag==1){ printf("Receive Message:%s\r\n",buf_uart2.buf);OLED_ShowString(0,4," ");sprintf(OledBuff,"Rec Data:%s",buf_uart2.buf);OLED_ShowString(0,4,OledBuff);Clear_Buffer_UART2();}delay_ms(10);}
}
uart.c
#include "stm32f10x.h"
#include "bsp_usart.h"
#include "stdio.h"
#include "string.h"
#include "stm32f10x_tim.h"////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////
//加入以下代码,支持printf函数,而不需要选择use MicroLIB
#if 1
#pragma import(__use_no_semihosting)
//标准库需要的支持函数
struct __FILE
{ int handle;
}; FILE __stdout;
//定义_sys_exit()以避免使用半主机模式
int _sys_exit(int x)
{ x = x; return 0;
}
//重定义fputc函数
int fputc(int ch, FILE *f)
{ while((USART1->SR&0X40)==0);//循环发送,直到发送完毕 USART1->DR = (u8) ch; return ch;
}
#endif#if EN_USART1UART_BUF buf_uart1; //CH340
//初始化IO 串口1
//bound:波特率
void usart1_init(u32 bound){//GPIO端口设置GPIO_InitTypeDef GPIO_InitStructure;USART_InitTypeDef USART_InitStructure;NVIC_InitTypeDef NVIC_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE); //使能USART1,GPIOA时钟USART_DeInit(USART1); //复位串口1//USART1_TX PA.9GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化PA9//USART1_RX PA.10GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//浮空输入GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化PA10//USART 初始化设置USART_InitStructure.USART_BaudRate = bound;//一般设置为115200;USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模式USART_Init(USART1, &USART_InitStructure); //初始化串口USART_Cmd(USART1, ENABLE); //使能串口 #if EN_USART1_RX USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启相关中断USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);//开启相关中断USART_ClearFlag(USART1, USART_FLAG_TC);//Usart1 NVIC 配置NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;//串口1中断通道NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3;//抢占优先级3NVIC_InitStructure.NVIC_IRQChannelSubPriority =3; //子优先级3NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器、#endif}/*********************************串口1的服务函数*************************************************/
void USART1_Send_byte(char data)
{while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);USART_SendData(USART1, data);
}
/*-------------------------------------------------*/
/*函数名:串口1 发送数组 */
/*参 数:bound:波特率 */
/*返回值:无 */
/*-------------------------------------------------*/
void USART1_Send(char *Data,uint16_t Len)
{ uint16_t i;for(i=0; i<Len; i++){USART1_Send_byte(Data[i]);}
}
void USART1_SendStr(char*SendBuf)//串口1打印数据
{while(*SendBuf){while((USART1->SR&0X40)==0);//等待发送完成 USART1->DR = (u8) *SendBuf; SendBuf++;}
}/*****************************************************
清空电脑反馈的缓冲数据 串口1
*****************************************************/
void Clear_Buffer_UART1(void)//清空缓存
{buf_uart1.index=0;buf_uart1.rx_flag=0;memset(buf_uart1.buf,0,BUFLEN);
}
void UART1_receive_process_event(char ch ) //串口2给4g用
{if(buf_uart1.index >= BUFLEN){buf_uart1.index = 0 ;}else{buf_uart1.buf[buf_uart1.index++] = ch;}
}//串口1的接收中断程序
void USART1_IRQHandler(void) //串口1中断服务程序
{uint8_t Res;Res=Res;if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中断,可以扩展来控制{Res=USART_ReceiveData(USART1);//接收模块的数据;UART1_receive_process_event(Res);//接收模块的数据} if(USART_GetITStatus(USART1, USART_IT_IDLE) != RESET) //模块空闲{Res=USART_ReceiveData(USART1);//接收模块的数据;buf_uart1.rx_flag=1;} } #endif#if EN_USART2
UART_BUF buf_uart2; //EC200T
//初始化IO 串口2
//pclk1:PCLK1时钟频率(Mhz)
//bound:波特率
void usart2_init(u32 bound)
{ GPIO_InitTypeDef GPIO_InitStructure;USART_InitTypeDef USART_InitStructure;NVIC_InitTypeDef NVIC_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能,GPIOA时钟RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);//USART2USART_DeInit(USART2); //复位串口2//USART2_TX PA.2GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; //PA.2GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化PA2//USART2_RX PA.3GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化PA3//USART 初始化设置USART_InitStructure.USART_BaudRate = bound;//115200USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模式USART_Init(USART2, &USART_InitStructure); //初始化串口USART_Cmd(USART2, ENABLE); //使能串口 #if EN_USART2_RX USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);//开启相关中断USART_ITConfig(USART2, USART_IT_IDLE, ENABLE);//开启相关中断//Usart1 NVIC 配置NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;//串口1中断通道NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;//抢占优先级3NVIC_InitStructure.NVIC_IRQChannelSubPriority =1; //子优先级3NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器、
#endif
}void Clear_Buffer_UART2(void)//清空缓存
{buf_uart2.index=0;buf_uart2.rx_flag=0;memset(buf_uart2.buf,0,BUFLEN);
}/*********************************串口2的服务函数*************************************************/
void USART2_Send_byte(char data)
{while(USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET);USART_SendData(USART2, data);
}/*-------------------------------------------------*/
/*函数名:串口2 发送数组 */
/*参 数:bound:波特率 */
/*返回值:无 */
/*-------------------------------------------------*/
void USART2_Send(char *Data,uint16_t Len)
{ uint16_t i;for(i=0; i<Len; i++){USART2_Send_byte(Data[i]);}
}void USART2_SendStr(char*SendBuf)//串口1打印数据
{while(*SendBuf){while((USART2->SR&0X40)==0);//等待发送完成 USART2->DR = (u8) *SendBuf; SendBuf++;}
}void usart2_receive_process_event(unsigned char ch ) //串口2给4g用
{if(buf_uart2.index >= BUFLEN){buf_uart2.index = 0 ;}else{buf_uart2.buf[buf_uart2.index++] = ch;}
}
void USART2_IRQHandler(void) //串口2接收函数
{char Res;Res=Res;if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET) //接收中断,可以扩展来控制{Res=USART_ReceiveData(USART2);//接收模块的数据;usart2_receive_process_event(Res);//接收模块的数据} if(USART_GetITStatus(USART2, USART_IT_IDLE) != RESET) //模块空闲{Res=USART_ReceiveData(USART2);//接收模块的数据;buf_uart2.rx_flag=1;}
}#endif#if EN_USART3UART_BUF buf_uart3; //TTL
void usart3_init(u32 bound)
{//GPIO端口设置GPIO_InitTypeDef GPIO_InitStructure;USART_InitTypeDef USART_InitStructure;NVIC_InitTypeDef NVIC_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //使能,GPIOA时钟RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3,ENABLE);//USART3USART_DeInit(USART3); //复位串口3//USART3_TX PB10GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; //PB10GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出GPIO_Init(GPIOB, &GPIO_InitStructure); //初始化PA2//USART3_RX PB11GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入GPIO_Init(GPIOB, &GPIO_InitStructure); //初始化PB11//USART 初始化设置USART_InitStructure.USART_BaudRate = bound;//115200USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模式USART_Init(USART3, &USART_InitStructure); //初始化串口USART_Cmd(USART3, ENABLE); //使能串口 #if EN_USART3_RX USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);//开启相关中断USART_ITConfig(USART3, USART_IT_IDLE, ENABLE);//开启相关中断USART_ClearFlag(USART3, USART_FLAG_TC);//Usart3 NVIC 配置NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;//串口3中断通道NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;//抢占优先级1NVIC_InitStructure.NVIC_IRQChannelSubPriority =3; //子优先级3NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器、
#endif}void USART3_Send_byte(char data)
{while(USART_GetFlagStatus(USART3, USART_FLAG_TXE) == RESET);USART_SendData(USART3, data);
}/*-------------------------------------------------*/
/*函数名:串口2 发送数组 */
/*参 数:bound:波特率 */
/*返回值:无 */
/*-------------------------------------------------*/
void USART3_Send(char *Data,uint16_t Len)
{ uint16_t i;for(i=0; i<Len; i++){USART3_Send_byte(Data[i]);}
}void USART3_SendStr(char*SendBuf)//串口3打印数据
{while(*SendBuf){while((USART3->SR&0X40)==0);//等待发送完成 USART3->DR = (u8) *SendBuf; SendBuf++;}
}/*****************************************************
清空电脑反馈的缓冲数据 串口1
*****************************************************/
void Clear_Buffer_UART3(void)//清空缓存
{buf_uart3.index=0;buf_uart3.rx_flag=0;memset(buf_uart3.buf,0,BUFLEN);
}
void USART3_receive_process_event(char ch ) //串口2给4g用
{if(buf_uart3.index >= BUFLEN){buf_uart3.index = 0 ;}else{buf_uart3.buf[buf_uart3.index++] = ch;}
}
void USART3_IRQHandler(void) //串口3中断服务程序
{char Res;Res=Res;if(USART_GetITStatus(USART3, USART_IT_RXNE) != RESET) //接收中断,可以扩展来控制{Res=USART_ReceiveData(USART3);//接收模块的数据;USART3_receive_process_event(Res);} if(USART_GetITStatus(USART3, USART_IT_IDLE) != RESET) //模块空闲{Res=USART_ReceiveData(USART3);//接收模块的数据;buf_uart3.rx_flag=1;}
} #endif
🎯 代码下载链接
https://download.csdn.net/download/qq_41954594/92144370?spm=1001.2014.3001.5503