OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 82|回复: 1

同一个程序里面使用DMA接收和DMA发送出现问题

[复制链接]

5

主题

29

帖子

0

精华

初级会员

Rank: 2

积分
193
金钱
193
注册时间
2020-8-16
在线时间
39 小时
发表于 5 天前 | 显示全部楼层 |阅读模式
5金钱
在进行DMA接收和DMA发送时会出现发送两次的情况,主程序循环用DMA发送收到的数据,没有加延时就会发生发送两次的情况,加入一段时间延时就不会出现,但是开启了DMA的中断服务函数应该是发送完成就会进入中断清零,不明白为什么会发送两次相同的数据

UART_HandleTypeDef g_uart1_handle;  /* UART句柄 */
UART_HandleTypeDef g_uart2_handle;  /* UART句柄 */
UART_HandleTypeDef g_uart3_handle;  /* UART句柄 */
DMA_HandleTypeDef dma1_rx_handle;
DMA_HandleTypeDef dma1_tx_handle;
#if USART1_EN/*如果使能了串口1*/

/* 接收缓冲, 最大USART_REC_LEN个字节. */
uint8_t g_usart1_rx_buf[USART1_REC_LEN];
uint8_t g_usart1_rx_cnt = 0;

void usart1_init(uint32_t baudrate)
{
        GPIO_InitTypeDef gpio_init_struct;
      
        __HAL_RCC_GPIOA_CLK_ENABLE();
        __HAL_RCC_USART1_CLK_ENABLE();
      
        gpio_init_struct.Pin = GPIO_PIN_9;               /* 串口发送引脚号 */
        gpio_init_struct.Mode = GPIO_MODE_AF_PP;                /* 复用推挽输出 */
        gpio_init_struct.Pull = GPIO_PULLUP;                    /* 上拉 */
        gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;          /* IO速度设置为高速 */
        HAL_GPIO_Init(GPIOA, &gpio_init_struct);
                       
        gpio_init_struct.Pin = GPIO_PIN_10;               /* 串口RX脚 模式设置 */
        gpio_init_struct.Mode = GPIO_MODE_AF_INPUT;   
        HAL_GPIO_Init(GPIOA, &gpio_init_struct);   /* 串口RX脚 必须设置成输入模式 */

    /*UART 初始化设置*/
    g_uart1_handle.Instance = USART1;                                       /* USART_UX */
    g_uart1_handle.Init.BaudRate = baudrate;                                  /* 波特率 */
    g_uart1_handle.Init.WordLength = UART_WORDLENGTH_8B;                      /* 字长为8位数据格式 */
    g_uart1_handle.Init.StopBits = UART_STOPBITS_1;                           /* 一个停止位 */
    g_uart1_handle.Init.Parity = UART_PARITY_NONE;                            /* 无奇偶校验位 */
    g_uart1_handle.Init.HwFlowCtl = UART_HWCONTROL_NONE;                      /* 无硬件流控 */
    g_uart1_handle.Init.Mode = UART_MODE_TX_RX;                               /* 收发模式 */
    HAL_UART_Init(&g_uart1_handle);                                           /* HAL_UART_Init()会使能UART1 */

#if USART1_EN_RX
        __HAL_UART_ENABLE_IT(&g_uart1_handle, UART_IT_IDLE);
        __HAL_UART_ENABLE_IT(&g_uart1_handle, UART_IT_RXNE);
        HAL_NVIC_EnableIRQ(USART1_IRQn);                      /* 使能USART1中断通道 */
        HAL_NVIC_SetPriority(USART1_IRQn, 0, 1);              /* 组2,最低优先级:抢占优先级3,子优先级3 */
#endif

#if USART1_DMA_RX
        __HAL_RCC_DMA1_CLK_ENABLE();

        dma1_rx_handle.Instance = DMA1_Channel5;             //指令基地址
        dma1_rx_handle.Init.Direction = DMA_PERIPH_TO_MEMORY; //外设到内存

        dma1_rx_handle.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;//8字节对齐
        dma1_rx_handle.Init.MemInc           = DMA_MINC_ENABLE;

        dma1_rx_handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;//8字节对齐
        dma1_rx_handle.Init.PeriphInc           = DMA_PINC_DISABLE;

        dma1_rx_handle.Init.Priority            = DMA_PRIORITY_MEDIUM;
        dma1_rx_handle.Init.Mode                = DMA_NORMAL;
        HAL_DMA_Init(&dma1_rx_handle);

        __HAL_LINKDMA(&g_uart1_handle,hdmarx,dma1_rx_handle);//在函数中将句柄与dma建立关联

        //将uart1_handle的数据保存到串口的缓冲区,串口大小
        HAL_UART_Receive_DMA(&g_uart1_handle, g_usart1_rx_buf,USART1_REC_LEN);
#endif

#if USART1_DMA_TX

        __HAL_RCC_DMA1_CLK_ENABLE();
      
        dma1_tx_handle.Instance = DMA1_Channel4;                               /* USART1_TX使用的DMA通道为: DMA1_Channel4 */
    dma1_tx_handle.Init.Direction = DMA_MEMORY_TO_PERIPH;             /* DIR = 1 , 存储器到外设模式 */
    dma1_tx_handle.Init.PeriphInc = DMA_PINC_DISABLE;                 /* 外设非增量模式 */
    dma1_tx_handle.Init.MemInc = DMA_MINC_ENABLE;                     /* 存储器增量模式 */
    dma1_tx_handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;    /* 外设数据长度:8位 */
    dma1_tx_handle.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;       /* 存储器数据长度:8位 */
    dma1_tx_handle.Init.Mode = DMA_NORMAL;                            /* DMA模式:正常模式 */
    dma1_tx_handle.Init.Priority = DMA_PRIORITY_MEDIUM;               /* 中等优先级 */

    HAL_DMA_Init(&dma1_tx_handle);
    __HAL_LINKDMA(&g_uart1_handle,hdmatx,dma1_tx_handle);
      
        HAL_NVIC_EnableIRQ(DMA1_Channel4_IRQn);                      /* 使能USART1中断通道 */
        HAL_NVIC_SetPriority(DMA1_Channel4_IRQn, 0, 2);              /* 组2,最低优先级:抢占优先级3,子优先级3 */
      

#endif
}

