STM32 UART DMA打印和接收

本文介绍如何使用DMA和USART空闲中断在STM32上实现高效数据传输,避免了频繁中断对CPU效率的影响。通过具体代码示例,展示了如何配置DMA进行数据接收和发送,以及如何处理接收完成和错误情况。

 

DMA,全称为: Direct Memory Access,即直接存储器访问。 DMA 传输方式无需 CPU 直接
控制传输,也没有中断处理方式那样保留现场和恢复现场的过程,通过硬件为 RAM 与 I/O 设备
开辟一条直接传送数据的通路, 能使 CPU 的效率大为提高。

 

普通usart中断接收数据利用的是频繁的发生中断,影响CPU效率。

DMA接收 + 串口空闲中断 可以高效解决这个问题

 

下载https://download.youkuaiyun.com/download/sudaroot/12100167

下面是STM32CbueMX USART1 DMA 配置设置

 

下面是2020-01-13文章更新

 

变量定义,用法含义如其名:

#define     UART_BUFFER_SIZE        1024

uint32_t ReceiveError = 0;
uint32_t ReceiveLength = 0;
uint32_t TransmitLength = 0;
uint32_t ReceiveComplete = 0;
uint32_t TransmitComplete = 1;
uint8_t  aRxBuffer[UART_BUFFER_SIZE] = {0};
uint8_t  aTxBuffer[UART_BUFFER_SIZE] = {0};

通过DMA打印,使用方法和printf一样。

void UART_Printf_DMA(char *format, ...)
{
    va_list args;
    uint32_t length;

    //---等待上一帧数据发送完成------------------------
    while(TransmitComplete != 1);

    TransmitComplete = 0;
    va_start(args, format);
    length = vsnprintf((char *)aTxBuffer, UART_BUFFER_SIZE, format, args);
    va_end(args);    
    HAL_UART_Transmit_DMA(&huart1, (uint8_t *)aTxBuffer, length);
}

void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
    if(huart->Instance == USART1)
    {
        memset(aTxBuffer, 0, TransmitLength);
        __HAL_UART_CLEAR_FLAG(&huart1, UART_FLAG_TC);
        TransmitComplete = 1;  // UART_DMA 发送完成标志
    }
}

 

UART_DMA接收数据,高效原理是利用了串口空闲中断(UART_IT_IDLE)及空闲标志位(UART_FLAG_IDLE)

void UART1_IT_IDLE_ReceiveDMA(void)
{
	if (__HAL_UART_GET_IT_SOURCE(&huart1, UART_IT_IDLE) != RESET  \
        && __HAL_UART_GET_FLAG(&huart1, UART_FLAG_IDLE) == SET)
	{
		__HAL_UART_CLEAR_FLAG(&huart1, UART_FLAG_RXNE);
		__HAL_UART_CLEAR_IDLEFLAG(&huart1);
		HAL_UART_DMAStop(&huart1);
		ReceiveLength = UART_BUFFER_SIZE - (__HAL_DMA_GET_COUNTER(huart1.hdmarx));

		if (ReceiveLength < 3 || aRxBuffer[ReceiveLength - 2] != 0x0D   \
            || aRxBuffer[ReceiveLength - 1] != 0x0A)        
			HAL_UART_Receive_DMA(&huart1, aRxBuffer, UART_BUFFER_SIZE);        
		else  ReceiveComplete = 1;    //接收完成         
	}
}

中断函数:

void USART1_IRQHandler(void)
{
    UART1_IT_IDLE_ReceiveDMA();

    HAL_UART_IRQHandler(&huart1);
}

接收错误,接收的数据长度超过缓存区的最大长度

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    if(huart->Instance == USART1)
    {
        ReceiveError = 1;    // 接收超过最大缓存区,ERROR
    }
}

 

主函数:

int main(void)
{
    HAL_Init();
    SystemClock_Config();
    __HAL_RCC_DMA2_CLK_ENABLE();
    MX_GPIO_Init();
    MX_DMA_Init();
    MX_USART1_UART_Init();
    __HAL_UART_DISABLE_IT(&huart1, UART_IT_IDLE);
    __HAL_UART_CLEAR_FLAG(&huart1, UART_FLAG_RXNE);
    __HAL_UART_CLEAR_IDLEFLAG(&huart1);
    __HAL_UART_CLEAR_FLAG(&huart1, UART_FLAG_TC);
    __HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);
    HAL_UART_Receive_DMA(&huart1, aRxBuffer, UART_BUFFER_SIZE);

    while (1)
    {
        if(ReceiveComplete == 1)
        {
            while(TransmitComplete != 1);

            TransmitComplete = 0;
            ReceiveComplete = 0;
            TransmitLength = ReceiveLength;
            memcpy(aTxBuffer, aRxBuffer, TransmitLength);
            HAL_UART_Transmit_DMA(&huart1, (uint8_t *)aTxBuffer, TransmitLength);
            HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
            HAL_UART_Receive_DMA(&huart1, aRxBuffer, UART_BUFFER_SIZE);
        }

        if(ReceiveError == 1)   Error_Handler();
    }
}

 

效果图:1ms定时发送回显测试,发送173036字节,回显173036字节。

 

 

 

 

 

全篇完。

本人博客仅仅代表我个人见解方便记录成长笔记。

若有与 看官老爷见解有冲突,我坚信看官老爷见解是对的,我的是错的。

感谢~!

