STM32中断学习记录

news2024/11/13 16:46:22

文章目录

    • NVIC
      • NVIC是什么
      • NVIC寄存器
      • NVIC 结构体
      • NVIC 相关固件库函数
    • 如何定义优先级
    • 中断编程
    • 外部中断 EXTI
      • EXIT 外部中断/事件控制器
      • EXIT的使用
      • EXTI内部寄存器分析
      • GPIO触发中断例程
      • 为什么中断后要清除中断标志位
    • SysTick的使用
      • SysTick分析

NVIC

NVIC是什么

待补充.........

NVIC寄存器

/*文件core_cm4.h*/
/** \ingroup    CMSIS_core_register
    \defgroup   CMSIS_NVIC  Nested Vectored Interrupt Controller (NVIC)
    \brief      Type definitions for the NVIC Registers
  @{
 */

/** \brief  Structure type to access the Nested Vectored Interrupt Controller (NVIC).
 */
typedef struct
{
  __IO uint32_t ISER[8];                 /*!< Offset: 0x000 (R/W)  Interrupt Set Enable Register           */
       uint32_t RESERVED0[24];
  __IO uint32_t ICER[8];                 /*!< Offset: 0x080 (R/W)  Interrupt Clear Enable Register         */
       uint32_t RSERVED1[24];
  __IO uint32_t ISPR[8];                 /*!< Offset: 0x100 (R/W)  Interrupt Set Pending Register          */
       uint32_t RESERVED2[24];
  __IO uint32_t ICPR[8];                 /*!< Offset: 0x180 (R/W)  Interrupt Clear Pending Register        */
       uint32_t RESERVED3[24];
  __IO uint32_t IABR[8];                 /*!< Offset: 0x200 (R/W)  Interrupt Active bit Register           */
       uint32_t RESERVED4[56];
  __IO uint8_t  IP[240];                 /*!< Offset: 0x300 (R/W)  Interrupt Priority Register (8Bit wide) */
       uint32_t RESERVED5[644];
  __O  uint32_t STIR;                    /*!< Offset: 0xE00 ( /W)  Software Trigger Interrupt Register     */
}  NVIC_Type;

一般只使用 ISER(使能中断)、ICER(失能中断)、和IP(设置中断优先级 )这三个寄存器。

NVIC 结构体

/** 
  * @brief  NVIC Init Structure definition  
  */

typedef struct
{
  uint8_t NVIC_IRQChannel;                    /*!< Specifies the IRQ channel to be enabled or disabled.
                                                   This parameter can be an enumerator of @ref IRQn_Type 
                                                   enumeration (For the complete STM32 Devices IRQ Channels
                                                   list, please refer to stm32f4xx.h file) */

  uint8_t NVIC_IRQChannelPreemptionPriority;  /*!< Specifies the pre-emption priority for the IRQ channel
                                                   specified in NVIC_IRQChannel. This parameter can be a value
                                                   between 0 and 15 as described in the table @ref MISC_NVIC_Priority_Table
                                                   A lower priority value indicates a higher priority */

  uint8_t NVIC_IRQChannelSubPriority;         /*!< Specifies the subpriority level for the IRQ channel specified
                                                   in NVIC_IRQChannel. This parameter can be a value
                                                   between 0 and 15 as described in the table @ref MISC_NVIC_Priority_Table
                                                   A lower priority value indicates a higher priority */

  FunctionalState NVIC_IRQChannelCmd;         /*!< Specifies whether the IRQ channel defined in NVIC_IRQChannel
                                                   will be enabled or disabled. 
                                                   This parameter can be set either to ENABLE or DISABLE */   
} NVIC_InitTypeDef;
成员描述
uint8_t NVIC_IRQChannel中断源,IRQn_Type类型
uint8_t NVIC_IRQChannelPreemptionPriorityuint8_t NVIC_IRQChannelPreemptionPriority抢占优先级,由优先级分组确定
uint8_t NVIC_IRQChannelSubPriority子优先级,操作NVIC_ISER和NVIC_ICER这两个寄存器
FunctionalState NVIC_IRQChannelCmd中断使能或失能

NVIC 相关固件库函数

** 相关固件库函数由core_cm4.h和misc.h提供 **

函数名描述
void NVIC_EnableIRQ(IRQn_Type IRQn)使能中断
void NVIC_DisableIRQ(IRQn_Type IRQn)失能中断
void NVIC_SetPendingIRQ(IRQn_Type IRQn)设置外部中断挂起位
void NVIC_ClearPendingIRQ(IRQn_Type IRQn)清除外部中断挂起位
uint32_t NVIC_GetPriority(IRQn_Type IRQn)获取挂起的外部中断的编号
void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority)设置中断优先级
void NVIC_SetPriorityGrouping(uint32_t PriorityGroup)设置中断优先级组
uint32_t NVIC_GetPriority(IRQn_Type IRQn)获取中断优先级
uint32_t NVIC_GetPriorityGrouping(void)获取中断优先级组号
void NVIC_SystemReset(void)系统复位
上述固件库函数是在core_cm4.h中提供的,含有一部分在misc.h中提供,misc.h中的函数调用core_cm4.h中提供的函数设置中断
void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup);
void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct);
void NVIC_SetVectorTable(uint32_t NVIC_VectTab, uint32_t Offset);
void NVIC_SystemLPConfig(uint8_t LowPowerMode, FunctionalState NewState);
void SysTick_CLKSourceConfig(uint32_t SysTick_CLKSource);

