中断系统
中断:在主程序运行过程中,当出现了特定的中断触发条件,CPU就可以暂停当前正在运行的程序去处理中断程序,并把当前程序的地址压入堆栈,中断程序处理完成后把地址弹出堆栈,回到刚刚暂停的位置继续执行程序。
中断优先级:当有多个中断源同时申请中断时,CPU会根据中断源的优先级进行判断后优先响应优先级更高的中断源,stm32的中断优先级有抢占优先级和响应优先级。
中断嵌套:当一个中断程序正在运行时,又有新的更高优先级的中断源申请中断,CPU再次暂停当前中断程序,转而去处理新的中断程序,并把当前程序的地址压入堆栈,中断程序处理完成后把地址弹出堆栈,处理完成后再执行第二优先级的中断程序,直到返回主程序。
stm32的外部中断
EXTI(External interrupt/event controller)—外部中断/事件控制器,可以通过NVIC申请中断或产生事件。
EXTI可以监测指定GPIO口的电平,当IO口产生电平变化时,EXTI将立即向NVIC发出中断申请,经过NVIC后即可中断CPU主程序,使CPU执行EXTI对应的中断程序。
STM32的每个IO都可以作为外部中断输入,但是每一组IO口相同的引脚不能同时出发外部中断,这是因为所有IO口的每一个相同号数的引脚只能对应到同一条中断通道上。
EXTI有 20个中断/事件线,占用 EXTI0至 EXTI15,16-19分别是PVD输出,RTC时钟事件,USB唤醒事件,互联型以太网唤醒事件。
NVIC先挖个坑,之后再补充(中断分组)
中断向量表与中断函数
STM32在中断向量表中只有这几个函数的符号,要编写中断函数就要设置相应的函数名,编译器才能通过函数名找到中断程序入口。
可见中断函数只有7个,其中0-4通道分别占一个函数,5-9通道和10-15通道分别占用一个函数。在后面两个函数中,可以进入中断函数后判断是哪一路通道被触发而执行对应的中断程序。例如这里选择7号通道作为中断源。
外部中断常用库函数
void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct);
//用配置完后的结构体初始化EXTI
void EXTI_StructInit(EXTI_InitTypeDef* EXTI_InitStruct);
//默认初始化结构体
EXTI_InitTypeDef EXTI_InitStructure;
//定义结构体,可配置结构体成员来设置EXTI模式
void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource);
//配置IO口与中断线的映射关系
FlagStatus EXTI_GetFlagStatus(uint32_t EXTI_Line);
//获取中断线的状态,判断是否产生了中断
void EXTI_ClearITPendingBit(uint32_t EXTI_Line);
//在产生中断后需要手动软件重置标志位,不然会在中断函数中循环
光敏传感器数字输出控制LED灯
void LightSensorExtiInit()
{
//PB7 上拉输入 光敏传感器DO
//先初始化时钟,GPIO和AFIO
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
//要使能GPIO口和复用功能,因此提供时钟
//初始化GPIO
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStructure);
//映射中断源
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource7);//配置AFIO中断引脚,将7线拨到GPIOB上
//配置EXTI
EXTI_InitTypeDef EXTI_InitStructure;
EXTI_InitStructure.EXTI_Line = EXTI_Line7;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling;
//这里设置上升沿和下降沿触发
EXTI_Init(&EXTI_InitStructure);//这里别写错了,是中断的初始化,不是结构体的初始化
//这里刚开始的时候写成EXTI_StructInit,导致一直没有现象,找了半天才找到问题= =
//这里只有一个中断源,中断分组可以随便设置
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//中断分组
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;//抢占优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //响应优先级,这里随便设置
NVIC_Init(&NVIC_InitStructure);
}
//先配置IO口,然后使能复用功能,之后配置中断功能,最后配置NVIC通道
//stm32中断函数的函数名都是固定的,对应中断向量表
void EXTI9_5_IRQHandler(void)
{
//先判断是不是这条通道
if(EXTI_GetITStatus(EXTI_Line7) == 1)
{
LEDTurn();
//LED开关切换
}
EXTI_ClearITPendingBit(EXTI_Line7);
//最后要清除标志位,否则会一直申请中断,卡死
}
选择上升沿和下降沿触发,当光线太暗,光敏传感器的DO口从0输出1,是一个上升沿,此时LEDTURN触发,灯打开,光线变亮泽再触发,灯关闭,即实现了所需功能。