精华内容
下载资源
问答
  • 外部中断事件

    2018-11-12 23:13:23
    外部中断事件 众所周知,CPU在计算机系统中,除了能够执行指令,进行运算外,还应该有输入输出功能。比如说,我现在在打字输入‘a’,CPU他会处理这个按键,并在你的屏幕上显示‘a’。我们想想,它能显示,是不是...

    外部中断事件

    众所周知,CPU在计算机系统中,除了能够执行指令,进行运算外,还应该有输入输出功能。比如说,我现在在打字输入‘a’,CPU他会处理这个按键,并在你的屏幕上显示‘a’。我们想想,它能显示,是不是打印机工作了,打印机工作。是不是CPU给它指令了,那是不是我们按键,然后CPU处理并执行。

            那么,CPU现在要处理键盘(也就是外设的输入),很明显要解决两个问题。

    1. 我们是不是随时按按键他都能执行,那么CPU如何得知。
    2. CPU如何得到外设的输入,以及他如何区别键盘输入的内容。

    接口和端口

            CPU和外设的联系是通过端口实现并控制外设的输入和输出。外设的输入不直接送入内存和CPU,而是先送到相应接口芯片的端口中:输出也是如此。CPU向外设输出控制指令也是如此。

    中断信息

            我们现在知道了,外设的输入是存放在端口中,但是它随时都有可能发生,那么CPU如何及时的知道。也就是我们提出的第一个问题。这时,CPU提供中断机制来满足这种需求。 当CPU内部需要有处理的事情发生的时候,将产生终端信息,引发中断过程,中断过程此处不多讲。这种中断信息被称为内部中断。

            还有一种中断信息,来自于CPU外部,比如说外设的输入到达。CPU在执行完当前指令的时候,会读取中断控制器信息,引发中断过程,处理外设输入

    PC系统中外中断过程(可屏蔽):

    1. 取中断类型码;
    2. 标志寄存器入栈,IF = 0,TF = 0;
    3. CS,IP入栈;
    4. 得到中断服务程序的入口地址(IP) = (n*4),(cs) = (n*4+2)
    5. 处理中断服务程序

    PC系统中外中断过程(不可屏蔽):中断类型码固定为2,所以在中断过程中不需要取中断类型码

    1. 标志寄存器入栈,IF = 0,TF = 0;
    2. CS,IP入栈
    3. (IP) = (8),(CS) = (0AH)。

    这里主要举个键盘的外部中断例子

    键盘事件:int 09h中断

         当键盘输入到端口地址60h,相关控制芯片会向CPU发出中断类型号为9的可屏蔽外部中断信息,如果此时IF(中断屏蔽标志位)为1则执行相应的中断处理。处理如下

    1. 读出60h端口中的扫描码
    2. 将扫描码和字符码送入BIOS键盘缓冲区;如果是控制键他会将其转换成状态字节(二进制)送入存储键盘状态的单元(0040:17);
    3. 对键盘系统发出相关的控制。

    编写int 9 中断例程 :

    展开全文
  • STM32的中断事件

    千次阅读 2017-07-12 18:53:36
    学习单片机一贯的套路,搞完时钟和GPIO...1.2 异常是指由于cpu本身故障、程序故障或者请求服务等引起的错误,异常属于不正常现象。Cortex-M3内核总共支持256个中断,其中包含16个内核异常和240个外部中断,但是各个芯

    学习单片机一贯的套路,搞完时钟和GPIO就要折腾中断了。

    1. 中断和异常的区别

    1.1 中断是指系统停止当前正在运行的程序转而其他服务,可能是程序接收了比自身高优先级的请求,或者是人为设置中断,中断是属于正常现象。
    1.2 异常是指由于cpu本身故障、程序故障或者请求服务等引起的错误,异常属于不正常现象。

    Cortex-M3内核总共支持256个中断,其中包含16个内核异常和240个外部中断,但是各个芯片产商在设计芯片的时候会对CM3内核的芯片进行精简设计,如STM32F103系列,所搭载的异常响应系统,包含10个系统异常和60个外部中断,用一张表将它们管理起来,编号0~15位系统异常,16以上称为外部中断。

    系统异常清单:
    这里写图片描述
    外部中断清单:
    这里写图片描述

    这里写图片描述

    外部中断信号从核外发出,信号最终要传递到NVIC(嵌套向量中断控制器)。NVIC跟内核紧密耦合,它控制着整个芯片中断的相关功能。

    2. 中断优先级

    STM32支持两种优先级:抢占优先级和子优先级。所有优先级可编程的中断源都需要指定这两种优先级。
    抢占优先级决定是否可以产生中断嵌套,子优先级决定中断响应顺序,若两种优先级一样则看中断源在中断向量表中的偏移量,偏移量小的先响应。
    对这句话的解释为:

    (1)抢占优先级高的中断源可以中断抢占优先级低的中断处理函数,进而执行高优先级的中断处理函数,执行完毕后再继续执行被中断的低优先级的处理函数。
    (2)当两个中断源的抢占优先级相同时,即这两个中断将没有嵌套关系,当一个中断到来后,若此时cpu正在处理另一个中断,则这个后到来的中
    断就要等到前一个中断处理函数处理完毕后才能被处理,当这两个中断同时到达,则中断控制器会根据它们的子优先级决定先处理哪个。
    (3)如果它们的抢占优先级和子优先级都相等,则根据它们在中断表中的排位顺序决定先处理哪一个。

    每个中断源都需要被指定抢占优先级和子优先级,自然需要相应的寄存器来记录。在NVIC中有一个专门处理中断优先级的寄存器NICV_IPRx,用于配置中断源的优先级。IPR的宽度为8Bit,对于CM3内核来说,因为它支持的中断源为256个,那么原则上每个外部中断源可配置的优先级位0~255,数值越小优先级越高。但是因为绝大多数CM3芯片都会精简设计,所以不会使用到全部位,在STM32F103中只使用4Bit。
    这里写图片描述
    注意,个别系统系统的优先级是固定的,所以它们的中断优先级是不可编程的。

    2.1 CM3核的优先级分组方式
    CM3中定义了8个Bit用于设置中断源的优先级,这8个Bit可以分配为:

    (1)8bit用于响应优先级
    (2)最高1位用于指定抢占优先级,最低7位用于执行子优先级
    (3)最高2位用于指定抢占优先级,最低6位用于执行子优先级
    (4)最高3位用于指定抢占优先级,最低5位用于执行子优先级
    (5)最高4位用于指定抢占优先级,最低4位用于执行子优先级
    (6)最高5位用于指定抢占优先级,最低3位用于执行子优先级
    (7)最高6位用于指定抢占优先级,最低2位用于执行子优先级
    (8)最高7位用于指定抢占优先级,最低1位用于执行子优先级

    CM3核的优先级分组方式,使用的设置函数

    NVIC_SetPriorityGrouping()

    在Libraries\CMSIS\CM3\CoreSupport\core_cm3.h文件中实现:

    static __INLINE void NVIC_SetPriorityGrouping(uint32_t PriorityGroup)
    {
      uint32_t reg_value;
      uint32_t PriorityGroupTmp = (PriorityGroup & 0x07);                         /* only values 0..7 are used          */
    
      reg_value  =  SCB->AIRCR;                                                   /* read old register configuration    */
      reg_value &= ~(SCB_AIRCR_VECTKEY_Msk | SCB_AIRCR_PRIGROUP_Msk);             /* clear bits to change               */
      reg_value  =  (reg_value                       |
                    (0x5FA << SCB_AIRCR_VECTKEY_Pos) | 
                    (PriorityGroupTmp << 8));                                     /* Insert write key and priorty group */
      SCB->AIRCR =  reg_value;
    }

    该函数写在.h文件中,且声明为内联函数(__INLINE),内联函数跟宏替换差不多,可以避免函数调用的压栈出栈等开销。PriorityGroup的取值为0~7。

    2.2 STM32的优先级分组方式
    CM3核的优先级分组方式是针对256个中断全部用上的场合,但是Cortex-M3也允许在具有较少中断源时用较少的寄存器位指定中断源的优先级。STM32并没有使用Cortex-M3内核嵌套向量中断全套东西,而是使用了它的一部分:

    (1)STM32F103系列有16个内核异常和60个外部中断
    (2)STM32F107系列有16个内核异常和68个外部中断

    STM32的优先级分组使用标准库函数

    NVIC_PriorityGroupConfig()

    该函数在Libraries\STM32F10x_StdPeriph_Driver\src\misc.c中实现:

    void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup)
    {
      /* Check the parameters */
      assert_param(IS_NVIC_PRIORITY_GROUP(NVIC_PriorityGroup));
    
      /* Set the PRIGROUP[10:8] bits according to NVIC_PriorityGroup value */
      SCB->AIRCR = AIRCR_VECTKEY_MASK | NVIC_PriorityGroup;
    }

    可见,这个函数也是在设置SCB->AIRCR寄存器,只是这里的取值为:

    (1)NVIC_PriorityGroup_0:0bit for 抢占优先级,4bit for 子优先级,即有24次方个子优先级
    (2)NVIC_PriorityGroup_1:1bit for 抢占优先级,3bit for 子优先级,即有23次方个子优先级
    (3)NVIC_PriorityGroup_2:2bit for 抢占优先级,2bit for 子优先级,即有22次方个子优先级
    (4)NVIC_PriorityGroup_3:3bit for 抢占优先级,1bit for 子优先级,即有21次方个子优先级
    (5)NVIC_PriorityGroup_4:4bit for 抢占优先级,0bit for 子优先级,即有20次方个子优先级

    3. NVIC操作相关函数

    NVIC的描述结构体在core_cm3.h中:

    typedef struct
    {
      __IO uint32_t ISER[8];        /* 中断使能寄存器(Interrupt Set Enable Register),Offset: 0x000 */
           uint32_t RESERVED0[24];                                   
      __IO uint32_t ICER[8];        /* 中断清除寄存器(Interrupt Clear Enable Register),Offset: 0x080 */
           uint32_t RSERVED1[24];                                    
      __IO uint32_t ISPR[8];        /* 中断使能挂起寄存器(Interrupt Set Pending Register),Offset: 0x100 */
           uint32_t RESERVED2[24];                                   
      __IO uint32_t ICPR[8];        /* 中断清除挂起寄存器(Interrupt Clear Pending Register),Offset: 0x180 */
           uint32_t RESERVED3[24];                                   
      __IO uint32_t IABR[8];        /* 中断有效位寄存器(Interrupt Active bit Register ),Offset: 0x200 */
           uint32_t RESERVED4[56];                                   
      __IO uint8_t  IP[240];        /* 中断优先级寄存器(Interrupt Priority Register),Offset: 0x300 (8Bit wide) */
           uint32_t RESERVED5[644];                                  
      __O  uint32_t STIR;           /* 软中断触发寄存器(Software Trigger Interrupt Register),Offset: 0xE00 */
    }  NVIC_Type;

    编程中常用的是ISER、ICER和IP这三个寄存器。ISER和ICER分别用于enable、disable中断,IP用于控制中断优先级。
    同在core_cm3.h中,定义了对结构体成员的操作函数,这是针对Cortex-M3内核芯片都适用的函数:

    (1)设置优先级分组寄存器: NVIC_SetPriorityGrouping(uint32_t PriorityGroup)
    (2)从NVIC中断控制器得到优先级分组设置值: NVIC_GetPriorityGrouping(void)
    (3)使能中断: NVIC_EnableIRQ(IRQn_Type IRQn) 
    (4)失能中断: NVIC_DisableIRQ(IRQn_Type IRQn) 
    (5)获取挂起中断编号: NVIC_GetPendingIRQ(IRQn_Type IRQn) 
    (6)设置中断挂其位: NVIC_SetPendingIRQ(IRQn_Type IRQn) 
    (7)清除中断挂起位: NVIC_ClearPendingIRQ(IRQn_Type IRQn) 
    (8)NVIC_GetActive(IRQn_Type IRQn)
    (9)设置中断源的中断优先级: NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority) 
    (10)获取中断源的中断优先级: NVIC_GetPriority(IRQn_Type IRQn) 
    (11)编码一个中断的优先级,不知道干嘛: NVIC_EncodePriority (uint32_t PriorityGroup, uint32_t PreemptPriority, uint32_t SubPriority)
    (12)解码一个中断的优先级,不知道干嘛: NVIC_DecodePriority (uint32_t Priority, uint32_t PriorityGroup, uint32_t* pPreemptPriority, uint32_t* pSubPriority) 
    (13)系统复位: NVIC_SystemReset(void)

    在外设库misc.h定义了针对STM32的NVIC的初始化描述结构体:

    typedef struct
    {
      uint8_t NVIC_IRQChannel;                    /* 中断源 */
      uint8_t NVIC_IRQChannelPreemptionPriority;  /* 抢占优先级 */
      uint8_t NVIC_IRQChannelSubPriority;         /* 子优先级 */
      FunctionalState NVIC_IRQChannelCmd;         /* 中断使能或者失能 */   
    } NVIC_InitTypeDef;

    misc.c也定义了针对STM32的NVIC的操作函数:

    (1)设置优先级分组寄存器: NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup)
    (2)初始化NVIC_InitTypeDef类的结构体: NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct)
    (3)设置中断向量表位置和偏移: NVIC_SetVectorTable(uint32_t NVIC_VectTab, uint32_t Offset)
    系统可以选择从SRAM启动,也可以选择从flash启动,对应的启动地址会映射到0地址处,而中断向量表是要被放在0地址处的,所以要将中      断向量表放在SRAM/flash的起始位置。函数参数一的取值为NVIC_VectTab_RAM/NVIC_VectTab_FLASH,参数二的取值必须是0x200的整数倍(STM32就是这么规定的)。
    (4)选择进入低功耗模式的条件: NVIC_SystemLPConfig(uint8_t LowPowerMode, FunctionalState NewState) 
    参数一取值NVIC_LP_SEVONPEND/NVIC_LP_SLEEPDEEP/NVIC_LP_SLEEPONEXIT,参数二取值ENABLE/DISABLE

    4. EXTI–外部中断和事件控制器

    EXTI有20个中断/事件线,每个GPIO都可以被设置为中断/事件的输入线,占用EXTI0~EXTI15,还有另外4根用于特定的外设事件的EXTI16~EXTI19:
    这里写图片描述
    注意,EXTIx与GPIOx的对应关系,EXTI0只能和P[x]0绑定(x = A、B、C、D…),
    这里写图片描述
    实现绑定操作的函数声明位于标准库Libraries\STM32F10x_StdPeriph_Driver\inc\stm32f10x_gpio.h中:

    GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource)
    参数一GPIO_PortSource的取值为GPIO_PortSourceGPIOx (x = A..G),
    参数二GPIO_PinSource的取值为GPIO_PinSourcex(x = 0..15)

    这个函数在一般初始化EXTI寄存器时候调用。因为外部中断是GPIO引脚的复用功能,所以同时要开启GPIO复用功能的时钟:

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE)

    5. EXTI描述结构体的初始化

    EXTI描述结构体声明在标准外设库Libraries\STM32F10x_StdPeriph_Driver\inc\stm32f10x_exti.h中:

    typedef struct
    {
      uint32_t EXTI_Line;               /* 中断事件线 */
      EXTIMode_TypeDef EXTI_Mode;       /* EXTI模式,事件/中断 */
      EXTITrigger_TypeDef EXTI_Trigger; /* 触发类型 */
      FunctionalState EXTI_LineCmd;     /* EXTI使能 */ 
    }EXTI_InitTypeDef;

    与EXTI操作相关的函数有:

    (1)去除EXTI_InitTypeDef结构体的初始化:EXTI_DeInit(void)
    (2)初始化EXTI_InitTypeDef结构体: EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct) 
    (3)默认初始化:EXTI_StructInit(EXTI_InitTypeDef* EXTI_InitStruct) 
    (4)EXTI_GenerateSWInterrupt(uint32_t EXTI_Line) 产生一个软件中断
    (5)获取产生中断的标志:EXTI_GetFlagStatus(uint32_t EXTI_Line) 
                       EXTI_GetITStatus(uint32_t EXTI_Line)
    (6)清除中断产生标志:EXTI_ClearFlag(uint32_t EXTI_Line) 
                      EXTI_ClearITPendingBit(uint32_t EXTI_Line)

    获取/清除产生中断的标志的实现是一样的,但是为什么要分成两组函数?
    也许这是STM32标准外设库设计者出自于为兼容性考虑吧。有的ARM芯片的中断体系分为两层,也就是说中断信号要抵达NVIC需要两层筛选,同理清除中断标志也需要清除两层。但是在CM3核的ARM只设计了一层,STM32为了兼容其他芯片,依旧还是将函数设计成两层,只不过这两层的实现体是一致的。

    6. 编程实现按键中断

    下来编程操作STM32的中断。未能免俗,还是以按键中断为例。
    实验采用正点原子miniSTM32硬件平台,
    这里写图片描述

    按键KEY0(PC5)和KEY1(PA15)的原理图:
    这里写图片描述
    这里写图片描述
    这里写图片描述

    LED0(PA8)和LED1(PD2)的原理图:
    这里写图片描述
    这里写图片描述

    实验实现按键产生外部中断,在中断处理函数中实现反向控制LED灯。编程的要点为:

    (1)初始化用来产生中断信号的GPIO
    (2)初始化中断/事件控制器EXTI
    (3)配置NVIC
    (4)编写中断服务函数

    EXTI用于设置中断源的触发方式、中断/事件类型和具体是哪一个中断源。
    中断信号产生后最终传递到NVIC,NVIC控制中断源优先级、中断线通道等,以便比对中断信号、根据优先级调用中断服务函数。
    实验采用MDK4集成开发环境,工程的目录结构如下:
    这里写图片描述

    exti_led.h声明实验中用到的函数:

    #ifndef __EXTI_LED_H__
    #define __EXTI_LED_H__
    
    #include "stm32f10x_conf.h"
    
    void TimeDelay(void);
    void Led_CfgInit(void);
    void Exti_CfgInit(void);
    void NVIC_CfgInit(void);
    void Key_CfgInit(void);
    
    #endif /* __EXTI_LED_H__ */

    mian.c实现各个功能模块:
    (1)初始化外接LED的GPIO引脚

    //PA8-->LED0,PD2-->LED1
    void Led_CfgInit(void)
    {
        GPIO_InitTypeDef GPIO_InitTypeStu;
    
        //开启PA和PD端口的时钟
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOD, ENABLE);
    
        //初始化PA8引脚为推挽输出
        GPIO_InitTypeStu.GPIO_Mode = GPIO_Mode_Out_PP;
        GPIO_InitTypeStu.GPIO_Pin = GPIO_Pin_8;
        GPIO_InitTypeStu.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(GPIOA, &GPIO_InitTypeStu);
        GPIO_SetBits(GPIOA,GPIO_Pin_8);         //LED0初始状态为灭
    
        //初始化PD2引脚为推挽输出
        GPIO_InitTypeStu.GPIO_Pin = GPIO_Pin_2;
        GPIO_Init(GPIOD, &GPIO_InitTypeStu);
        GPIO_SetBits(GPIOD,GPIO_Pin_2);         //LED1初始状态为灭
    }

    (2)初始化外接按键的引脚

    void Key_CfgInit(void)
    {
        GPIO_InitTypeDef GPIO_InitTypeStu;
    
        //开启PC和PA的时钟
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOA, ENABLE);
    
        //初始化PC5为上拉输入
        GPIO_InitTypeStu.GPIO_Mode = GPIO_Mode_IPU; // GPIO_Mode_IN_FLOATING;   
        GPIO_InitTypeStu.GPIO_Pin = GPIO_Pin_5;
        GPIO_InitTypeStu.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(GPIOC, &GPIO_InitTypeStu);
    
        //初始化PA15为上拉输入
        GPIO_InitTypeStu.GPIO_Mode = GPIO_Mode_IPU; // GPIO_Mode_IN_FLOATING;   
        GPIO_InitTypeStu.GPIO_Pin = GPIO_Pin_15;
        GPIO_InitTypeStu.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(GPIOA, &GPIO_InitTypeStu);
    }

    一开始我是设置PC5和PA15为浮空输入的,因为只需要考虑到按键按下是低电平,但是实验表明,浮空输入并不能确定引脚状态,即使在按键按下以后也不能触发中断,所以还是要将它们设置为上拉/下拉输入。

    (3)初始化EXTI

    void Exti_CfgInit(void)
    {
        EXTI_InitTypeDef EXTI_InitStu;  
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
    
        //EXTI5
        GPIO_EXTILineConfig(GPIO_PortSourceGPIOC, GPIO_PinSource5); //将具体GPIO和外部中断事件线绑定
        EXTI_InitStu.EXTI_Line = EXTI_Line5;
        EXTI_InitStu.EXTI_Mode = EXTI_Mode_Interrupt;               //中断模式
        EXTI_InitStu.EXTI_Trigger = EXTI_Trigger_Rising;            //上升沿触发
        EXTI_InitStu.EXTI_LineCmd = ENABLE;
        EXTI_Init(&EXTI_InitStu);
    
        //EXTI15
        GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource15);    
        EXTI_InitStu.EXTI_Line = EXTI_Line15;
        EXTI_InitStu.EXTI_LineCmd = ENABLE;
        EXTI_Init(&EXTI_InitStu);
    }

    GPIO用于传输外部中断信号属于GPIO复用部分的功能,所以需要打开RCC_APB2Periph_AFIO的时钟。

    (4)初始化NVIC

    void NVIC_CfgInit(void)
    {
        NVIC_InitTypeDef NVIC_InitTypeStu;
    
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);         //设置中断分组
        NVIC_InitTypeStu.NVIC_IRQChannel = EXTI9_5_IRQn;        //外部中断线EXTI5属于共享中断
        NVIC_InitTypeStu.NVIC_IRQChannelPreemptionPriority = 1; //抢占优先级
        NVIC_InitTypeStu.NVIC_IRQChannelSubPriority = 1;        //子优先级
        NVIC_InitTypeStu.NVIC_IRQChannelCmd = ENABLE;   
        NVIC_Init(&NVIC_InitTypeStu);
    
        NVIC_InitTypeStu.NVIC_IRQChannel = EXTI15_10_IRQn;      //外部中断线EXTI15属于共享中断
        NVIC_InitTypeStu.NVIC_IRQChannelSubPriority = 2;
        NVIC_Init(&NVIC_InitTypeStu);
    }

    (5)延时函数,这里只是简单延时,并没有精准计算

    void TimeDelay(void)
    {
        int i, j;
    
        for (i = 0; i < 100; i++)
            for (j = 0; j < 1000; j++);
    }

    (6)main函数

    int main(void)
    {
        Led_CfgInit();
        Key_CfgInit();
        Exti_CfgInit();
        NVIC_CfgInit();
    
        while(1);
        return 0;
    }

    当用户按下KEY0时,会进入EXTI9_5_IRQHandler()处理函数中,按下KEY1则进入EXTI15_10_IRQHandler()处理函数。这两个函数名是在启动文件写的,详细可参考文章http://blog.csdn.net/qq_29344757/article/details/74932235。处理函数的实现如下:

    void EXTI9_5_IRQHandler(void)
    {   
        //int i = 50;
        TimeDelay();    //延时去抖动
    
        if (!GPIO_ReadInputDataBit(GPIOC, GPIO_Pin_5) && EXTI_GetFlagStatus(EXTI_Line5))
        {
            GPIO_WriteBit(GPIOA, GPIO_Pin_8, ((BitAction)!GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_8)));
    
            //清中断
            //EXTI_ClearFlag(EXTI_Line5);
            EXTI_ClearITPendingBit(EXTI_Line5);
        }
    }
    
    void EXTI15_10_IRQHandler(void)
    {   
        TimeDelay();    //延时去抖动
    
        if (!GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_15) && EXTI_GetFlagStatus(EXTI_Line15))
        {
            GPIO_WriteBit(GPIOD, GPIO_Pin_2, ((BitAction)!GPIO_ReadInputDataBit(GPIOD, GPIO_Pin_2)));
    
            //清中断
            //EXTI_ClearFlag(EXTI_Line15);
            EXTI_ClearITPendingBit(EXTI_Line15);
        }
    }

    函数可在用户自定义的文件实现,也可以在标准库提供的工程模板文件stm32f10x_it.c中实现。由于是共享中断,所以需要调用EXTI_GetFlagStatus()函数来判断是否为目的中断源。其实在其他很多非共享中断的场合也有使用EXTI_GetFlagStatus()函数判断目的中断源,无关紧要了。

    STM32的中断系统非常强大,每一个外设都可以产生中断。关于STM32中断/事件部分的学习就先告一段落,详细内容可参考STM32F10X-中文参考手册》、《 Cortex-M3 内核编程手册》的4.3章节。下一个学习任务–系统定时器SysTick。

    展开全文
  • 中断

    万次阅读 2018-10-03 18:54:31
    整个过程称为中断处理,简称中断,而引起这一过程的事件称为中断事件中断是计算机实现并发执行的关键,也是操作系统工作的根本。 分类  中断事件来源分类,可以分为外部中断和内部中断中断事件来自于CPU...

    定义

           在计算机科学中,中断指计算机CPU获知某些事,暂停正在执行的程序,转而去执行处理该事件的程序,当这段程序执行完毕后再继续执行之前的程序。整个过程称为中断处理,简称中断,而引起这一过程的事件称为中断事件。中断是计算机实现并发执行的关键,也是操作系统工作的根本。

    分类

           中断按事件来源分类,可以分为外部中断和内部中断。中断事件来自于CPU外部的被称为外部中断,来自于CPU内部的则为内部中断。

           进一步细分,外部中断还可分为可屏蔽中断(maskable interrupt)和不可屏蔽中断(non-maskable interrupt)两种,而内部中断按事件是否正常来划分可分为软中断和异常两种。

           外部中断的中断事件来源于CPU外部,必然是某个硬件产生的,所以外部中断又被称为硬件中断(hardware interrupt)。计算机的外部设备,如网卡、声卡、显卡等都能产生中断。外部设备的中断信号是通过两根信号线通知CPU的,一根是INTR,另一根是NMI。CPU从INTR收到的中断信号都是不影响系统运行的,CPU可以选择屏蔽(通过设置中断屏蔽寄存器中的IF位),而从NMI中收到的中断信号则是影响系统运行的严重错误,不可屏蔽,因为屏蔽的意义不大,系统已经无法运行。

           内部中断来自于处理器内部,其中软中断是由软件主动发起的中断,常被用于系统调用(system call);而异常则是指令执行期间CPU内部产生的错误引起的。异常也和不可屏蔽中断一样不受eflags寄存器的IF位影响,区别在于不可屏蔽中断发生的事件会导致处理器无法运行(如断电、电源故障等),而异常则是影响系统正常运行的中断(如除0、越界访问等)。

    中断描述符表

           中断描述符表(Interrupt Descriptor Table,IDT)是保护模式下用于存储中断处理程序入口的数据结构,实模式中采用中断向量表(Interrupt Vector Table,IVT)。当CPU接收一个中断时,需要用中断向量在此表中检索对应的中断描述符,在该描述符中找到中断处理程序的起始地址,然后才能执行中断处理程序。

           中断描述符表中不仅仅有中断描述符,还可以有任务门描述符和陷阱门描述符,它们实质上都是记录着某段程序的起始地址,因此可以统称为门。

    中断处理过程及保护

           中断过程因中断来源而异,外部中断由外设发出,经中断代理芯片接收并处理后将该中断的中断向量号发送到CPU,最后由CPU执行该中断向量号对应的中断处理程序。内部中断则不经过中断代理芯片。

           中断在处理器内部的处理程序如下:

    (1)处理器根据中断向量号定位中断门描述符。

           中断向量号是中断描述符的索引,当处理器收到一个外部中断向量号后,它用此向量号在中断描述符表中查询对应的中断描述符,然后再去执行该中断描述符指向的中断处理程序。中断描述符占8字节,因此处理器用中断向量号乘8后再与IDTR中的中断描述符表地址相加得到中断描述符的位置。

    (2)特权级检查

           中断向量号只是一个整数,其中没有RPL,所以在对由中断引起的特权级转移特权级检查时并不涉及RPL。

           如果是由软中断int n、int3、和into这些由用户进程引发的中断,由用户代码控制,处理器要检查当前特权级CPL和门描述符DPL,数值上CPL≤门描述符DPL才能通过检查。通过上一步检查后还需要检查CPL和门描述符中所记录的选择子对应的目标代码段DPL,数值上CPL>目标代码段DPL才能通过检查,因为除返回指令外,特权转移只能由低到高。

           若中断是由外部设备或异常引起的,只检查CPL和目标代码段的DPL即可。

    (3)执行中断处理程序

           特权级检查通过后,将门描述符中目标代码段选择子加载到段寄存器CS中,把门描述符中的中断处理程序的偏移地址加载到EIP,然后开始执行中断处理程序。

           中断发生后,eflags中的NT位和TF位都会被置0。如果中断对应的门描述符是中断门,标志寄存器eflags中的IF位也会被置0以避免中断嵌套(中断处理过程中又处理新的中断),即默认情况下处理器对中断门描述符的中断例程处理是不可中断的。若中断发生时对应的门描述符是任务门或陷阱门的话,CPU不会将状态寄存器中的IF位清0,即允许中断嵌套。

     

                                                                                                   本文部分内容摘自《操作系统真象还原》,有改动

    展开全文
  • 51单片机 (4)中断系统

    千次阅读 2014-03-20 02:46:17
    引起中断事件称为中断源。中断源向CPU提出处理的请求称为中断请求。 发生中断时被打断程序的暂停点成为断点。CPU暂停现行程序而转为响应中断请求的过程称为中断响应。 处理中断源的程序称为中断处理程序。CPU执行...

    【转载请注明出处:http://blog.csdn.net/leytton/article/details/21577883

    相关概念

    • 中断源:引起中断的事件
    • 中断请求:中断源向CPU提出处理的请求
    • 断点:发生中断时被打断程序的暂停点
    • 中断响应:CPU暂停现行程序而转为响应中断请求的过程
    • 中断处理程序:处理中断源的程序
    • 中断处理:CPU执行有关的中断处理程序
    • 中断返回:返回断点的过程

    中断与子程序的区别

    调用有点相似、但两者是不同的概念。

    • 源不同。中断是由外部中断源产生的、具有不可预测和随机性、比如抛异常。子程序是由主程序安排调用的。
    • 响应不同。中断系统需要保护断点和现场、子程序只需保存断点。
    • 功能不同。中断程序主要处理CPU外部异步事件、子程序调用是为主程序服务。

    中断类型

    • 外部中断源:外部硬件资源产生。上下沿触发和高低电平触发。
    • 定时中断源:定时器/计数器溢出触发。
    • 串口中断源:串行通信时发送或接收完毕信息触发。

    TCON中断标志

    • IE1:外部中断1请求标志位。
    • IT1:外部中断1触发方式选择位。当IT1=0,为低电平触发方式;当IT1=1,为下降沿触发方式。
    • IE0:外部中断0请求标志位。
    • IT0:外部中断0触发方式选择位。 当IT0=0,为低电平触发方式;当IT0=1,为下降沿触发方式。

    SCON中断标志

    • RI:串行接口时接收信息完毕后、硬件自动置RI=1、CPU响应中断。注意不会自动清零置RI=0、需软件置RI=0
    • TI:串行接口发送信息完毕后、硬件自动置TI=1、CPU响应中断。注意不会自动清零置TI=0、需软件置TI=0

    中断初始化的一般步骤

    1、确定工作方式(即对TMOD赋值);
    2、预置定时或计数的初值(可直接将初值写入TH0、TL0或TH1、TL1);
    3、根据需要开放定时器/计数器的中断(直接对IE位赋值);
    4、启动定时器/计数器(若已规定用软件启动,则可把TR0或TR1置“1”;若已规定由外中断引脚电平启动,则需给外引脚加启动电平。当实现了启动要求后,定时器即按规定的工作方式和初值开始计数或定时)。

    中断允许标志

    • EX1:外部中断1允许位;
    • EX0:外部中断0允许位; 
    • ET1:定时/计数器T1中断允许位; 
    • ET0:定时/计数器T0中断允许位;
    • ES:串行口中断允许位; 
    • EA: CPU中断允许(总允许)位。

    中断优先级标志

    0为低优先级、1为高优先级
    • PS:串行接口中断优先级设置位
    • PT1:定时器/计数器中断1中断优先级设置位
    • PT0:定时器/计数器中断0中断优先级设置位
    • PX1:外部中断1中断优先级设置位
    • PX0:外部中断0中断优先级设置位

    51单片机中断号

    • 外部中断0(INT0),对应中断号是0, 中断入口地址0003H
    • 定时/计数器0(T1),对应中断号1 ,中断入口地址000BH
    • 外部中断1(INT1),中断号2 入口地址0013H
    • 定时/计数器1(T1)中断号3 入口地址001BH
    • 串行口(RI/TI)中断号4 入口地址0023H
    • 这五个是AT89S51的,52还多了下面这个
    • 定时/计数器2(T2)中断号5,入口地址002BH
    1. 函数名()interrupt 0 {} //对应外部中断0;
    2. 函数名()interrupt 1 {} //对应定时器/计数器0中断;
    3. 函数名()interrupt 2 {} //对应外部中断1;
    4. 函数名()interrupt 3 {} //对应定时器/计数器1中断;
    5. 函数名()interrupt 4 {} //对应串口中断;
    一共5种中断,优先级自上向下;[摘自百度知道link]





    展开全文
  • stm32异常、中断事件的区别

    千次阅读 2019-08-20 09:36:28
    异常是指由于CPU本身故障、程序故障或者请求服务等引起的错误,异常属于不正常现象。 Cortex-M3内核总共支持256个中断,其中包含16个内核异常和240个外部中断,但是各个芯片产商在设计芯片的时候会对CM3内核的芯片...
  • STM32的"异常“、“中断”和“事件”区别和理解

    千次阅读 多人点赞 2018-01-18 11:34:35
    1 异常与中断(Cortex-M3)1.1 异常与中断原话: Cortex‐M3 在内核水平上搭载了一个异常响应... 所有能打断正常执行流的事件称为异常。异常的概念包含中断的概念,即中断是异常的子集。异常与中断都是硬件支持的
  • 中断概念

    千次阅读 2016-04-01 19:27:57
    一、中断的概念 1、中断产生:CPU在处理某一事件A时,发生了另一事件B请求CPU迅速去...二、中断系统结构 引起CPU中断的根源,称为中断源(中断源有外部触发,定时器中断两种形式)。 中断源向CPU提出的中断请求。 CPU暂时
  • 51单片机中断系统

    万次阅读 多人点赞 2018-12-11 20:04:08
    中断定义  CPU在处理某一事件A时,发生了另一事件B请求CPU迅速去处理(中断发生);... 引起CPU中断的根源,称为中断源。中断源向CPU提出的中断请求。CPU暂时中断原来的事务A,转去处理事件B。对事件...
  • 中断技术

    2016-12-28 14:55:01
    中断源:引起中断发生的事件。 中断请求:中断源向CPU发出的请求中断处理信号。 中断响应:CPU收到中断请求后转相应的事件处理程序的一个过程。 中断屏蔽:在中断请求产生后,系统用软件的方式有选择的封闭部分...
  • 中断系统

    2018-12-11 15:54:00
    中断系统  版权声明:未经授权,严禁转载!  中断定义 ... CPU在处理某一事件A时,发生了另一事件B请求CPU迅速去处理(中断发生); CPU暂时中断当前的工作,转去... 引起CPU中断的根源,称为中断源。中断源...
  • 中断中断处理(一)

    千次阅读 2015-07-13 07:45:34
    (一):中断中断本质上是...这些中断值被称为中断请求线(IRQ)。中断是随时随地发生的,也就是说中断并不考虑与处理器的时钟同步。异常:异常的产生必须与处理器时钟同步,异常也被成为同步中断。在处理器执行到由于
  • linux中断编程、中断基础介绍

    千次阅读 2017-11-16 19:47:23
    中断基础介绍中断就是CPU正常运行期间,由于内、外部事件引起的CPU暂时停止正在运行的程序,去执行该内部事件或外部事件引起的服务中去,服务执行完毕后再返回断点处继续执行的情形。中断的意义极大提高CPU运行...
  • 单片机中断

    千次阅读 2017-04-24 14:21:00
    什么是中断?就是打断当前要做的事,转而去执行...我们把引起中断事件叫做中断源(如老妈给我的任务,以及我的尿意。。。外部引起的叫外部中断,内部引起的叫内部中断),产生中断后就要去处理它,这称为中断的响应。
  • 操作系统中断

    千次阅读 2012-05-27 23:06:32
    自愿性中断事件:是由正在运行的进程执行一条访管指令用以请求系统调用而引起中断,这种中断称为"访管中断"。 一般情况下,优先级的高低顺序依次为:硬件故障中断、自愿中断、程序性中断,外部中断和输入输出...
  • 中断机制和中断描述符表、中断和异常的处理

    千次阅读 多人点赞 2013-09-16 10:09:26
    1、中断向量 Intel x86 系列微机共支持256 种向量中断,为使处理器较容易地识别每种中断源,将它们从0~256 编号,即赋予一个中断类型码 n,Intel 把这个8 位的无符号整数叫做一个向量,因此,也叫中断向量。...
  • 中断技术学习

    2017-04-14 19:24:48
    其中,引起中断事件称为中断源,发现中断源并产生中断的硬件成为中断装置中断源分类 强迫性中断 字面意思理解,(CPU:不是咱想停,,咱是被逼的!) (1) 机器故障 (2) 程序性中断:除数为0,地址越界,定点...
  • 这里写目录标题先验知识回顾控制寄存器回顾1、8086中断类型1、外部可屏蔽中断2、外部不可屏蔽中断3、除法错中断4、单步中断5、断点中断6、溢出中断7、软中断2、8086中断向量表3、8086中断响应1、外部可屏蔽中断响应2...
  • 操作系统是如何利用中断机制的

    千次阅读 2016-06-17 01:11:36
    自愿性中断事件 是由正在运行的进程执行一条访管指令用以请求系统调用而引起中断,这种中断称为”访管中断”。 一般情况下,优先级的高低顺序依次为:硬件故障中断、自愿中断、程序性中断,外部中断和输入输出...
  • 操作系统中的中断

    2020-08-28 22:38:34
    如I/O中断、时钟中断,一种是来自CPU内部事件或程序执行中引起中断,例如程序非法操作,地址越界、浮点溢出)称为中断,或者(异常,陷入),最后一种是在程序中使用了系统调用引起的。而中断处理一般分为中断...
  • 中断向量,中断向量表 ,中断服务函数

    千次阅读 多人点赞 2019-07-29 12:31:52
    所谓中断是指CPU在正常执行程序的过程中,由于内部/外部事件的触发或由程序的预先安排,引起CPU暂时中断当前正在运行的程序,而转去执行为内部/外部事件或程序预先安排的事件的服务子程序,待中断服务子程序执行完毕...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 47,876
精华内容 19,150
热门标签
关键字:

引起中断的事件称为