OpenEdv-开源电子网

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

我使用了USART_IDLE中断和DMA_TC完成中断,但是DMA中断服务函数始终无法进入,跪求大佬求解!

[复制链接]

1

主题

2

帖子

0

精华

新手上路

积分
23
金钱
23
注册时间
2020-7-27
在线时间
4 小时
发表于 2022-11-11 15:52:21 | 显示全部楼层 |阅读模式
1金钱
我遇到了一个匪夷所思的问题,我开启了IDLE中断和DMA中断,其中IDLE中断是可以正常运行的,DMA中断却始终无法进入中断服务函数,哪怕在IDLE中断中用串口打印了出了dma相应的中断标志位是1,但仍然无法进入dma中断服务函数,不知道问题出在了哪里,跪求大佬指点!下面是程序..烦请各路高手过目...
----------------------------------------------------------------------------------------------------------------------------------------------------------
//dma.c配置函数,其中设置dma缓冲为5,循环模式,开启DMA1_IT_TC5中断,dma抢占优先级为1,高于usart的中断优先级
void DMA_Config(DMA_Channel_TypeDef* DMA_CHx, u32 dir, u32 cpar, u32 cmar, u16 cndtr)   //形参是在特定应用中需要格外声明的状态,该函数的作用是配置官方库函数中的 DMA_InitType 结构体
{
       
//使能DMA时钟
        RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);
       
//记录传输数据量       
        CNDTR = cndtr;
       
//配置DMA中断
        NVIC_InitStructure_DMA.NVIC_IRQChannel = DMA1_Channel5_IRQn; //开启DMA中断通道
        NVIC_InitStructure_DMA.NVIC_IRQChannelPreemptionPriority=1 ;//抢占优先级2,优先于串口中断
        NVIC_InitStructure_DMA.NVIC_IRQChannelSubPriority = 3;                //子优先级3
        NVIC_InitStructure_DMA.NVIC_IRQChannelCmd = ENABLE;                        //IRQ通道使能
        NVIC_Init(&NVIC_InitStructure_DMA);        //根据指定的参数初始化VIC寄存器
       
//去初始化DMA
        DMA_DeInit(DMA_CHx);
       
//为 DMA_InitTpyeDef 结构体成员赋值       
        DMA_InitStruct. DMA_PeripheralBaseAddr = cpar;
        DMA_InitStruct. DMA_MemoryBaseAddr = cmar;
        DMA_InitStruct. DMA_BufferSize = cndtr;
        DMA_InitStruct. DMA_Priority = DMA_Priority_Medium;
        DMA_InitStruct. DMA_DIR = dir;
        DMA_InitStruct. DMA_Mode = DMA_Mode_Circular;  //循环模式
        DMA_InitStruct. DMA_PeripheralInc = DMA_PeripheralInc_Disable;
        DMA_InitStruct. DMA_MemoryInc = DMA_MemoryInc_Enable;
        DMA_InitStruct. DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
        DMA_InitStruct. DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
        DMA_InitStruct. DMA_M2M = DMA_M2M_Disable;
       
//DMA中断标志位初始化
  DMA_ClearITPendingBit(DMA1_IT_TC5);
       
//DMA1_CH5_TC中断使能
  DMA_ITConfig(DMA_CHx,DMA1_IT_TC5, ENABLE);  //开启DMA1_CH5_TC中断,DMA传输完成标志!
       
//DMA初始化
        DMA_Init(DMA_CHx, &DMA_InitStruct);
       
//使能DMA
  DMA_Cmd(DMA_CHx, ENABLE);
       
}

----------------------------------------------------------------------------------------------------------------------------------------------------------




----------------------------------------------------------------------------------------------------------------------------------------------------------
//dma开启函数,过程为关闭dma,重新赋值dma缓冲通道,开启dma
void DMA_EnableCmd(DMA_Channel_TypeDef* DMA_CHx)
{
//每次开启DMA之前必须先重装在CNDTR,开启CNDTR之前必须关闭DMA
        DMA_Cmd(DMA_CHx, DISABLE);
       
//重装在CNDTR
        DMA_SetCurrDataCounter(DMA_CHx, CNDTR);

//开启本次DMA传输
        DMA_Cmd(DMA_CHx, ENABLE);
}


----------------------------------------------------------------------------------------------------------------------------------------------------------




----------------------------------------------------------------------------------------------------------------------------------------------------------

//DMA1_IT_TC5中断服务函数,功能是每次dma传输完成后,将MyFlag全局变量置1,但是这个中断服务函数始终进不去!!难受≧ ﹏ ≦


void DMA_EnableCmd(DMA_Channel_TypeDef* DMA_CHx)
{
//每次开启DMA之前必须先重装在CNDTR,开启CNDTR之前必须关闭DMA
        DMA_Cmd(DMA_CHx, DISABLE);
       
//重装在CNDTR
        DMA_SetCurrDataCounter(DMA_CHx, CNDTR);

//开启本次DMA传输
        DMA_Cmd(DMA_CHx, ENABLE);
}


