STM32F407使用cube空闲中断DMA串口环形缓冲区

前面的系统配置不在赘述,直接从串口配置开,我这边使用到5组串口,具体使用按照实际需求,

1.这边需要打开DMA Settings,在Mode选择Normal,后生成代码。(注意要勾起来中断)

2.现在进入代码,创建一个.H 文件专门用于串口处理(名字按照喜欢的取就行)

#ifndef __UART_TOOL_H
#define __UART_TOOL_H

#include "usart.h"

#define RXTXBUF_SIZE 1024

/*串口环形缓冲串口接收*/
typedef struct
{
    UART_HandleTypeDef dut_huart; //为串口 huart1
    unsigned char *pRxBuf;    //接收缓冲区
    unsigned int usRxBufSize; //接收大小
    unsigned int usRxWrite;    //当前位置
    unsigned int usRxRead;   //读取位置
    unsigned char rec_end_flag; //接收完成标志位
    DMA_HandleTypeDef dut_dma; //接收DMA
    unsigned char *dmaRxbuf;  //DMA接收指针
    volatile unsigned int dmaRxlen; //DMA 接收长度

}DUT_USART_FIFO;

unsigned char GetBuf(DUT_USART_FIFO *_pUart,unsigned char *p_ucBuf,unsigned int *_usBufLen);
void UartIRQ(DUT_USART_FIFO *_pUart);
void EnabledUart(DUT_USART_FIFO *_pUart);

#endif


3.在来到创建.c阶段(同样名字用自己喜欢就行)

#include "UART_tool.h"

unsigned char GetChar(DUT_USART_FIFO *_pUart, unsigned char *_pByte)
{
    unsigned int usRxWrite=_pUart->usRxWrite;
    if (_pUart->usRxRead == usRxWrite)
    {
            return 0;
    }
    else
    {
        *_pByte = _pUart->pRxBuf[_pUart->usRxRead];
        if (++_pUart->usRxRead >= _pUart->usRxBufSize)
        {
            _pUart->usRxRead = 0;
        }
        return 1;
    }
}
unsigned char GetBuf(DUT_USART_FIFO *_pUart,unsigned char *p_ucBuf,unsigned int *_usBufLen)
{
    unsigned int i =0;
    unsigned int usRxBufSize = _pUart->usRxBufSize;
    unsigned int usDataRxNum;
    unsigned int usRxWrite,usRxRead;
    unsigned char aside;

    if ( _pUart->usRxRead == _pUart->usRxWrite )
    {
        *_usBufLen = 0;
        return 0;
    }
    usRxWrite = _pUart->usRxWrite; //usRxWrite为缓冲区下一次要写入的位置//
    usRxRead = _pUart->usRxRead;
    (usRxWrite > usRxRead) ? (usDataRxNum  = usRxWrite - usRxRead)
                           : (usDataRxNum  = usRxWrite + usRxBufSize - usRxRead);
    *_usBufLen = usDataRxNum;  
    while ( _pUart->usRxRead != _pUart->usRxWrite )
    {
         if ( i++ < usDataRxNum )
         {
             GetChar( _pUart, p_ucBuf++ );
          }
            else
            {
                GetChar( _pUart, &aside );
            }
      }
     return 1;
}

void UartIRQ(DUT_USART_FIFO *_pUart)
{
    if((__HAL_UART_GET_FLAG(&_pUart->dut_huart,UART_FLAG_IDLE) != RESET))
    {
            __HAL_UART_CLEAR_IDLEFLAG(&_pUart->dut_huart);//清除标志
            HAL_UART_DMAStop(&_pUart->dut_huart); //停止接收,这边一定要要这条,不然会出现上一条和本次接收的一起回复回来的情况
      _pUart->dmaRxlen  = RXTXBUF_SIZE - __HAL_DMA_GET_COUNTER(&_pUart->dut_dma);
//            printf("2._pUart->dmaRxlen %d\n",_pUart->dmaRxlen);
            for (unsigned int i = 0; i < _pUart->dmaRxlen; i++)
            {
                _pUart->pRxBuf[_pUart->usRxWrite]=_pUart->dmaRxbuf[i];
                if (++_pUart->usRxWrite>=_pUart->usRxBufSize)
                {
                    _pUart->usRxWrite = 0;
                }
                
            }
            memset(_pUart->dmaRxbuf,0x00,sizeof(_pUart->dmaRxbuf));
            _pUart->dmaRxlen = 0;
      _pUart->rec_end_flag = 1; // 接受完成标志位置1
            HAL_UART_Receive_DMA(&_pUart->dut_huart,_pUart->dmaRxbuf,RXTXBUF_SIZE);//重新打开DMA接收
    }  
}

void EnabledUart(DUT_USART_FIFO *_pUart)
{
    __HAL_UART_ENABLE_IT(&_pUart->dut_huart, UART_IT_IDLE); 
  HAL_UART_Receive_DMA(&_pUart->dut_huart,_pUart->dmaRxbuf,RXTXBUF_SIZE);
}

4.到 usart.c 初始化我们的结构体和打开中断

DUT_USART_FIFO g_tUART_1;

unsigned char g_tUART_1_RXBuf[RXTXBUF_SIZE]={0};

