目录
中断系统
中断:在主程序运行过程中,出现了特定的中断触发条件(中断源),使得CPU暂停当前正在运行的程序,转而去处理中断程序,处理完成后又返回原来被暂停的位置继续运行
中断优先级:当有多个中断源同时申请中断时,CPU会根据中断源的轻重缓急进行裁决,优先响应更加紧急的中断源
中断嵌套:当一个中断程序正在运行时,又有新的更高优先级的中断源申请中断,CPU再次暂停当前中断程序,转而去处理新的中断程序,处理完成后依次进行返回
STM32中断
68个可屏蔽中断通道(中断源),包含EXTI、TIM、ADC、USART、SPI、I2C、RTC等多个外设 使用NVIC统一管理中断,每个中断通道都拥有16个可编程的优先等级,可对优先级进行分组,进一步设置抢占优先级和响应优先级
NVIC优先级分组(越高越优先,学习阶段一般使用分组2)
NVIC的中断优先级由优先级寄存器的4位(0~15)决定,这4位可以进行切分,分为高n位的抢占优先级和低4-n位的响应优先级 抢占优先级高的可以中断嵌套,响应优先级高的可以优先排队,抢占优先级和响应优先级均相同的按中断号排队
抢占优先级和响应优先级都是越高越优先
NVIC函数解析
注意:整个芯片只能用一种分组,如果是模块化要确保都一样
EXTI简介
EXTI(Extern Interrupt)外部中断
EXTI可以监测指定GPIO口的电平信号,当其指定的GPIO口产生电平变化时,EXTI将立即向NVIC发出中断申请,经过NVIC裁决后即可中断CPU主程序,使CPU执行EXTI对应的中断程序
支持的触发方式:上升沿/下降沿/双边沿/软件触发 支持的GPIO口:所有GPIO口,但相同的Pin (比如GPIOA0和GPIOB0和GPIOC0,GPIOA1和GPIOB1) 不能同时触发中断
通道数:16个GPIO_Pin,外加PVD输出、RTC闹钟、USB唤醒、以太网唤醒
触发响应方式:
中断响应
事件响应(不通向CPU,通向外设)
EXTI函数解析(带IT的为中断中使用)
AFIO复用IO口
AFIO函数解析
外部中断配置步骤
1.配置GPIO(RCCAPB2和Init)
2.配置AFIO(RCCAPB2和GPIO_EXTILineConfig)
3.配置EXTI (EXTI_Init)(LineConfig要分开)
4.配置NVIC (NVIC_PriorityGroupConfig(中断分组)和 NVIC_Init)
5.中断函数
(EXTI和NVIC一直打开的,不用RCC再打开 EXTI是外设也不知道为啥不用开启时钟 NVIC是内核外设,RCC管不着内核外设)
#include "stm32f10x.h" // Device header
uint16_t OIRSensor_count=0;
void OIRSensor_Init(void)
{
//以对射式红外计次为例
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
GPIO_InitTypeDef GPIOB_Initstructure;
GPIOB_Initstructure.GPIO_Mode=GPIO_Mode_IPU;
GPIOB_Initstructure.GPIO_Pin=GPIO_Pin_14;
GPIOB_Initstructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIOB_Initstructure);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//开启AFIO时钟
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource14);//配置中断引脚
EXTI_InitTypeDef EXTI_InitStruct;
EXTI_InitStruct.EXTI_Line=EXTI_Line14;//选择中断引脚
EXTI_InitStruct.EXTI_LineCmd=ENABLE;//开启中断
EXTI_InitStruct.EXTI_Mode=EXTI_Mode_Interrupt;//配置为中断响应
EXTI_InitStruct.EXTI_Trigger=EXTI_Trigger_Falling;//下降沿触发中断
EXTI_Init(&EXTI_InitStruct);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//配置为NVIC分组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);
}
uint16_t Get_OIRSensor_Count(void)
{
return OIRSensor_count;
}
void EXTI15_10_IRQHandler(void)//中断函数
{
if(EXTI_GetITStatus(EXTI_Line14)==SET)//中断函数中获取中断标志位
{
OIRSensor_count++;
EXTI_ClearITPendingBit(EXTI_Line14);//中断函数中清除中断标志位
}
}
main.c
#include "stm32f10x.h" // Device header
#include "OLED.h"
#include "OIRsensor.h"
int main(void)
{
OLED_Init();
OLED_ShowString(1,1,"OIR Sensor Count");
OIRSensor_Init();
while(1)
{
OLED_ShowNum(2,1,Get_OIRSensor_Count(),10);
OLED_ShowNum(3,1,GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_14),3);
}
}
注意!!!
中断函数中尽量不要去操作寄存器,不然有时候会莫名卡住,建议使用标志位的方式