<think>好的,用户的问题是关于如何在STM32中使用UARTDMA时关闭接收功能。我需要先理解用户的具体需求。用户可能正在开发一个项目,需要通过UART发送数据,但不需要接收数据,或者想暂时关闭接收以节省资源或避免干扰。首先,我应该回忆STM32UARTDMA相关配置。UART接收功能通常涉及DMA通道的配置,比如使用DMA来循环接收数据到缓冲区。要关闭接收功能,可能需要停止DMA传输,禁用相关中断,并关闭UART接收使能位。接下来,参考用户提供的引用内容。引用[1]提到了DMA发送完成中断的处理,包括清除标志禁用DMA通道。引用[2]讨论了USART3的DMA接收配置,特别是环形缓冲区的设置。引用[3]展示了UART初始化DMA相关的头文件定义,这可能涉及到DMA的初始化控制函数。根据这些信息,关闭接收功能的步骤可能包括: 1.停止DMA接收通道:使用DMA_Cmd函数禁用对应的DMA通道。2.关闭UART接收中断:可能需要禁用UART的中断,如RXNE(接收寄存器非空中断)。3.复位UART接收相关的DMA请求:通过UART的CR3寄存器来断开DMA接收的关联。 4.清理DMAUART的标志位,避免残留中断触发。 此外,用户提供的代码示例中有处理DMA发送完成中断的函数,这可能对如何处理DMA的禁用有帮助。例如,在引用[1]中,DMA通道在传输完成后被禁用,并清除了相关标志。这可能适用于发送,但接收方面需要类似的操作,不过针对接收DMA通道中断。需要注意的是,不同的STM32系列或库版本(如标准库、HAL库)可能有不同的函数配置方式。用户可能使用的是标准库,因为引用中的代码使用了DMA_Cmd等函数,而HAL库则使用不同的接口。因此,在回答时要明确是基于标准库的实现。另外,用户可能希望完全关闭接收功能,而不仅仅是暂停,所以需要确保UART接收器被禁用,而不仅仅是DMA。这可能需要修改UART的CR1寄存器,关闭RE(接收使能)位。总结步骤: -停止DMA接收通道。 -禁用UART接收相关中断。-断开DMAUART接收的关联。-关闭UART接收功能。 -清理标志位。同时,需要提供代码示例,比如如何调用库函数来实现这些步骤。还要考虑可能的问题,比如如果在传输过程中突然关闭接收,是否会导致数据丢失或错误,以及如何安全地处理这种情况。 最后,生成相关问题,帮助用户进一步了解相关主题,比如如何重新启用接收,如何配置DMA的双向传输,或者如何处理DMA错误中断等。</think>在STM32中关闭UARTDMA接收功能需要结合硬件配置软件控制,以下是具体实现步骤: --- ### **一、关闭DMA接收通道** 1. **停止DMA传输** 通过库函数禁用DMA接收通道: ```c DMA_Cmd(DMA1_ChannelX, DISABLE); // 标准库写法,X为对应的DMA通道号 ``` 或使用HAL库: ```c HAL_DMA_Abort(&hdma_usartX_rx); // 终止接收DMA ``` 2. **清除DMA请求映射** 在UART的CR3寄存器中关闭DMA接收请求: ```c USART_DMACmd(USARTX, USART_DMAReq_Rx, DISABLE); // 标准库 ``` HAL库通过配置外设实现自动关联。 --- ### **二、关闭UART接收功能** 1. **禁用UART接收器** 修改UART的CR1寄存器,关闭接收使能位: ```c USART_ReceiveCmd(USARTX, DISABLE); // 标准库 ``` 或直接操作寄存器: ```c USARTX->CR1 &= ~USART_CR1_RE; // 关闭接收器 ``` 2. **关闭接收中断** 禁用UART接收相关中断(如RXNE中断): ```c USART_ITConfig(USARTX, USART_IT_RXNE, DISABLE); // 标准库 ``` --- ### **三、清理标志位** 清除可能触发的残留中断标志,防止误进入中断服务程序: ```c USART_ClearFlag(USARTX, USART_FLAG_RXNE); // 清除接收标志 DMA_ClearFlag(DMA1_FLAG_TCX); // 清除DMA传输完成标志 ``` --- ### **代码示例(标准库)** ```c void UART_DisableRxDMA(USART_TypeDef* USARTX, DMA_Channel_TypeDef* DMA_Ch) { // 1. 关闭DMA接收通道 DMA_Cmd(DMA_Ch, DISABLE); // 2. 断开UARTDMA的映射 USART_DMACmd(USARTX, USART_DMAReq_Rx, DISABLE); // 3. 关闭UART接收器 USART_ReceiveCmd(USARTX, DISABLE); // 4. 清理标志位 USART_ClearFlag(USARTX, USART_FLAG_RXNE); DMA_ClearFlag(DMA1_FLAG_TC4); // 根据实际通道号修改 } ``` --- ### **关键点** - **DMA配置差异**:若接收DMA配置为循环模式(如引用[2]中提到的环形缓冲区),需先改为单次模式再关闭,否则可能残留未处理请求[^2]。 - **中断安全**:在关闭过程中需临时屏蔽中断,避免操作过程中被中断打断[^1]。 - **硬件关联性**:部分STM32型号的UARTDMA通道有固定映射关系(如USART3_RX对应DMA1_Channel6),需根据数据手册确认通道号[^3]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值