使用FIFO实现串口数据的收发功能
FIFO的相关实现参照链接:CSDNhttps://mp.csdn.net/mp_blog/creation/editor/120448361
1、Cubemx串口配置
使用Cubmx对串口进行配置如下:
???????
2、驱动程序编写
2.1驱动初始化
进行串口收发FIFO的创建,进行发送FIFO回调函数的初始化,调用函数UsartStartCloseHT实现串口DMA+IDLE模式接收,同时关闭DMA的半满中断,减少进中断次数。
/**
***************************************************
* @brief bsp_uart_Init
* @note 串口初始化
* FIFO的初始化,以DMA IDLE 模式开启接收
* @param NONE
* @retval NONE
* @data 2021.09.03
* @auth WXL
* @his 1.0.0.0 2021.09.03 WXL
* create
***************************************************
**/
void bsp_uart_Init()
{Usart1RxFifo = func_fifo_Create(UART_RX_BUFF_SIZE*2,FIFO_TYPE_INT_PUSH);Usart1TxFifo = func_fifo_Create(UART_TX_BUFF_SIZE*2,FIFO_TYPE_INT_PULL);Usart1TxFifo->func_timmer = Usart1_SendInTimer;Usart6RxFifo = func_fifo_Create(UART_RX_BUFF_SIZE*2,FIFO_TYPE_INT_PUSH);Usart6TxFifo = func_fifo_Create(UART_TX_BUFF_SIZE*2,FIFO_TYPE_INT_PULL);Usart6TxFifo->func_timmer = Usart6_SendInTimer;UsartStartCloseHT(&huart1, (uint8_t*)&Usart1RxBuff[0], UART_RX_BUFF_SIZE);UsartStartCloseHT(&huart6, (uint8_t*)&Usart6RxBuff[0], UART_RX_BUFF_SIZE);
}
static void UsartStartCloseHT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
{HAL_StatusTypeDef ret = HAL_BUSY;while(ret != HAL_OK){ret = HAL_UARTEx_ReceiveToIdle_DMA(huart, pData, Size);}huart->hdmarx->Instance->CR &= (uint32_t)~DMA_IT_HT;
}
2.2串口接收处理
使用HAL库使能串口接收DMA+IDLE后,串口在接收完成或DMA满后会进入到中断中,并调用回调函数HAL_UARTEx_RxEventCallback,我们在该函数中将接收到的数据进行FIFO写入操作。
串口接收过程中我们使用了两个缓冲区,中断中进行缓冲区的切换及数据向FIFO的写入操作。
/**
***************************************************
* @brief HAL_UARTEx_RxEventCallback
* @note 串口接收中断函数
* 进行当前中断时需写入到FIFO中数量的计算???????
* 更新FIFO的状态???
* @param huart 指向对应的串???????
* Size 数量
* @retval NONE
* @data 2021.09.03
* @auth WXL
* @his 1.0.0.0 2021.09.03 WXL
* create
***************************************************
**/
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{if(huart == &huart1){if(huart1.hdmarx->Instance->M0AR == (int32_t)&Usart1RxBuff[0]){UsartStartCloseHT(&huart1, (uint8_t*)&Usart1RxBuff[1], UART_RX_BUFF_SIZE);func_fifo_PushInt(Usart1RxFifo, Size, (uint8_t*)&Usart1RxBuff[0]);}else{UsartStartCloseHT(&huart1, (uint8_t*)&Usart1RxBuff[0], UART_RX_BUFF_SIZE);func_fifo_PushInt(Usart1RxFifo, Size, (uint8_t*)&Usart1RxBuff[1]);}}if(huart == &huart6){if(huart6.hdmarx->Instance->M0AR == (int32_t)&Usart6RxBuff[0]){UsartStartCloseHT(&huart6, (uint8_t*)&Usart6RxBuff[1], UART_RX_BUFF_SIZE);func_fifo_PushInt(Usart6RxFifo, Size, (uint8_t*)&Usart6RxBuff[0]);}else{UsartStartCloseHT(&huart6, (uint8_t*)&Usart6RxBuff[0], UART_RX_BUFF_SIZE);func_fifo_PushInt(Usart6RxFifo, Size, (uint8_t*)&Usart6RxBuff[1]);}}
}
2.2串口发送处理
串口发送过程中,先将数据压入到串口发送的FIFO中,判断串口发送不繁忙时,将数据读取到发送缓冲区记性DMA发送。
/**
***************************************************
* @brief USART_SendData
* @note 串口接收中断函数
* 进行当前中断时需写入到FIFO中数量的计算??????
* 更新FIFO的状态???
* @param huart 指向对应的串??????
* Size 数量
* @retval NONE
* @data 2021.09.03
* @auth WXL
* @his 1.0.0.0 2021.09.03 WXL
* create
***************************************************
**/
FifoErr bsp_uart_Send(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
{FifoErr err = FIFO_EOK;INT16U len = 0;if(huart == &huart1){//将数据压入到发的FIFO中去err = func_fifo_Push(Usart1TxFifo, Size, pData);if (huart->gState == HAL_UART_STATE_READY){if( func_fifo_PullPartInt(Usart1TxFifo, UART_TX_BUFF_SIZE, Usart1TxBuff, &len) == FIFO_EOK){HAL_UART_Transmit_DMA(&huart1, Usart1TxBuff, len);}}return err;}if(huart == &huart6){//将数据压入到发的FIFO中去err = func_fifo_Push(Usart6TxFifo, Size, pData);if (huart->gState == HAL_UART_STATE_READY){if( func_fifo_PullPartInt(Usart6TxFifo, UART_TX_BUFF_SIZE, Usart6TxBuff, &len) == FIFO_EOK){HAL_UART_Transmit_DMA(&huart6, Usart6TxBuff, len);}}return err;}return FIFO_EFAILED;
}
DMA发送完成后会进入发送完成中断,中断对未发送完的数据进行继续发送
/**
***************************************************
* @brief HAL_UART_TxCpltCallback
* @note HAL库回调函数
* @param NONE
* @retval NONE
* @data 2021.09.03
* @auth WXL
* @his 1.0.0.0 2021.09.03 WXL
* create
***************************************************
**/
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{bsp_uart_TxCallBack(huart);
}
/**
***************************************************
* @brief bsp_uart_SendTimer
* @note 串口发送时的FIFO回调函数。
* @param NONE
* @retval NONE
* @data 2021.09.03
* @auth WXL
* @his 1.0.0.0 2021.09.03 WXL
* create
***************************************************
**/
static void bsp_uart_TxCallBack(UART_HandleTypeDef *huart)
{INT16U len = 0;if (huart->gState == HAL_UART_STATE_READY){if(huart == &huart1){HAL_GPIO_WritePin(O_SERIAL_GPIO_Port, O_SERIAL_Pin, GPIO_PIN_SET);if( func_fifo_PullPart(Usart1TxFifo, UART_TX_BUFF_SIZE, Usart1TxBuff, &len) == FIFO_EOK){HAL_UART_Transmit_DMA(&huart1, Usart1TxBuff, len);}}if(huart == &huart6){if( func_fifo_PullPart(Usart6TxFifo, UART_TX_BUFF_SIZE, Usart6TxBuff, &len) == FIFO_EOK){HAL_UART_Transmit_DMA(&huart6, Usart6TxBuff, len);}}}
}
2.3串口FIFO的定时器功能
FIFO定时器遍历FIFO链表
对接收FIFO实现备份缓冲到FIFO的写入操作
对发送FIFO实现未发送完成数据的继续发送。
2.3串口错误处理
解决串口接收发送过程中发生溢出中断等意外情况
/**
***************************************************
* @brief HAL_UART_ErrorCallback
* @note 错误中断处理
* @param huart 指向对应的串口
* @retval NONE
* @data 2021.09.17
* @auth WXL
* @his 1.0.0.0 2021.09.17 WXL
* create
***************************************************
**/
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{__HAL_UART_CLEAR_OREFLAG(huart);if(huart == &huart1){UsartStartCloseHT(&huart1, (uint8_t*)&Usart1RxBuff[1], UART_RX_BUFF_SIZE);}if(huart == &huart6){UsartStartCloseHT(&huart6, (uint8_t*)&Usart6RxBuff[0], UART_RX_BUFF_SIZE);}
}
2.3详细完整代码
/* 说明:* @实现需要的支持:* 1)USART 串口外设,进行数据接收及发送* 2)func_fifo.h 提供接收发送FIFO支持** @实现原理及功能:* 串口接收使用DMA+IDLE模式实现(关闭了DMA的半满中断)* 1)中断中在FIFO不繁忙时将接收数据写入到FIFO中。* 2)中断中在FIFO繁忙时,将数据写入到BACK区域* 通过FIFO的定时器来实现BACK数据向FIFO的写入功能。* 串口的发送使用发送完成中断结合DMA的定时器回调功能实现。* @his* ver:1.0.0.0* author:WXL* note:create 2021.09.04** ver:1.0.0.1* author:WXL* note:create 2021.09.17* 增加错误中断处理,解决串口1不接受数据的问题。*/
/************************************************************************************************************************** 宏定义
**************************************************************************************************************************/
#include "bsp_uart.h"
/************************************************************************************************************************** 宏定义
**************************************************************************************************************************/
#define UART_TX_BUFF_SIZE 1024
#define UART_RX_BUFF_SIZE 1024
/************************************************************************************************************************** 局部变量
**************************************************************************************************************************/
FifoTypeDef* Usart1RxFifo;
static FifoTypeDef* Usart1TxFifo;
static INT8U Usart1RxBuff[2][UART_RX_BUFF_SIZE]={0};
static INT8U Usart1TxBuff[UART_TX_BUFF_SIZE]={0};FifoTypeDef* Usart6RxFifo;
static FifoTypeDef* Usart6TxFifo;
static INT8U Usart6RxBuff[2][UART_RX_BUFF_SIZE]={0};
static INT8U Usart6TxBuff[UART_TX_BUFF_SIZE]={0};
/************************************************************************************************************************** 全局变量
**************************************************************************************************************************/
extern UART_HandleTypeDef huart1;
extern UART_HandleTypeDef huart6;
/************************************************************************************************************************** 局部函数
**************************************************************************************************************************//**
***************************************************
* @brief bsp_uart_SendTimer
* @note 串口发送时的FIFO回调函数。
* @param NONE
* @retval NONE
* @data 2021.09.03
* @auth WXL
* @his 1.0.0.0 2021.09.03 WXL
* create
***************************************************
**/
static void bsp_uart_TxCallBack(UART_HandleTypeDef *huart)
{INT16U len = 0;if (huart->gState == HAL_UART_STATE_READY){if(huart == &huart1){HAL_GPIO_WritePin(O_SERIAL_GPIO_Port, O_SERIAL_Pin, GPIO_PIN_SET);if( func_fifo_PullPart(Usart1TxFifo, UART_TX_BUFF_SIZE, Usart1TxBuff, &len) == FIFO_EOK){HAL_UART_Transmit_DMA(&huart1, Usart1TxBuff, len);}}if(huart == &huart6){if( func_fifo_PullPart(Usart6TxFifo, UART_TX_BUFF_SIZE, Usart6TxBuff, &len) == FIFO_EOK){HAL_UART_Transmit_DMA(&huart6, Usart6TxBuff, len);}}}
}
/**
***************************************************
* @brief Usart1_SendInTimer
* @note 串口1发送时的FIFO回调函数。
* @param NONE
* @retval NONE
* @data 2021.09.03
* @auth WXL
* @his 1.0.0.0 2021.09.03 WXL
* create
***************************************************
**/
static void Usart1_SendInTimer()
{bsp_uart_TxCallBack(&huart1);
}
/**
***************************************************
* @brief Usart6_SendInTimer
* @note 串口1发送时的FIFO回调函数。
* @param NONE
* @retval NONE
* @data 2021.09.03
* @auth WXL
* @his 1.0.0.0 2021.09.03 WXL
* create
***************************************************
**/
static void Usart6_SendInTimer()
{bsp_uart_TxCallBack(&huart6);
}
/**
***************************************************
* @brief UsartStartCloseHT
* @note 串口1发送时的FIFO回调函数。
* @param NONE
* @retval NONE
* @data 2021.09.03
* @auth WXL
* @his 1.0.0.0 2021.09.03 WXL
* create
***************************************************
**/
static void UsartStartCloseHT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
{HAL_StatusTypeDef ret = HAL_BUSY;while(ret != HAL_OK){ret = HAL_UARTEx_ReceiveToIdle_DMA(huart, pData, Size);}huart->hdmarx->Instance->CR &= (uint32_t)~DMA_IT_HT;
}
/************************************************************************************************************************** 全局函数
**************************************************************************************************************************/
/**
***************************************************
* @brief bsp_uart_Init
* @note 串口初始化
* FIFO的初始化,以DMA IDLE 模式开启接收
* @param NONE
* @retval NONE
* @data 2021.09.03
* @auth WXL
* @his 1.0.0.0 2021.09.03 WXL
* create
***************************************************
**/
void bsp_uart_Init()
{Usart1RxFifo = func_fifo_Create(UART_RX_BUFF_SIZE*2,FIFO_TYPE_INT_PUSH);Usart1TxFifo = func_fifo_Create(UART_TX_BUFF_SIZE*2,FIFO_TYPE_INT_PULL);Usart1TxFifo->func_timmer = Usart1_SendInTimer;Usart6RxFifo = func_fifo_Create(UART_RX_BUFF_SIZE*2,FIFO_TYPE_INT_PUSH);Usart6TxFifo = func_fifo_Create(UART_TX_BUFF_SIZE*2,FIFO_TYPE_INT_PULL);Usart6TxFifo->func_timmer = Usart6_SendInTimer;UsartStartCloseHT(&huart1, (uint8_t*)&Usart1RxBuff[0], UART_RX_BUFF_SIZE);UsartStartCloseHT(&huart6, (uint8_t*)&Usart6RxBuff[0], UART_RX_BUFF_SIZE);
}
/**
***************************************************
* @brief USART_SendData
* @note 串口接收中断函数
* 进行当前中断时需写入到FIFO中数量的计算??????
* 更新FIFO的状态???
* @param huart 指向对应的串??????
* Size 数量
* @retval NONE
* @data 2021.09.03
* @auth WXL
* @his 1.0.0.0 2021.09.03 WXL
* create
***************************************************
**/
FifoErr bsp_uart_Send(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
{FifoErr err = FIFO_EOK;INT16U len = 0;if(huart == &huart1){//将数据压入到发的FIFO中去err = func_fifo_Push(Usart1TxFifo, Size, pData);if (huart->gState == HAL_UART_STATE_READY){if( func_fifo_PullPartInt(Usart1TxFifo, UART_TX_BUFF_SIZE, Usart1TxBuff, &len) == FIFO_EOK){HAL_UART_Transmit_DMA(&huart1, Usart1TxBuff, len);}}return err;}if(huart == &huart6){//将数据压入到发的FIFO中去err = func_fifo_Push(Usart6TxFifo, Size, pData);if (huart->gState == HAL_UART_STATE_READY){if( func_fifo_PullPartInt(Usart6TxFifo, UART_TX_BUFF_SIZE, Usart6TxBuff, &len) == FIFO_EOK){HAL_UART_Transmit_DMA(&huart6, Usart6TxBuff, len);}}return err;}return FIFO_EFAILED;
}void bsp_uart_Test()
{INT8U temp[1024] = {0};INT16U len = 0;if(func_fifo_PullPart(Usart6RxFifo, 1024, temp,&len) == FIFO_EOK){bsp_uart_Send(&huart6, temp, len);}if(func_fifo_PullPart(Usart1RxFifo, 1024, temp,&len) == FIFO_EOK){bsp_uart_Send(&huart1, temp, len);}
}/************************************************************************************************************************** HAL库回调函数
**************************************************************************************************************************//**
***************************************************
* @brief HAL_UARTEx_RxEventCallback
* @note 串口接收中断函数
* 进行当前中断时需写入到FIFO中数量的计算???????
* 更新FIFO的状态???
* @param huart 指向对应的串???????
* Size 数量
* @retval NONE
* @data 2021.09.03
* @auth WXL
* @his 1.0.0.0 2021.09.03 WXL
* create
***************************************************
**/
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{if(huart == &huart1){if(huart1.hdmarx->Instance->M0AR == (int32_t)&Usart1RxBuff[0]){UsartStartCloseHT(&huart1, (uint8_t*)&Usart1RxBuff[1], UART_RX_BUFF_SIZE);func_fifo_PushInt(Usart1RxFifo, Size, (uint8_t*)&Usart1RxBuff[0]);}else{UsartStartCloseHT(&huart1, (uint8_t*)&Usart1RxBuff[0], UART_RX_BUFF_SIZE);func_fifo_PushInt(Usart1RxFifo, Size, (uint8_t*)&Usart1RxBuff[1]);}}if(huart == &huart6){if(huart6.hdmarx->Instance->M0AR == (int32_t)&Usart6RxBuff[0]){UsartStartCloseHT(&huart6, (uint8_t*)&Usart6RxBuff[1], UART_RX_BUFF_SIZE);func_fifo_PushInt(Usart6RxFifo, Size, (uint8_t*)&Usart6RxBuff[0]);}else{UsartStartCloseHT(&huart6, (uint8_t*)&Usart6RxBuff[0], UART_RX_BUFF_SIZE);func_fifo_PushInt(Usart6RxFifo, Size, (uint8_t*)&Usart6RxBuff[1]);}}
}
/**
***************************************************
* @brief HAL_UART_ErrorCallback
* @note 错误中断处理
* @param huart 指向对应的串口
* @retval NONE
* @data 2021.09.17
* @auth WXL
* @his 1.0.0.0 2021.09.17 WXL
* create
***************************************************
**/
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{__HAL_UART_CLEAR_OREFLAG(huart);if(huart == &huart1){UsartStartCloseHT(&huart1, (uint8_t*)&Usart1RxBuff[1], UART_RX_BUFF_SIZE);}if(huart == &huart6){UsartStartCloseHT(&huart6, (uint8_t*)&Usart6RxBuff[0], UART_RX_BUFF_SIZE);}
}/**
***************************************************
* @brief HAL_UART_TxCpltCallback
* @note HAL库回调函数
* @param NONE
* @retval NONE
* @data 2021.09.03
* @auth WXL
* @his 1.0.0.0 2021.09.03 WXL
* create
***************************************************
**/
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{bsp_uart_TxCallBack(huart);
}
#ifndef _BSP_UART_H_
#define _BSP_UART_H_
/************************************************************************************************************************** 头文件
**************************************************************************************************************************/
#include "main.h"
#include "func_fifo.h"
/************************************************************************************************************************** 全局变量申明
**************************************************************************************************************************/
extern FifoTypeDef* Usart1RxFifo;
extern FifoTypeDef* Usart6RxFifo;
/************************************************************************************************************************** 函数声明
**************************************************************************************************************************/
extern void bsp_uart_Init();
extern FifoErr bsp_uart_Send(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);
extern void bsp_uart_Test();#endif