** 上述函数参数说明 **

参数名描述
IRQn_Type是一个枚举类型,在core_cm4中定义,内容为stm32对应为设备的中断编号(stm32f407中有十个系统异常和82个外部中断)
PriorityGroup优先级组号 0~7

如何定义优先级

优先级分组:不同系列的单片机优先级分组有多种,一般来说中断优先级分组在整个程序中只需用设置一次就可以了,重复设置只是覆盖以前设置的值。设置中断优先级分组使用的是SCB->AIRCR寄存器的PRIGROUP的[10:8]位,那么设置中断优先级分组的意义是什么呢?设置中断优先级分组实际上是确定了中断抢占优先级(主优先级)和子优先级所占的位数,core_cm4.h提供的** NVIC_SetPriorityGrouping(uint32_t PriorityGroup)函数设置中断优先级分组 **
该函数内容如下:

_STATIC_INLINE void NVIC_SetPriorityGrouping(uint32_t PriorityGroup)
{
  uint32_t reg_value;
  uint32_t PriorityGroupTmp = (PriorityGroup & (uint32_t)0x07UL);             /* only values 0..7 are used          */

  reg_value  =  SCB->AIRCR;                                                   /* read old register configuration    */
  reg_value &= ~((uint32_t)(SCB_AIRCR_VECTKEY_Msk | SCB_AIRCR_PRIGROUP_Msk));             /* clear bits to change               */
  reg_value  =  (reg_value                                   |
                ((uint32_t)0x5FAUL << SCB_AIRCR_VECTKEY_Pos) |
                (PriorityGroupTmp << 8)                       );              /* Insert write key and priorty group */
  SCB->AIRCR =  reg_value;
}
// 0x5FUL 的具体含义是指 将 0x5F 指定为UL类型,即usigned long (无符号长整型)

再来看一下设置中断优先级的函数

