中断
允许 CPU 在执行程序的过程中,暂停当前任务,转而去处理更高优先级的任务(称为中断服务程序,ISR),处理完成后再返回原来的任务继续执行。
为什么需要中断?
中断的主要作用包括:
- 提高 CPU 效率:
- 在没有中断的情况下,CPU 需要通过轮询(Polling)的方式不断检查设备状态,这会浪费大量的 CPU 资源。中断机制允许 CPU 在设备需要处理时才响应,从而提高效率。
- 实时响应:
- 中断可以确保关键事件(如按键按下、定时器溢出等)得到及时处理,满足实时性要求。
- 多任务处理:
- 中断机制使得 CPU 可以在多个任务之间快速切换,实现多任务处理。
- 硬件事件处理:
- 硬件设备(如键盘、鼠标、定时器等)通过中断通知 CPU 有事件发生,CPU 可以及时处理这些事件。
如何实现中断?
中断的实现通常包括以下几个步骤:
(1) 硬件支持
- 中断源:能够触发中断的事件或设备(如定时器、外部按键、串口接收数据等)。
- 中断控制器:负责管理多个中断源,并根据优先级决定哪个中断先被处理(如 ARM Cortex-M 中的 NVIC)。
- 中断向量表:存储中断服务程序(ISR)入口地址的表格,CPU 根据中断号查找对应的 ISR。
(2) 软件实现
- 初始化中断:
- 配置中断源(如定时器、GPIO 等)。
- 设置中断优先级。
- 使能中断。
- 编写中断服务程序(ISR):
- ISR 是处理中断事件的函数,通常需要快速执行并清除中断标志。
- 处理中断:
- 当中断发生时,CPU 保存当前上下文(如寄存器值),跳转到 ISR 执行,执行完成后恢复上下文并继续原来的任务。
具体例子:STM32 定时器中断
以下是一个基于 STM32 的定时器中断示例,展示了如何实现中断。
(1) 硬件环境
- STM32 微控制器(如 STM32F103)。
- 定时器(如 TIM2)用于周期性触发中断。
(2) 代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| void TIM5_Int_Init(u16 arr,u16 psc) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE); TIM_TimeBaseStructure.TIM_Period = arr; TIM_TimeBaseStructure.TIM_Prescaler =psc; TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM5, &TIM_TimeBaseStructure); TIM_ITConfig(TIM5,TIM_IT_Update,ENABLE );
NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 5; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure);
TIM_Cmd(TIM5, ENABLE); }
void TIM3_IRQHandler(void) { if(TIM_GetITStatus(TIM3,TIM_IT_Update)==SET) { printf("TIM3输出.......\r\n"); } TIM_ClearITPendingBit(TIM3,TIM_IT_Update); }
|
在 main
函数中调用 TIM2_Int_Init(4999, 7199);
后,定时器会独立于 main
函数继续运行,并且当满足条件时(如定时器计数溢出),CPU 会自动跳转到中断服务函数(ISR)中处理中断事件。
1 2 3 4 5 6 7 8 9 10 11 12
| int main(void) { NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4); delay_init(); uart_init(115200); LED_Init(); TIM3_Int_Init(10000-1,7200-1); while(1){ } }
|