硬汉嵌入式论坛

 找回密码
 立即注册
12
返回列表 发新帖
楼主: 旮旯旭
收起左侧

[UART] STM32H7基于STM32CubeMX的串口DMA+空闲中断接收不定长数据实现(HAL库1.9.0自带函数实现)

  [复制链接]

5

主题

229

回帖

249

积分

高级会员

积分
249
 楼主| 发表于 2025-3-17 08:28:50 | 显示全部楼层
1350280419 发表于 2025-3-9 01:39
我额外使能字节中断才接收正常__HAL_UART_ENABLE_IT(huart, UART_IT_RXNE);
另外请教一下,如果串口数据超 ...

你用的是那个版本的HAL库,接收使能开启空闲中断的函数HAL库调用使能了呀。串口如果超过缓冲区长度你需要处理串口接收满中断,重新开启接收。接收到的数据要么丢弃,要么暂存等后续数据包合并处理
回复

使用道具 举报

1

主题

2

回帖

5

积分

新手上路

积分
5
QQ
发表于 2025-3-20 11:40:39 | 显示全部楼层
years 发表于 2022-10-31 11:44
这个测试过多个串口公用吗‘?  我用两个串口dma  发现有一个就接收不到’

同,我也是一个接收正常另一个就收不到
回复

使用道具 举报

5

主题

229

回帖

249

积分

高级会员

积分
249
 楼主| 发表于 2025-3-21 08:31:36 | 显示全部楼层
The_Last_FOX3 发表于 2025-3-20 11:40
同,我也是一个接收正常另一个就收不到

不会吧,代码上传看看,我项目里面6个串口收发DMA空闲中断的也没出问题啊
回复

使用道具 举报

0

主题

1

回帖

1

积分

新手上路

积分
1
发表于 2025-5-7 23:31:04 | 显示全部楼层
旮旯旭 发表于 2022-11-1 22:38
测试过啊,我开了4个串口接收发送没问题

我开第二个串口的时候接收的数据长度不对,请问是啥情况
回复

使用道具 举报

5

主题

229

回帖

249

积分

高级会员

积分
249
 楼主| 发表于 2025-5-8 09:11:16 | 显示全部楼层
1350280419 发表于 2025-3-9 01:39
我额外使能字节中断才接收正常__HAL_UART_ENABLE_IT(huart, UART_IT_RXNE);
另外请教一下,如果串口数据超 ...

1.你是不是直接在中断回调里面直接调用空闲接收函数了?又或者你进了错误中断没有重新开启接收吧,我使用的时候不需要开启这个__HAL_UART_ENABLE_IT(huart, UART_IT_RXNE);


2.如果串口数据超过缓冲区长度,我工程里面HAL_UARTEx_RxEventCallback 这个函数我写了开启空闲接收DMA完成的判断,内容没写
  如果超过数据长度,下面是我实际项目中用到的代码,如果有用的数据放到队列邮箱里面,无效的数据直接扔掉就行
  需要注意的是如果在中断回调里面调用HAL库的重启接收函数(BSP_UART_ReceiveMode 函数里面的这几个函数)由于HAL_LOCK的关系,
  主流程里面对应串口的发送函数需要在调用前关闭中断执行完开启中断,如下
  HAL_NVIC_DisableIRQ(eIRQn);
  HAL_UART_Transmit_IT(phuartx->huart, phuartx->pTxBuf, Size);
  HAL_NVIC_EnableIRQ(eIRQn);
  不做处理的话串口会卡死,原因就是主流程里面串口发送执行一半进入中断(HAL库串口状态此时为忙),这个时候如果中断回调里面调用接收函数会失败,因为串口此时为忙





[C] 纯文本查看 复制代码
/**
 * @brief 串口接收事件回调函数 如果是空闲中断触发ReceptionType = HAL_UART_RECEPTION_STANDARD
 * 
 * @param huart 
 * @param Size 
 */
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
    BspUart_t *phuartx = UART_GetHandlePtr(huart);
    /* HAL_UART_RECEPTION_TOIDLE 说明是DMA接收完成,或者半传输完成 */
    if (huart->ReceptionType == HAL_UART_RECEPTION_TOIDLE)
    {
        if(Size == phuartx->rxSize)
        {
            phuartx->rxLen  = Size;
            phuartx->rxFlag = 2;
            phuartx->pRxBuf[phuartx->rxSize  ] = phuartx->rxLen/256;
            phuartx->pRxBuf[phuartx->rxSize+1] = phuartx->rxLen%256;
            osStatus_t tOSStatus = osMessageQueuePut(phuartx->rxMqId, phuartx->pRxBuf, 0U, 0U);
            if(tOSStatus)
            {
                printf("tOSStatus:%d\r\n", tOSStatus);
            }
            BSP_UART_ReceiveMode(phuartx, phuartx->rxMode);
        }
    }
    /* HAL_UART_RECEPTION_STANDARD 说明是空闲中断触发的接收事件 */
    if (huart->ReceptionType == HAL_UART_RECEPTION_STANDARD)
    {
        /*结算接收到的数据长度 置rxFlag = 1,接收到一帧数据*/
        phuartx->rxLen  = Size;
        phuartx->rxFlag = 1;
        /* 如果不使用FIFO 计算接收长度,置帧接收完成标志 */
        if(phuartx->rxCache == UART_CACHE_SRAM)
        {
            osThreadFlagsSet(phuartx->threadId, UART_RX_CPLT);
        }
        /* 如果使用FIFO 缓冲区最后一个字节作为接收长度,且将数据压入缓存区 */
        else if(phuartx->rxCache == UART_CACHE_FIFO)
        {
            phuartx->pRxBuf[phuartx->rxSize  ] = phuartx->rxLen/256;
            phuartx->pRxBuf[phuartx->rxSize+1] = phuartx->rxLen%256;
            osMessageQueuePut(phuartx->rxMqId, phuartx->pRxBuf, 0U, 0U);
        }
        /* 重新开启串口接收 如果在中断里面开启接收,发送函数需要开关中断
        具体原因请看文档UART里面关于 __HAL_LOCK 说明 */
        BSP_UART_ReceiveMode(phuartx, phuartx->rxMode);
    }
}


