STM32和STM32CubeMX实现UART不定长接收数据 保姆级教程
最近在做的项目上要用到4G模块,4G模块跟我的板子之间,其实是通过串口通信的,也就是UART,我板子上的芯片是STM32G474VET6,这个芯片有3个UART,随便用一个就行,所以,搞4G通信完全没有问题。但是,4G模块接收的时候,你不知道对方会发多长的信息来,这个时候,就需要实现用UART来接收不定长的数据。网上的文章和视频有很多,我也来写个保姆级的教程,做个笔记,以备我将来查找方便。
好了,直接上教程。
1. 用STM32CubeMX进行配置,我用的是UART2

上面都是默认的,不用改

在DMA Settings里面,点Add,选RX,CubeMX就都给你搞定了,其他都不用改。

可以看一下中断配置里,DMA相关中断已经默认配置好了。
注意,此处UART的中断也要勾上。
2. 相关代码
可以看到,main.c里面有这些变量
UART_HandleTypeDef huart2;
DMA_HandleTypeDef hdma_usart2_rx;
我为了通信,另外声明了这些变量
uint8_t rx2_buf[RX2_BUFFER_SIZE]= {0}; // uart2 receiver buffer
uint8_t mqtt_recv_flag = 0; // 0: idel; 1: recving; 2: recved
然后,uart.h是这样的
#ifndef _UART_H_
#define _UART_H_
#include "main.h"
#include "string.h"
void uart2_sendstr(uint8_t *str);
#define RX2_BUFFER_SIZE 1024
extern uint8_t rx2_buf[RX2_BUFFER_SIZE];
extern uint8_t mqtt_recv_flag;
extern UART_HandleTypeDef huart2;
extern DMA_HandleTypeDef hdma_usart2_rx;
#endif /* _UART_H_ */
需要说明一下,因为不知道会接收到多少信息,rx2_buf的大小要设大一点,这里设定的是1024。否则会覆盖掉数据。
uart.c是这样的
#include "uart.h"
void uart2_sendstr(uint8_t *str)
{
//HAL_UART_Transmit(&huart2, str, strlen((char*)str), HAL_MAX_DELAY);
HAL_UART_Transmit(&huart2, str, strlen((char*)str), 1000);
}
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
if(huart->Instance == USART2)
{
HAL_UARTEx_ReceiveToIdle_DMA(huart, rx2_buf, RX2_BUFFER_SIZE);
__HAL_DMA_DISABLE_IT(&hdma_usart2_rx, DMA_IT_HT);
if(mqtt_recv_flag == 1)
{
mqtt_recv_flag = 2;
}
}
}
需要说明的是,UART接收用DMA传输后,为了接收不定长数据,要一直接收到UART的RX线上为Idle为止,所以,要用HAL_UARTEx_ReceiveToIdle_DMA,这个函数来启动UART2的接收,这个函数在启动UART的同时会启动DMA中断,同时,要用HAL_UARTEx_RxEventCallback这个中断回调函数来处理中断服务,因为这个中断回调函数在DMA传输到一半时也会触发,所以用函数__HAL_DMA_DISABLE_IT(&hdma_usart2_rx, DMA_IT_HT);把DMA传输到一半时的中断关掉。那么,只有到DMA全部传输完成才会触发这个中断回调函数。在回调函数里,接收数据,并把接收到数据的标志设为2.
在main.c里是这样处理数据的。
- 在main.c里,先启动UART2
// huart2 start, using DMA to receive Variable length data
HAL_UARTEx_ReceiveToIdle_DMA(&huart2, rx2_buf, RX2_BUFFER_SIZE);
__HAL_DMA_DISABLE_IT(&hdma_usart2_rx, DMA_IT_HT);
然后,初始化4G模块的MQTT后,mqtt_recv_flag设为1
// MQTT start
comm_4G_init();
mqtt_recv_flag=1;
主循环里
while (1)
{
if(mqtt_recv_flag==2)
{
mqtt_recv_flag=1;
usb_printf((char*)rx2_buf);
HAL_Delay(5);
}
}
当收到了4G模块的信息,就把接收标志设为1,并把信息打印出来,看收到了什么信息。
3. 结果检验


可以收到发布MQTT命令的回应,也能收到MQTT发布的topic。
好了,大功告成,亲个嘴儿。
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐

所有评论(0)