打印
[STM32H7]

STM32H750 UART 空闲中断 +DMA传输

[复制链接]
41|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
tpgf|  楼主 | 2024-11-7 10:00 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
STM32H750在使用串口外设配合DMA,和其他不带高速数据缓冲区的MCU差别就是,在调用DMA收发函数时,如果开启了数据高速缓存区,需要对将要调用的数据存储区域进行缓存清空处理。因为DMA传输的数据不在高速缓冲区范围内。如果不是调用DMA相关收发函数,就不需要此操作。



开启缓冲区
  /* Enable I-Cache---------------------------------------------------------*/
  SCB_EnableICache();
  /* Enable D-Cache---------------------------------------------------------*/
  SCB_EnableDCache();


清除指定缓冲区方法
SCB_CleanDCache_by_Addr((uint32_t *)UART_RX_STA, UART_RX_LEN);
SCB_CleanInvalidateDCache_by_Addr ((uint32_t *)UART_RX_STA, UART_RX_LEN);//或者


如果开启了MPU功能,需要注意所定义的变量存储位置在可读写范围内,不是定义在MPU内存保护区地址内,否则无法存储所接收的数据。
串口接收事件中断回调(HAL_UARTEx_RxEventCallback )和接收完成中断回调(HAL_UART_RxCpltCallback )差异说明
HAL_UARTEx_RxEventCallback 和 HAL_UART_RxCpltCallback 是两个不同的回调函数,它们在STM32的HAL库中用于处理UART(通用异步收发传输器)的接收事件。

HAL_UART_RxCpltCallback: 这个回调函数在UART接收完成时被调用。当UART接收到指定数量的数据(通常是一个字节或一个数据包)后,DMA(直接内存访问)传输完成,此时会触发这个回调函数。
◦ 它通常用于处理接收到的数据,例如将数据存储到缓冲区或进行进一步的处理。

HAL_UARTEx_RxEventCallback: 这个回调函数在UART接收到数据时被调用,而不仅仅是在接收完成时。它可以在接收到每个字节或每个数据包时被触发,具体取决于UART的配置。与 HAL_UART_RxCpltCallback 不同,HAL_UARTEx_RxEventCallback 提供了更细粒度的控制,可以在数据接收的过程中进行实时处理。
总结:
• HAL_UART_RxCpltCallback 在UART接收完成时调用,用于处理接收到的完整数据。
• HAL_UARTEx_RxEventCallback 在UART接收到数据时调用,可以在数据接收的过程中进行实时处理。
采用不同的接收回调函数,决定了中断处理内容的不同。具体使用哪种方式,可以根据具体的实际需求来设定中断回调。

STM32CubeMX工程配置
串口外设的基本配置:无特殊要求,默认参数即可



串口DMA配置参数





使能串口全局中断



业务代码完善
开启串口DMA接收
HAL_UART_Receive_DMA(&huart1,UART_RX_BUF,UART_RX_LEN);//开启DMA串口接收



开启空闲中断
        __HAL_UART_ENABLE_IT(&huart1,UART_IT_IDLE);//空闲中断


串口中断处理函数
void USART1_IRQHandler(void)
{
  /* USER CODE BEGIN USART1_IRQn 0 */

  /* USER CODE END USART1_IRQn 0 */
  HAL_UART_IRQHandler(&huart1);
  /* USER CODE BEGIN USART1_IRQn 1 */
if(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_IDLE) != RESET)  // 空闲中断标记被置位
        {
            __HAL_UART_CLEAR_IDLEFLAG(&huart1);  // 清除中断标记
            HAL_UART_DMAStop(&huart1);           // 停止DMA接收
            UART_RX_STA = UART_RX_LEN - __HAL_DMA_GET_COUNTER(huart1.hdmarx);  // 总数据量减去未接收到的数据量为已经接收到的数据量
            UART_RX_BUF[UART_RX_STA] = 0;  // 添加结束符
            UART_RX_STA |= 0X8000;         // 标记接收结束
            HAL_UART_Receive_DMA(&huart1, UART_RX_BUF, UART_RX_LEN);  // 重新启动DMA接收
        }
  /* USER CODE END USART1_IRQn 1 */
}





串口接收完成,数据处理内容:
                if(UART_RX_STA & 0X8000)
{
                                        SCB_CleanDCache_by_Addr((uint32_t *)UART_RX_STA, UART_RX_LEN);
        //                                SCB_CleanInvalidateDCache_by_Addr ((uint8_t *)UART_RX_STA, UART_RX_LEN);//或者
                        HAL_UART_Transmit_DMA(&huart1,(uint8_t *)UART_RX_BUF, UART_RX_STA & 0X7FFF);//配合上面的函数一起使用
//        HAL_UART_Transmit(&huart1, UART_RX_BUF, UART_RX_STA & 0X7FFF, 100);    // 将接收到的数据发送回去
        UART_RX_STA = 0;  // 清除标记
}


接收事件回调实现方法
在中断处理函数中添加:
void USART1_IRQHandler(void)
{
  /* USER CODE BEGIN USART1_IRQn 0 */

  /* USER CODE END USART1_IRQn 0 */
  HAL_UART_IRQHandler(&huart1);
  /* USER CODE BEGIN USART1_IRQn 1 */

        HAL_UARTEx_ReceiveToIdle_DMA(&huart1,UART_RX_BUF,UART_RX_LEN);        //重新开启串口空闲中断和DMA接收,一定要放在这里
  /* USER CODE END USART1_IRQn 1 */
}


添加接收事件回调函数处理内容:
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
        if(huart->Instance == USART1)
        {

            UART_RX_STA = UART_RX_LEN - __HAL_DMA_GET_COUNTER(huart1.hdmarx);  // 总数据量减去未接收到的数据量为已经接收到的数据量
                UART_RX_BUF[UART_RX_STA] = 0;  // 添加结束符
                UART_RX_STA |= 0X8000;         // 标记接收结束
                __HAL_UNLOCK(huart);
                HAL_UARTEx_ReceiveToIdle_DMA(&huart1,UART_RX_BUF,UART_RX_LEN) ;
                HAL_GPIO_TogglePin(GPIOE,GPIO_PIN_12 ) ;
        }

}


main串口接收空闲中断初始化
在main外设初始化后,添加:

HAL_UARTEx_ReceiveToIdle_DMA(&huart1,UART_RX_BUF,UART_RX_LEN) ;


接收数据回调事件,数据处理内容:
                if(UART_RX_STA & 0X8000)
{
                                        SCB_CleanDCache_by_Addr((uint32_t *)UART_RX_STA, UART_RX_LEN);
                        //                SCB_CleanInvalidateDCache_by_Addr ((uint32_t *)UART_RX_STA, UART_RX_LEN);//或者
                        HAL_UART_Transmit_DMA(&huart1,(uint8_t *)UART_RX_BUF, UART_RX_STA & 0X7FFF);//配合上面的函数一起使用
//        HAL_UART_Transmit(&huart1, UART_RX_BUF, UART_RX_STA & 0X7FFF, 100);    // 将接收到的数据发送回去
        UART_RX_STA = 0;  // 清除标记
}
————————————————

                            本文为Perseverance52博主原创文章,未经博主允许,不得转载!

原文链接:https://blog.csdn.net/weixin_42880082/article/details/143470897

使用特权

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

本版积分规则

1897

主题

15568

帖子

11

粉丝