[C] 纯文本查看 复制代码
/**
 * @brief 串口IT中断模式发送函数 pData会copy到pTxBuf
 * 
 * @param phuartx   串口句柄
 * @param pData     串口发送数据地址
 * @param Size      串口发送数据长度
 */
void BSP_UART_Transmit_IT(BspUart_t *phuartx,  uint8_t *pData, uint16_t Size)
{
    while(phuartx->txStat == UART_TX_STATE_BUSY)
    {
        
    }
    phuartx->txStat = UART_TX_STATE_BUSY;
    memcpy(phuartx->pTxBuf, pData, Size);

    IRQn_Type eIRQn = (IRQn_Type)__UART_IRQ(phuartx->huart);
    HAL_NVIC_DisableIRQ(eIRQn);
    HAL_UART_Transmit_IT(phuartx->huart, phuartx->pTxBuf, Size);
    HAL_NVIC_EnableIRQ(eIRQn);

}

/**
 * @brief 串口DMA模式发送函数 pData会copy到pTxBuf
 * 
 * @param phuartx 串口句柄
 * @param pData 发送数据的缓存地址
 * @param Size 发送数据的大小
 */
void BSP_UART_Transmit_DMA(BspUart_t *phuartx,  uint8_t *pData, uint16_t Size)
{
    while(phuartx->txStat == UART_TX_STATE_BUSY)
    {
        
    }
    phuartx->txStat = UART_TX_STATE_BUSY;
    memcpy(phuartx->pTxBuf, pData, Size);

    IRQn_Type eIRQn = (IRQn_Type)__UART_IRQ(phuartx->huart);
    HAL_NVIC_DisableIRQ(eIRQn);
    HAL_UART_Transmit_DMA(phuartx->huart, phuartx->pTxBuf, Size);
    HAL_NVIC_EnableIRQ(eIRQn);
}

[C] 纯文本查看 复制代码
void BSP_UART_ReceiveMode(BspUart_t *phuartx, uint8_t rxMode)
{
    if(rxMode == UART_RX_IDLE_DMA)
    {
        HAL_UARTEx_ReceiveToIdle_DMA(phuartx->huart, phuartx->pRxBuf, phuartx->rxSize);
    }
    else if(rxMode == UART_RX_IDLE_IT)
    {
        HAL_UARTEx_ReceiveToIdle_IT(phuartx->huart, phuartx->pRxBuf, phuartx->rxSize);
    }
    else if(rxMode == UART_RX_ONLY_DMA)
    {
        HAL_UART_Receive_DMA(phuartx->huart, phuartx->pRxBuf, phuartx->rxSize);
    }
    else /* if(rxMode == UART_RX_ONLY_IT) */ 
    {
        HAL_UART_Receive_IT(phuartx->huart, phuartx->pRxBuf, phuartx->rxSize);
    }
}

[C] 纯文本查看 复制代码
/* 串口控制句柄 */
BspUart_t *g_ptBspUart[UART_NUM];


/**
 * @brief 通过huart->Instance 来获取串口号 0~7 [USART1~USART3 UART4~5 USART6 UART7~8]
 * 
 * @param huart 
 * @return BspUart_t* 串口句柄指针
 */
static BspUart_t *UART_GetHandlePtr(UART_HandleTypeDef *huart)
{
    uint8_t idx = __UART_INDEX(huart);
    return g_ptBspUart[idx];
}

[C] 纯文本查看 复制代码
#define UART_NUM    8
#define __UART_INDEX(__HANDLE__) \
 (((__HANDLE__)->Instance == USART1 ) ? 0 : \
  ((__HANDLE__)->Instance == USART2 ) ? 1 : \
  ((__HANDLE__)->Instance == USART3 ) ? 2 : \
  ((__HANDLE__)->Instance == UART4  ) ? 3 : \
  ((__HANDLE__)->Instance == UART5  ) ? 4 : \
  ((__HANDLE__)->Instance == USART6 ) ? 5 : \
  ((__HANDLE__)->Instance == UART7  ) ? 6 : \
  ((__HANDLE__)->Instance == UART8  ) ? 7 : \
  0xFF)








回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2025-8-12 03:37 , Processed in 0.040730 second(s), 23 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表