void DMA1_Channel4_IRQHandler(void)
{
        if ( __HAL_DMA_GET_FLAG(&dma1_tx_handle, DMA_FLAG_TC4))   /* 等待 DMA1_Channel4 传输完成 */
        {
                __HAL_DMA_CLEAR_FLAG(&dma1_tx_handle, DMA_FLAG_TC4);
                g_usart1_rx_cnt = 0;
                HAL_UART_DMAStop(&g_uart1_handle);                  /* 传输完成以后关闭串口DMA */
                HAL_UART_Receive_DMA(&g_uart1_handle,g_usart1_rx_buf,USART1_REC_LEN);
        }
}

void USART1_IRQHandler(void)
{
#if SYS_SUPPORT_OS                          /* 使用OS */
    OSIntEnter();   
#endif
      
        uint8_t res;
        static uint16_t len;
#if USART1_DMA_RX
        if ((__HAL_UART_GET_FLAG(&g_uart1_handle, UART_FLAG_IDLE) != RESET)) /* 接收到数据 */
    {
                //清除空闲中断
                __HAL_UART_CLEAR_IDLEFLAG(&g_uart1_handle);
                //停止DMA传输干扰
                HAL_UART_DMAStop(&g_uart1_handle);
                //获取接收到的数据长度 当前还有多少个数据没有传输
                len = USART1_REC_LEN - __HAL_DMA_GET_COUNTER(&dma1_rx_handle);
                //打印接收到的内容
//                HAL_UART_Transmit(&g_uart1_handle, g_usart1_rx_buf, len, 1000);
               
                //清空接收缓冲
//                memset(g_usart1_rx_buf,0,sizeof(len));
                g_usart1_rx_cnt = len;
                len = 0;
                //重新开启dma传输
                //使能串口接收  串口句柄,串口接收的缓冲区,size
                HAL_UART_Receive_DMA(&g_uart1_handle,g_usart1_rx_buf,USART1_REC_LEN);
    }
#else
    if ((__HAL_UART_GET_FLAG(&g_uart1_handle, UART_FLAG_RXNE) != RESET)) /* 接收到数据 */
    {
        HAL_UART_Receive(&g_uart1_handle, &res, 1, 1000);

        if (len < USART1_REC_LEN)         /* 缓冲区未满 */
        {
            g_usart1_rx_buf[len] = res;   /* 记录接收到的值 */
            len++;                       /* 接收数据增加1 */
        }
    }
        if ((__HAL_UART_GET_FLAG(&g_uart1_handle, UART_FLAG_IDLE) != RESET)) /* 接收到数据 */
    {
                __HAL_UART_CLEAR_IDLEFLAG(&g_uart1_handle); // 清除IDLE中断标志位
                HAL_UART_Transmit_DMA(&g_uart1_handle, g_usart1_rx_buf, len);
                g_usart1_rx_cnt = len;
                len = 0;
               
    }
#endif


#if SYS_SUPPORT_OS                          /* 使用OS */
    OSIntExit();
#endif

}

#endif

主程序就只有while循环发送收到的数据
while(1)
    {
                HAL_UART_Transmit_DMA(&g_uart1_handle, g_usart1_rx_buf, g_usart1_rx_cnt);
    }

最佳答案

查看完整内容[请看2#楼]

已经找到问题,应该是在DMA发送中主程序循环又再次进入了DMA发送所以导致有的时候会发送两次
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

5

主题

29

帖子

0

精华

初级会员

Rank: 2

积分
193
金钱
193
注册时间
2020-8-16
在线时间
39 小时
 楼主| 发表于 5 天前 | 显示全部楼层
已经找到问题,应该是在DMA发送中主程序循环又再次进入了DMA发送所以导致有的时候会发送两次
回复

使用道具 举报

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

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-3-31 07:17

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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