__STATIC_INLINE void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority)
{
  if((int32_t)IRQn < 0) {
    SCB->SHP[(((uint32_t)(int32_t)IRQn) & 0xFUL)-4UL] = (uint8_t)((priority << (8 - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL);
  }
  else {
    NVIC->IP[((uint32_t)(int32_t)IRQn)]               = (uint8_t)((priority << (8 - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL);
  }
}

可以看到stm32提供的函数在设置中断优先级时形参为中断号和要设置的中断优先级,中断号小于0时使用的是SCB-SHP寄存器,首先看一看SHP寄存器和IP寄存器是什么

typedef struct
{
  __I  uint32_t CPUID;                   /*!< Offset: 0x000 (R/ )  CPUID Base Register                                   */
  __IO uint32_t ICSR;                    /*!< Offset: 0x004 (R/W)  Interrupt Control and State Register                  */
  __IO uint32_t VTOR;                    /*!< Offset: 0x008 (R/W)  Vector Table Offset Register                          */
  __IO uint32_t AIRCR;                   /*!< Offset: 0x00C (R/W)  Application Interrupt and Reset Control Register      */
  __IO uint32_t SCR;                     /*!< Offset: 0x010 (R/W)  System Control Register                               */
  __IO uint32_t CCR;                     /*!< Offset: 0x014 (R/W)  Configuration Control Register                        */
  __IO uint8_t  SHP[12];                 /*!< Offset: 0x018 (R/W)  System Handlers Priority Registers (4-7, 8-11, 12-15) */
  __IO uint32_t SHCSR;                   /*!< Offset: 0x024 (R/W)  System Handler Control and State Register             */
  __IO uint32_t CFSR;                    /*!< Offset: 0x028 (R/W)  Configurable Fault Status Register                    */
  __IO uint32_t HFSR;                    /*!< Offset: 0x02C (R/W)  HardFault Status Register                             */
  __IO uint32_t DFSR;                    /*!< Offset: 0x030 (R/W)  Debug Fault Status Register                           */
  __IO uint32_t MMFAR;                   /*!< Offset: 0x034 (R/W)  MemManage Fault Address Register                      */
  __IO uint32_t BFAR;                    /*!< Offset: 0x038 (R/W)  BusFault Address Register                             */
  __IO uint32_t AFSR;                    /*!< Offset: 0x03C (R/W)  Auxiliary Fault Status Register                       */
  __I  uint32_t PFR[2];                  /*!< Offset: 0x040 (R/ )  Processor Feature Register                            */
  __I  uint32_t DFR;                     /*!< Offset: 0x048 (R/ )  Debug Feature Register                                */
  __I  uint32_t ADR;                     /*!< Offset: 0x04C (R/ )  Auxiliary Feature Register                            */
  __I  uint32_t MMFR[4];                 /*!< Offset: 0x050 (R/ )  Memory Model Feature Register                         */
  __I  uint32_t ISAR[5];                 /*!< Offset: 0x060 (R/ )  Instruction Set Attributes Register                   */
       uint32_t RESERVED0[5];
  __IO uint32_t CPACR;                   /*!< Offset: 0x088 (R/W)  Coprocessor Access Control Register                   */
} SCB_Type;


typedef struct
{
  __IO uint32_t ISER[8];                 /*!< Offset: 0x000 (R/W)  Interrupt Set Enable Register           */
       uint32_t RESERVED0[24];
  __IO uint32_t ICER[8];                 /*!< Offset: 0x080 (R/W)  Interrupt Clear Enable Register         */
       uint32_t RSERVED1[24];
  __IO uint32_t ISPR[8];                 /*!< Offset: 0x100 (R/W)  Interrupt Set Pending Register          */
       uint32_t RESERVED2[24];
  __IO uint32_t ICPR[8];                 /*!< Offset: 0x180 (R/W)  Interrupt Clear Pending Register        */
       uint32_t RESERVED3[24];
  __IO uint32_t IABR[8];                 /*!< Offset: 0x200 (R/W)  Interrupt Active bit Register           */
       uint32_t RESERVED4[56];
  __IO uint8_t  IP[240];                 /*!< Offset: 0x300 (R/W)  Interrupt Priority Register (8Bit wide) */
       uint32_t RESERVED5[644];
  __O  uint32_t STIR;                    /*!< Offset: 0xE00 ( /W)  Software Trigger Interrupt Register     */
}  NVIC_Type;

从SCB结构体的定义中我们可以看到SHP是System Handlers Priority Registers(系统优先处理寄存器),IP是NVIC寄存器中的Interrupt Priority Register (中断优先级寄存器),再看看中断号小于0的是那些中断

typedef enum IRQn
{
/******  Cortex-M4 Processor Exceptions Numbers ****************************************************************/
  NonMaskableInt_IRQn         = -14,    /*!< 2 Non Maskable Interrupt                                          */
  MemoryManagement_IRQn       = -12,    /*!< 4 Cortex-M4 Memory Management Interrupt                           */
  BusFault_IRQn               = -11,    /*!< 5 Cortex-M4 Bus Fault Interrupt                                   */
  UsageFault_IRQn             = -10,    /*!< 6 Cortex-M4 Usage Fault Interrupt                                 */
  SVCall_IRQn                 = -5,     /*!< 11 Cortex-M4 SV Call Interrupt                                    */
  DebugMonitor_IRQn           = -4,     /*!< 12 Cortex-M4 Debug Monitor Interrupt                              */
  PendSV_IRQn                 = -2,     /*!< 14 Cortex-M4 Pend SV Interrupt                                    */
  SysTick_IRQn                = -1,     /*!< 15 Cortex-M4 System Tick Interrupt  
  /*省略*/
  }IRQn_Type;

通过上述分析,我们可以了解到,在设置中断优先级时若中断优先级为负数,则那些中断都是系统级的中断,需要优先处理,在函数中通过中断号确定数组下标,以数组形式访问SCB->SHP寄存器,将优先级写入相关位。当中断号大于0时,设置的则是NVIC->IP寄存器,同样以数组形式访问并将优先级写入,很明显不同的数组元素位置对应不同的中断。

再回到最初的问题,中断优先级分组的作用,在设置优先级的函数中可以看到在写入优先级时将参数转换为uint_8,说明中断优先级由八位确认,而中断优先级的不同分组就是确认在在这8位中那几位确定主优先级(高位),那些位确定子优先级(低位),比如主优先级占3位,则主优先级就有8钟,子优先级有32种。

如果同时有中断发生,则先处理优先级高的中断,中断优先级的确定顺序是:主优先级>子优先级>硬件中断编号(IRQn_Type)

中断编程

  1. 使能外设的中断,一般由具体外设的相关寄存器控制
/*NVIC初始化结构体*/
typedef struct
{
  uint8_t NVIC_IRQChannel;                    /*!< Specifies the IRQ channel to be enabled or disabled.
                                                   This parameter can be an enumerator of @ref IRQn_Type 
                                                   enumeration (For the complete STM32 Devices IRQ Channels
                                                   list, please refer to stm32f4xx.h file) */

  uint8_t NVIC_IRQChannelPreemptionPriority;  /*!< Specifies the pre-emption priority for the IRQ channel
                                                   specified in NVIC_IRQChannel. This parameter can be a value
                                                   between 0 and 15 as described in the table @ref MISC_NVIC_Priority_Table
                                                   A lower priority value indicates a higher priority */

  uint8_t NVIC_IRQChannelSubPriority;         /*!< Specifies the subpriority level for the IRQ channel specified
                                                   in NVIC_IRQChannel. This parameter can be a value
                                                   between 0 and 15 as described in the table @ref MISC_NVIC_Priority_Table
                                                   A lower priority value indicates a higher priority */

  FunctionalState NVIC_IRQChannelCmd;         /*!< Specifies whether the IRQ channel defined in NVIC_IRQChannel
                                                   will be enabled or disabled. 
                                                   This parameter can be set either to ENABLE or DISABLE */   
} NVIC_InitTypeDef;

/*NVIC初始化函数*/
/**
  * @brief  Initializes the NVIC peripheral according to the specified
  *         parameters in the NVIC_InitStruct.
  * @note   To configure interrupts priority correctly, the NVIC_PriorityGroupConfig()
  *         function should be called before. 
  * @param  NVIC_InitStruct: pointer to a NVIC_InitTypeDef structure that contains
  *         the configuration information for the specified NVIC peripheral.
  * @retval None
  */
void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct)
{
  uint8_t tmppriority = 0x00, tmppre = 0x00, tmpsub = 0x0F;
  
  /* Check the parameters */
  assert_param(IS_FUNCTIONAL_STATE(NVIC_InitStruct->NVIC_IRQChannelCmd));
  assert_param(IS_NVIC_PREEMPTION_PRIORITY(NVIC_InitStruct->NVIC_IRQChannelPreemptionPriority));  
  assert_param(IS_NVIC_SUB_PRIORITY(NVIC_InitStruct->NVIC_IRQChannelSubPriority));
    
  if (NVIC_InitStruct->NVIC_IRQChannelCmd != DISABLE)
  {
    /* Compute the Corresponding IRQ Priority --------------------------------*/    
    tmppriority = (0x700 - ((SCB->AIRCR) & (uint32_t)0x700))>> 0x08;
    tmppre = (0x4 - tmppriority);
    tmpsub = tmpsub >> tmppriority;

    tmppriority = NVIC_InitStruct->NVIC_IRQChannelPreemptionPriority << tmppre;
    tmppriority |=  (uint8_t)(NVIC_InitStruct->NVIC_IRQChannelSubPriority & tmpsub);
        
    tmppriority = tmppriority << 0x04;
        
    NVIC->IP[NVIC_InitStruct->NVIC_IRQChannel] = tmppriority;
    
    /* Enable the Selected IRQ Channels --------------------------------------*/
    NVIC->ISER[NVIC_InitStruct->NVIC_IRQChannel >> 0x05] =
      (uint32_t)0x01 << (NVIC_InitStruct->NVIC_IRQChannel & (uint8_t)0x1F);
  }
  else
  {
    /* Disable the Selected IRQ Channels -------------------------------------*/
    NVIC->ICER[NVIC_InitStruct->NVIC_IRQChannel >> 0x05] =
      (uint32_t)0x01 << (NVIC_InitStruct->NVIC_IRQChannel & (uint8_t)0x1F);
  }
}

在初始化函数中,通过结构体的值和中断号操作 ** NVIC** 的 ** ISER ** 和 ICER操作使中断的通道使能或失能。但这里的通道的失能或失能并不是外设中断的失能或者失能。

  1. 初始化NVIC_InitTypeDef结构体,配置中断优先级分组、设置抢占优先级和子优先级、使能中断请求(misc.c 中提供的函数)
  2. 编写中断服务函数,可以在stm32f4xx_it.c中(终端服务名称是固定的,涉及中断向量表。可参考startup文件)
    使能外设的中断:未理解,待补充…

外部中断 EXTI

EXIT 外部中断/事件控制器

exti 有23个中断/事件线,0~15 对应于GPIO的不同分组,16 ~ 22 对应7个特定的事件。通过配置SYSCFG->EXTIx寄存器可以配置EXTI关联信息(使用GPIO时)。
在这里插入图片描述
GPIO 个各个引脚通过EXTI0~EXTI15连接到16个外部中断/事件线,另外7个中断/时间线的连接如下:
● EXTI 线 16 连接到 PVD 输出
● EXTI 线 17 连接到 RTC 闹钟事件
● EXTI 线 18 连接到 USB OTG FS 唤醒事件
● EXTI 线 19 连接到以太网唤醒事件
● EXTI 线 20 连接到 USB OTG HS(在 FS 中配置)唤醒事件
● EXTI 线 21 连接到 RTC 入侵和时间戳事件
● EXTI 线 22 连接到 RTC 唤醒事件
而连接到中断/事件线之后就进入了EXTI内部,EXTI内部功能框图如下:
在这里插入图片描述
可以看到在EXTI内部是由EXTI相关的寄存器配置的,通个不同的配置可以选择是在被触发后生成事件还是中断(事件一般通过脉冲发生器产生一个方波)。
总结:
通过对EXTI的分析我们可以知道,要使用EXTI由23个,7个(16~22)是固定连接的,在使用这7个事件线时只需要配置EXTi内部相关的寄存器就可以了。但是如果要使用GPIO触发中断或事件就需要多一步配置,因为不同GPIO的相同引脚连接到了SYSCFG->EXTICRx(x=0-15),然后SYSCFG->EXTICRx连接到了EXTI的0 ~15 号中断/事件线。所以要使用GPIO触发中断,要先将GPIO引脚设置为IN模式,然后然后配置SYSCFG->EXTICRx,确定是那一组GPIO的哪一个引脚,然后配置EXTI内部的寄存器。
**注意1:**EXTI内部寄存器是一组,23个线占各自寄存器的一位。
**注意2:**GPIO触发中断要使用SYSCFG寄存器,所以要开启SYSCFG的时钟。

EXIT的使用

在STM32提供的固件库函数中,使用一个外设必然要先通过配置相关挂的结构体来进行初始化的,EXTI也是如此。

typedef struct
{
  uint32_t EXTI_Line;               /*!< Specifies the EXTI lines to be enabled or disabled.
                                         This parameter can be any combination value of @ref EXTI_Lines */
   
 EXTIMode_TypeDef EXTI_Mode;       /*!< Specifies the mode for the EXTI lines.
                                         This parameter can be a value of @ref EXTIMode_TypeDef */

 EXTITrigger_TypeDef EXTI_Trigger; /*!< Specifies the trigger signal active edge for the EXTI lines.
                                         This parameter can be a value of @ref EXTITrigger_TypeDef */

  FunctionalState EXTI_LineCmd;     /*!< Specifies the new state of the selected EXTI lines.
                                         This parameter can be set either to ENABLE or DISABLE */ 
}EXTI_InitTypeDef; 

由EXTI初始化结构体可以看到,想使用一个EXTI首先要选择中断/事件线(0~22,据此使能对应中断/事件线),然后选择EXTI模式(中断还是事件),接着选择触发模式(上升沿触发还是下降沿触发或是混合触发),最后选择中断/事件线的状态(使能或失能)
接下来分析一下EXTI初始化函数

void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct)
{
  uint32_t tmp = 0;

  /* Check the parameters */
  assert_param(IS_EXTI_MODE(EXTI_InitStruct->EXTI_Mode));
  assert_param(IS_EXTI_TRIGGER(EXTI_InitStruct->EXTI_Trigger));
  assert_param(IS_EXTI_LINE(EXTI_InitStruct->EXTI_Line));  
  assert_param(IS_FUNCTIONAL_STATE(EXTI_InitStruct->EXTI_LineCmd));

  tmp = (uint32_t)EXTI_BASE;
     
  if (EXTI_InitStruct->EXTI_LineCmd != DISABLE)
  {
    /* Clear EXTI line configuration */
    EXTI->IMR &= ~EXTI_InitStruct->EXTI_Line;
    EXTI->EMR &= ~EXTI_InitStruct->EXTI_Line;
    
    tmp += EXTI_InitStruct->EXTI_Mode;

    *(__IO uint32_t *) tmp |= EXTI_InitStruct->EXTI_Line;

    /* Clear Rising Falling edge configuration */
    EXTI->RTSR &= ~EXTI_InitStruct->EXTI_Line;
    EXTI->FTSR &= ~EXTI_InitStruct->EXTI_Line;
    
    /* Select the trigger for the selected external interrupts */
    if (EXTI_InitStruct->EXTI_Trigger == EXTI_Trigger_Rising_Falling)
    {
      /* Rising Falling edge */
      EXTI->RTSR |= EXTI_InitStruct->EXTI_Line;
      EXTI->FTSR |= EXTI_InitStruct->EXTI_Line;
    }
    else
    {
      tmp = (uint32_t)EXTI_BASE;
      tmp += EXTI_InitStruct->EXTI_Trigger;

      *(__IO uint32_t *) tmp |= EXTI_InitStruct->EXTI_Line;
    }
  }
  else
  {
    tmp += EXTI_InitStruct->EXTI_Mode;

    /* Disable the selected external lines */
    *(__IO uint2_t *) tmp &= ~EXTI_InitStruct->EXTI_Line;
  }
}
/*EXTI结构体*/
typedef struct
{
  __IO uint32_t IMR;    /*!< EXTI Interrupt mask register,            Address offset: 0x00 */
  __IO uint32_t EMR;    /*!< EXTI Event mask register,                Address offset: 0x04 */
  __IO uint32_t RTSR;   /*!< EXTI Rising trigger selection register,  Address offset: 0x08 */
  __IO uint32_t FTSR;   /*!< EXTI Falling trigger selection register, Address offset: 0x0C */
  __IO uint32_t SWIER;  /*!< EXTI Software interrupt event register,  Address offset: 0x10 */
  __IO uint32_t PR;     /*!< EXTI Pending register,                   Address offset: 0x14 */
} EXTI_TypeDef;

在EXTI初始化函数中,设置的寄存器都是EXTI内部的寄存器,若要使用GPIO则还要配置SYSCFG->EXTICRx,SYSCF作为外设也提供了对应的固件库函数。

 void SYSCFG_EXTILineConfig(uint8_t EXTI_PortSourceGPIOx, uint8_t EXTI_PinSourcex)
{
  uint32_t tmp = 0x00;

  /* Check the parameters */
  assert_param(IS_EXTI_PORT_SOURCE(EXTI_PortSourceGPIOx));
  assert_param(IS_EXTI_PIN_SOURCE(EXTI_PinSourcex));

  tmp = ((uint32_t)0x0F) << (0x04 * (EXTI_PinSourcex & (uint8_t)0x03));
  SYSCFG->EXTICR[EXTI_PinSourcex >> 0x02] &= ~tmp;
  SYSCFG->EXTICR[EXTI_PinSourcex >> 0x02] |= (((uint32_t)EXTI_PortSourceGPIOx) << (0x04 * (EXTI_PinSourcex & (uint8_t)0x03)));
}

在这个函数中通过传入的参数确定选择那几位,先清空再赋值。

在这里插入图片描述

GPIO触发中断流程:
1、开启GPIO时钟,SYSCFG时钟
2、配置GPIO模式,配置SYSCFG->EXTICRx寄存器
3、配置EXTI内部寄存器
4、设置NVIC,确定中断优先级
5、写中断服务函数
**注意:**在编写中断服务函数时,5~9、10 ~ 15 外部中断使用两个中断服务函数,所以在使用这两个范围的外部中断时编写中断服务函数需要判断一下具体的中断源是哪一个再做处理,使用函数ITStatus EXTI_GetITStatus(uint32_t EXTI_Line)

ITStatus EXTI_GetITStatus(uint32_t EXTI_Line)
{
  FlagStatus bitstatus = RESET;
  /* Check the parameters */
  assert_param(IS_GET_EXTI_LINE(EXTI_Line));
  
  if ((EXTI->PR & EXTI_Line) != (uint32_t)RESET)
  {
    bitstatus = SET;
  }
  else
  {
    bitstatus = RESET;
  }
  return bitstatus;
  
}

可以看到这个函数是通过EXTI->PR(挂起寄存器)寄存寄存器判断具体的中断源的

EXTI内部寄存器分析

待补充。。。。。

GPIO触发中断例程

为什么中断后要清除中断标志位

EXTI_ClearITPendingBit(EXTI_Line0); 待补充

SysTick的使用

SysTick分析

SysTick (系统定时器)是CM4内核的一个外设,是一个24位的递减的计数器,当递减为0的时候系统产生一个中断。中断编号为-1,属于可编程的中断。通过源码对SysTick的定义可以了解该寄存器

//在中断向量表中的中断编号
 SysTick_IRQn                = -1,     /*!< 15 Cortex-M4 System Tick Interrupt 

/** \brief  Structure type to access the System Timer (SysTick).
 */
typedef struct
{
  __IO uint32_t CTRL;                    /*!< Offset: 0x000 (R/W)  SysTick Control and Status Register */
  __IO uint32_t LOAD;                    /*!< Offset: 0x004 (R/W)  SysTick Reload Value Register       */
  __IO uint32_t VAL;                     /*!< Offset: 0x008 (R/W)  SysTick Current Value Register      */
  __I  uint32_t CALIB;                   /*!< Offset: 0x00C (R/ )  SysTick Calibration Register        */
} SysTick_Type;

通过SysTick的结构体可以看到SysTick有四个寄存器。下面分析这四个寄存器。

名称描述
CTRL(SYSTICK控制和状态寄存器)[0]:SysTick使能位 [1]:置1,计数至0 产生中断,置0无动作 [2]:时钟源选择 [16]:在上次读取该寄存器后,若技术至0,该位置1
LOAD (重载寄存器)VAL计数至0后加载该寄存器值到VAL
VAL(当前值寄存器)每1/SYSCLK计数一次(递减),计数至0产生中断
CALIB(校准寄存器)

**思考:**CTRL的[16]:在上次读取该寄存器后,若技术至0,该位置1,那么在计0后,该位是否需要手动置0。
在这里插入图片描述
很明显不需要。

/** \brief  System Tick Configuration

    The function initializes the System Timer and its interrupt, and starts the System Tick Timer.
    Counter is in free running mode to generate periodic interrupts.

    \param [in]  ticks  Number of ticks between two interrupts.

    \return          0  Function succeeded.
    \return          1  Function failed.

    \note     When the variable <b>__Vendor_SysTickConfig</b> is set to 1, then the
    function <b>SysTick_Config</b> is not included. In this case, the file <b><i>device</i>.h</b>
    must contain a vendor-specific implementation of this function.

 */
__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks)
{
  if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk) { return (1UL); }    /* Reload value impossible */

  SysTick->LOAD  = (uint32_t)(ticks - 1UL);                         /* set reload register */
  NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); /* set Priority for Systick Interrupt */
  SysTick->VAL   = 0UL;                                             /* Load the SysTick Counter Value */
  SysTick->CTRL  = SysTick_CTRL_CLKSOURCE_Msk |
                   SysTick_CTRL_TICKINT_Msk   |
                   SysTick_CTRL_ENABLE_Msk;                         /* Enable SysTick IRQ and SysTick Timer */
  return (0UL);                                                     /* Function successful */
}
/*通过SysTick 计时 ms*/
void SysTick_Delay_Ms( __IO uint32_t ms)
{

	uint32_t i;
	SysTick_Config(SystemCoreClock/1000);

	for (i=0; i<ms; i++) {
	// 当计数器的值减小到 0 的时候, CRTL 寄存器的位 16 会置 1
	// 当置 1 时,读取该位会清 0
		while ( !((SysTick->CTRL)&(1<<16)) );
		}
	// 关闭 SysTick 定时器
		SysTick->CTRL &=~ SysTick_CTRL_ENABLE_Msk;
	}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1916225.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ChatTTS的爆火是必然,它正在重新定义我们与机器对话的方式

