HC-05蓝牙模块--------手机与STM32通信(代码编写)(上位机配置)保姆级教程_stm32蓝牙模块代码
阿里云国内75折 回扣 微信号:monov8 |
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6 |
⏩ 大家好哇我是小光嵌入式爱好者一个想要成为系统架构师的大三学生。
⏩因为之前无论是电赛还是做项目都用到了蓝牙模块如手机和stm32的通信电赛中的双车通信还是遥感小车的stm32与stm32的无线通信等等
⏩本篇文章对HC-05蓝牙模块与手机的通信做一个详细的使用教程。
⏩感谢你的阅读不对的地方欢迎指正。
蓝牙
一.蓝牙模块原理
1.蓝牙模块的工作原理
蓝牙设备使用无线电波连接手机和电脑。蓝牙产品包含一块小小的蓝牙模块以及支持连接的蓝牙无线电和软件。当两台蓝牙设备想要相互交流时它们需要进行配对。蓝牙设备之间的通信在短程被称为微微网指设备使用蓝牙技术连接而成的网络的临时网络中进行。这种网络可容纳两至八台设备进行连接。当网络环境创建成功一台设备作为主设备而所有其它设备作为从设备。英唐众创在蓝牙设备加入和离开无线电短程传感时动态、自动建立。
2.蓝牙模块的传输方式
随着近年来蓝牙技术的不断发展在功耗不断降低的情形下蓝牙的传输速率也不断地得到提高使蓝牙的应用范围更加广泛。但若想设计一套完善的蓝牙系统就必须充分掌握蓝牙的相关技术知识如射频设计、协议堆栈、系统集成及蓝牙模块的选型等方面的专门知识。
蓝牙模块可以通过串口SPI、IIC和MCU控制设备进行数据传输。蓝牙模块可以做为主机和从机。主机就是能够搜索别的蓝牙模块并主动建立连接从机则不能主动建立连接只能等别人连接自己。
3.蓝牙模块种类
1、HC-05蓝牙模块介绍
HC-05 蓝牙串口通讯模块以下简称模块具有两种工作模式命令响应工作模式和自动连接工作模式在自动连接工作模式下模块又可分为主Master、从Slave和回环Loopback三种工作角色。
当模块处于自动连接工作模式时将自动根据事先设定的方式进行数据传输当模块处于命令响应工作模式时能执行下述所有AT命令用户可向模块发送各种AT指令为模块设定控制参数或发布控制命令。通过控制模块外部引脚PIO11的输入电平可以实现模块两种工作模式的切换。
2、HC-06从机蓝牙模块
只能作为从机
其他的还有低功耗BLE蓝牙4.0模块(cc2540或cc2541)、JDY-10 蓝牙4.0 BLE模块等等这里我们用的是HC-05蓝牙模块作为示例。
二.手机与STM32通信
1.蓝牙模块配置
配置步骤
1按住蓝牙模块上的en按键通过USB转TTL模块接入电脑
若模块以两秒的间隔闪烁表示连接成功进入AT命令模式
注若无按键则将en引脚接高再通过USB转TTL接入电脑
2打开XCOM串口调试助手选择连接的串口配置波特率38400打开串口
注若找不到串口请检查是否安装CH340驱动。
3指令配置
输入AT+ORGL
\\恢复默认状态
返回OK
输入AT
返回OK
输入AT+NAME=xiaoguang
\\设置蓝牙设备名称
返回OK
输入AT+PSWD=1234
\\设置蓝牙设备密码
返回OK
输入AT+UART=9600,0,0
\\设置串口波特率115200,无停止位无校验位
返回OK
输入AT+CMODE=1
\\任意蓝牙地址连接
返回OK
注若除AT+NAME?
指令外未返回OK请检查蓝牙模块是否进入命令响应模式
4蓝牙模块重新上电指示灯快速闪烁打开我们手机上面的蓝牙调试器连接我们的蓝牙模块,连接后蓝牙模块以间隔两秒闪烁两次
如果找不到名字可以根据AT+ADDR?
指令查看地址进行连接
到这里说明我们的蓝牙模块已经可以和手机连接了。
2.代码编写
我们配置的通信协议是
包头(0xA5)+数据+校验位+包尾(0x5A)
我们的示例中需要接收的数据是一个int整形和一个char型一共是5个字节所以一整个的数据包就是8个字节
串口初始化以及中断服务函数配置
/*bsp_usart.h*/
#ifndef __BSP_USART_H
#define __BSP_USART_H
#include "stm32f10x.h"
#include <stdio.h>
#define REC_BUF_SIZE 8 //接收数据包的大小
#define DEBUG_USARTx USART2 //蓝牙所用串口2
#define DEBUG_USART_CLK RCC_APB1Periph_USART2 //串口时钟
#define DEBUG_USART_APBxClkCmd RCC_APB1PeriphClockCmd //串口时钟使能
#define DEBUG_USART_BAUDRATE 9600 //波特率设置·
#define DEBUG_USART_GPIO_CLK RCC_APB2Periph_GPIOA
#define DEBUG_USART_GPIO_APBxClkCmd RCC_APB2PeriphClockCmd //端口时钟
#define DEBUG_USART_TX_GPIO_PORT GPIOA //端口宏定义
#define DEBUG_USART_TX_GPIO_PIN GPIO_Pin_2
#define DEBUG_USART_RX_GPIO_PORT GPIOA
#define DEBUG_USART_RX_GPIO_PIN GPIO_Pin_3
#define DEBUG_USART_IRQ USART2_IRQn
#define DEBUG_USART_IRQHandler USART2_IRQHandler //中断服务函数
static void NVIC_Config(void);
void USART_Config(void);
void Usart_SendByte(USART_TypeDef*pUSARTx,uint8_t data);
#endif
/*bsp_usart.c*/
__IO uint8_t usart_value=0;//接收一个字节数据的变量
uint8_t len=0; //接收数据的数组当前下标
uint8_t num[20]; //存放接收一次数据包的数组
uint8_t Flag=0; //接收到数据之后Flag=1
static uint8_t f = 0; //从0xA5开始接收0x5A结束
// 中断服务函数
void DEBUG_USART_IRQHandler(void){
if(USART_GetITStatus(DEBUG_USARTx,USART_IT_RXNE)){ //接收中断标志位变化
usart_value=USART_ReceiveData(DEBUG_USARTx); //接收一个字节的数据
if(usart_value == 0xA5) //从0xA5开始
{
f = 1;
}
if(f == 1) //0xA5之后的数据存放到num[]数组
{
num[len]=usart_value;
len++;
}
}
if(len==REC_BUF_SIZE && usart_value == 0x5A){ //接收到包尾结束本次接收
Flag=1;
len=0;
f = 0;
}
else if(len > REC_BUF_SIZE){ //如果长度大于数据包的长度也结束本次接收
f = 0;
len = 0;
}
USART_ClearFlag(DEBUG_USARTx,USART_IT_RXNE); //清除中断标志位
}
看不懂可以看看注释
接收数据包代码
/*function.h*/
#ifndef __FUNCTION_H
#define __FUNCTION_H
#include "stm32f10x.h"
#include "bsp_usart.h"
#include "function.h"
typedef struct {
int num;
char c;
}INPUT;
INPUT DATARecv();//接收上位机数据
void BL_Send(USART_TypeDef*pUSARTx,u8 send_ok);//发送数据给上位机
#endif
#include "function.h"
#include "bsp_usart.h"
#include "math.h"
#include "stm32f10x_it.h"
extern uint8_t Flag;//数据包是否发送
extern uint8_t num[20];//存储上位机发出的数据包
/**************************************************************************
函数名DATARecv
作用 将中断接收的数据包导出到我们的INPUT结构体结构体和DATARccv可根据实际情况进行更改
返回值INPUT类型的结构体
使用BL_Send(DEBUG_USARTx,mode,quan)
***************************************************************************/
INPUT DATARecv(){
int a=0;
uint8_t i;
INPUT structure;
//接收一个char类型的数据
structure.c=num[1];
//接收一个int整形数据
for(i=2;i<=6;i++){
a+=num[i]<<((i-2)*8);
}
structure.num=a;
a = 0;
Flag=0; //接收完成
return structure;
}
/**************************************************************************
函数名BL_Send
作用 上位机数据显示板子发送上位机根据要发送的数据字节在调试器上设置接收数据包
参数1代表串口后面代表发送的数据可根据实际情况进行更改
参数(串口类型要发送的参数1参数2参数3)可修改个数同时也要修改发送的字节就是下面注释掉的部分
使用BL_Send(DEBUG_USARTx,mode,quan)
***************************************************************************/
void BL_Send(USART_TypeDef*pUSARTx,u8 send_ok){
u8 t;
u8 sum=0;//校验位--数据字节之和的低八位
u8 i;
Usart_SendByte(pUSARTx,0xA5);//头
///发送模式
Usart_SendByte(pUSARTx,send_ok);
sum+=send_ok;//校验位就是把数据的每一个字节相加很重要不然手机无法接收数据
Usart_SendByte(pUSARTx,sum);//校验位
Usart_SendByte(pUSARTx,0x5A);//尾
}
发送整形数代码
t=(mode>>0)&0x00FF;
sum+=t;
Usart_SendByte(pUSARTx,t);
t=(mode>>8)&0x00FF;
sum+=t;
Usart_SendByte(pUSARTx,t);
t=(mode>>16)&0x00FF;
sum+=t;
Usart_SendByte(pUSARTx,t);
t=(mode>>24)&0x00FF;
sum+=t;
Usart_SendByte(pUSARTx,t);
上位机数据包配置
1上位机发送数据包设置
包头1+ c1+num4+校验位1+包尾1= 8字节
2上位机接收数据包设置
包头1+ ok1+校验位1+包尾1= 4字节
3数据包结构设置
4编辑上位机图形界面
发送
num可编辑文本
c 开关
接收
ok 文本
三.调试结果
1.主函数示例代码
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "function.h"
extern uint8_t Flag; //数据包是否发送
INPUT Rec; //从车回馈信息
int main(void)
{
delay_init(); //延时函数初始化
LED_Init(); //初始化与LED连接的硬件接口
USART_Config(); //串口二初始化,若想更改 请在 bsp_usart.h 头文件更改配置
while(1)
{
if(Flag == 1) //接收到数据
{
Rec = DATARecv(); //将数据包的数据赋值到结构体中
if(Rec.c == 0) //如果接收到0,灭灯
LED0 = 1;
else //其他情况开灯
LED0 = 0;
BL_Send(USART2,Rec.num);//将接收的num发送回去
}
}
}
2.结果
可以看到一开始的灯是灭的我们发送了数据100返回了数据100
我们打开开关c并更改num数据小灯亮起返回数据更改
四 .总结
问题汇总
1.蓝牙模块无法进入AT命令模式
就是蓝牙模块坏了直接换一个
2.可以进入AT指令模式但是发送指令不会返回OK
蓝牙模块坏了直接换
3.手机无法与蓝牙模块连接或者找不到设置好名字的蓝牙模块
解决方法重新上电
通过AT+ADDR?查看蓝牙模块的地址找到对应的地址进行连接
4.接收不到手机上位机发送的数据
检查接收代码看看是否是我教的方法进行配置的
5.手机上位机接收不到数据
检查数据包的格式是否正确校验位是否计算正确
6.接收数据错乱
一定要像我上面的中断接收函数一样从包头开始接收包尾结束这样数据就不会错位
注如果大家还有没有解决的问题可以放在评论区或者私信我哦
总结
其实STM32和STM32通信也是一样的方法就是将上面的代码再写一份更改一下数据包接收。
上位机用的是蓝牙调试器代码是自己改的如果有需要可以私信我哦。