精华内容
下载资源
问答
  • 中断过程的流程图

    2021-11-23 16:37:51
    中断处理过程 中断隐指令 关中断 保存断点 引出中断服务程序 中断(处理)程序 保存现场和屏蔽字 中断服务程序 开中断 执行中断服务程序 关中断 恢复现场和屏蔽字 开中断 中断返回 ...

    (1).中断请求

    • 内中断外中断
    • 硬件中断软件中断
    • 非屏蔽中断和可屏蔽中断

    (2).中断判优

    (3).中断响应

    (4).中断处理过程

    • 中断隐指令
      • 关中断
      • 保存断点
      • 引出中断服务程序
    • 中断(处理)程序
      • 保存现场和屏蔽字
      • 中断服务程序
        • 开中断
        • 执行中断服务程序
        • 关中断
      • 恢复现场和屏蔽字
      • 开中断
      • 中断返回
        xmind中断图示
    展开全文
  • 文章目录并发的进程切换中断技术中断中断过程特权指令和非特权指令进程调度 并发的进程切换 要了解并发进程的切换,首先要清楚知道什么是并发的进程!! 并发的进程最主要的特点就是走走停停的状态,从运行的...

    并发的进程切换

    要了解并发进程的切换,首先要清楚知道什么是并发的进程!!
    并发的进程最主要的特点就是走走停停的状态,从运行的开始到结束不是一步运行到底的,是走走,然后cup被调度走就停停,等到需要进程继续执行的时候,又可以被分配到cpu资源,然后走走;如此反复,知道进程运行结束!


    在这里插入图片描述


    (单cpu的讨论)如上图的两个进程process1和process2,虚线部分表示进程停止,实线部分表示进程运行,当process1停的时候,process2就运行,此时这个过程就是进程切换。


    我们需要关注的两个问题:
    1.❓ 是什么导致了进程切换?

    中断。

    2. ❓进程切换要做什么?

    进程切换的时机有主动和被动离开cpu;
    主动:比如:IO语句,系统调用;
    被动:比如:高优先级进程,时间片到期;
    进程切换就是和中断很基本一样的方式,而进程之所以能够被切换,也是有中断处理程序在执行,让进程能够切换,所以说中断处理程序也是一个很特殊的中断,它能够让进程发生切换。
    总的来说:进程切换就是要执行中断处理程序咯,还有做的事情和中断做的事情。

    在这里插入图片描述


    中断技术

    在这里插入图片描述
    在这里插入图片描述
    理解上面的图:

    当发生某个事件时,意味着进程不能继续执行了,那么cpu就不会为进程服务了;
    然后引起中断的事件,也就是使得进程不能继续运行的事件,它就会被执行;
    当中断事件执行完毕后,会返回原程序继续执行,也就是回到进程继续执行;


    运行的进程在用户态,而进行中断的事件是在内核态;而中断的过程就是一种陷阱机制,也就是说,从用户态陷入内核态执行内核态的进程,当执行完毕中断事件后,又会回到用户态继续执行原进程。


    中断源

    ❓进程发生中断的原因是来自什么?
    在这里插入图片描述

    中断分为两种:

    1. 一种是外中断(我们通常叫为interruption);外中断特点是异步中断,就是随机中断,它的中断源是不可预知的,即对于进程来说是不知道什么时候会发生中断;
    2. 一种是内中断(也就是异常exception);内中断时同步中断,指程序执行过程中发生的中断,不是外部引起的,是程序自身引起的
      这两种都是中断;

    中断的过程

    在这里插入图片描述
    中断的过程:
    是从用户态陷入内核态的一个过程:在从用户态陷入内核态之前:会先保存进程上下文的内存信息;
    然后再进入内核态,进入内核态要知道中断源是什么,然后处理中断源;
    然后处理中断程序结束后,就会选择进程来恢复上下文信息,就继续执行恢复后的进程;
    ❓什么是进程上下文的信息呢

    就是该进程的对cpu使用的时间,进程的计算结果等其他和进程的关键的信息,由于这个信息很多,所以用一个抽象的说法,上下文信息,主要是为了中断事件结束后,还能回到原来中断时候的地方继续执行进程。举个例子:比如你家里写作业,有5到题要写,写着一半,你妈妈突然喊你曲吃饭,此时,你就需要去吃饭,而在你的大脑中,会记住你作业做到哪里的位置,这样等吃完饭回来后,你还可以从上次没写完的那个地方开始写作业。你记住写作业写到哪里的位置就是上下文信息啦。


    特权指令和非特权指令

    特权指令:就是运行在内核态的一些指令:
    常见的特权指令有:如下图的;其中我们要讲的进程切换也是运行在内核态的特权指令
    在这里插入图片描述
    ❓cpu怎么知道要执行的指令是特权指令还是非特权指令?

    靠的是硬件来完成:硬件中有个个双模式dual mode的bit位:0 表示内核模式,1表示用户模式;


    用户态和内核态的模式切换:
    中断是从用户态切换到内核态的唯一途径!!!
    一旦发生中断,就会有模式切换的过程,就是用户态到内核态的切换!!!
    在这里插入图片描述
    下图:从中断的时刻开始,到中断处理程序的过程的开始中:就是模式切换的过程
    在这里插入图片描述


    进程的切换

    一个进程要被切换,肯定是处于运行状态才有资格被切换,进程被切换了意味着进程要离开cpu,离开cup的原因就有两种:一种是主动离开,一种是被动离开;比如主动离开的是执行IO设备啊等其他原因,被动离开的是进程时间片到了等其他原因;那么进程离开cpu就去哪了呢? 进程离开cpu就会到等待状态,或者就绪状态
    在这里插入图片描述
    进程切换和中断有什么关系呢?


    进程控制块–PCB

    每个进程都有一个PCB,这个PCB我们成为进程控制块,其实就是一个数据结构的代码。这个数据结构的代码保存了进程的控制信息;
    在这里插入图片描述
    对于一个完整的进程来说:是包含PCB和进程的实体(进程实体就是进程运行时候所需要的数据,代码,变量等信息)。


    进程在物理内存的存放

    进程在物理内存存放并不是连续的存放的,是离散的存放的。
    比如一个进程1:包含PCB和stack heap data text等信息,都是离散的在内存存放的;


    而离散存放的目的为了减少连续存放带来内存碎片等问题;
    同时离散存放也带来的问题是:必须要有一个表来记录这些进程离散的信息,来找到一个进程的实体;(者都是内存管理的问题,以后再讲)


    进程队列

    ❓操作系统是如何管理进程呢?
    是通过进程队列的数据结构管理的,进程队列会有就绪态的队列,和等待态的队列,一般来说,等待态的队列分为很多种,这是为方便管理每种不同的设备而设置的。
    在这里插入图片描述
    对于进程队列来说:管理的进程都是进程的PCB,而不是整个进程的上下文(PCB+进程实体)
    这是因为进程的PCB已经包含了进程的其他信息,可以通过PCB找到进程实体的信息,而且进程的PCB相对进程实体来说,也比较小,而进程实体可能会很大,频繁的入队出队,会消耗大量的cpu资源管理,这样并不好。

    进程调度

    进程调度,简单的说就是进程在各个进程队列中跑来跑去,被操作系统调去就绪队列呀,或者等待队列,或者运行态,或者运行结束!
    在这里插入图片描述
    比如一个新创建的进程,一开始就会被调度到就绪队列中,然后cpu就会在某个时间调度该进程进入运行态,如果是一直运行结束就结束进程了,如果是发生中断那么又会被调度到等待队列或者就绪队列中。

    展开全文
  • STM32异常与中断过程详解

    千次阅读 多人点赞 2021-06-14 15:14:52
    1. 异常与中断概念引入 异常主要是指来自CPU内部的意外事件,比如执行了未定义指令、算术溢出、除零运算等发生在CPU内部的意外事件,这些异常的发生,会引起CPU运行相应的异常处理程序;中断一般来自硬件(如片上...

    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 概述

    上面讲到当CPU产生异常/中断时,CPU会暂停当前程序的运行,转而去处理异常/中断的处理函数。但是这里有一些疑问:CPU如何调用异常/中断的处理函数?调用完之后如何返回?在运行中断处理函数之后,如何保证原来被打断的运行环境不被中断处理函数所改变?这几个问题是异常与中断处理流程中非常关键的问题,这些问题会在下面进行讨论,并给出解答。

    当异常/中断发生时,ARM架构对于异常/中断的处理流程基本都是:

    1. 保存现场
    2. 分辨异常/中断,调用对应的异常/中断处理函数
    3. 恢复现场

    但是细分到不同的架构(比如M3和A7架构)时,具体的处理流程还是有一些差异的,而对于STM32来说,中断的整个处理流程硬件帮我们做了大部分的工作,比如保存现场、分别异常/中断,跳转执行、恢复现场等工作,都是硬件帮我们实现了的。那么我们要做的事情是什么?我们只需要编写中断服务函数中具体想要实现的逻辑代码即可,发生异常/中断后,CPU跳转执行的就是我们实现的这部分代码。

    2.2 异常向量表

    对于STM32,当某一个外设的中断发生时,CPU如何去调用相应外设的中断服务函数?这就需要引入异常向量表的概念了。STM32的中断向量表可以看成是一个指针数组,这个数组里面存放的就是一个个的中断服务函数的入口地址(向量表首地址规定是栈顶指针)。当CPU检查到某个中断产生时,硬件会根据我们提供的中断号自动跳转到向量表中与这个中断号对应的这个中断服务函数的入口地址,从而执行相应的中断服务函数。

    比如发生了Reset异常,那么CPU会从异常向量表的第1项找到Reset_Handler函数的地址,然后跳转到该函数执行;如果发生其他中断,CPU同样可以从表格里面找到对应的中断服务函数的地址,然后跳转到该函数执行。

    STM32F103的中断向量表如下所示:

    __Vectors       DCD     __initial_sp               ; Top of Stack
                    DCD     Reset_Handler              ; Reset Handler
                    DCD     NMI_Handler                ; NMI Handler
                    DCD     HardFault_Handler          ; Hard Fault Handler
                    DCD     MemManage_Handler          ; MPU Fault Handler
                    DCD     BusFault_Handler           ; Bus Fault Handler
                    DCD     UsageFault_Handler         ; Usage Fault Handler
                    DCD     0                          ; Reserved
                    DCD     0                          ; Reserved
                    DCD     0                          ; Reserved
                    DCD     0                          ; Reserved
                    DCD     SVC_Handler                ; SVCall Handler
                    DCD     DebugMon_Handler           ; Debug Monitor Handler
                    DCD     0                          ; Reserved
                    DCD     PendSV_Handler             ; PendSV Handler
                    DCD     SysTick_Handler            ; SysTick Handler
    
                    ; External Interrupts
                    DCD     WWDG_IRQHandler            ; Window Watchdog
                    DCD     PVD_IRQHandler             ; PVD through EXTI Line detect
                    DCD     TAMPER_IRQHandler          ; Tamper
                    DCD     RTC_IRQHandler             ; RTC
                    DCD     FLASH_IRQHandler           ; Flash
                    DCD     RCC_IRQHandler             ; RCC
                    DCD     EXTI0_IRQHandler           ; EXTI Line 0
                    DCD     EXTI1_IRQHandler           ; EXTI Line 1
                    DCD     EXTI2_IRQHandler           ; EXTI Line 2
                    DCD     EXTI3_IRQHandler           ; EXTI Line 3
                    DCD     EXTI4_IRQHandler           ; EXTI Line 4
                    DCD     DMA1_Channel1_IRQHandler   ; DMA1 Channel 1
                    DCD     DMA1_Channel2_IRQHandler   ; DMA1 Channel 2
                    DCD     DMA1_Channel3_IRQHandler   ; DMA1 Channel 3
                    DCD     DMA1_Channel4_IRQHandler   ; DMA1 Channel 4
                    DCD     DMA1_Channel5_IRQHandler   ; DMA1 Channel 5
                    DCD     DMA1_Channel6_IRQHandler   ; DMA1 Channel 6
                    DCD     DMA1_Channel7_IRQHandler   ; DMA1 Channel 7
                    DCD     ADC1_2_IRQHandler          ; ADC1 & ADC2
                    DCD     USB_HP_CAN1_TX_IRQHandler  ; USB High Priority or CAN1 TX
                    DCD     USB_LP_CAN1_RX0_IRQHandler ; USB Low  Priority or CAN1 RX0
                    DCD     CAN1_RX1_IRQHandler        ; CAN1 RX1
                    DCD     CAN1_SCE_IRQHandler        ; CAN1 SCE
                    DCD     EXTI9_5_IRQHandler         ; EXTI Line 9..5
                    DCD     TIM1_BRK_IRQHandler        ; TIM1 Break
                    DCD     TIM1_UP_IRQHandler         ; TIM1 Update
                    DCD     TIM1_TRG_COM_IRQHandler    ; TIM1 Trigger and Commutation
                    DCD     TIM1_CC_IRQHandler         ; TIM1 Capture Compare
                    DCD     TIM2_IRQHandler            ; TIM2
                    DCD     TIM3_IRQHandler            ; TIM3
                    DCD     TIM4_IRQHandler            ; TIM4
                    DCD     I2C1_EV_IRQHandler         ; I2C1 Event
                    DCD     I2C1_ER_IRQHandler         ; I2C1 Error
                    DCD     I2C2_EV_IRQHandler         ; I2C2 Event
                    DCD     I2C2_ER_IRQHandler         ; I2C2 Error
                    DCD     SPI1_IRQHandler            ; SPI1
                    DCD     SPI2_IRQHandler            ; SPI2
                    DCD     USART1_IRQHandler          ; USART1
                    DCD     USART2_IRQHandler          ; USART2
                    DCD     USART3_IRQHandler          ; USART3
                    DCD     EXTI15_10_IRQHandler       ; EXTI Line 15..10
                    DCD     RTCAlarm_IRQHandler        ; RTC Alarm through EXTI Line
                    DCD     USBWakeUp_IRQHandler       ; USB Wakeup from suspend
                    DCD     TIM8_BRK_IRQHandler        ; TIM8 Break
                    DCD     TIM8_UP_IRQHandler         ; TIM8 Update
                    DCD     TIM8_TRG_COM_IRQHandler    ; TIM8 Trigger and Commutation
                    DCD     TIM8_CC_IRQHandler         ; TIM8 Capture Compare
                    DCD     ADC3_IRQHandler            ; ADC3
                    DCD     FSMC_IRQHandler            ; FSMC
                    DCD     SDIO_IRQHandler            ; SDIO
                    DCD     TIM5_IRQHandler            ; TIM5
                    DCD     SPI3_IRQHandler            ; SPI3
                    DCD     UART4_IRQHandler           ; UART4
                    DCD     UART5_IRQHandler           ; UART5
                    DCD     TIM6_IRQHandler            ; TIM6
                    DCD     TIM7_IRQHandler            ; TIM7
                    DCD     DMA2_Channel1_IRQHandler   ; DMA2 Channel1
                    DCD     DMA2_Channel2_IRQHandler   ; DMA2 Channel2
                    DCD     DMA2_Channel3_IRQHandler   ; DMA2 Channel3
                    DCD     DMA2_Channel4_5_IRQHandler ; DMA2 Channel4 & Channel5
    __Vectors_End
    

    一般来说向量表都会被链接到一个程序存储的最前面的位置的,对于STM32F103来说,程序运行和加载的起始地址都是0x08000000,所以STM32的异常向量表也会会被加载到0x08000000地址处的。

    对于ARM架构,规定向量表的基地址默认是0x00000000或0xFFFF0000位置的(对于STM32向量表的默认基地址就是0地址),而STM32向量表的基地址是被链接在了0x08000000的地址处,这样当中断发生时,不就跳转到了错误的函数入口地址了吗?为了解决这个问题,ARM允许可以修改异常向量表的基地址,这样就可以把异常向量表的基地址重新修改在内部Flash的起始地址0x08000000位置了。完成这一工作的是官方固件库的SystemInit函数,相关代码如下:

    #define FLASH_BASE       ((uint32_t)0x08000000) /*!< FLASH base address in the alias region */
    #define VECT_TAB_OFFSET  0x0 /*!< Vector Table base offset field. This value must be a multiple of 0x200. */
    #define SCB              ((SCB_Type *)           SCB_BASE)         /* !< SCB configuration struct         */
    
    void SystemInit (void)
    {
        /****************此处省略部分代码****************/
    #ifdef VECT_TAB_SRAM
      SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET;  /* Vector Table Relocation in Internal SRAM.  */
    #else
      SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH. */
    #endif 
    }
    

    其中 SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; 这一行代码就是把异常向量表基地址更改到了0x08000000的地址中去了。

    补充:我曾自己写过简单的启动文件测试,并没有去调用SystemInit函数,自己也没有在其他地方对向量表的基地址更改到0x08000000的地址中去,但是当CPU检查到有中断发生时,还是可以跳转到正确的中断服务函数的入口地址处。为什么会这样?我查阅了下相关的资料,了解到当STM32从Flash启动时,实际上会把Flash的那段存储空间0x08000000 ~ 0x0807FFFF映射到0x00000000 ~ 0x0007FFFF这一段地址的存储空间,也就是说当CPU从Flash启动时,CPU从0地址处开始执行指令和从0x08000000地址处开始执行指令是一样的。所以,这个时候我没有去更改异常向量表的基地址,CPU仍然可以跳转到正确的中断服务程序。

    2.3 保存现场

    2.3.1 概念引入

    我们在Keil里面写一段非常简单的代码,实现 a = a + b; 这个式子。当然我们并不是要去关心这个式子本身,而是利用Keil的仿真功能,去查看一下CPU执行这个式子后,其内部寄存器的变化。仿真截图如下:
    在这里插入图片描述
    从上面这个仿真的汇编代码可以看出,CPU要完成 a = a + b; 的运算,实际上是先去读取a, b的内存所保存的数据到内部寄存器r0, r1中,然后再执行r0 = r0 + r1的运算,最后把r0的值写回到内存a中,这样才完成了一次a = a + b; 的运算。另外,可以观察到CPU在运行程序的过程中,它内部的r0 - r15,还有程序状态寄存器xPSR的值,都是在不断的变化中的。

    那么问题来了,假设CPU在运行 a = a + b; 这个式子的中途,程序运行过程被中断信号打断了。要想这个式子可以得到正确的结果,那么就要确保中断前CPU的这几个寄存器的值以及中断返回后这些寄存器的值都要保持不变,还有保存在内存空间a, b的值也不会被改变。这样运行这个式子得到的最终结果才是正确的。

    对于保持a, b内存的值不变,这个好办,中断程序中不要去改写a, b的值即可。但是我们如何保持中断前后CPU内部寄存器的值不被改变呢?因为中断程序的运行肯定也是需要用到CPU内部的寄存器的,所以必须得有一种机制去保持中断前后CPU内部寄存器的值不被改变。也就是说,所谓的现场,实际上就是CPU运行到某一时刻时,CPU内部寄存器的值

    那么如何保存现场和恢复现场呢?这就需要用到栈。CPU在跳转到异常/中断程序前,就需要把这些不希望被中断程序所改变的寄存器的值保存到栈中,这就是保存现场。在异常/中断处理完之后,从栈中恢复这些寄存器的值,这就是恢复现场

    2.3.2 保存哪些寄存器的值

    上面说了,所谓保存现场就是保存CPU内部一些寄存器的值到栈中。CPU内部常用的寄存器有 r0 ~ r15,再加上程序状态寄存器,一共16个(当然其他模式下可能还有对应的其他寄存器)。下图就是STM32F103内部寄存器示例(M3内核不具有浮点运算单元,这里不讨论浮点运算单元的寄存器了):
    在这里插入图片描述
    当发生异常/中断时,CPU跳转之前,就需要把这些寄存器的值保存到栈中,那么我们需要把CPU的这16个寄存器都保存到栈中吗?很显然是不需要的。

    ARM公司推出了一个ATPCS标准,即ARM-THUMB procedure call standard(ARM-Thumb过程调用标准)。在这份标准里面,都规定了这16个寄存器的使用规则,如下表所示:

    寄存器别名使用规则
    r15pc程序计数器
    r14lr连接寄存器
    r13sp数据栈指针
    r12ip子程序内部调用的scratch寄存器
    r11v8ARM状态局部变量寄存器8
    r10v7、s1ARM状态局部变量寄存器7、在支持数据栈检查的ATPCS中为数据栈限制指针
    r9v6、sbARM状态局部变量寄存器6、在支持RWPI的ATPCS中为静态基址寄存器
    r8v5ARM状态局部变量寄存器5
    r7v4、wrARM状态局部变量寄存器4、Thumb状态工作寄存器
    r6v3ARM状态局部变量寄存器3
    r5v2ARM状态局部变量寄存器2
    r4v1ARM状态局部变量寄存器1
    r3a4参数/结果/scratch 寄存器4
    r2a3参数/结果/scratch 寄存器3
    r1a2参数/结果/scratch 寄存器2
    r0a1参数/结果/scratch 寄存器1

    其中,r0 ~ r3是函数调用时用来传递参数或者保存函数返回值的,r4 ~ r11是用来保存局部变量的,r12 ~ r15是特殊功能寄存器。这些寄存器一般会被拆分成2部分:调用者保存的寄存器(r0-r3, r12, lr, psr)被调用者保存的寄存器(r4-r11)

    比如函数A调用函数B,那么函数A就是调用者,函数B就是被调用者。那么根据这份ATPCS规则,函数A在调用函数B之前,函数A就应该要保存r0-r3, r12, lr, psr这几个调用者要保存的寄存器;而对于r4-r11这几个寄存器,调用函数B的前后,函数B本身会保证调用前后这些寄存器的值保持不变。

    那么,如果函数B是中断服务函数,因为函数B本身会保证r4-r11的值不会被改变,所以保存现场也就是保存r0-r3, r12, lr, psr这几个寄存器的值即可。

    2.3.3 STM32如何保存现场

    我们已经知道了什么是现场,保存现场要保存哪些寄存器的值了。那么对于STM32来说,是如何保存这些寄存器的值到栈中的呢?

    非常幸运的是,STM32保存现场的工作是CPU的硬件自动帮我们完成的(我们不要想当然的认为所有架构的硬件都会帮我们完成这部分工作,对于Cortex-A7架构来说就不是硬件帮我们完成的),我们不需要自己写代码去把中断前需要保存的寄存器的值存放到栈中。具体过程如下图所示:
    在这里插入图片描述

    2.4 恢复现场

    恢复现场就是指CPU执行完异常/中断服务函数后,返回到LR寄存器所指示的地址处(就是中断前的下一条指令的地址),并且把保存在栈中寄存器的值恢复到寄存器中去。

    对于如何返回到中断前下一条指令的地址,其实很容易就可以实现,只要我们把下一条指令的地址存放到LR寄存器即可,CPU返回的话就是把LR寄存器的值赋值给PC程序计数器,这样就可以返回到了中断前下一条指令中继续运行程序了。但是如果这样做的话,硬件帮我们保存在栈中的寄存器的值,返回去是怎么恢复那些寄存器的值?

    对于这个问题,STM32帮我们实现了一套机制。CPU进入异常/中断服务程序时,LR寄存器保存的并不是中断前下一条指令的地址,而是会保存一个特殊的数值,被称为EXC_RETURN。对于EXC_RETURN位域的定义和具体的数值含义,可以查看《ARM Crotex-M3与Cortex-M4权威指南》一书中第八章的描述。这里截图如下作为参考:
    在这里插入图片描述
    所以,当异常/中断返回时,LR寄存器赋值给PC的值是一个被称为EXC_RETURN的值,而一旦CPU识别到PC的值等于EXC_RETURN的话,那么就会触发异常/中断返回机制,这个机制会帮我们把保存在栈中r0-r3, r12, lr, psr的寄存器的值恢复回去。

    展开全文
  • UCOSII的中断过程简介系统接收到中断请求后,如果CPU处于开中断状态,系统就会中止正在运行的当前任务,而按中断向量的指向去运行中断服务子程序,当中断服务子程序运行完成后,系统会根据具体情况返回到被中止的...

    一.   UCOSII的中断过程简介

    系统接收到中断请求后,如果CPU处于开中断状态,系统就会中止正在运行的当前任务,而按中断向量的指向去运行中断服务子程序,当中断服务子程序运行完成后,系统会根据具体情况返回到被中止的任务继续运行,或转向另一个中断优先级别更高的就绪任务。

    由于UCOS II是可剥夺型的内核,所以中断服务程序结束后,系统会根据实际情况进行一次任务调度,如果有优先级更高的任务,就去执行优先级更高的任务,而不一定要返回被中断了的任务。

    二.UCOSII的中断过程的示意图

    三.具体中断过程

    1.中断到来,如果被CPU识别,CPU将查中断向量表,根据中断向量表,获得中断服务子程序的入口地址。

    2.将CPU寄存器的内容压入当前任务的任务堆栈中(依处理器的而定,也可能压入被压入被中断了的任务堆栈中。

    3.通知操作系统将进入中断服务子程序。即:调用OSIntEnter()或OSIntNesting直接

    加1。

    4.If(OSIntNesting==1) {OSTCBCur->OSTCBStrPtr=SP;} //如果是第一层中断,则将堆栈指针保存到被中断任务的任务控制块中

    5.清中断源,否则在开中断后,这类中断将反复的打入,导致系统崩贵

    6.执行用户ISR

    7.中断服务完成后,调用OSIntExit().如果没有高优先级的任务被中断服务子程序激活而进入就绪态,那么就执行被中断了的任务,且只占用很短的时间.

    8.恢复所有CPU寄存器的值.

    9.执行中断返回指令.

    四.相关代码

    与编译器相关的数据类型:

    typedef unsigned char BOOLEAN;

    typedef unsigned char INT8U;

    typedef unsigned int OS_STK; //堆栈入口宽度为16 位

    (一) void  OSIntEnter (void)的理解

    uCOS_II.H中定义:

    #ifdef   OS_GLOBALS

    #define  OS_EXT

    #else

    #define  OS_EXT  extern

    #endif     //定义全局宏OS_EXT

    #ifndef  TRUE

    #define  TRUE   1

    #endif

    OS_EXT  BOOLEAN   OSRunning; //定义外部BOOLEAN类型全局变量,用来指示

    //核是否在运行

    OS_EXT  INT8U   OSIntNesting;//定义外部8位无符号整型数全局变量,用来表

    //示中断嵌套层数

    OS_CORE.C中的OSIntEnter()函数原型:

    void  OSIntEnter (void)

    {

    if (OSRunning == TRUE) //如果内核正在运行则进入if

    {

    if (OSIntNesting < 255) //如果嵌套层数小于255,则可以继//续

    {

    OSIntNesting++; //嵌套层数加1

    }

    }

    }

    (二)在中断服务子程序中加if ( OSIntNesting == 1){…}的原因

    uCOS_II.H中定义:

    typedef struct os_tcb {

    OS_STK    *OSTCBStkPtr;//声明指向任务堆栈栈顶的16位指针

    ………………

    } OS_TCB;//定义名为OS_TCB的结构体数据类型,即任务控制块的数据结构

    OS_EXT  OS_TCB   *OSTCBCur;//声明一个指向任务控制块的全局指针变量

    //用于指向当前任务的任务控制块

    中断服务程序中添加的代码:

    if ( OSIntNesting == 1)

    {

    OSTCBCur->OSTCBStkPtr = SP; // 如果是第一层中断,则将被中断任务

    //的堆栈指针保存在被中断任务的任务

    //任务控制块中

    }

    关于uCOS-II的中断服务程序(ISR)中必须加“OSIntNesting == 1”的原因 ==避免调整堆栈指针.

    出现这个问题的根源是当低优先级的任务被中断,当中断完成后由于有高优先级的任务就绪,则必须调度高优先级的任务,原来的低优先级任务继续被中断着,但是此时的低优先级任务的堆栈已经被破坏,已不能被调度程序直接调度了,要想被调度而必须调整堆栈指针。如下图所示的场景:

    问题分析:   要想理解加上上面两句的原因,不妨假设有下面场景出现:void MyTask(void)

    {

    ...

    }该任务在执行过程中被中断打断,下面是它的服务子程序

    void MyISR(void)

    {保存现场(PUSHA)

    OSIntEnter();

    //此时的堆栈指针是正确的,再往下就不对了,应该在此处保存用户任务堆栈指针 OSIntExit();恢复现场(POPA)    中断返回}

    OSIntExit(),大体如下:

    OSIntExit()

    {

    OS_ENTER_CRITICAL();

    if( OSIntNesting==0 && OSLockNesting == 0 ) {找到目前系统中就绪表中优先级最的任务      如果不是当前任务,则调度它执行OSIntCtxSw();

    }

    OS_EXIT_CRITICAL();

    }

    综上所述,任务调用链如下:MyTask --> MyISR -->

    ①     OSIntExit -->

    ②        OS_ENTER_CRITICAL(); ③

    OSIntCtxSw();        ④

    然而在实际的移植过程中,需要调整的指针偏移量是与编译器相关的,如果想要避免调整,显然一个简单的方法就是在调用OSIntExit之前先把堆栈指针保存下来,以后调度该用户任务时,直接从此恢复堆栈指针,而不再管实际的堆栈内容了(因为下面的内容相对于调度程序来说已经没有用处了)

    (三) void OSIntExit (void)的理解

    OS_CPU.H中的宏定义:

    typedef unsigned short OS_CPU_SR;      //定义OS_CPU_SR为16位的CPU状态寄存器

    #if      OS_CRITICAL_METHOD == 1

    #define  OS_ENTER_CRITICAL()  asm  CLI // OS_ENTER_CRITICAL()即为将处理器标志

    //寄存器的中断标志为清0,不允许中断

    #define  OS_EXIT_CRITICAL()   asm  STI // OS_ENTER_CRITICAL()即为将处理器标志

    //寄存器的中断标志为置1,允许中断

    #endif                                 //此一整段代码定义为开关中断的方式一

    #if      OS_CRITICAL_METHOD == 2

    #define  OS_ENTER_CRITICAL()  asm {PUSHF; CLI} //将当前任务的CPU的标志寄存器入

    //然后再将中断标志位清0

    #define  OS_EXIT_CRITICAL()   asm  POPF  //将先前压栈的标志寄存器的值出栈,恢复

    //到先前的状态,如果先前允许中断则现在

    //仍允许,先前不允许现在仍不允许

    #endif                                 //此一整段代码定义为开关中断的方式二

    #if      OS_CRITICAL_METHOD == 3

    #define  OS_ENTER_CRITICAL()  (cpu_sr = OSCPUSaveSR()) //保存CPU的状态寄存器到

    //变量cpu_sr中,cpu_sr

    //为OS_CPU_SR型变量

    #define  OS_EXIT_CRITICAL()   (OSCPURestoreSR(cpu_sr))// 从cpu_sr中恢复状态寄存

    //器

    #endif                                  //此一整段代码定义为开关中断的方式三,

    //此段代码只是示意代码,OSCPUSaveSR()及

    //OSCPURestoreSR(cpu_sr)具体什么函数由

    //用户编译器所提供的函数决定.

    //以上宏定义非常重要,在使用不同处理器时要使用相应处理器的开关中断指令,在代码移//植时很有用

    uCOS_II.H中定义:

    OS_EXT  INT8U   OSLockNesting; //8位无符号全局整数,表示锁定嵌套计数器

    void  OSIntExit (void)

    {

    #if OS_CRITICAL_METHOD == 3

    OS_CPU_SR  cpu_sr;

    #endif   //采用开关中断方式三

    if (OSRunning == TRUE) //如果内核正在运行,则进入if

    {

    OS_ENTER_CRITICAL();//进入临界段,关中断

    if (OSIntNesting > 0) //判断最外层中断任务是否已完成

    {

    OSIntNesting--;//由于此层中断任务已完成,中断嵌套计数器减//一

    }

    if ((OSIntNesting == 0) && (OSLockNesting == 0))

    // OSIntNesting==0表示程序的最外层中断任务以完成, OSLockNesting == 0

    //表示是否存在任务锁定,整句代码的意思是如果全部中断处理完了且没有其他

    //任务锁定任务调度则执行下列任务调度代码

    {

    OSIntExitY  = OSUnMapTbl[OSRdyGrp];                  //1

    OSPrioHighRdy = (INT8U)((OSIntExitY << 3) + OSUnMapTbl[OSRdyTbl[OSIntExitY]]);  //2

    if (OSPrioHighRdy != OSPrioCur)                  //3

    {

    OSTCBHighRdy  = OSTCBPrioTbl[OSPrioHighRdy];

    OSCtxSwCtr++;

    OSIntCtxSw();

    }

    }

    OS_EXIT_CRITICAL();//开中断

    }

    }

    要理解1,2,3处的代码含义.首先要理解任务是如何调度的,所以先讲一下任务调度的核心算法:

    a.数据结构:

    1.就绪表:就绪表包含两个变量,他们分别是OSRdyGrp(在uCOS_II.H中为OS_EXT  INT8U  OSRdyGrp;即8位无符号整型的全局变量)和OSRdyTb1[](在uCOS_II.H中为OS_EXT  INT8U   OSRdyTbl[OS_RDY_TBL_SIZE];)

    先分析 OS_EXT INT8U  OSRdyTbl[OS_RDY_TBL_SIZE];是怎么回事

    #define OS_LOWEST_PRIO  12 //在OS_CFG.H中

    这个宏定义了任务所能具有的最低优先级,那么此处共有从0到12共13个优先级,用户在代码移植时可以修改它,自定义所需要的优先级个数,但max(OS_LOWEST_PRIO)==63

    #define  OS_RDY_TBL_SIZE   ((OS_LOWEST_PRIO) / 8 + 1) //在uCOS_II.中

    OS_RDY_TBL_SIZE用于确定数组OSRdyTbl[]的大小,如果OS_LOWEST_PRIO==63,则上述宏实际上为#define  OS_RDY_TBL_SIZE  8,由于每个数组元素为8位,如果每一位表示一个优先级,则共有8*8=64个优先级

    现在回到就绪表,操作系统将优先级分为8组,优先级从0到7分为第一组,对应于OSRdyGrp的第0位,从8到15分为第二组,对应于OSRdyGrp的第1位,以此类推,64个优先级就有下面的对应关系(OSRdyTb1[]每组元素的每一位代表一个优先级):

    OSRdyTb1[0]--------------优先级从0到7--------------OSRdyGrp第0位

    OSRdyTb1[1]--------------优先级从8到15-------------OSRdyGrp第1位

    OSRdyTb1[2]--------------优先级从16到23-------------OSRdyGrp第2位

    OSRdyTb1[3]--------------优先级从24到31-------------OSRdyGrp第3位

    OSRdyTb1[4]--------------优先级从32到39-------------OSRdyGrp第4位

    OSRdyTb1[5]--------------优先级从40到47-------------OSRdyGrp第5位

    OSRdyTb1[6]--------------优先级从48到55-------------OSRdyGrp第6位

    OSRdyTb1[7]--------------优先级从55到63-------------OSRdyGrp第7位

    现在再做如下对应:

    当OSRdyTbl[0]中的任何一位是1时,OSRdyGrp的第0位置1,

    当OSRdyTbl[1]中的任何一位是1时,OSRdyGrp的第1位置1,

    当OSRdyTbl[2]中的任何一位是1时,OSRdyGrp的第2位置1,

    当OSRdyTbl[3]中的任何一位是1时,OSRdyGrp的第3位置1,

    当OSRdyTbl[4]中的任何一位是1时,OSRdyGrp的第4位置1,

    当OSRdyTbl[5]中的任何一位是1时,OSRdyGrp的第5位置1,

    当OSRdyTbl[6]中的任何一位是1时,OSRdyGrp的第6位置1,

    当OSRdyTbl[7]中的任何一位是1时,OSRdyGrp的第7位置1,

    如果置1表示有任务进入就绪态,那么上面的表可以理解为:OSRdyGrp的第N位(0<=N<=7)为1,那么在OSRdyTb1[N]中至少有一位是1,也就是说在OSRdyTb1[N]对应的任务中至少有一个任务处于就绪态

    该表在OS_CORE.C中定义如下:

    INT8U  const  OSMapTbl[]={0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};

    //8位无符号整型常量数组

    3.表(数组)OSUnMapTb1[]:用于求出一个8位整型数最低位为1的位置

    该数组在OS_CORE.C中定义如下:

    INT8U  const  OSUnMapTbl[] = {

    0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,       /* 0x00 to 0x0F */

    4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,       /* 0x10 to 0x1F */

    5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,       /* 0x20 to 0x2F */

    4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,       /* 0x30 to 0x3F */

    6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,       /* 0x40 to 0x4F */

    4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,       /* 0x50 to 0x5F */

    5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,       /* 0x60 to 0x6F */

    4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,       /* 0x70 to 0x7F */

    7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,       /* 0x80 to 0x8F */

    4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,       /* 0x90 to 0x9F */

    5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,       /* 0xA0 to 0xAF */

    4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,       /* 0xB0 to 0xBF */

    6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,       /* 0xC0 to 0xCF */

    4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,       /* 0xD0 to 0xDF */

    5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,       /* 0xE0 to 0xEF */

    4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0        /* 0xF0 to 0xFF */

    };

    理解: 我把问题转化为:

    “一个无符号的8位整数,如何确定最低位为1的位的位置?”

    即对于任意一个8位整型数,比如4,考虑它的二进制位中所有为1的位,确定最低位为1的位置(相对第0位的偏移),一般来讲首先想到的方法是移位的方法.如:

    pos=0;//pos用于统计相对于第0位的偏移

    while( !(num & 0x01) )//与00000001按位于,如果最低位为1,退出循环,即找到最低位//为1的位

    {

    num=num>>1;//将二进制数右移一位

    pos++;//进行一次移位,则pos加一

    }

    最后得到的pos就是所有位中为1的最低位的偏移量,但这样计算需要时间,尽管最多右移7次。为了节省时间,使用的方法是“空间换时间”的办法,即把8位无符号数,所有可能的情况的都列了出来,共有256个数字,把每个数字的最低为1位的位置都预先计算好。比如4对应二进制数为100,最低为1位相对第0位偏移量为2,则查表时,以4为索引,马上就得到2这个数字。(即:OSUnMapTb1[4]==2)

    b.构建OSRdyGrp和OSRdyTb1[]算法:

    代码原型在OS_CORE.C中,实际代码大致如下:(prio为任务优先级)

    INT8U  OS_TCBInit (INT8U prio, OS_STK *ptos, OS_STK *pbos, INT16U id, INT32U stk_size, void *pext, INT16U opt)

    {

    …………

    ptcb->OSTCBY         = prio >> 3;

    ptcb->OSTCBBitY      = OSMapTbl[ptcb->OSTCBY];

    ptcb->OSTCBX         = prio & 0x07;

    ptcb->OSTCBBitX      = OSMapTbl[ptcb->OSTCBX];

    …………..

    OSRdyGrp               |= ptcb->OSTCBBitY;

    OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;

    …………..

    }//此函数在创建任务时被调用,即OSTaskCreate(..)中,用于初始化任务控制块

    以上代码可以等效于:

    OSRdyGrp  |=  OSMapTbl[prio>>3];

    OSRdyTb1[prio>>3] |= OSMapTbl[prio&0x07];

    此处 prio >> 3 是右移3位,就相当于连续除以3个2,因此相当于:prio / 8 ;

    prio & 0x07 是求低3位的值,而由高5位构成的值正好是8的整数倍,因此是取余运算,

    即:prio % 8

    因此又可将算法等效为:

    OSRdyGrp  |=  OSMapTbl[prio / 8];

    OSRdyTb1[prio / 8] |= OSMapTbl[prio % 8];

    算法的作用相当于如下流程:(假定prio=28)

    就这样把任务的优先级放入了就绪表.在此我产生一个疑问,”prio>>3与prio&0x07并不直观,为什么不用prio/8与prio%8呢?”我做如下解释:

    处理器一般具有如下结构

    累加器是具有移位功能的,prio>>3可以在累加器中完成而不必进入ALU,而prio/8则不同,要进入ALU,ALU处理速度不如累加器,如果采用prio/8将降低操作系统的实时性,同样prio&0x07只是一个间单的位与操作,而prio%8则还要经过ALU,如采用prio%8也将降低实时性.

    现在回到OSIntExit()处,看1,2,3处的代码:

    OSIntExitY  = OSUnMapTbl[OSRdyGrp];                //1

    OSPrioHighRdy = (INT8U)((OSIntExitY << 3) + OSUnMapTbl[OSRdyTbl[OSIntExitY]]);//2

    if (OSPrioHighRdy != OSPrioCur)                    //3

    {

    OSTCBHighRdy  = OSTCBPrioTbl[OSPrioHighRdy];

    OSCtxSwCtr++;

    OSIntCtxSw();

    }

    在uCOS_II.H中有如下定义:

    OS_EXT  INT8U   OSIntExitY;//8位无符号全局整型变量,用于存放就绪表中就绪的任务组

    OS_EXT  INT8U   OSPrioHighRdy;// 8位无符号全局整型变量,用于存放具有最高优先级任务的优先级

    OSUnMapTbl[]:用于计算偏移量,偏移量即为优先级最高的就绪任务组在OSRdyGrp中的位置

    以及优先级最高的任务在最高优先级任务组OSRdyTbl[N](N表示最高优先级任务组,0<=N<=7)中的位置.

    OSIntExitY  = OSUnMapTbl[OSRdyGrp];//表示获得具有最高优先级的组

    例如OSRdyGrp值为01101000(0x68),则第3,5,6组中有任务就绪,查表OSUnMapTbl[0x68]==3,即优先级最高任务组为第3组.

    OSUnMapTbl[OSRdyTbl[OSIntExitY]] //表示获得最高优先级任务组中的优先级最高的任务

    例如OSRdyTbl[3]的值为01110000(0x70),则第4,5,6位中有任务绪,OSUnMapTbl[0x70]==4,即优先级最高的任务在组中位于第4位.

    OSPrioHighRdy = (INT8U)((OSIntExitY << 3) + OSUnMapTbl[OSRdyTbl[OSIntExitY]]);

    //就是3*8+4==28,再经强制类型转换成INT8U型,赋给OSPrioHighRdy

    这样OSPrioHighRdy就获得了就绪表中优先级最高的任务

    展开全文
  • 中断响应过程

    千次阅读 2021-03-11 09:21:49
    32位微处理器的结构与工作模式 32位微处理器结构简介 32位微处理器的工作模式 寄存器 用户级寄存器 系统级寄存器 程序调试寄存器 保护模式下的内存管理 段内存管理技术 ...任务调用、链接和切换过程 ...
  • 本文介绍STM32F USB OTG FS主机的中断过程及时序,关于USB通信的原理与报文不在本文的介绍,请参考其他文档。本文根据实际的使用USB主机详细的描述的USB主机中断发生的过程及顺序,是全网少有的文章。本文介绍所...
  • 本文介绍STM32F USB OTG FS主机的中断过程及时序,关于USB通信的原理与报文不在本文的介绍,请参考其他文档。本文根据实际的使用USB主机详细的描述的USB主机中断发生的过程及顺序,是全网少有的文章。本文介绍所涉及...
  • 缺页中断处理过程.ppt

    2020-12-20 04:41:16
    缺页中断处理过程3.5.3 存储保护与共享 1. 分页式存储中的存储保护与共享 . 在页式环境下,存储保护以页面为单位。在页表的每个表项里设置一个所谓的“保护位”,由该位的不同取值定义对应页是可读、可写或只可读等...
  • Linux中断处理

    2020-12-29 10:02:16
    2.中断类型分类以及具体的中断。3.中断向量的注册。4.中断处理流程。5.各类型中断的具体执行流程。中断的类型及具体的种类Linux0.11内核注释1.可屏蔽硬件中断。优先级较低,可以被忽略或者延后处理,通常有键盘,...
  • 6.浮点加减运算过程。7.说明原码两位乘法操作步骤。8.说明单通道DMA控制器连接方式的基本工作原理和构成。9.假设一个CPU设有如下寄存器:一个内存地址寄存器(memory address register--MAR),一个内存缓冲寄存器...
  • 简述CPU中断响应过程的九大步骤

    千次阅读 2020-12-19 13:28:25
    CPU响应中断:就是CPU要去执行相应的中断服务程序,其响应过程是CPU将现在执行程序的指令地址压入堆栈,跳转到中断服务程序入口地址,中断服务程序的入口地址就是中断向量,这个中断向量用2个16位寄存器存放。...
  • 一个完整的中断处理过程应该包括

    千次阅读 2020-12-23 01:30:11
    一个完整的中断处理过程应该包括:中断请求、中断排队或中断判优、中断响应、中断处理和中断返回等环节,下面分别进行讨论。1.中断请求中断请求是由中断源向CPU发出中断请求信号。外部设备发出中断请求信号要具备...
  • 微型计算机原理及应用学习笔记 8086/8088的中断编辑整理:贵州自考网 发表时间:2013-12-05 【大 中 小】8086/8088有一个简单而灵活的中断系统,每个中断都有一个中断类型码(Type Code),以供CPU进行识别,8086/...
  • 中断中断处理流程

    千次阅读 2020-12-20 04:41:20
    1. 中断概念中断是指由于接收到来自外围硬件(相对于中央处理器和内存)的异步信号或来自软件的同步信号,而进行相应的硬件/软件处理。发出这样的信号称为进行中断请求(interrupt request,IRQ)。硬件中断导致处理器...
  • 汇编语言—中断

    2021-10-13 20:15:59
    中断——外设随机地(指主程序运行到任何一条指令时)或程序预先安排产生中断请求...中断过程 一个完整的中断基本过程包括:中断请求、中断判优、中断响应、中断处理及中断返回等五个基本过程。 (1)中断请求 ...
  • 现在,我们正式地认识一下中断中断是指微处理器在正常执行程序的过程中,当出现某些意外情况或某种外部设备请求时,暂停正在执行的程序,转而去执行某一个特定的程序,并在执行后返回原来暂停执行的程序继续执行的...
  • 中断的产生、含义,处理过程

    千次阅读 2021-06-03 09:36:39
    中断是什么           中断:cpu里面发生了某些事,需要 cpu 马上去处理,这就叫中断,处理事情的程序 叫做中断程序 除法错误 单步执行 执行 into 指令 执行 int 指令     &...
  • 本发明实施例涉及通信技术领域,尤其涉及一种PCIe中断方法和系统。背景技术:PCIe(Peripheral Component Interconnect Express,高速外围组件互联)是最新的总线和接口标准,这个新标准将全面取代现行的PCI和AGP,...
  • DSP28335笔记 ———— 中断系统 之 外部中断 我用的开发板是“硬汉DSP28335开发板”,文中对于硬件的描述可以说是没有,而且我还没有附上电路图希望在看的朋友不要喷我。 然后,我个人感觉普中的DSP28335开发手册...
  • 中断”与“轮询”“中断”处理并非单片机控制系统所特有的现象,在我们的日常生活中“中断”的例子也随处可见。...图1:“中断”处理示意图如果不用“中断”处理等待方式的话,在看书的过程中...
  • Linux软中断原理浅析

    2021-05-16 17:31:59
    在系统设计过 程中,大家都清楚中断上下文不能处理太多的事情,需要快速的返回,否则很容易导致中断事件的丢失,所以这就产生了一个问题:中断发生之后的事务软中断原理浅析Linux中的软中断机制用于系统中对时间要求...
  • STC51中断

    2021-04-17 16:37:45
    出去开门->中断过程;继续看书->返回工作   CPU与外设并行工作,当外设数据准备好或者有某种突发事件发生时,向CPU提出请求,CPU暂停正在进行的工作,转而为该外设服务(或者是处理紧急事件),处理完毕后再...
  • 外部中断执行流程

    2021-10-22 18:45:44
    设备->中断请求芯片->CPU->...4、保存断点,CPU根据中断号在RAM中的中断向量表中寻找对应中断程序 5、CPU开始执行中断程序 6、中断程序执行完毕,恢复断点 中断请求芯片8259A如下图: ...
  • 中断服务程序流程图

    千次阅读 2020-12-20 04:41:10
    引言输入/输出是微机系统与外部设备进行信息交换的过程。输入/输出设备称为外部设备,与存储器相比,外部设备有其本身的特点,存储器较为标准,而外部设备则比较复杂,性能的离散性比较大,不同的外部设备,其结构...
  • 【简答题】【单选题】某基本体的三视图及相关数据,判断正确的是【单选题】由曲面围成或由曲面和平面围成的立体称为曲面立体,如圆柱体由圆形平面和柱面构成,圆环体由圆环面构成,圆锥体由【判断题】若圆柱体的底面为...
  • DSP F28335中断系统

    2021-12-14 22:40:10
    引起 CPU 暂时中断正在运行的程序,转去执行一段特殊的服务程序(中断服务子程序或中断处理程序),以处理该事件,该事件处理完后又返回被中断的程序继续执行,这一过程就称为中断,引发中断的称为中断源。 1.2 F...
  • 如何中断Promise?

    2021-08-06 03:06:09
    Promise 有个缺点就是一旦创建就无法取消,所以本质上 Promise 是无法被终止的,但我们在开发过程中可能会遇到下面两个需求:中断调用链就是在某个 then/catch 执行之后,不想让后续的链式调用继续执行了,即:...
  • 三种中断方式接口数据是否会被覆盖 ... 中断处理时间(中断请求,中断判优,中断响应(中断隐指令硬件),中断服务(程序软件),中断返回) 是否大于IO接口充入一次的数据时间 DMA方
  • 每按一下按键(外部 0 中断 P3.2),8 个 LED 从下向上流水 1 次。 电路图: 代码: #include<reg51.h> #include<intrins.h> void delay(unsigned int m) { unsigned int i; for(;m>0;m--) { ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 499,718
精华内容 199,887
关键字:

中断的过程