当AI技术与语音合成相遇&#xff0c;开源技术众多&#xff0c;为什么 ChatTTS 能够一夜爆火&#xff1f;你有听说过能说情感真切文字的 AI 吗&#xff1f; 前言 想象一下&#xff0c;你只需输入一句话&#xff0c;AI就能念得声情并茂&#xff0c;不仅支持中英文混读&#xff0…

自注意力简介

在注意力机制中&#xff0c;每个查询都会关注所有的键值对并生成一个注意力输出。如果查询q&#xff0c;键k和值v都来自于同一组输入&#xff0c;那么这个注意力就被称为是自注意力&#xff08;self-attention&#xff09;。自注意力这部分理论&#xff0c;我觉得台大李宏毅老师…

一位互联网公司项目经理繁忙的一天

早晨&#xff1a;准备与计划 7:00 AM - 起床与准备 项目经理起床后&#xff0c;快速洗漱并享用早餐。之后花几分钟查看手机上的邮件和消息&#xff0c;确保没有紧急事务需要立即处理。 7:30 AM - 通勤时间 前往公司。在通勤途中&#xff0c;通过手机或平板电脑查看当天的会议…

硅谷甄选运营平台-vue3组件通信方式

vue3组件通信方式 vue2组件通信方式&#xff1a; props:可以实现父子组件、子父组件、甚至兄弟组件通信自定义事件:可以实现子父组件通信全局事件总线$bus:可以实现任意组件通信pubsub:发布订阅模式实现任意组件通信vuex:集中式状态管理容器&#xff0c;实现任意组件通信ref:父…