unsigned char g_DMA_1_Rxbuf[RXTXBUF_SIZE]={0}

void UART_init(void)
{
    g_tUART_1.dut_huart = huart1;
    g_tUART_1.pRxBuf = g_tUART_1_RXBuf;
    g_tUART_1.usRxBufSize = ARRAY_SIZE(g_tUART_1_RXBuf);
    g_tUART_1.usRxRead = 0;
    g_tUART_1.usRxWrite = 0;
    g_tUART_1.rec_end_flag = 0;
    g_tUART_1.dut_dma = hdma_usart1_rx;
    g_tUART_1.dmaRxbuf = g_DMA_1_Rxbuf;
    g_tUART_1.dmaRxlen = 0;
   EnabledUart(&g_tUART_1);
}

5.在中断文件下stm32f4xx_it.c 添加 UartIRQ(&g_tUART_1); 同步声明 extern DUT_USART_FIFO g_tUART_1

extern DUT_USART_FIFO g_tUART_1;

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 */
  UartIRQ(&g_tUART_1);
  /* USER CODE END USART1_IRQn 1 */
}

6.到main.C上初始化后,在死循环查询串口是否接收到信息,并且打印出来

6.看效果每隔50ms发送一次,发送S:6174,接收R:6174

  • 0
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 当STM32F407串口DMA传输完成后,会触发空闲中断。在空闲中断中,可以读取DMA传输的数据并进行处理。需要注意的是,在使用DMA传输时,需要配置DMA的循环模式和传输长度,以确保数据能够正确传输。同时,还需要配置串口空闲中断使能位,以便能够正确触发空闲中断。 ### 回答2: STM32F407作为一款强大的微控制器,集成了丰富的外设。其中,串口DMA都是常用的外设,对于高效率的数据传输来说,使用串口DMA非常有优势。 在使用串口DMA传输数据时,DMA控制器可以在串口传输数据的过程中,自动地将数据从内存中读出并写入串口寄存器中,从而大大减少了CPU的负担。同时,随着数据传输的完成,DMA控制器会生成空闲中断,通知CPU可以开始下一次数据传输。 当出现串口DMA空闲中断时,应用需要先判断当前是否存在剩余的数据需要发送。如果仍然有数据需要传输,则可以重启DMA传输,如果不再需要进行数据传输,则可以关闭DMA控制器以及相应的中断。具体的实现细节如下: 1. 初始化DMA控制器和串口外设,配置相应的传输参数,例如数据长度、传输模式等。 2. 配置空闲中断,使得DMA传输完成后能够自动生成空闲中断。 3. 在空闲中断中,先判断是否还有剩余数据需要传输。如果有,则重启DMA传输;如果没有,则关闭DMA控制器和相应的中断。 4. 在应用程序中,可以使用缓存区来存储需要传输的数据,通过修改缓存区指针来实现数据的发送和接收。 5. 为了避免出现DMA数据丢失或者数据错乱的情况,可以在应用层中实现数据的校验和重传机制。 需要注意的是,在进行串口DMA传输时,如果数据长度过长,可能会导致传输速度较慢,影响整个系统的性能。因此,在实际应用中,需要根据具体的情况来确定数据长度和传输速度的配置,以达到最优的系统性能。 ### 回答3: STM32F407是一款功能强大的微控制器,其串口DMA空闲中断是其中一个非常重要的功能。下面我们就来了解一下串口DMA空闲中断的相关知识。 1. 什么是串口DMA空闲中断使用串口进行通信时,需要不断地发送和接收数据,如果采用传统的中断方式,轮询串口状态,效率低下,且占用CPU资源。因此,STM32F407采用DMA(直接内存访问)方式进行串口数据传输,DMA在CPU不参与的情况下,直接将数据放在内存中进行传输。而串口DMA空闲中断则是用来提示DMA传输数据的空闲状态。 2. 原理 当DMA传输数据完成后,串口会发出空闲中断,告诉CPU数据已经传输完毕。此时,可以及时对数据进行处理或将数据放入缓冲区。 3. 使用方法 需要注意的是,使用串口DMA空闲中断,需要打开DMA空闲中断,并设置传输数据长度。具体步骤如下: (1)打开串口DMA传输:使用HAL库的“HAL_UART_Transmit_DMA()”函数或“HAL_UART_Receive_DMA()”函数,开启DMA传输。 (2)设置DMA空闲中断:在“HAL_UART_TxCpltCallback()”函数监听DMA传输完成,并在其中调用“HAL_UART_DMAResume()”函数,重新启动DMA传输,以此实现循环传输。 (3)使用DMA空闲中断:在“HAL_UART_IDLECallback()”函数中处理接收到的数据或将数据存储到缓冲区中。 4. 应用场景 串口DMA空闲中断广泛应用于嵌入式系统和物联网领域中,主要用于实现高效稳定的数据传输。比如,通过串口传输数据进行音频、视频、图像等非常量数据的传输和处理,以及物联网设备之间的数据通信等。 总之,串口DMA空闲中断STM32F407微控制器提供了高速,高效的数据传输方式,并为嵌入式系统和物联网应用提供了广泛的应用场景。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值