Keil转STM32CubeIDE笔记四
之后就是数据包的检错匹配功能。本次实验使用的是利用蓝牙通信连接移动端和单片机,实现串口收发数据包控制三盏小灯的亮灭,完成此项目的小伙伴可以自称点灯圣手了,蓝牙模块是大家生活中非常常见的设备,所以也是非常重要的,希望可以更加熟练的掌握蓝牙通信,将它运用得更加得心应手,用在更多更有趣的地方。为了避免实验的偶然性,所以还需要再做一个小测验,这回的数据包的含义是:起始位为0xAA,数据包长度为9,0x07
利用蓝牙模块串口收发数据包点亮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,最后的结果也是符合实验预期的!


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



所有评论(0)