简单了解下安全测试!

一、基本概念 安全测试是在软件产品开发基本完成时&#xff0c;验证产品是否符合安全需求定义和产品质量标准的过程。它主要检查系统对非法侵入渗透的防范能力&#xff0c;旨在通过全面的脆弱性安全测试&#xff0c;发现系统未知的安全隐患并提出相关建议&#xff0c;确保系统…

星申刹车盘平衡机:精准与高效兼备

星申动双工位刹车盘动平衡机是一款具备测量和切削两个工位的高精度设备。该机器由平衡测量单元、内部搬运系统、切削校正模块及电气控制部分组成&#xff0c;专为满足自动化生产需求设计。其主要功能特点包括&#xff1a; 1. 实现全自动刹车盘平衡测试&#xff0c;精度高达30gm…

vue3 ts 报错:无法找到模块“../views/index/Home.vue”的声明文件

解决办法&#xff1a; env.d.ts 新增代码片段&#xff1a; declare module "*.vue" {import type { DefineComponent } from "vue";// eslint-disable-next-line typescript-eslint/no-explicit-any, typescript-eslint/ban-typesconst component: Define…

ExtruOnt——为工业 4.0 系统描述制造机械类型的本体

概述 论文地址 &#xff1a;https://arxiv.org/abs/2401.11848 原文地址&#xff1a;https://ai-scholar.tech/articles/ontology/ExtruOnt 在工业 4.0 应用场景中&#xff0c;以机器可解释代码提供的、语义丰富的制造机械描述可以得到有效利用。然而&#xff0c;目前显然还缺…

