最近在做的项目上要用到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。

好了,大功告成,亲个嘴儿。

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