草庐IT

基于STM32F103C8T6的HC-06蓝牙通信

qq_46015224 2023-05-18 原文

文章目录


前言 注意看 !

如果朋友们遇到了如下问题,可以仔细借鉴本文章和另一篇专门讲解蓝牙通信问题的文章,一定能够解决你在蓝牙通信时遇到的诸多困难

1.在调试蓝牙模块AT指令时无返回值

2.身边无USB转TTL模块可以直接调试蓝牙模块(本人就是由于无模块花了了整整一天才调试成功)

3.在调试蓝牙模块AT指令时存在诸多异常
(1)上位机接收数据时乱码
(2)卡死在数据接受中断当中,导致接受不了数据或者一直发送数据等异常情况。
(3)拨动,或者拔掉数据线,会出现大量的数据发送情况等异常。

如果朋友们只是想了解蓝牙通信过程或者应用思路那这篇文章基本可以满足入门的朋友。(本文章采用蓝牙模块为HC-06模块)


提示:以下是本篇文章正文内容,下面案例可供参考

一、蓝牙通信流程

最简单实际的的蓝牙通信过程就是
单片机——蓝牙——手机蓝牙app
蓝牙作为桥梁进行单片机与手机数据的交换
蓝牙就如同一个无线的USART一样,将两者连接。

二、怎么实现蓝牙通信

1.了解蓝牙模块功能

1.引脚功能:

HC-06共有4个外接引脚分别为RXD(接收数据),TXD(发送数据)
工作电源3.6-6v,我采用STM32F103C8t6的5V电源口供电。(其余两个引脚功能可以自查,如果图效率也可以不用管)

2.传输数据格式:数据位8位,停止位1位,无校验,无流控制,除了波特率以外,和基础USART串口通信设置基本一致。

2.了解蓝牙通信本质

**就是将蓝牙当做一个无线的额外的串口模块进行单片机与其他通信源的连接。
而要正确的使用串口,一定要知道的三要素是:
1.波特率 2.串口号 3.数据格式

3.进行AT命令调试

之前说过,蓝牙通信的本质就是串口通信,那么我们在AT命令调试时,也相当于串口通信,**电脑发送调试命令给单片机,单片机再发送给蓝牙,蓝牙再返还命令处理结果给单片机,单片机再上传给电脑。所以需要两个USART串口,分别连接电脑与蓝牙。
(有额外的USB转TTL模块则不需要这么麻烦)

所以,我们需要先编写串口通信的代码。

以下是usart.c文件 在其中编写串口初始化与NVIC中断管理设置
(一般都为数据接受中断,当某个串口接收到数据时,执行中断服务函数)

#include "usart.h"
//设置NVIC中断管理器
void NVIC_config(USART_TypeDef* USARTx,uint8_t USARTx_IRQn,uint8_t Sub)
{
	NVIC_InitTypeDef NVIC_InitStruct;  //构建NVIC结构体
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);         //中断优先级分组
	
	NVIC_InitStruct.NVIC_IRQChannel=USARTx_IRQn;       //设置中断源
	NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=1; //主优先级
	NVIC_InitStruct.NVIC_IRQChannelSubPriority=Sub;	     //子优先级
	
	NVIC_Init(&NVIC_InitStruct);
}


//可以多次调用,从而初始化多个USART串口
   //利用续行符来声明变量
