Interrupt
1.中断介绍
1.1中断的概念
中断是指 CPU 在正常运行程序时,由于内部或外部事件引起暂时中止现行程序,转去执行请
求 CPU 为其服务的那个外设或事件的 服务程序,等待该服务程序执行完成后又返回到被中止
的地方程序,这样一个过程。
1.2中断的优先级
中断中的优先级大致分为三类:抢占优先级,比较优先级,自然优先级。其中优先级的作用强度为抢占优先级>比较优先级>自然优先级。优先级越高,在发生中断时会更快被处理。
1.2.1 抢占优先级
抢占优先级顾名思义,是能对其他中断进行中断的中断,发生的这个过程我们一般叫做中断嵌套,即正在执行主函数时,发生了一个抢占优先级较低的中断服务程序A,CPU先转去执行中断服务函数A,正在执行中断服务函数A时,又产生了一个抢占优先级较高的中断请求B,先去执行中断服务函数B,B执行完后,继续执行A,A执行完后,回到主函数继续执行。
1.2.2 比较优先级
当中断在抢占优先级相同时,比较优先级高的先执行。
1.2.3 自然优先级
当中断在抢占优先级和比较优先级相同时,比较优先级高的先执行。
1.2.4 总结
(1)只有抢占优先级可以产生中断嵌套(即高抢占优先级能打断低抢占优先级)。
(2)抢占优先级和比较优先级是我们可以设定的,而自然优先级(硬件优先级)是厂商出厂就设定好的。
1.3中断的分类
(1)外设中断
(2)定时器中断
(3)外部中断
(4)内核异常
(5)软件中断
1.3.1 外设中断
这种中断是由单片机的片上外设,如USART产生的。当这些设备需要处理器注意时,它们会发送一个信号,请求CPU暂停当前任务,处理中断请求。
以USART1为例:
//中断初始化
void USART1_ITInit(u8 PreemptionPriority, u8 SubPriority)
{
//开启USART1的接收中断
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitTypeDef NVIC_InitStruct;
NVIC_InitStruct.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = PreemptionPriority;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = SubPriority;
NVIC_Init(&NVIC_InitStruct);
}
//中断处理函数
void USART1_IRQHandler(void)
{
if(USART_GetITStatus(USART1, USART_IT_RXNE) == SET)
{
USART1_RecString(data);
t = atoi(data);
printf("Receive data = %s\r\n", data);
USART_ClearITPendingBit(USART1, USART_IT_RXNE);
}
}
1.3.2 定时器中断
也称为周期性中断,是由系统定时器产生的。定时器可以设置特定的时间间隔,当时间到达时,定时器中断会被触发,通常用于执行周期性任务或时间管理。
以SysTick为例:
//中断初始化
void SysTick_ITInit(u8 PreemptionPriority, u8 SubPriority)
{
//开启定时器中断
SysTick->CTRL |= 1<<1;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitTypeDef NVIC_InitStruct;
NVIC_InitStruct.NVIC_IRQChannel = SysTick_IRQn;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = PreemptionPriority;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = SubPriority;
NVIC_Init(&NVIC_InitStruct);
}
//中断处理函数
void SysTick_Handler(void)
{
if(SysTick->CTRL & (1<<16))
{
if(GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_4) == 0)
{
cnt1++;
}
EXTI_GenerateSWInterrupt(EXTI_Line1);
//清除标志位,其实这一步可要可不要,因为标志位在之前我们读的时候就已自动清除
SysTick->CTRL;
}
}
1.3.3 外部中断
与外设中断类似,但更广泛地指任何来自系统外部的中断信号,如网络中断、电源中断等。这些中断通常是由外部事件触发的,需要系统立即响应。
以PA0为例:
//中断初始化
void EXTI0_Init(u8 PreemptionPriority, u8 SubPriority)
{
//开启EXIT的时钟线
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG,ENABLE);
//选择GPIOA的0引脚接入EXTI
SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA, EXTI_PinSource0);
EXTI_InitTypeDef EXTI_InitStruct;
EXTI_InitStruct.EXTI_Line = EXTI_Line0;
EXTI_InitStruct.EXTI_LineCmd = ENABLE;
EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising_Falling;
EXTI_Init(&EXTI_InitStruct);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitTypeDef NVIC_InitStruct;
NVIC_InitStruct.NVIC_IRQChannel = EXTI0_IRQn;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = PreemptionPriority;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = SubPriority;
NVIC_Init(&NVIC_InitStruct);
}
//中断处理函数
void EXTI0_IRQHandler(void)
{
判断EXTI线0的标志位是否置位
if(EXTI_GetITStatus(EXTI_Line0) == SET)
{
//LED1翻转
LED1_T;
//清除标志位
EXTI_ClearITPendingBit(EXTI_Line0);
}
}
1.3.4 软件中断
这种中断是由软件指令触发的,通常是通过执行特定的中断指令来实现。软件中断用于实现系统调用或请求操作系统服务。
//中断初始化
void EXTI1_SW_Init(u8 PreemptionPriority, u8 SubPriority)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG,ENABLE);
EXTI_InitTypeDef EXTI_InitStruct;
EXTI_InitStruct.EXTI_Line = EXTI_Line1;
EXTI_InitStruct.EXTI_LineCmd = ENABLE;
EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising_Falling;
EXTI_Init(&EXTI_InitStruct);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitTypeDef NVIC_InitStruct;
NVIC_InitStruct.NVIC_IRQChannel = EXTI1_IRQn;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = PreemptionPriority;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = SubPriority;
NVIC_Init(&NVIC_InitStruct);
}
//中断处理函数
void EXTI1_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line1) == SET)
{
printf("%d\r\n",cnt1);
EXTI_ClearITPendingBit(EXTI_Line1);
}
}
2.相关库函数
//misc.h
void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup);
void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct);
void SysTick_CLKSourceConfig(uint32_t SysTick_CLKSource);
//stm32f4xx_syscfg.h
void SYSCFG_EXTILineConfig(uint8_t EXTI_PortSourceGPIOx, uint8_t EXTI_PinSourcex);
//stm32f4xx_exti.h
void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct);