中断分析(标准库)
这篇文章主要是通过标准库进行一下分析中断的配置,通过四个按键进入中断,(在文章的末尾也会写一下寄存器版本的中断如何配置,感兴趣的也可以看一下)。这篇文章中没有怎么对中断进行讲解,在后续等我真正搞明白了会再写一期讲解的文章,这里主要是配置是其运行。
目前来说已经学过了中断,定时器,和串口。因为也是一直在学习,所以抽空才开写了第二篇的中断分析。后面在周末也会进行补上这一周的学习。
中断函数分析
中断是什么呢,按我的理解(一个小白的理解)就是跟在主函数里写if条件判断有些相似,只不过中断对于单片机主程序来说相当于是一个非阻塞的判断,(只是相当于),因为中断要求的是快进快出,人眼看不出来主程序被打断了。就是主程序在运行然后给你一个中断信号,接收到后就去执行中断服务函数里的内容,执行完毕后立刻重新返回主函数进行。(这个想法可以作为一个参考,个人想法)。
在STM32ZET6中一共有ABCDEFG7个端口,EXTI0输入线可以与该7个端口的0引脚的联系起来,EXTI1输入线可以与该7个端口的1引脚的联系起来,以此类推。然后需要配置EXTI输入线的初始化,选择中断模式,选择触发方式,使能该输入线,最后完成初始化。
接下来开始对NVIC的配置,需要配置其中断通道,优先级,使能该通道,完成初始化。
最后是写中断服务函数
EXTI_InitTypeDef EXTI_InitStructure={0};
NVIC_InitTypeDef NVIC_InitStructure={0};
/* Enable AFIO clock */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); //开启时钟
/*选择EXTI0输入线跟哪个GPIO联系起来*/
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0); //按键1
GPIO_EXTILineConfig(GPIO_PortSourceGPIOC, GPIO_PinSource4); //按键2
GPIO_EXTILineConfig(GPIO_PortSourceGPIOC, GPIO_PinSource5); //按键3
GPIO_EXTILineConfig(GPIO_PortSourceGPIOC, GPIO_PinSource6); //按键4
/* Configure EXTI0 456 line */
//初始化四个按键的中断线
EXTI_InitStructure.EXTI_Line = EXTI_Line0|EXTI_Line4|EXTI_Line5|EXTI_Line6;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //EXTI为中断模式
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; //上升沿触发
EXTI_InitStructure.EXTI_LineCmd = ENABLE; //使能输入线
EXTI_Init(&EXTI_InitStructure);
/* Enable and set EXTI0 Interrupt to the lowest priority */
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn; //配置中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x03; //抢占优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x03; //响应优先级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能通道
NVIC_Init(&NVIC_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = EXTI4_IRQn; //配置中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02; //抢占优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02; //响应优先级
NVIC_Init(&NVIC_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn; //配置中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x01; //抢占优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01; //响应优先级
NVIC_Init(&NVIC_InitStructure);
按键3和4共用了一个中断通道EXTI9_5_IRQn,这里是芯片定义的,我们调用。需要记住。所以就是使能了三个中断。
接下来就是对中断服务函数的分析了,这里又有一个小坑,中断服务函数在STM32的启动文件了有一一对应的,我们写的函数必须写在启动文件的函数名里。不然的话无法使用。这里我写一个EXTI9_5_IRQHandler()的服务函数,另外的EXTI4_IRQHandler()和EXTI0_IRQHandler()就比较简单了,不在举例了。为什么写这个就是因为他是5-9集成在一起的函数,要想分开使用就需要加入if条件判断了。
if(EXTI_GetITStatus(EXTI_Line5) != RESET) //按键3触发中断
{
/* Toggle LED1 */
G_Toggle(); //亮起RGB灯绿灯(宏定义)可以换位自己想要的操作
/* Clear the EXTI line 0 pending bit */
EXTI_ClearITPendingBit(EXTI_Line5);
}
if(EXTI_GetITStatus(EXTI_Line6) != RESET)
{
/* Toggle LED1 */
B_Toggle(); //蜂鸣器开关(宏定义)可以加入自己想做的操作
/* Clear the EXTI line 0 pending bit */
EXTI_ClearITPendingBit(EXTI_Line6); //按键4触发中断
}
其实到这里,中断配置就已经结束了。然后再根据上一期写的按键就可以完成对中断的配置。可以按照自己的想法去实现自己想要的功能。
备注:寄存器编写中断
EXTI初始化
//1,开启AFIO时钟
RCC->APB2ENR |= 1;
//2,选择PA0 作为EXTI0的输入引脚 PC456
AFIO->EXTICR[0] &= ~0xF; //注意不要写错
AFIO->EXTICR[1] |= 0x222;//选择PC为EXTI456输入线的引脚
//3,配置EXTI0的触发边沿为上升沿
EXTI->RTSR |= 1;
EXTI->RTSR |= 7<<4;//配置EXTI输入线456为上升沿触发
//4,开启EXTI0中断屏蔽寄存器
EXTI->IMR |= 1;
EXTI->IMR |= 7<<4;//配置EXTI开启中断请求
//5,先清除一下PR寄存器
EXTI->PR |= 1;
EXTI->PR |= 7<<4;//清除EXTI输入线456上的挂起寄存器
//6,开启中断通道,配置中断通道优先级
NVIC_SetPriority(EXTI0_IRQn,0);//抢占0 响应0
NVIC_EnableIRQ(EXTI0_IRQn);
NVIC_SetPriority(EXTI4_IRQn,5);//抢占1 响应1
NVIC_EnableIRQ(EXTI4_IRQn);
NVIC_SetPriority(EXTI9_5_IRQn,4);//抢占1 响应0
NVIC_EnableIRQ(EXTI9_5_IRQn);
中断服务函数,同样以9_5为例
if((EXTI->PR & (1<<5)) != 0)//EXTI5触发中断
{
G_Toggle();
// Delay_nms(3000);
// BEEP_OFF();
//清除一下PR寄存器
EXTI->PR |= 1<<5;
}
if((EXTI->PR & (1<<6)) != 0)//EXTI6触发中断
{
B_ON();
Delay_nms(3000);
B_OFF();
//清除一下PR寄存器
EXTI->PR |= 1<<6;
}
对比寄存器和库函数来讲,但从这里看寄存器确实比库函数配置简单。但是库函数对于移植操作的方便就远远不是寄存器能比的了。
时间比较紧急,本次分析就先到这里,后面对于中断的分析讲解可能会过二十天左右,等在来复习的时候才会进行更加细致的讲解,肯定比现在理解要深刻。