中断-STM32
中断:在主程序运行过程中,出现了特定的中断触发条件 (中断源),使得CPU暂停当前正在运行的程序转而去处理中断程序处理完成后又返回原来被暂停的位置继续运行。
中断优先级:当有多个中断源同时申请中断时,CPU会根据中断源的轻重缓急进行裁决,优先响应更加紧急的中断源。
中断嵌套:当一个中断程序正在运行时,又有新的更高优先级的中断源申请中断CPU再次暂停当前中断程序,转而去处理新的中断程序,处理完成后依次进行返回。
68个可屏蔽中断通道包含EXTI、TIM、ADCUSART、SPI、12C、RTC等多个外设。
使用NVIC统一管理中断,每个中断通道都拥有16个可编程的优先等级,可对优先级进行分组,进一步设置抢占优先级和响应优先级。
GPIO_Pin中Pin相同的不能同时触发中断。
配置步骤
第一步,配置RCC,把涉及的外设的时钟都打开。
第二步,配置GPIO,选择端口为输入模式。
第三步,配置AFIO,选择用的这一路GPIO,连接到后面的EXTI。
第四步,配置EXTI,选择边沿触发方式,比如上升沿、下降沿或者双边沿。还有选择触发响应方式,可以选择中断响应和事件响应。(一般选择中断响应)。
第五步,配置NMIC,给我们这个中断选择一个合适的优先级。通过NVIC,外部中断信号就能进入CPU了。CPU才能收到中断信号,才能跳转到中断函数里执行中断程序。
以IRQHandler结尾的字符串就是中断函数的名字
#include "stm32f10x.h" // Device header
//用一个数字来统计中断触发的次数
uint16_t CountSensor_Count;
void CountSensor_Inint(void)
{
//第一步:配置时钟
//开启RRC时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//注意函数和参数的这个APB2、APB1和AHB要对应起来
//开启AFIO的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
//第二步:配置GPIO
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;//跟参考手册选择上拉模式,复用
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_14;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStruct);
//第三步:配置AFIO
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource14);//选择GPIOB_14为中断引脚
//第四步:配置EXTI
EXTI_InitTypeDef EXTI_InitStruct;
EXTI_InitStruct.EXTI_Line = EXTI_Line14;//选择第14路中断
EXTI_InitStruct.EXTI_LineCmd = ENABLE;//使能中断
EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;//中断触发
EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Falling;//下降沿触发
EXTI_Init(&EXTI_InitStruct);
//配置NVIC
//注意:分组方式整个芯片只能用一种,因此,分组的代码只需要执行一次
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitTypeDef NVIC_InitStruct;
NVIC_InitStruct.NVIC_IRQChannel = EXTI15_10_IRQn;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;
NVIC_Init(&NVIC_InitStruct);
}
//编写中断函数
//中断函数的名字都是固定的,中断函数都是无参数无返回值的
//写错了就进不了中断了,最好是直接从启动文件复制过来
//中断函数就不用声明,因为中断函数不需要调用,它是自动执行的
void EXTI15_10_IRQHandler(void)
{
//一般先进行中断标志位的判断
if(EXTI_GetITStatus(EXTI_Line14) == SET)
{
CountSensor_Count++;//记录进入中断的次数
//每次中断程序结束后,都应该清除一下中断标志位
EXTI_ClearITPendingBit(EXTI_Line14);
}
}
//返回中断次数
uint16_t Get_CountSensor_Count(void)
{
return CountSensor_Count;
}
#ifndef _COUNTSENSOR_H
#define _COUNTSENSOR_H
void CountSensor_Inint(void);
uint16_t Get_CountSensor_Count(void);
#endif
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "LED.h"
#include "KEY.h"
#include "CountSensor.h"
int main(void)
{
CountSensor_Inint();
while(1)
{
}
}
注意:
在中断函数里,最好不要执行耗时过长的代码。
不要在中断函数和主函数调用相同的函数或者操作同一个硬件。
建议:在中断里操作变量或者标志位,当中断返回时,再对这个变量操作。既能保证中断函数的筒短快速,又能保证不产生冲突的硬件操作。