导语:看了我写的上一个笔记的朋友知道,示例中让LED灯亮是通过不断检测按键的电平高低来实现的,即把if检测语句放在While(1)里不断循环。但如果用STM32的中断思路来编写程序,就不需要在主程序里用while(1)来进行轮询(即不断检测),用中断的话CPU会自动后台帮你监控,一旦按下按钮,即跳转至中断服务函数(中断服务函数是我们自己编写,目的是发生中断后告诉CPU我们要做什么,拿示例来说就是我们要让灯亮变灭或者灭变亮),因此我的理解是中断函数可以极大的简化程序,不需要用各种if的嵌套和while的轮询。
看了导语,对中断就应该有一个大致的初步认识,即设置一个条件,发生了该条件,运行中断服务,跳转至我们自己设置的中断服务函数并执行,然后回到主函数中,有这么一个大概的感觉就好,后文会更详细的提到。本文适合初学者。
学习中断,先来理清一下思路,如上一段所提,
我们需要配置的是:1.什么条件
2.运行什么
这只是两个很浅显的思路,具体到程序要复杂的多,先来了解两个重要的知识点:NVIC和EXTI
NVIC:
一个复杂的工程肯定不止一个中断,既然涉及到多个中断,如果同时发生,先执行谁呢?
因此,中断的优先级由此产生,即如果多个中断产生,我该怎么去排执行顺序。
NVIC的作用就是如此,他会把我们配置的每个中断给排序,分先后,每个中断的排序有两个参数,相应优先级和抢占优先级,通俗来讲抢占优先级就是第一排序数,响应优先级就是第二排序数,先比第一排序数大小,再比第二排序数大小,越小优先级越大。
以两中断A和B为例:
若A两优先级为1和3(前者为抢占,后者为响应) B为2和3,则A先执行,且如果B正在执行,A发生,则A打断B先执行,执行完再执行B
若A两优先级为2和3(前者为抢占,后者为响应) B为2和4,则A先执行
若A两优先级为1和3(前者为抢占,后者为响应) B为1和3,则根据硬件内部编号大小决定
到这里可能又有一个新问题,我能设置多大的优先级数,换言之,这两个排序数的大小范围多大?
NVIC中的优先级分为5组,分别为0,1,2,3,4组。
网上其他该分组的具体教程也很多,如果只是运用,只需要记住该组号用二进制运算赋值给抢占优先级,然后4-(组号)得到的数字用二进制运算再减一赋给响应优先级。
比如设置为组号1,则抢占优先级最小为2的1次方减一即1,可设置该优先级范围为0到1;
而响应优先级为2的(4-1)次方减一,即为7,可设置该优先级范围为0到7;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_X);
该函数即是用来分组,X为我们给的值(0,1,2,3,4)
在NVIC中还需要配置中断源,即选择不同的通道来选择不同的中断来源,不同的中断源的编号不一样。
分为:1.通道0到4 EXTIX_IRQn X为0到4中一数字
2.通道5到9 都用EXTI9_5_IRQn
3.通道10到15 都用EXTI15_10_IRQn
新人只需跟我一样记住配置为使用的IO口的引脚号就好,我还没理解透彻QAQ
比如我用PA4口,那我设置为EXTI4_IRQn
最后还要中断使能,后面上代码会提到,很简单,固定的一句话。
EXTI
我们配置完NVIC后,还需要配置一个新的函数,通俗讲就是配置EXTI
我理解可能比较浅,我理解的EXTI就是用来设置中断来源是哪儿(不要与上一个配置NVIC通道搞混),是上升沿触发还是下降沿触发还是都触发。
EXTI的配置需要
1.使能新的时钟源 不同于GPIO(后面代码会提到)
然后配置中断来源,SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOX,EXTI_PinSourceY);
比如配置为PA4, SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA,EXTI_PinSource4);
2.选择EXTI模式,分为中断和事件
就个人的简单理解来说,中断就是条件满足后,发送数据给CPU,CPU收到数据进行处理,然后执行我们编写的中断服务函数(即发生中断后我们想让它干嘛,亮灯,灭灯?等等)
事件是条件满足后,我们不发送数据给CPU,而是跳过CPU,直接产生一个触发信号,这个触发信号可以通向其他外设,比如可以用来触发ADC转换等等。
通常所说的中断都是EXTI的中断,事件用的较少,先不涉及。(其实是我自己都还没学懂事件hhh)
3.选择触发方式
4.使能通道
5.引用库函数初始化
(没具体讲的,代码都很固定,代码后面会给,先不给代码,结合代码和注释理解更深刻。)
GPIO
我们中断产生的来源可以是内部也可以是外部,内部比较常见的就是定时器的中断(我还没学会QAQ),暂时讲的是外部的中断,一般用外设板块接入单片机,外设板块输出脉冲到单片机上,单片机接收然后产生特定脉冲就中断。
如上述,若用外设(超声波模块,红外模块等等)接单片机,则需要将GPIO配置为输入模式,我的上一个文章有涉及到。
该处不在赘述。
中断服务函数配置
之前我们都配置好了优先级,中断源等参数,现在需要配置运行内容,即如果发生了中断,我要CPU去做什么,比如最简单的、我就让灯亮。
该中断函数在stm32f4xx_it.c文件中,每个不同中断源都需要用不同的函数。
具体配置马上结合代码说,不难
示例分析
之前的比赛多了个红外模块,我以红外模块为例,如果检测到反射光,设置中断,开发板自带的LED模块由亮变灭或者由灭变量,即开关作用。
我选择PA4作为接受红外信号的IO口
主函数
#include"stm32f4xx.h"
#include "led.h"
#include"EXTI.h"
int main(void)
{
LED_GPIO_Config();//控制LED的GPIO口初始化(查手册得是那个IO口)
NVIC_Config(); //NVIC配置
EXTI_Key_Config();//EXTI配置
GPIO_config(); //接受红外模块脉冲的IO口配置
while(1); //设置死循环,保证STM32正常工作
}
NVIC函数
void NVIC_Config(void)
{
NVIC_InitTypeDef NVIC_InitStructure; //结构体引用
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); //优先级分组设置为1
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //抢占优先级设置为1(0到1均可)
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //响应优先级设置为1(0到7均可)
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //通道使能(如前述,记住就好)
NVIC_InitStructure.NVIC_IRQChannel = EXTI4_IRQn; //引脚号为4,故为EXTI4_IRQn
NVIC_Init(&NVIC_InitStructure); //引用库函数,初始化NVIC结构体
}
EXTI函数
void EXTI_Key_Config(void)
{
EXTI_InitTypeDef EXTI_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE); //使能SYSCFG时钟
SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA,EXTI_PinSource4); //连接EXTI中断源PA4
EXTI_InitStructure.EXTI_Line = EXTI_Line4; //选择EXTI中断源为line4
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //设置为中断,而不是事件
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; //上升沿触发
EXTI_InitStructure.EXTI_LineCmd = ENABLE; //通道使能
EXTI_Init(&EXTI_InitStructure); //引用库函数初始化EXTI结构体
}
接收口GPIO配置(PA4)
void GPIO_config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA ,ENABLE);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; //注意是浮空输入,高低电平全由红外决定
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
中断服务函数stm32f4xx_it.c
void EXTI4_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line4) != RESET) //如果中断发生
{
GPIOF->ODR ^=GPIO_Pin_6; //直接对寄存器读写,电平求反
EXTI_ClearITPendingBit(EXTI_Line4); //清除中断标志位,每一次中断都要进行清除
}
}
最后别忘了在各自的头文件声明主程序要使用的函数
最后放一张测试图emmm虽然图片也看不出什么,但是是可以正常运行的。
原创文,甚至是今天刚学会QAQ,怕忘了。
肯定有很多错,希望大佬指出呜呜呜,我想学我想学