目录
1.认识中断
与51中定时器中断类似,这次学习的是外部中断,即中断信号是由32单片机外部的芯片产生中断信号,32单片机额接收到特定的中断信号后,暂时停下执行主程序转而去处理中断函数内的代码。
在32中,中断的优先级分为响应优先级和抢占优先级,这点不同于51。其中,响应优先级和51中的优先级差不多,优先级高的中断优先执行,然后再依次执行优先级低的(0的优先级最大)。抢占优先级高的可以在低优先级中断执行时,打断低优先级中断的执行,转而执行高优先级的程序,也就是中断嵌套。总结来说,就是响应优先级高的排队排在前面,而抢占优先级高的可以插队,也就是进行中断嵌套。
2.外部中断EXTI的基本结构
由图可知EXTI基本结构由GPIO,AFIO,EXTI边沿检测及控制,NVIC组成,接下来逐一介绍这几个模块。
2.1丶GPIO
GPIO部分就是上次介绍过,不做过多叙述。
2.2丶AFIO
AFIO:复用IO口;在STM32中,AFIO主要有两个功能,第一个,复用功能引脚重映射,也就是在STM32中有些引脚的功能有多个,在使用这些引脚时,因为有多个功能,所以就要先选择用哪个功能,这就是复用功能引脚重映射的作用。第二个,就是中断引脚选择。
AFIO在中断引脚选择中就是几个数据选择器,将GPIOx的同一个Pin值引脚连在同一个数据选择器,通过代码选通某一路AFIO,将GPIOx及其GPIO_Pin_x选通作为中断引脚。
注意,在标准库中,AFIO的函数是用GPIO来命名的,因为是将GPIO的引脚作为中断引脚。函数名使用GPIO,但在实际操作时是对AFIO的寄存器操作的。
2.3丶EXTI边沿检测及控制
图中的门电路部分比较简单,不做过多叙述。主要来看看这几个寄存器。
首先是两个上升沿/下降沿触发器,EXTI的触发方式主要有四种:上升沿/下降沿/双边沿/软件触发。边沿触发则可由这两个寄存器控制,软件触发是在标准库中有专门的函数,当调用那个函数时就触发中断,具体是哪个函数最后会统一给出。
然后是软件中断寄存器,EXTI触发后,对应的响应有两种:中断响应/事件响应。中断响应就是一直在讲的中断,而事件响应不会触发中断,事件响应一般是与其他外设联动时使用,当事件响应触发时不会触发中断,而是会触发与其他外设的联动,这点学到再说。
再次之是请求挂起寄存器,和事件屏蔽寄存器。请求挂起寄存器其实就是个标志位寄存器,可以通过读取该寄存器来获得中断的状态。事件屏蔽寄存器顾名思义,其取0时封锁于门。
这些寄存器了解即可,通过标准库写代码其实并不需要对这些寄存器有太多了解,多多熟悉标准库函数帮助更大。
2.4丶NVIC
NVIC可以看成是CPU的一个秘书,从EXTI的结构就可以看出,中断的配置还是挺麻烦的,用到的外设比较多,如果这些工作繁琐小事也交给CPU处理,大材小用不说,还会影响CPU的速度,所以把这些繁琐小事都交给NVIC来处理,NVIC只把最后要处理的结果交给CPU。
在NVIC中可以配置响应优先级。优先级寄存器内有四位,即最多可以设置0~15个优先级,但是前面也说了,优先级分为抢占优先级和响应优先级,这两个优先级共用一个四位寄存器。在32的标准库中给出了四种分配方式:
分组方式 | 抢占优先级 | 响应优先级 |
分组0 | 0位,取值为0 | 4位,取值为0~15 |
分组1 | 1位,取值为0~1 | 3位,取值为0~7 |
分组2 | 2位,取值为0~3 | 2位,取值为0~3 |
分组3 | 3位,取值为0~7 | 1位,取值为0~1 |
分组4 | 4位,取值为0~15 | 0位,取值为0 |
这里的四种分组均可直接通过标准库的函数选择,只需了解内容即可。
3.Keil5代码
中断配置过程大致与GPIO步骤一样,通过外部中断的配置也更能体会到标准库相对于寄存器操作的便捷。
第一步,还是先使能时钟。使能GPIO和AFIO的时钟,而EXTI和NVIC并不需要使能,NVIC是因为在32内核里面,本来就是工作着的,而EXTI不需要使能的原因不太清除。
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
第二步,配置GPIO。先定义结构体变量,然后对结构体变量里每个变量赋值,最后调用初始化函数。
GPIO_InitTypeDef GPIO_Initstructure;
GPIO_Initstructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Initstructure.GPIO_Pin = GPIO_Pin_12;
GPIO_Initstructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_Initstructure);
第三步,配置AFIO。直接调用函数即可。函数的意义是讲GPIOB的第12号引脚设置为中断引脚。
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource12);
第四步,配置EXTI边沿检测及控制。与GPIO类似,定义结构体,赋值,初始化。其中EXTI_Line是选通哪一路,LineCmd是使能,MODE就是中断响应和事件响应两者二选一,Trigger是选择触发方式,这里写的是采用下降沿触发。
EXTI_InitTypeDef EXTI_Initstructure;
EXTI_Initstructure.EXTI_Line = EXTI_Line12;
EXTI_Initstructure.EXTI_LineCmd = ENABLE;
EXTI_Initstructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_Initstructure.EXTI_Trigger = EXTI_Trigger_Falling;
第五步,配置NVIC。仍旧是定义结构体,赋值,初始化。但首先要先选择分组模式,这里选择分组模式2.注意外部中断的分组模式要一致,可以在主函数中设置分组模式,在模块驱动函数中直接设置优先级即可。IRQChannel是中断通道,可以在标准库中查看。CMD使能,剩下两个就是抢占优先级和响应优先级的分配了。这里因为只有一个外设需要中断,所以可以随便给。注意优先级是相对其他外设而言的,要和其他外设的优先级比较时才有意义。
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //分组模式2,4个抢占优先级,4个响应优先级
NVIC_InitTypeDef NVIC_Initstructure;
NVIC_Initstructure.NVIC_IRQChannel = EXTI15_10_IRQn;
NVIC_Initstructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Initstructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_Initstructure.NVIC_IRQChannelSubPriority = 1; //抢占优先级和响应优先级都是和其他外设的优先级比较才有意义
NVIC_Init(&NVIC_Initstructure);
4.本节标准库函数介绍
/*GPIO函数用处:
GPIO_DeInit GPIO复位
GPIO_AFIODeInit AFIO复位
GPIO_PinLockConfig 锁定GPIO的配置
GPIO_EventOutputConfig
GPIO_EventOutputCmd 这两个是事件输出配置的函数,用到再说
GPIO_PinRemapConfig 引脚重映射
GPIO_EXTILineConfig 配置AFIO的数据选择器,选择那一路做中断引脚
GPIO_ETH_MediaInterfaceConfig 与以太网有关,现阶段接触不到
*/
/*
EXTI函数用处
EXTI_DeInit 复位
EXTI_Init 初始化对应数组
EXTI_StructInit 赋予初始化的数组一个默认值
EXTI_GenerateSWInterrupt 软件触发中断,该函数被调用时触发中断
EXTI_GetFlagStatus 获得指定的标志位寄存器是否被置1,所有地方都可以用
EXTI_ClearFlag 对置1的标志位清零,所有地方都可以用
EXTI_GetITStatus 获得指定标志位寄存器是否被置1,特用于在中断中读取
EXTI_ClearITPendingBit 对置1的标志位清零,特用于在中断中读取
*/
NVIC函数用法
NVIC_PriorityGroupConfig 用于中断分组
NVIC_Init 初始化
NVIC_SetVectorTable 设置中断向量表,用的不多学到再说
NVIC_SystemLPConfig 系统低功耗配置,用的不多学到再说
具体函数参数可以在Keil5中查看。且对于EXTI中查看标志位的函数,在中断中查看一般用后两者。两组查看和清零本质功能时一样的,但是下面的一组专门用于中断中使用,而上面的一组在任何地方都可以使用,使用场景有区别。