Bootstrap

STM32CubeMX_配置UART_+DMA实现不定长数据发送和接收

STM32CubeMX_配置UART_+DMA实现不定长数据发送和接收

本文写作写时使用的平台:

STM32CubeMX 版本:6.6.1

MCU:STM32F103CBT6

在STM32CubeMX生成工程

1.先设置串口配置,波特率

在这里插入图片描述

2.把DMA接收设置成为循环模式。

在这里插入图片描述

3.打开uart中断,同时设置好对应的优先级

在这里插入图片描述

然后生成代码。

修改工程代码

1.修改void MX_USART1_UART_Init(void)函数中的代码,加入如下代码打开空闲中断

__HAL_UART_CLEAR_IDLEFLAG(&huart1);
__HAL_UART_ENABLE_IT(&huart1,UART_IT_IDLE);

2.定义缓存区和dma发送标志

#define USART1_BUFFER_SIZE           32

uint8_t usart1_tx_buffer[USART1_BUFFER_SIZE] ={0};
uint8_t usart1_rx_buffer[USART1_BUFFER_SIZE] ={0};

volatile uint8_t usart1_tx_dma_status = 0;
volatile uint8_t usart1_rx_dma_status = 0;

3.添加初始化函数

lp_err_t bsp_st32_uart1_init(void)
{
	lp_err_t ret = LP_OK;
	
    if(HAL_UART_Receive_DMA(&huart1,usart1_rx_buffer,USART1_BUFFER_SIZE) != HAL_OK) //这个函数最要是设置接收缓存区
    {
        //error
		LOG_OUT("bsp_st32_uart1_init Fail\r\n");
		ret = LP_FAIL;
    }
	
	return ret;
}

4.新增两个函数一个是发送完成回调,一个接收完成回调。

extern
lp_err_t lp_sys_os_serial_rev_data_complete_hook(lp_u8_t serial_register,lp_u8_t* data,lp_u16_t len);
void UART_RxIdleCallback(UART_HandleTypeDef *huart,DMA_HandleTypeDef *hdma_usart_rx)
{
	uint8_t dma_recv_len;
     
	if(huart->Instance == USART1){
	
		if(__HAL_UART_GET_FLAG(huart,UART_FLAG_IDLE)){
			__HAL_UART_CLEAR_IDLEFLAG(huart);
			HAL_UART_DMAStop(huart);
			
			dma_recv_len = USART1_BUFFER_SIZE - __HAL_DMA_GET_COUNTER(hdma_usart_rx);//这个是本次接收到的长度
            //这个是我自己封装好的接收的数据放入队列
			lp_sys_os_serial_rev_data_complete_hook(LP_UART1_E,&usart1_rx_buffer[0],dma_recv_len);
            //再次打开DMA
			HAL_UART_Receive_DMA(huart,usart1_rx_buffer,USART1_BUFFER_SIZE);
		
		}
	}
    
}

extern
lp_err_t lp_sys_os_serial_tx_data_complete_hook(lp_u8_t serial_register);
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
    if(huart->Instance == USART1)
    {
		usart1_tx_dma_status = 0; //发送完成标志设置为空闲
        //发送完成回调可以用来做一些清理的工作,比如485ctl 设置为接收。
		lp_sys_os_serial_tx_data_complete_hook(LP_UART1_E);
    }
}

5.把函数void UART_RxIdleCallback(UART_HandleTypeDef *huart,DMA_HandleTypeDef *hdma_usart_rx)在空闲中断中调用

void UART_RxIdleCallback(UART_HandleTypeDef *huart,DMA_HandleTypeDef *hdma_usart_rx);
void USART1_IRQHandler(void)
{
  /* USER CODE BEGIN USART1_IRQn 0 */

  /* USER CODE END USART1_IRQn 0 */
  HAL_UART_IRQHandler(&huart1);
  /* USER CODE BEGIN USART1_IRQn 1 */
	
	UART_RxIdleCallback(&huart1,&hdma_usart1_rx);
  /* USER CODE END USART1_IRQn 1 */
}

6.封装发送函数

lp_err_t bsp_st32_uart1_send(lp_u8_t *data,lp_u16_t len)
{
	
	if(usart1_tx_dma_status != 0)
	{
		return LP_FAIL;
	}

	usart1_tx_dma_status = 1;
    if(HAL_UART_Transmit_DMA(&huart1,data,len) != HAL_OK)
    {
        //error
		LOG_OUT("HAL_UART_Transmit_DMA Fail\r\n");
    }
	
	return LP_OK;
}


lp_err_t bsp_st32_uart1_send_is_busy(void)
{
	
	if(usart1_tx_dma_status == 0)
	{
		return LP_OK;
	}

	return LP_FAIL;
}
```c

lp_err_t bsp_st32_uart1_send_is_busy(void)
{
	
	if(usart1_tx_dma_status == 0)
	{
		return LP_OK;
	}

	return LP_FAIL;
}

完成编译

;