对于在项目使用多串口与不同模块通信的情况,实时数据有收有发,没有良好的接受机制与任务调度机制容易丢数据。
方法一
正常配置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实时通信
方法二