void usart_config(GPIO_TypeDef* GPIOx, \
uint16_t USART_Pin_RX,uint16_t USART_Pin_TX, \
uint32_t USART_IO_Clock,uint32_t USART_Clock, \
USART_TypeDef* USARTx,uint8_t USARTx_IRQn,uint8_t Sub,uint32_t BaudRate)	 //对应的GPIO时钟与USART的时钟
{
	GPIO_InitTypeDef GPIO_RXInitStruct;								//两个Pin 两个结构体
	GPIO_InitTypeDef GPIO_TXInitStruct;
	USART_InitTypeDef USART_InitStruct;					//声明USART初始化结构体
	
	RCC_APB2PeriphClockCmd(USART_IO_Clock , ENABLE);      //开IO时钟
	
	GPIO_RXInitStruct.GPIO_Pin=USART_Pin_RX;	
	GPIO_RXInitStruct.GPIO_Mode=GPIO_Mode_IN_FLOATING;		//设置为浮空输入,不需要设置速度


	GPIO_TXInitStruct.GPIO_Pin=USART_Pin_TX;
	GPIO_TXInitStruct.GPIO_Mode=GPIO_Mode_AF_PP;           //要使用复用推挽输出
	GPIO_TXInitStruct.GPIO_Speed=GPIO_Speed_50MHz;
	
	GPIO_Init(GPIOx, &GPIO_RXInitStruct);       //加&指明结构体位置
	GPIO_Init(GPIOx, &GPIO_TXInitStruct);       //初始化USART 所用的 GPIO 
	
	if(USARTx_IRQn==USART1_IRQn)
	{
		RCC_APB2PeriphClockCmd(USART_Clock , ENABLE);         //开串口外设时钟
	}
	if(USARTx_IRQn==USART2_IRQn)
	{
		RCC_APB1PeriphClockCmd(USART_Clock , ENABLE); //!!!!!!时钟线不一样
	}
	USART_InitStruct.USART_BaudRate=BaudRate;					 //B Rate
	USART_InitStruct.USART_HardwareFlowControl=USART_HardwareFlowControl_None; //No controlFlow
	USART_InitStruct.USART_Mode=USART_Mode_Rx|USART_Mode_Tx; //双向
	USART_InitStruct.USART_Parity=USART_Parity_No;			 //No Parity 无校验
	USART_InitStruct.USART_StopBits=USART_StopBits_1;		 //1stop Bit
	USART_InitStruct.USART_WordLength=USART_WordLength_8b;   //8bit data
	
	USART_Init(USARTx,&USART_InitStruct);   //初始化串口结构体
	NVIC_config(USARTx,USARTx_IRQn,Sub);
	
	USART_ITConfig(USARTx, USART_IT_RXNE, ENABLE);	//使能串口接收中断
	
	USART_Cmd(USARTx,ENABLE);	//使能串口
}

可以看出来函数体中的参数较多,是为了减少编写的数次,之后调用函数体,输入对应的参数即可,注意除了USART1挂载在APB2时钟上其他都挂载在APB1上!

代码执行功能如下

NVIC_Init(&NVIC_InitStruct);//初始化NVIC中断管理器
RCC_APB2PeriphClockCmd(USART_IO_Clock , ENABLE); //开GPIO时钟
if(USARTx_IRQn==USART1_IRQn)
		RCC_APB2PeriphClockCmd(USART_Clock , ENABLE);//开串口时钟
if(USARTx_IRQn==USART2_IRQn)
		RCC_APB1PeriphClockCmd(USART_Clock , ENABLE); 
USART_Init(USARTx,&USART_InitStruct);   //初始化串口结构体
USART_ITConfig(USARTx, USART_IT_RXNE, ENABLE);	//使能串口接收中断
USART_Cmd(USARTx,ENABLE);	//使能串口

此时已经配置好了串口,还需要编写中断服务函数,编写中断服务函数时要在stm32f10x.it.c文件下编写(其他问题如函数名,中断号可自查)

uint8_t temp1;
uint8_t temp2;
void USART1_IRQHandler(void)
{
	if(USART_GetITStatus(USART1,USART_IT_RXNE) !=  RESET)//判断中断位
	{
		USART_ClearITPendingBit(USART1, USART_IT_RXNE);
		temp1 = USART_ReceiveData(USART1); //接收数据 
		usart_sendByte(USART2,temp1);
		LED1_TOOGLE;	//作为可视信号,亮灯	
	}
}

void USART2_IRQHandler(void)
{
	if(USART_GetITStatus(USART2,USART_IT_RXNE) !=  RESET)//判断中断位
	{
		USART_ClearITPendingBit(USART2, USART_IT_RXNE);
		temp2 = USART_ReceiveData(USART2); //接收数据 
		usart_sendByte(USART1,temp2);
		LED1_TOOGLE;		
	}
}

中断函数的功能与完整调试过程如下:
当上PC端发送调试命令给USART1时,接受的命令再通过USART2发送给蓝牙。
当蓝牙接收到调试命令,反馈出调试结果发送到USART2,接收到的结果再通过USART1发送到PC端。

