多串口高速率数据收发(dma+空闲中断+fifo)

在多串口通信项目中,为防止数据丢失,采用DMA循环模式配合空闲中断和FIFO策略。方法一是利用大缓存和空闲中断持续DMA传输,识别并处理新数据。方法二是空闲中断时关闭DMA接收,处理完数据后再开启。通过任务调度和FIFO管理,实现高效稳定的数据收发。
摘要由CSDN通过智能技术生成

对于在项目使用多串口与不同模块通信的情况,实时数据有收有发,没有良好的接受机制与任务调度机制容易丢数据。

方法一

正常配置stm32cubemx,开启dma(开启循环模式)、TIM与相应中断

将缓存区取得适当大一点,充分利用缓存区空间可以提高效率

 usart.h

#include "stdio.h"   
#include "string.h"
#include "stdio.h"

#define BUFFER_SIZE  1024
extern volatile uint8_t usart1_rx_len ;           //接收一帧数据的长度
extern volatile uint8_t usart2_rx_len ;           //接收一帧数据的长度
extern uint8_t  usart1_rx_buffer[BUFFER_SIZE];    //接收数据缓存数组
extern uint8_t  usart2_rx_buffer[BUFFER_SIZE];    //接收数据缓存数组
extern volatile uint8_t numdata ;                 //接收缓存区位置标记
extern volatile uint8_t numdata1 ;                //接收缓存区位置标记

 usart.c

volatile uint8_t usart1_rx_len = 0;               //接收一帧数据的长度
volatile uint8_t usart2_rx_len = 0;               //接收一帧数据的长度
uint8_t  usart1_rx_buffer[BUFFER_SIZE]={0};       //接收数据缓存数组
uint8_t  usart2_rx_buffer[BUFFER_SIZE]={0};       //接收数据缓存数组
volatile uint8_t numdata=0 ; 
volatile uint8_t numdata1=0 ;

stm32f1xx_it.c

#include "usart.h"
#include "string.h"
#include "stdio.h"

#include "fifo.h"

/**
  * @brief This function handles USART1 global interrupt.
  */
void USART1_IRQHandler(void)
{
  /* USER CODE BEGIN USART1_IRQn 0 */
	if((__HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE) != RESET))//idle标志被置位  
	{	   
		__HAL_UART_CLEAR_IDLEFLAG(&huart1);                    //清除标志位
		usart1_rx_len =  BUFFER_SIZE - __HAL_DMA_GET_COUNTER(&hdma_usart1_rx);
		uint8_t len=usart1_rx_len-numdata;
		
		if (usart1_rx_len >= numdata)
    {
        fifo_enqueue_frame(&uart1_rec, &usart1_rx_buffer[numdata], len);		    
        numdata = usart1_rx_len;
    }
    else
    {
        uint8_t first_part_len = BUFFER_SIZE - numdata;	  		
			  uint8_t second_part_len = usart1_rx_len;
			  
        fifo_enqueue_frame(&uart1_rec, &usart1_rx_buffer[numdata], first_part_len);
        fifo_enqueue_frame(&uart1_rec, usart1_rx_buffer, second_part_len);		
        numdata = usart1_rx_len;
    }
	}
  /* USER CODE END USART1_IRQn 0 */
  HAL_UART_IRQHandler(&huart1);
  /* USER CODE BEGIN USART1_IRQn 1 */

  /* USER CODE END USART1_IRQn 1 */
}

/**
  * @brief This function handles USART2 global interrupt.
  */
void USART2_IRQHandler(void)
{
  /* USER CODE BEGIN USART2_IRQn 0 */
	if((__HAL_UART_GET_FLAG(&huart2,UART_FLAG_IDLE) != RESET))//idle标志被置位  
	{	
		__HAL_UART_CLEAR_IDLEFLAG(&huart2);                    //清除标志位
		usart2_rx_len =  BUFFER_SIZE - __HAL_DMA_GET_COUNTER(&hdma_usart2_rx); 
				
		if (usart2_rx_len >= numdata1)
    {
			  uint8_t len=usart2_rx_len-numdata1;
        fifo_enqueue_frame(&uart2_rec, &usart2_rx_buffer[numdata1], len);		    
        numdata1 = usart2_rx_len;
    }
    else
    {
        uint8_t first_part_len = BUFFER_SIZE - numdata1;	  		
			  uint8_t second_part_len = usart2_rx_len;
			  		  
        fifo_enqueue_frame(&uart2_rec, &usart2_rx_buffer[numdata1], first_part_len);
        fifo_enqueue_frame(&uart2_rec, usart2_rx_buffer, second_part_len);		
        numdata1 = usart2_rx_len;
    }
	 }
  /* USER CODE END USART2_IRQn 0 */
  HAL_UART_IRQHandler(&huart2);
  /* USER CODE BEGIN USART2_IRQn 1 */

  /* USER CODE END USART2_IRQn 1 */
}

循环模式下,在空闲中断触发后不停止dma传输,其中的关键点在于识别新传入的数据,并作相应的处理(存入fifo)

测试结果如下,usart1与usart2与PC实时通信

 方法二

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值