OpenEdv-开源电子网

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

STM32F103使用串口DMA空闲中断,初始化后只有第一次时接收正常的,此后的接收进入中断处理之后,DMA的剩余接收数一直....

[复制链接]

1

主题

2

帖子

0

精华

新手入门

积分
18
金钱
18
注册时间
2020-5-4
在线时间
7 小时
发表于 2021-7-17 17:30:44 | 显示全部楼层 |阅读模式
20金钱
本人使用STM32F103,串口2的DMA空闲中断,用来接收不定长的数据,初始化及处理代码如下,问题为:第一次进入中断正常处理,但是此后进入读取到的剩余传输字节一直是累加的,并不是接收一次处理完就复位,非常困惑。贴出代码如下:
USART2初始化如下:
void USART2_Init(u32 br_num)
{
        //GPIO端口设置
        GPIO_InitTypeDef GPIO_InitStructure;
        USART_InitTypeDef USART_InitStructure;
        NVIC_InitTypeDef NVIC_InitStructure;

        RCC_APB2PeriphClockCmd(RCC_USART2, ENABLE); //使能USART2,GPIOA时钟
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);

        USART_DeInit(USART2); //复位串口2
        /**USART2 GPIO Configuration   
    PA2     ------> USART2_TX
    PA3     ------> USART2_RX
        */

        GPIO_InitStructure.GPIO_Pin = USART2_Pin_TX; //PA2
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //
        GPIO_Init(GPIO_USART2, &GPIO_InitStructure);        //

        GPIO_InitStructure.GPIO_Pin = USART2_Pin_RX;                  //PA3
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //
        GPIO_Init(GPIO_USART2, &GPIO_InitStructure);                  //

        //USART2 NVIC 配置
        NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = NVIC_USART2_P; //抢占优先级3
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = NVIC_USART2_S;                  //子优先级3
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                                                  //IRQ通道使能
        NVIC_Init(&NVIC_InitStructure);                                                                                  //根据指定的参数初始化VIC寄存器

        //USART2 初始化设置
        USART_InitStructure.USART_BaudRate = br_num;                                                                        //串口波特率
        USART_InitStructure.USART_WordLength = USART_WordLength_8b;                                                //字长为8位数据格式
        USART_InitStructure.USART_StopBits = USART_StopBits_1;                                                        //一个停止位
        USART_InitStructure.USART_Parity = USART_Parity_No;                                                                //无奇偶校验位
        USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //无硬件数据流控制
        USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;                                        //收发模式

        USART_Init(USART2, &USART_InitStructure); //初始化串口2
#if USE_USART2_DMA_RX

        /* 使能串口DMA */
        USART2_DMA_Rx_Config();
        // 开启 串口空闲IDEL 中断
        USART_ITConfig(USART2, USART_IT_IDLE, ENABLE);
        // 开启串口DMA接收
        USART_DMACmd(USART2, USART_DMAReq_Rx, ENABLE);   

#else


        USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);

#endif


#if USE_USART2_DMA_TX
        // 开启串口DMA发送
        //        USART_DMACmd(DEBUG_USARTx, USART_DMAReq_Tx, ENABLE);
        USART2_DMA_Tx_Config();
#endif

        USART_Cmd(USART2, ENABLE); //使能串口2

}


DMA通道6初始化如下:


        DMA_InitTypeDef DMA_InitStructure;


        // 开启DMA时钟
        RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
        // 设置DMA源地址:串口数据寄存器地址*/
        DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)USART2_DR_ADDRESS;
        // 内存地址(要传输的变量的指针)
        DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)Usart2_Rx_Buf;
        // 方向:从内存到外设
        DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
        // 传输大小
        DMA_InitStructure.DMA_BufferSize = USART2_RX_BUFF_SIZE;
        // 外设地址不增
        DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
        // 内存地址自增
        DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
        // 外设数据单位
        DMA_InitStructure.DMA_PeripheralDataSize =
                DMA_PeripheralDataSize_Byte;
        // 内存数据单位
        DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
        // DMA模式,一次或者循环模式
        //DMA_InitStructure.DMA_Mode = DMA_Mode_Normal ;
        DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
        // 优先级:中
        DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
        // 禁止内存到内存的传输
        DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
        // 配置DMA通道
        DMA_Init(USART2_RX_DMA_CHANNEL, &DMA_InitStructure);
        // 清除DMA所有标志
        DMA_ClearFlag(DMA1_FLAG_TC6);
        DMA_ITConfig(USART2_RX_DMA_CHANNEL, DMA_IT_TE, ENABLE);
        // 使能DMA
        DMA_Cmd(USART2_RX_DMA_CHANNEL, ENABLE);



中断处理如下:


void USART2_IRQHandler(void)
{

        if ((USART2->SR & (1 << 7)) && (USART2->CR1 & USART_CR1_TXEIE))
        {
                USART2->DR = TxBuffer2[TxCounter2++]; //写DR清除中断标志
                if (TxCounter2 == count2)
                {
                        USART2->CR1 &= ~USART_CR1_TXEIE; //关闭TXE中断
                }
        }
        /*暂不使用DMA 必须要接收完才进空闲中断 CI1006发送家电控制时连续发了16帧*/
#if USE_USART2_DMA_RX
        /* 使用串口DMA */
        if (USART_GetITStatus(USART2, USART_IT_IDLE) != RESET) //串口空闲中断
        {
                /* 接收数据 */

        REMAIN_count = USART2->SR; //读SR的作用是?
        REMAIN_count = USART2->DR; //读DR的作用是?
        USART_ClearITPendingBit(USART2, USART_IT_IDLE); //清掉空闲中断      


                /* 关闭DMA ,防止干扰 */
                DMA_Cmd(USART2_RX_DMA_CHANNEL, DISABLE); /* 暂时关闭dma,数据尚未处理 */

                /* 清DMA标志位 */
                DMA_ClearFlag(DMA1_FLAG_TC6);
//        DMA_ClearFlag(DMA1_FLAG_GL6 | DMA1_FLAG_TC6 | DMA1_FLAG_TE6 | DMA1_FLAG_HT6);


        REMAIN_count=DMA_GetCurrDataCounter(USART2_RX_DMA_CHANNEL);//获取剩余字节

                memcpy(RxBuffer.DAT, Usart2_Rx_Buf, USART2_RX_BUFF_SIZE);
        printf("%d|%d|%d|\r\n",USART2_RX_BUFF_SIZE-REMAIN_count,REMAIN_count,USART2_RX_BUFF_SIZE);  

//        printf("%s\r\n",Usart2_Rx_Buf);
        memset(Usart2_Rx_Buf, 0x00, USART2_RX_BUFF_SIZE);



                /* 重新赋值计数值,必须大于等于最大可能接收到的数据帧数目 */
                USART2_RX_DMA_CHANNEL->CNDTR = USART2_RX_BUFF_SIZE;        
                /* 此处应该在处理完数据再打开*/
                DMA_Cmd(USART2_RX_DMA_CHANNEL, ENABLE);
        USART_Cmd(USART2, ENABLE); //使能串口2               
//                USART_ReceiveData(USART2);         
        }
#else
        /* 接收中断 */
        if (USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)
        {
                u8 com_data = USART2->DR;
                SN_Reply_Get(com_data);
        }
#endif
}


串口调试输出如下,每次发送接收数据都在累计,没被复位:




正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

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

本版积分规则



关闭

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

正点原子公众号

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

GMT+8, 2025-5-24 01:42

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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