使用nvm安装node包后,安装vue提示“vue不是内部或外部命令,也不是可运行的程序或批处理命令”

前言 使用 npm 安装了 vue-cli 后&#xff0c;输入 "vue -V" 查询vue版本命令提示&#xff1a; “vue不是内部或外部命令,也不是可运行的程序或批处理命令”。 解决方法 第一步&#xff1a;首先&#xff0c;查看 C 盘下有没有 npm 文件夹。 目录类似于&#xff1…

六、数据可视化—Echars(爬虫及数据可视化)

六、数据可视化—Echars&#xff08;爬虫及数据可视化&#xff09; Echarts应用 Echarts Echarts官网&#xff0c;很多图表等都是我们可以 https://echarts.apache.org/zh/index.html 是百度自己做的图表&#xff0c;后来用的人越来越多&#xff0c;捐给了orange组织&#xf…

网络渗透CTF实践:获取靶机Web Developer 文件/root/flag.txt中flag

实验目的&#xff1a;通过对目标靶机的渗透过程&#xff0c;了解CTF竞赛模式&#xff0c;理解CTF涵盖的知识范围&#xff0c;如MISC、PPC、WEB等&#xff0c;通过实践&#xff0c;加强团队协作能力&#xff0c;掌握初步CTF实战能力及信息收集能力。熟悉网络扫描、探测HTTP web服…

