STM32异常与中断过程详解

本文介绍了中断和异常的基本概念,包括它们的产生原因和处理方式。通过一个烧开水的比喻解释了中断的必要性,阐述了中断如何提高CPU效率。在ARM体系中,中断处理涉及中断初始化、中断服务程序执行等步骤。在STM32中,中断处理主要由硬件自动完成,包括异常向量表用于定位中断服务函数,以及自动保存和恢复现场。文章还详细讨论了STM32如何保存和恢复现场,以及异常返回机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 异常与中断概念引入

异常主要是指来自CPU内部的意外事件,比如执行了未定义指令、算术溢出、除零运算等发生在CPU内部的意外事件,这些异常的发生,会引起CPU运行相应的异常处理程序;中断一般来自硬件(如片上外设、外部I/O输入等)发生的事件,当这些硬件产生中断信号时,CPU会暂停当前运行的程序,转而去处理相关硬件的中断服务程序。但无论是异常还是中断,都会引起程序执行偏离正常的流程,转而去执行异常/中断的处理函数。

下面对异常和中断的介绍,如果中断信号的产生原因来自CPU内部,则称之为异常;如果中断信号来自CPU外部,则称之为中断。有些场合如果没有明确指出是异常还是中断,就统称为中断。

1.1 为什么需要中断

在网上看到一个非常有意思的例子,这里引用下类似的例子来说明为什么需要中断。当你正在看一部很喜欢的电影时,这个时候你觉得有点口渴了,需要去烧一壶开水,假设水烧开需要10分钟。那么请问你如何知道水烧开了呢?也许你会有这两种选择:

  1. 每隔一小会你就跑去看一下这壶水有没有被烧开,然后回来接着看电影;
  2. 你可以等到水壶发出水被烧开的声音才去看一下,这期间你一直在看电影。

第一种情况的处理方式,实际上就是不断的查询水是否被烧开了,如果烧开了就关火,没烧开就接着继续看电影,这种处理方式可能会累死你,而且你也会觉得自己有点笨。写程序描述如下:

while (1)
{
   
	see a film(看电影)
    check water boiling(查看水是否烧开)
    if (水还没开)
        return(继续看电影)
    else
        关火    
}

第二种方式可以看作是烧开水的声音发出了一个信号给你,你接收到这个信号,然后就知道了我该去关火了,也就是说这个信号中断了你看电影的过程,而在这之前你可以一直享受看电影的过程。写程序描述如下:

while (1)
{
   
	see a film(看电影)   
}

中断服务程序()
{
   
    关火
}

这个例子类比于CPU的话,CPU也是可以选择这两种方式去处理意外事件的,查询方式或者中断方式。对于查询方式很明显会使得CPU的资源无法得到充分的利用,因为CPU的速度是远远大于外设的速度的,CPU在查询外设的状态时就需要等待外设的响应,使得CPU做了很多无用功。而对于中断方式,当外部事件还没达到就绪状态时(类比就是水还没烧开这件事),CPU可以专心的做其他任务,一旦CPU接收到中断信号时,转而去处理中断请求,CPU处理完毕之后再接着执行原来的任务。

从这个类比的例子可以看出,中断机制使得CPU具有了异步处理能力。有了中断机制之后,CPU可以一直专心的执行它的主任务,不用一直去查询设备的状态。设备本身如果达到了就绪状态,需要CPU去处理的时候,此时设备发出一个中断信号给CPU,通知CPU说:“我要你来处理一下了,赶紧来吧”!CPU收到通知之后,先把主任务暂停一会,然后跳转到相应外设的中断服务函数处理该外设的中断请求,处理完之后CPU再继续回去执行主任务。

1.2 ARM体系如何使用中断

在ARM体系中,使用中断的过程一般有如下步骤:

  1. 中断初始化

    1.1 设置中断源,让某个外设可以产生中断;

    1.2 设置中断控制器,使能/屏蔽某个外设的中断通道,设置中断优先级等;

    1.3 使能CPU中断总开关

  2. CPU在运行正常的程序

  3. 产生中断,比如用户按下了按键 —> 中断控制器 —> CPU

  4. CPU每执行完一条指令都会检查是否有异常/中断产生

  5. 发现有异常/中断产生,开始处理:

    5.1 保存现场

    5.2 分辨异常/中断,调用对应的异常/中断处理函数

    5.3 恢复现场

2. STM32异常与中断处理流程

2.1 概述

上面

