STM32EXTI中断函数代码实现
- 对射式红外传感器&旋转编码器计次
- 配置外部中断的步骤:
- AFIO相关函数&GPIO的一个函数
- EXTI相关函数
- 代码
- NVIC中断函数
- 启动文件里的中断函数名字
- 中断编程的建议:
对射式红外传感器&旋转编码器计次
一般一个模块要写的第一个就是初始化函数,把模块要用的资源配置好
配置外部中断的步骤:
1.配置RCC,把我们涉及到的外设的时钟都打开
2.配置GPIO,选择端口为输入模式
3.配置AFIO,选择我们用的这一路GPIO,连接到后面的EXTI
4.配置EXTI,选择中断或事件响应
5.配置NVIC,给中断选择一个合适的优先级
最后,通过NVIC,外部中断信号就能进入CPU了
CPU收到中断信号,跳转到中断函数里执行中断函数
EXTI是一个独立外设,按理需要开启时钟,但是寄存器里面却没有EXTI时钟的控制位,(论推测可能是和EXTI唤醒有关,或者其他的一些电路设计上的考虑)
另外NVIC也不需要开启时钟,因为NVIC是内核的外设,内核外设都不需要开启时钟,和CPU一起的,在内核。
而RCC管的都是内核外的外设,
AFIO相关函数&GPIO的一个函数
AFIO没有专门分配库函数文件,是和GPIO在一个文件里面
GPIO_ADIODeInit()复位AFIO外设,调用此函数,AFIO外设的配置就会全部清除
GPIO_PinLockConfig 锁定GPIO配置,调用此函数,参数指定某个引脚,引脚配置就锁定,防止意外更改
GPIO_EventOutputConfig、GPIO_EventOutputCmd是用来配置AFIO的事件输出功能的,用的不多
GPIO_PinRemapConfig 可以用来进行引脚重映射,第一个参数可以选择要重映射的方式,第二个参数是新的状态
GPIO_EXTILineConfig 本节需要用到的,可以配置AFIO的数据选择器,来选择我们想要的中断引脚
GPIO_ETH_MediaInterfaceConfig 和以太网相关,这个芯片没有以太网外设,用不到
EXTI相关函数
EXTI_DeInit 可以把EXTI的配置都清除,恢复成上电默认的状态
EXTI_Init 可以根据结构体里的参数配置EXTI外设,初始化主要用的这个函数,使用方法和GPIO_Init是一样的,
EXTI_StructInit 可以把参数传递的结构体变量赋一个默认值
这三个函数,基本所有的外设都有,就像是库函数的模板函数一样,基本每个外设都需要这些类型的函数,会用一个之后,再见到这种函数,就很容易上手。为什么要用结构体来初始化模块,还得定义结构体,结构体赋值,然后再传递结构体的地址,是因为其他外设也都一样,一个套路,而且结构体可以看到参数的名字,参数也都可以复制粘贴,根本不用查看寄存器,随便选参数就配置好了。
EXTI_GenerateSWInterrupt 用来软件触发外部中断,调用这个函数,参数给一个指定的中断线,就能软件触发一次外部中断,如果程序中需要用到这个功能,可以使用这个函数,如果程序中只需要外部引脚触发中断,那就不需要用这个函数了。
FlagStatus EXTI_GetFlagStatus(uint32_t EXTI_Line);
void EXTI_ClearFlag(uint32_t EXTI_Line);
ITStatus EXTI_GetITStatus(uint32_t EXTI_Line);
void EXTI_ClearITPendingBit(uint32_t EXTI_Line);
这四个函数也是库函数的模板函数,很多模块都有着四个函数,因为外设运行过程中,会产生一些状态标志位,比如外部中断来了,会有一个挂起寄存器置了一个标志位,对于串口收到数据,会置标志位,定时器时间到,也会置标志位。这些标志位都是放在状态寄存器,当程序想要看这些标志位时,可以用到这4个函数
GetFlagStatus可以获取指定的标志位是否被置1了
ClearFlag可以对置1的标志位进行清除
对于标志位,有的比较紧急,在置标志位后会触发中断,在中断函数里,如果想查看标志位和清除标志位,那用下面两个函数,
GetITStatus 获取中断标志位是否被置1了、
ClearITPendingBit 清除中断挂起中断位
总结:如果想再主程序里面查看和清除标志位,就用上面两个函数
如果想在中断函数里查看和清除标志位,就用下面两个函数。
本质上,四个函数都是对状态寄存器的读写,只不过下面的两个函数只能读写与中断有关的标志位,并且对中断是否允许做出了判断,而上面的连个函数只是一般的读写标志位,没有额外的处理,能不能触发中断的标志位都能读取。
库函数对这两种场景,区分了两类读写函数,实在随便用也问题不大。
代码
此处注释写错了,所以才有有很多的版本来修订
NVIC中断函数
1.用来中断分组的,参数是中断分组的方式
2.根据结构体里指定的参数初始化NVIC
3.设置中断向量表
4.系统低功耗配置
3.4函数用的不多,可以先不看
For the complete STM32 Devices IRQ Channels list, please refer to stm32f10x.h file
对于完成的STM32中断通道列表,请参考stm32f10x.h文件,这个意思是IRQn_Type的定义不在这个文件,要到stm32f10x.h里去找。
可以看到这里有很多的中断通道,因为这个库函数可以兼容所有的F1系列芯片,但是不同的芯片中断列表是不一样的,所以有很多条件编译,用来选择所使用芯片的中断通道列表。
启动文件里的中断函数名字
在STM32中,中断函数的名字都是固定的,每个中断通道都对应一个中断函数,中断函数的名字可以参考启动文件。
可以看到定义了中断向量表,这里面以IRQ结尾的字符串就是中断函数的名字,EXTI15_10_IRQHandler就是EXTI15_10的中断函数
中断函数都无参无返回值。在中断函数里,一般都是先进行一个中断标志位的判断,确保使我们想要的中断源触发的这个函数,因为这个函数EXTI10-15都能进来,所以要先判断是不是想要的EXTI14进来了
中断编程的建议:
1.在中断函数里,最好不要执行耗时过长的代码,中断函数要简短快速,别刚进中断就执行一个Delay多少毫秒这样的代码,因为中断是处理一个突发的事情,如果为了一个突发的事情待在中断里出不来了,那主程序就会收到严重的阻塞
2.不要在中断函数和主函数调用相同的函数或者操作同一硬件,尤其是硬件相关函数,比如OLED显示函数,如果既在主函数里调用LED,又在中断调用OLED,OLED就会显示错误。因为可能在主程序中,OLED刚显示一半,进入中断后,还是OLED显示函数,那OLED就可能挪到其他地方显示了,当中断结束之后,需要继续原来的显示就出问题了。因为硬件的显示位置被挪到其他地方了,所以再回来时,继续显示的内容就会跟着跑到其他地方去。
虽然在中断进入和退出时,会有保护现场和恢复现场,但这只能保证CPU程序能正常返回不出问题,对于外部硬件的话,并没有在进入中断时进行现场保护。为了避免这样可能存在的问题,就最好不要在主程序和中断程序里,操作可能产生冲突的硬件。
可以在中断里操作变量或者标志位,当中断返回时,再对这个变量进行显示和操作,这样既能保证中断函数的简短快捷,又能保证不产生冲突的硬件操作。这就是中断程序设计的注意事项。
其他地方也可以多用变量或者标志位,来减少代码之间的耦合性,让各部分代码相互独立,仅使用变量、标志位或者函数作为接口,这样让程序更加清晰、代码更加强健。