接线方式:
STM32连接电脑任意端口

蓝牙上电后与STM32连接
蓝牙 RXD: PA2(USART2 TXD)
蓝牙 TXD: PA3(USART2 RXD)

开始调试
打开串口调试软件 设置波特率,数据格式与编写时的格式一致,开始调试
可以看到我们发送出AT后,回得到一个OK返还信息,说明调试成功,如果没有得到返还需要去找出错误原因。如果需要执行其他命令操作,比如修改密码,蓝牙名称,可以查找对应的命令表。

4.调试完成,连接通信

在进行正式通信前我们还需要下载一个蓝牙串口助手这样才能更简单的进行数据发送与接受。(要设置好接收到的数据编码,与发送出去的数据编码)
通信效果如下。

三、结尾

蓝牙通信的过程十分简单,可以说就是一个串口通信的过程,不过需要一个调试命令和连接的阶段,不过蓝牙通信可以说是我们入门STM32的一个很重要的时刻,因为无线操作永远比按键或者有线操作来得骚,可以给我们极大的发挥空间,比如可以远程控制LLED亮灭,或者蓝牙小车,远程监控等等更加高级的思路就应运而生。

但是调试的过程中遇到困难是不可避免的,打击和bug层出不穷,希望不是很富裕又想学STM32的同志们看到这篇文章时,坚持的走下去,就像在实现调试过程中,绝大部分人 包括我去询问的B站UP主,和众多帖吧老哥,都是用了额外的USB转TTL模块进行调试,不过我没有米,所以才不得不采另辟蹊径。

谢谢同志们阅读!

