[其他ST产品]

STM32 串口 FIFO

[复制链接]
836|15
手机看帖
扫描二维码
随时随地手机跟帖
梵蒂冈是神uy|  楼主 | 2023-11-28 16:24 | 显示全部楼层 |阅读模式
使用FIFO实现串口数据的收发功能


1、Cubemx串口配置

        使用Cubmx对串口进行配置如下:

751806565a3ac8e4ce.png


384066565a3b96d0ff.png

677466565a3bf8b2f7.png


使用特权

评论回复
梵蒂冈是神uy|  楼主 | 2023-11-28 16:24 | 显示全部楼层
2、驱动程序编写
2.1驱动初始化
        进行串口收发FIFO的创建,进行发送FIFO回调函数的初始化,调用函数UsartStartCloseHT实现串口DMA+IDLE模式接收,同时关闭DMA的半满中断,减少进中断次数。
/**
***************************************************
* [url=home.php?mod=space&uid=247401]@brief[/url]    bsp_uart_Init
* [url=home.php?mod=space&uid=536309]@NOTE[/url]     串口初始化
*                     FIFO的初始化,以DMA IDLE 模式开启接收
* @param        NONE
* @retval          NONE
* [url=home.php?mod=space&uid=130263]@DATA[/url]           2021.09.03
* [url=home.php?mod=space&uid=638116]@auth[/url]           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);
}

使用特权

评论回复
梵蒂冈是神uy|  楼主 | 2023-11-28 16:25 | 显示全部楼层
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;
}

使用特权

评论回复
梵蒂冈是神uy|  楼主 | 2023-11-28 16:25 | 显示全部楼层
2.2串口接收处理
        使用HAL库使能串口接收DMA+IDLE后,串口在接收完成或DMA满后会进入到中断中,并调用回调函数HAL_UARTEx_RxEventCallback,我们在该函数中将接收到的数据进行FIFO写入操作。

使用特权

评论回复
梵蒂冈是神uy|  楼主 | 2023-11-28 16:25 | 显示全部楼层
  串口接收过程中我们使用了两个缓冲区,中断中进行缓冲区的切换及数据向FIFO的写入操作。

使用特权

评论回复
梵蒂冈是神uy|  楼主 | 2023-11-28 16:25 | 显示全部楼层
/**
***************************************************
* @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]);
                }
        }
}

使用特权

评论回复
梵蒂冈是神uy|  楼主 | 2023-11-28 16:25 | 显示全部楼层
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;
}

使用特权

评论回复
梵蒂冈是神uy|  楼主 | 2023-11-28 16:25 | 显示全部楼层
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);
}

使用特权

评论回复
梵蒂冈是神uy|  楼主 | 2023-11-28 16:26 | 显示全部楼层
/**
***************************************************
* @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);
                        }
                }
        }
}

使用特权

评论回复
梵蒂冈是神uy|  楼主 | 2023-11-28 16:26 | 显示全部楼层
2.3串口FIFO的定时器功能
        FIFO定时器遍历FIFO链表

        对接收FIFO实现备份缓冲到FIFO的写入操作

        对发送FIFO实现未发送完成数据的继续发送。

使用特权

评论回复
梵蒂冈是神uy|  楼主 | 2023-11-28 16:26 | 显示全部楼层
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);
        }
}

使用特权

评论回复
梵蒂冈是神uy|  楼主 | 2023-11-28 16:26 | 显示全部楼层
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);
}

使用特权

评论回复
梵蒂冈是神uy|  楼主 | 2023-11-28 16:26 | 显示全部楼层
#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

使用特权

评论回复
公羊子丹| | 2024-7-11 07:17 | 显示全部楼层

防雷电路的输出残压值必须比被防护电路自身能够耐受的过电压峰值低,并有一定裕量

使用特权

评论回复
万图| | 2024-7-11 08:20 | 显示全部楼层

模信号是幅度相等且相位相同的信号

使用特权

评论回复
Uriah| | 2024-7-11 09:23 | 显示全部楼层

在完成测试后,需要分析测试结果并进行评估

使用特权

评论回复
帛灿灿| | 2024-7-11 11:19 | 显示全部楼层

构成各种滤波器对EMI进行滤波

使用特权

评论回复
Bblythe| | 2024-7-11 12:22 | 显示全部楼层

在动态测试之前,首先需要设定测试时间和测试频率

使用特权

评论回复
周半梅| | 2024-7-11 14:18 | 显示全部楼层

测试负载测试是在特定的测试条件下进行的

使用特权

评论回复
Pulitzer| | 2024-7-11 15:21 | 显示全部楼层

在测试中,可以改变负载电流,得到最大输出电流和输出电压

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

49

主题

694

帖子

1

粉丝