交易员需要克服的十大心理问题

撰文&#xff1a;Koroush AK 编译&#xff1a;Chris&#xff0c;Techub News 本文来源香港Web3媒体&#xff1a;Techub News 一个交易者在交易上所犯下的最大的错误可能更多来自于心态的失衡而并非技术上的失误&#xff0c;类似的情况已经发生在了无数交易者身上。作为交易者…

如何压缩pdf文件大小,怎么压缩pdf文件大小

在数字化时代&#xff0c;pdf文件因其稳定的格式和跨平台兼容性&#xff0c;成为了工作与学习中不可或缺的一部分。然而&#xff0c;随着pdf文件内容的丰富&#xff0c;pdf文件的体积也随之增大&#xff0c;给传输和存储带来了不少挑战。本文将深入探讨如何高效压缩pdf文件大小…

C++入门 模仿mysql控制台输出表格

一、 说明 控制台输出表格&#xff0c;自适应宽度 二、 源码 #include <iostream> #include <map> #include <string> #include <vector>using namespace std;void printTable(vector<vector<string>> *pTableData) {int row pTableDa…

前端八股文 箭头函数和普通函数的区别

箭头函数是匿名函数&#xff0c;不能作为构造函数&#xff0c;不能使用new箭头函数不绑定 arguments &#xff0c;取而代之用 rest 参数...解决箭头函数不绑定 this &#xff0c;会捕获其所在的上下文的this值&#xff0c;作为自己的this值箭头函数通过 call() 或 apply() 方法…

