利用蓝牙模块串口收发数据包点亮LED——点灯圣手篇

 

一,实验准备阶段

 

1,实验目标

利用蓝牙模块将单片机与手机连接,手机通过蓝牙调试app来发送数据包,单片机接收数据包并验证解析,使对应的LED灯引脚电平做出翻转,达成点亮对应LED灯的目标。

 

2,新建工程

点击File,选择新建工程,本期项目芯片选择为STM32F103C8T6型号

选择Next,将项目命名为serial_bluetooth(串口_蓝牙),点击完成

 

3,引脚初始化配置

LED灯选择三个,分别选择PA7,PA6,PA5,将其配置为GPIO_OUTput(输出),蓝牙模块选择USART2,对应的引脚为PA2(TX)和PA3(RX),当然小伙伴们别忘了打开SWD调试端口哦!

之后点击右方DMA,为USART2的TX和RX分别添加DMA传输通道。

所谓的DMA(Direct Memory Access,直接内存访问)是计算机系统中一种重要的数据传输技术,它允许外设(如硬盘、网卡、声卡等)直接与内存进行数据交换,而无需 CPU 的全程干预。这大大提高了数据传输效率,减轻了 CPU 的负担。下方的DMA参数保持默认即可。

当然还有点击NVIC,为我们选择的USART2以及两个DMA通道开启中断。 

 之后为USART2进行模式选择和参数配置,点击Connectivity下方的USART2,模式选择为Asynchronous(异步传输模式)(注:具体其他模式含义可查看Keil转STM32CubeIDE小白笔记三),下方参数根据蓝牙协议,需要将第一个波特率改为9600Bits/s,其余保持不变即可,也可按自己需求进行修改。

4,保存配置

点击上方Save图标或者快捷键Ctrl+S快速保存配置,然后等待CubeMX生成初始化代码。

二,代码实现

 

1,数据包的创建思想

我们首先需要创建一个数据包,里面必要的信息要有:能够区分控制哪个LED灯,能够选择LED灯的引脚电平,并且对于错误或者信息缺失的数据包要有最基本的检错筛选的能力。

所以必不可少的我们需要给三盏小灯命名,命名规则有很多,这里我便以小灯所在引脚进行命名,那么三盏小灯的名字分别就是,0x07,0x06和0x05了。

选择LED的引脚电平功能较为简单,比较常用的就是将高电平设置为0xFF,低电平设置为0x00。

之后就是数据包的检错匹配功能。一般数据包需要一个起始位,我们设置为0xAA,之后就是表示数据包的长度的信息,中间的是我们的功能实现信息,最后还需要一个校验和(即前面所有信息之和)。通过来判断起始位,比较数据包长度,判断校验和是否匹配这三项便可基本确定收到的数据包是否正确,并将不正确的数据包直接忽略。

 

2,代码实现功能

首先创建一个存放数据包的数组receive。

uint8_t receive[50];

之后接收来自移动端的数据包并存放在数组receive中,由于是未知长度的数组并且使用DMA传输通道来搬运数据,所以这里的函数应当使用 HAL_UARTEx_ReceiveToIdle_DMA();并且按住Ctrl左键点击函数,跳转函数定义处,阅读函数成员含义并进行填写。(注,此函数应放在main函数中用于第一次触发后续回调函数!)

  HAL_UARTEx_ReceiveToIdle_DMA(&huart2, receive, sizeof(receive));

 再然后完成HAL_UARTEx_ReceiveToIdle_DMA()函数后便会触发中断跳转到 HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)回调函数执行函数内部的指令,这里也是我们实现数据包判断,数据包实现功能的部分。

 

代码具体功能便不一一赘述了,结合注释,相信聪明的小伙伴们一定可以理解的

void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size){ //回调函数,当 main函数里的HAL_UARTEx_ReceiveToIdle_DMA()接收数据完成后跳转过来执行这句;
	if(huart == &huart2){                                                  //养成好习惯,进入回调函数内部第一步先判断中断是否由USART2触发
		HAL_UART_Transmit_DMA(huart, receive, sizeof(Size));               //将接收到的receive发送回主机
		if(receive[0] == 0xAA ){                                           //判断数据包起始位
			if(receive[1]==Size){                                          //判断数据包长度
				uint8_t sum=0,i=0;
				for(i=0; i< Size-1 ;i++){
					sum+=receive[i];
				}
				if(receive[Size-1]==sum){                                 //判断校验和
					for(i=2;i<Size-1;i+=2){                               //执行判断小灯的点亮或熄灭的条件判断语句
						GPIO_PinState state =GPIO_PIN_SET;
						if(receive[i+1]== 0x00){
							state = GPIO_PIN_RESET;
						}
						if(receive[i]== 0x07){                            //根据小灯命名来判断控制对应小灯的引脚电平
							HAL_GPIO_WritePin(GPIOA, GPIO_PIN_7, state);
						}
						if(receive[i]== 0x06){
							HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, state);
						}
						if(receive[i]== 0x05){
							HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, state);
						}
					}
				}
			}
		}
	}
	  HAL_UARTEx_ReceiveToIdle_DMA(&huart2, receive, sizeof(receive));     //为接收下一个数据包做准备
}

而为什么使用 HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)和

HAL_UARTEx_ReceiveToIdle_DMA()这两个函数呢,这是因为使用DMA数据传输通道结合回调函数触发中断,可以极大程度的减轻我们CPU的负担,省出更多的资源和空间让CPU能够去处理其他更加重要的任务!这是我们编程时的一个重要思想,大家需要多多运用DMA这个小助手。

 三,硬件连接

三盏小灯正极接在单片机引脚,蓝牙模块依旧是TX,RX与单片机上的USART2的PA2(TX)和PA3(RX)进行反接,GND共地,然后5V电压可以借用ST-LINK上的5V电压,接线如图

 

 

四,实验现象

我们需要使用蓝牙调试设备来给单片机发送数据包,所以需要各位小伙伴去下载一个蓝牙调试app,我这里便不多说,接下来就是打开手机的蓝牙和定位,连接蓝牙模块,并使用HEX模式发送16进制的数据包。

这里我发送的数据包的含义就是,起始位为0xAA,长度为7,操控0x07的LED开灯,操控0x05的LED开灯,数据包校验和为0xBB。实验现象如下 ,可以看到,如我们预料的一样,位于PA7上的红灯和位于PA5上的蓝灯如约亮起!

 

为了避免实验的偶然性,所以还需要再做一个小测验,这回的数据包的含义是:起始位为0xAA,数据包长度为9,0x07的LED关灯,0x06的LED开灯,0x05的LED关灯,校验和为0xC4,最后的结果也是符合实验预期的!

 

五,实验小结本次

本次实验使用的是利用蓝牙通信连接移动端和单片机,实现串口收发数据包控制三盏小灯的亮灭,完成此项目的小伙伴可以自称点灯圣手了,蓝牙模块是大家生活中非常常见的设备,所以也是非常重要的,希望可以更加熟练的掌握蓝牙通信,将它运用得更加得心应手,用在更多更有趣的地方。

 

目录

利用蓝牙模块串口收发数据包点亮LED——点灯圣手篇

一,实验准备阶段

1,实验目标

2,新建工程

3,引脚初始化配置

4,保存配置

二,代码实现

1,数据包的创建思想

2,代码实现功能

 三,硬件连接

四,实验现象


 

 

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