----------------------------------------------------------------------------------------------------------------------------------------------------------





----------------------------------------------------------------------------------------------------------------------------------------------------------
//usart.c配置函数,其中开启了usart1的dma功能
void uart_init(u32 bound){

        GPIO_InitTypeDef GPIO_InitStructure;
        USART_InitTypeDef USART_InitStructure;
        NVIC_InitTypeDef NVIC_InitStructure;
         
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE);        //使能USART1,GPIOA时钟

        //USART1_TX   GPIOA.9
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;        //复用推挽输出
        GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.9

        //USART1_RX          GPIOA.10初始化
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
        GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.10  

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

         //USART 初始化设置

        USART_InitStructure.USART_BaudRate = bound;//串口波特率
        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(USART1, &USART_InitStructure); //初始化串口1
        USART_ITConfig(USART1,USART_IT_IDLE,ENABLE); //开启串口空闲检测IDLE中断
        USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE); //开启串口DMA接收
        USART_Cmd(USART1, ENABLE);                    //使能串口1

}


----------------------------------------------------------------------------------------------------------------------------------------------------------






----------------------------------------------------------------------------------------------------------------------------------------------------------
//IDLE中断服务函数,先打印dma对应的中断标志位,再打印MyFlag标志,其中MyFlag是一个全局变量,初始化为0,在dma中断服务函数中置1,也就是说如果打印得到DMA1_IT_TC5是1的话,MyFlag打印也应该得到1才对!但是实际情况是DMA1_IT_TC5打印值为1时,MyFlag依然打印值是0,说明根本没进入dma中断服务函数,要哭了...

                        if(USART_GetITStatus(USART1,USART_IT_IDLE) != RESET)
                        {
                                 DMA_FLAG = DMA_GetFlagStatus(DMA1_IT_TC5);                                 //获取DMA1_IT_TC5中断标志位
                                 printf("The DMA1_TC5 status is %d\r\n",DMA_FLAG);                            //打印DMA1_IT_TC5中断标志位
                                 printf("The MyFlag is %d\r\n",MyFlag);                                                 //打印MyFlag全局变量
                                 printf("The IDLE status was SET!\r\n");
                                 IDLE_ClearBit = USART_ReceiveData(USART1);                                     //清除IDLE标志位
                                 if(USART_GetITStatus(USART1,USART_IT_IDLE) == RESET)
                                 {
                                          printf("The IDLE status is CLEAR!\r\n");
                                                if(MyFlag == 0)   
                                                {
                                                         Cmd = ServoCmd(USART_RX_BUF);
                                                         printf("The current Cmd is %d\r\n",Cmd);
                                                         if(Cmd >= 20 && Cmd <= 90)
                                                                {
                                                                         printf("占空比是%d%%\r\n",Cmd);
                                                       Duty_Count = Cmd * arr /100;
                                                 TIM_SetCompare1(TIM4,Duty_Count);                                    //IDLE中断控制TIM4_CH1的CCR寄存器,用于修改占空比
                                                                }       
                                                         else printf("非法指令!请重新输入:(输入范围:20至90)\r\n");
                                                }
                                                else
                                                {
                                                         MyFlag = 0;    //如果超载,重新刷新MyFlag,本次USART_RX_BUF中的数据无效,不做处理!
                                                         printf("数据超载!请重新输入o3o\r\n");
                                                }
                                                DMA_EnableCmd(DMA1_Channel5);                                       //重置DMA,使之从BUF[0]开始记录数据
                                                printf("接收缓冲器内的数据是 %s\r\n",USART_RX_BUF);          //打印USART_RX_BUF的数据
                                                memset(USART_RX_BUF,0,sizeof(USART_RX_BUF));               
                                 }
                        }





用串口打印结果如下:
输入“50\r\n”时,数据长度还没有达到dma缓冲长度,可以得到正确的结果:DMA1_IT_TC5 = 0,MyFlag = 0;
输入“123\r\n”时,数据长度达到了dma缓冲长度,dma完成一次传输,DMA1_IT_TC5 = 1,但是MyFlag依然是0,说明DMA1_IT_TC5中断服务函数没有运行!!




麻烦大佬们看看鄙人哪里出了纰漏,感激不尽!

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

使用道具 举报

16

主题

426

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2765
金钱
2765
注册时间
2018-11-8
在线时间
438 小时
发表于 2022-11-11 19:42:58 | 显示全部楼层
DMA中断服务函数在哪儿呢
回复

使用道具 举报

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

本版积分规则



关闭

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

正点原子公众号

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

GMT+8, 2025-2-25 21:41

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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