【学术会议征稿】第四届新材料与化学工程国际学术会议(AMCE 2024)

第四届新材料与化学工程国际学术会议&#xff08;AMCE 2024&#xff09; 2024 4th International Conference on Advanced Materials and Chemical Engineering 为了促进我国新材料与化学工程领域绿色、规范、持续、健康发展,提升科技创新能力&#xff0c;推进学科交叉融合和…

苹果笔记本电脑能玩哪些游戏 苹果电脑可以玩的单机游戏推荐

苹果笔记本有着优美的外观和强大的性能。用户不仅可以使用苹果笔记本办公、剪辑&#xff0c;越来越多的用户开始关注苹果笔记本在游戏领域的表现&#xff0c;尤其是在大型游戏方面。本文将为你详细介绍苹果笔记本都能玩什么游戏&#xff0c;以及为你推荐苹果电脑可以玩的单机游…

浙江宁波G761-3005B穆格伺服阀 有货

G761-3005B穆格伺服阀是一种用于流体控制的阀门。 宁波秉圣与各国的多家进口产品维护服务提供商建立了紧密的合作关系。我们售出的产品提供1年的质保&#xff0c;并且都经过了严格的测试和认证。公司的优势品牌如下&#xff1a;德国MOOG、美国 PARKER&#xff08;派克&#xf…

Sqli-labs合集之环境搭建

Sqli-labs的搭建 搭建第一个SQL注入学习靶场环境&#xff1a; 软件&#xff1a;sqli-labs 安装过程&#xff1a; 1.源码地址&#xff1a;GitHub - Audi-1/sqli-labs: SQLI labs to test error based, Blind boolean based, Time based.&#xff1b; 2.将压缩包解压到phpst…

特征值究竟体现了矩阵的什么特征?

特征值究竟体现了矩阵的什么特征&#xff1f; 简单来说就是x经过矩阵A映射后和自己平行 希尔伯特第一次提出eigenvalue,这里的eigen就是自己的。所以eigenvalue也称作本征值 特征值和特征向量刻画了矩阵变换空间的特征 对平面上的任意向量可以如法炮制&#xff0c;把他在特征…