<think>嗯,用户想了解PendSV和SysTick之间的关系。首先,我需要回忆一下这两个东西在嵌入式系统中的作用,尤其是在ARM Cortex-M系列处理器中的角色。 SysTick定时器是Cortex-M内核自带的一个系统定时器,主要用来产生周期性的中断。通常,操作系统(比如FreeRTOS或μC/OS)会用SysTick来作为系统时钟节拍,也就是时间片轮转调度的基础。每次SysTick中断发生时,系统会进行任务调度,检查是否有更高优先级的任务需要运行,从而进行上下文切换。 而PendSV(可挂起的系统调用)也是一种异常,但它的优先级通常被设置为最低。在操作系统中,PendSV通常用于执行实际的上下文切换操作。当系统需要延迟某个高优先级的中断处理时,比如在SysTick中断中触发任务切换,但又不希望立即执行,这时就可以挂起PendSV异常,等所有高优先级的中断处理完成后,再处理PendSV,进行上下文切换。 那它们之间的关系可能在于协作完成操作系统的任务调度。SysTick提供定时中断,触发调度需求,而PendSV则负责实际的上下文切换,避免在SysTick中断中直接进行切换,导致高优先级中断被延迟。 不过可能用户想知道更具体的交互过程。例如,当SysTick中断发生时,系统会设置一个标志,表示需要调度,然后触发PendSV异常。由于PendSV的优先级较低,当前中断处理完成后,PendSV才会执行,进行上下文切换。这样可以确保及时响应其他高优先级的中断,同时完成任务的切换。 需要确认的是,PendSV和SysTick都是异常,但优先级不同,SysTick的中断优先级一般较高,而PendSV被设置为最低,这样的设计是为了让调度操作不会阻塞其他中断的处理。 可能还需要解释上下文切换的具体步骤,比如保存当前任务的寄存器状态,恢复下一个任务的寄存器等,这些都是在PendSV处理函数中完成的,而SysTick只是触发调度的时机。 另外,可能存在的疑问是,为什么不用SysTick直接处理上下文切换?因为SysTick中断如果处理时间过长,可能会影响其他中断的响应,尤其是高优先级的中断。通过将实际的切换操作延迟到PendSV,系统可以更高效地处理中断嵌套,确保实时性。 总结来说,SysTick和PendSV在任务调度中各司其职:SysTick作为时间源触发调度请求,PendSV作为延迟的上下文切换执行者,两者协作实现高效的任务调度和中断管理。</think>在ARM Cortex-M系列处理器中,**PendSV**(可挂起的系统调用)和**SysTick**(系统定时器)是协作实现任务调度和上下文切换的关键组件。它们的关系可总结如下: --- ### 1. **SysTick的核心作用** - **周期性中断生成** SysTick是处理器内置的24位倒计时定时器,用于产生**周期性中断**(通常为1ms或10ms)。 **用途**:为操作系统(如FreeRTOS、RTOS)提供时间基准,驱动时间片轮转调度。 - **触发调度请求** 每次SysTick中断发生时,系统会检查是否需要任务切换(例如时间片耗尽、更高优先级任务就绪)。 --- ### 2. **PendSV的核心作用** - **延迟上下文切换** PendSV是一种可挂起的异常,**优先级最低**(确保不阻塞其他中断)。 **用途**:实际执行上下文切换操作(保存当前任务状态,恢复新任务状态)。 --- ### 3. **两者协作流程** 1. **SysTick中断触发** - 定时器到期时,SysTick中断触发,系统标记需要调度(如设置`os_context_switch_req = 1`)。 - **不立即切换**:避免在SysTick ISR(高优先级)中直接切换,防止中断延迟。 2. **触发PendSV异常** - 在SysTick中断退出前,手动触发PendSV异常(设置`ICSR.PENDSVSET = 1`)。 3. **执行PendSV处理** - 由于PendSV优先级最低,处理器会先完成所有高优先级中断,再进入PendSV处理函数。 - **实际上下文切换**:保存当前任务寄存器到栈,加载新任务寄存器,切换任务。 --- ### 4. **设计优势** - **实时性保障** SysTick快速标记调度需求,PendSV延迟切换,避免在高优先级中断中执行耗时操作。 - **中断嵌套友好** 即使SysTick中断被其他中断抢占,PendSV仍会在所有高优先级中断完成后执行。 --- ### 5. **代码示例(伪代码)** ```c // SysTick中断处理函数 void SysTick_Handler(void) { os_tick_increase(); // 更新时间戳 if (need_context_switch()) { SCB->ICSR |= SCB_ICSR_PENDSVSET_Msk; // 触发PendSV } } // PendSV处理函数 void PendSV_Handler(void) { save_current_task_context(); // 保存当前任务上下文 switch_to_next_task(); // 切换到新任务 restore_new_task_context(); // 恢复新任务上下文 } ``` --- ### 总结 - **SysTick**:提供时间基准,触发调度请求。 - **PendSV**:以最低优先级执行实际的上下文切换。 - **协作关系**:SysTick“发信号”,PendSV“干活”,确保实时性和低延迟。
评论 15
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值