有关基于STM32F103C8T6的HC-06蓝牙通信的更多相关文章

  1. STM32读取串口传感器数据(颗粒物传感器,主动上传) - 2

    文章目录1.开发板选择*用到的资源2.串口通信(个人理解)3.代码分析(注释比较详细)1.主函数2.串口1配置3.串口2配置以及中断函数4.注意问题5.源码链接1.开发板选择我用的是STM32F103RCT6的板子,不过代码大概在F103系列的板子上都可以运行,我试过在野火103的霸道板上也可以,主要看一下串口对应的引脚一不一样就行了,不一样的就更改一下。*用到的资源keil5软件这里用到了两个串口资源,采集数据一个,串口通信一个,板子对应引脚如下:串口1,TX:PA9,RX:PA10串口2,TX:PA2,RX:PA32.串口通信(个人理解)我就从串口采集传感器数据这个过程说一下我自己的理解,

  2. STM32的HAL和LL库区别和性能对比 - 2

    LL库和HAL库简介LL:Low-Layer,底层库HAL:HardwareAbstractionLayer,硬件抽象层库LL库和hal库对比,很精简,这实际上是一个精简的库。LL库的配置选择如下:在STM32CUBEMX中,点击菜单的“ProjectManager”–>“AdvancedSettings”,在下面的界面中选择“AdvancedSettings”,然后在每个模块后面选择使用的库总结:1、如果使用的MCU是小容量的,那么STM32CubeLL将是最佳选择;2、如果结合可移植性和优化,使用STM32CubeHAL并使用特定的优化实现替换一些调用,可保持最大的可移植性。另外HAL和L

  3. ESP32学习入门:WiFi连接网络 - 2

    目录一、ESP32简单介绍二、ESP32Wi-Fi模块介绍三、ESP32Wi-Fi编程模型四、ESP32Wi-Fi事件处理流程 五、ESP32Wi-Fi开发环境六、ESP32Wi-Fi具体代码七、ESP32Wi-Fi代码解读6.1主程序app_main7.2自定义代码wifi_init_sta()八、ESP32Wi-Fi连接验证8.1测试方法8.2服务器模拟工具sscom58.3测试代码8.4测试结果前言为了开发一款亚马逊物联网产品,开始入手ESP32模块。为了能够记录自己的学习过程,特记录如下操作过程。一、ESP32简单介绍ESP32是一套Wi-Fi(2.4GHz)和蓝牙(4.2)双模解决方

  4. Spring Security 6.0系列【32】授权服务器篇之默认过滤器 - 2

    有道无术,术尚可求,有术无道,止于术。本系列SpringBoot版本3.0.4本系列SpringSecurity版本6.0.2本系列SpringAuthorizationServer版本1.0.2源码地址:https://gitee.com/pearl-organization/study-spring-security-demo文章目录前言1.OAuth2AuthorizationServerMetadataEndpointFilter2.OAuth2AuthorizationEndpointFilter3.OidcProviderConfigurationEndpointFilter4.N

  5. ruby - 摘要::CRC32 与 Zlib - 2

    在我的代码中,我需要使用各种算法(包括CRC32)对文件进行哈希处理。因为我还在Digest系列中使用其他加密哈希函数,所以我认为为它们维护一个一致的接口(interface)会很好。为了记录,我确实找到了digest-crc,一颗完全符合我要求的gem。问题是,Zlib是标准库的一部分,并且有一个我想重用的CRC32工作实现。此外,它是用C编写的,因此它应该提供与digest-crc相关的卓越性能,后者是纯ruby​​实现。实现Digest::CRC32一开始看起来非常简单:%w(digestzlib).each{|f|requiref}classDigest::CRC32一切正常:

  6. ruby - 安装gem : Couldn't reserve space for cygwin's heap, Win32错误487错误 - 2

    我正在尝试在我的机器上安装win32-apigem,但在构建native扩展时我遇到了一些问题:$geminstallwin32-api--no-ri--rdocTemporarilyenhancingPATHtoincludeDevKit...Buildingnativeextensions.Thiscouldtakeawhile...C:\Programs\dev_kit\bin\make.exe:***Couldn'treservespaceforcygwin'sheap,Win32error0ERROR:Errorinstallingwin32-api:ERROR:Failed

  7. Ruby 1.9 - 没有这样的文件可以加载 'win32/open3' - 2

    我在Windows上运行ruby​​1.9.2并试图移植在Ruby1.8中工作的代码。该代码使用以前运行良好的Open4.popen4。对于1.9.2,我做了以下事情:通过geminstallPOpen4安装了POpen4需要POpen4通过require'popen4'尝试像这样使用POpen4:Open4.popen4("cmd"){|io_in,io_out,io_er|...}当我这样做时,我得到了错误:nosuchfiletoload--win32/open3如果我尝试安装win32-open3(geminstallwin32-open3),我会收到错误消息:win32-op

  8. Dell Inspiron 5488加内存32G - 2

    DellInspiron5488加内存32G 原装内置内存仅仅8G,目前看,真的太小了! 1.内存型号Dell5488内存型号:DDR42666。笔记本有两个内存插槽,原装占了一个,还能扩展一个。 2.买内存如果买Dell原装笔记本内存,8G就得500块左右。 我咨询了一下,三星的笔记本内存,可以兼容。16G,299块(2023年2月23日,京东价) Dell5488内存组合,最多只能插两根16G内存。 我于是买了两根三星16G内存。装上,很爽😄 跑国产系统统信UOS,再也看不到用交换区了,32G内存,爽!  

  9. ruby-on-rails - Rails 未定义方法 `strftime' 为 "2013-03-06":String - 2

    我遇到了错误“2013-03-06”的未定义方法`strftime':String当尝试使用strftime从字符串2013-03-06正常显示日期(2013年6月3日或类似日期)时。在我的index.html.erb中执行此操作的行看起来像这样我只是在学习Rails,所以我确信这只是一个愚蠢的初学者错误,我们将不胜感激。谢谢 最佳答案 当strftime是时间/日期类的方法时,您的截止日期看起来是一个字符串。你可以试试这个:Date.parse(task.duedate).strftime("%B%e,%Y")

  10. 蓝桥杯 stm32 MCP4017 - 2

    本文代码使用HAL库。文章目录前言一、MCP4017的重要特性二、MCP4017计算RBW阻值三、MCP4017地址四、MCP4017读写函数五、CubeMX创建工程(利用ADC测量MCP4017电压)、对应代码:总结前言一、MCP4017的重要特性蓝桥杯板子上的是MCP4017T-104ELT,如图1。MCP4017是一个可编程电阻,通过写入的数值可以改变电阻的大小。重点在于6引脚(W),5引脚(B&#

随机推荐