STM32中断学习记录

文章目录

    • 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 Channelslist, please refer to stm32f4xx.h file) */uint8_t NVIC_IRQChannelPreemptionPriority;  /*!< Specifies the pre-emption priority for the IRQ channelspecified in NVIC_IRQChannel. This parameter can be a valuebetween 0 and 15 as described in the table @ref MISC_NVIC_Priority_TableA lower priority value indicates a higher priority */uint8_t NVIC_IRQChannelSubPriority;         /*!< Specifies the subpriority level for the IRQ channel specifiedin NVIC_IRQChannel. This parameter can be a valuebetween 0 and 15 as described in the table @ref MISC_NVIC_Priority_TableA lower priority value indicates a higher priority */FunctionalState NVIC_IRQChannelCmd;         /*!< Specifies whether the IRQ channel defined in NVIC_IRQChannelwill 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 Channelslist, please refer to stm32f4xx.h file) */uint8_t NVIC_IRQChannelPreemptionPriority;  /*!< Specifies the pre-emption priority for the IRQ channelspecified in NVIC_IRQChannel. This parameter can be a valuebetween 0 and 15 as described in the table @ref MISC_NVIC_Priority_TableA lower priority value indicates a higher priority */uint8_t NVIC_IRQChannelSubPriority;         /*!< Specifies the subpriority level for the IRQ channel specifiedin NVIC_IRQChannel. This parameter can be a valuebetween 0 and 15 as described in the table @ref MISC_NVIC_Priority_TableA lower priority value indicates a higher priority */FunctionalState NVIC_IRQChannelCmd;         /*!< Specifies whether the IRQ channel defined in NVIC_IRQChannelwill 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 ConfigurationThe 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 thefunction <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 时,读取该位会清 0while ( !((SysTick->CTRL)&(1<<16)) );}// 关闭 SysTick 定时器SysTick->CTRL &=~ SysTick_CTRL_ENABLE_Msk;}

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

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

相关文章

Docker安装HomeAssistant

检查Docker服务是否正常运行&#xff0c;确保Docker正常运行。 systemctl status docker#输出---------------------- docker.service - Docker Application Container EngineLoaded: loaded (/usr/lib/systemd/system/docker.service; enabled; vendor preset: disabled)Activ…

旗晟智能巡检机器人:开启工业运维的智能化新篇章

在当今快速发展的工业领域&#xff0c;安全、效率和成本控制是企业运营的核心。旗晟科技以创新为驱动&#xff0c;推出了一站式的工业级智能巡检机器人数字化全景运维解决方案&#xff0c;为石油、天然气、化工、电力等高危行业提供了一个全新的运维模式。 一、面对挑战&#x…

人工智能算法工程师(中级)课程3-sklearn机器学习之数据处理与代码详解

大家好&#xff0c;我是微学AI,今天给大家分享一下人工智能算法工程师(中级)课程3-sklearn机器学习之数据处理与代码详解。 Sklearn&#xff08;Scikit-learn&#xff09;是一个基于Python的开源机器学习库&#xff0c;它提供了简单有效的数据挖掘和数据分析工具。Sklearn包含了…

动手学深度学习(Pytorch版)代码实践 -循环神经网络-57长短期记忆网络(LSTM)

57长短期记忆网络&#xff08;LSTM&#xff09; 1.LSTM原理 LSTM是专为解决标准RNN的长时依赖问题而设计的。标准RNN在训练过程中&#xff0c;随着时间步的增加&#xff0c;梯度可能会消失或爆炸&#xff0c;导致模型难以学习和记忆长时间间隔的信息。LSTM通过引入一组称为门…

碾压SOTA!最新视觉SLAM:渲染速度提升176倍,内存占用减少150%

视觉SLAM&#xff0c;一种结合了CV与机器人技术的先进方法。与激光SLAM相比&#xff0c;它成本低廉且信息量大&#xff0c;易于安装&#xff0c;拥有更优秀的场景识别能力&#xff0c;因此在自动驾驶等许多场景上都非常适用&#xff0c;是学术界与工业界共同关注的热门研究方向…

如何将heic格式转换jpg?四种将heic转换成jpg的方法!

如何将heic格式转换jpg&#xff1f;在现今的数字图像处理领域&#xff0c;Heic格式作为一种被吹捧的创新型图像格式&#xff0c;以其先进的压缩技术&#xff0c;迅速减小了图片文件的大小&#xff0c;然而&#xff0c;尽管其有许多优点&#xff0c;实际使用中Heic格式却带来了一…

RSA加密算法因N强度不足破解实例

已知如下RSA密文和公钥信息&#xff0c;要求解密得到明文。 ----------------------- ciphertext&#xff08;HEX&#xff09; 94808F954A8AF9B9 N&#xff08;HEX&#xff09; C6EAD137492B4631 e&#xff08;HEX&#xff09; 10001 ------------------------ 分析过…

【Linux】命令执行的判断依据:;,,||

在某些情况下&#xff0c;很多命令我想要一次输入去执行&#xff0c;而不想要分次执行时&#xff0c;该如何是好&#xff1f; 基本上有两个选择&#xff0c; 一个是通过shell脚本脚本去执行&#xff0c;一种则是通过下面的介绍来一次入多个命令。 1.cmd&#xff1a;cmd&#…

【Android】基于 LocationManager 原生实现定位打卡

目录 前言一、实现效果二、定位原理三、具体实现1. 获取权限2. 页面绘制3. 获取经纬度4. 方法调用5. 坐标转换6. 距离计算7. 完整代码 前言 最近公司有个新需求&#xff0c;想要用定位进行考勤打卡&#xff0c;在距离打卡地一定范围内才可以进行打卡。本文将借鉴 RxTool 的 Rx…

buuctf面具下的flag

细节: 这道题可能因为是vmdk的原因 导致在window上 7z无法得到全部的信息 所以最后解压要在linux系统上 解密网站 Brainfuck/Ook! Obfuscation/Encoding [splitbrain.org] 这道题010打开,可以发现里面隐藏了很多 binwalk解压 两个文件 vmdk可以直接 用7z解压 7z x flag.…

常用网络概念

&#x1f4d1;打牌 &#xff1a; da pai ge的个人主页 &#x1f324;️个人专栏 &#xff1a; da pai ge的博客专栏 ☁️宝剑锋从磨砺出&#xff0c;梅花香自苦寒来 ​​ 目录 了解组织 局域网技术 …

20240711 每日AI必读资讯

&#x1f3a8;Runway Gen-3 Alpha 详细使用教程以及提示词指南大全 - 7月9日&#xff0c;著名生成式AI平台Runway在官网公布了&#xff0c;最新发布的文生视频模型Gen-3 Alpha的文本提示教程。 - 从技术层面来说&#xff0c;输入的文本提示会被转换成“向量”&#xff0c;这些…

怎么提高音频声音大小?提高音频声音大小的四种方法

怎么提高音频声音大小&#xff1f;在音频处理和编辑中&#xff0c;增加声音的音量是一个常见的需求&#xff0c;尤其是在确保音频清晰度和听觉效果的同时。调整音频的音量不仅仅是简单地提高音频的响度&#xff0c;它也涉及到如何保持音质的高标准&#xff0c;确保没有失真或削…

如何写好品牌宣传稿提升品牌曝光?看这篇文章就够了

在这个信息爆炸的时代&#xff0c;一句精炼而富有力量的宣传语&#xff0c;足以让品牌在万千竞争者中脱颖而出。撰写一篇成功的品牌宣传稿&#xff0c;不仅是对文字艺术的驾驭&#xff0c;也是对品牌灵魂的深刻洞察与精准传达&#xff0c;更是连接品牌与消费者情感与认知的桥梁…

怎样将aac转换mp3格式?推荐四个aac转MP3的方法

怎样将aac转换mp3格式&#xff1f;当需要将aac格式音频转换为MP3格式时&#xff0c;有几种方法可以轻松实现这一目标。MP3是一种广泛支持的音频格式&#xff0c;几乎所有设备和平台都能播放MP3文件&#xff0c;包括各种音乐播放器、手机、平板电脑和汽车音响系统。而且它也提供…

实习记录3

1.Mybaits懒加载 MyBatis 延迟加载&#xff08;懒加载&#xff09;一篇入门-腾讯云开发者社区-腾讯云 (tencent.com) 2.高级映射 106-高级映射之多对一映射第一种方式_哔哩哔哩_bilibili 3.TableId(type IdType.INPUT) Mybatis-plus 主键生成策略_mybatis-plus 自增主键等于…

使用PEFT库进行ChatGLM3-6B模型的QLORA高效微调

PEFT库进行ChatGLM3-6B模型QLORA高效微调 QLORA微调ChatGLM3-6B模型安装相关库使用ChatGLM3-6B模型GPU显存占用准备数据集加载数据集数据处理数据集处理加载量化模型-4bit预处理量化模型配置LoRA适配器训练超参数配置开始训练保存LoRA模型模型推理合并模型使用微调后的模型 QLO…

Apache功能配置:访问控制、日志分割; 部署AWStats日志分析工具

目录 保持连接 访问控制 只允许指定ip访问 拒绝指定主机其他正常访问 用户授权 日志格式 日志分割 操作步骤 使用第三方工具cronolog分割日志 AWStats日志分析 操作步骤 访问AwStats分析系统 保持连接 Apache通过设置配置文件httpd-default.conf中相关的连接保持参…

Everything搜索无法搜索到桌面的文件(无法检索C盘 或 特定路径的文件)

现象描述 在Everything搜索框中输入桌面已存在的文件或随便已知位置的文件&#xff0c;无法找到。 搜索时检索结果中明显缺少部分磁盘位置的&#xff0c;例如无法检索C盘&#xff0c;任意关键字搜索时结果中没有位于C盘的&#xff0c;无论怎样都搜不到C盘文件。 解决方法 在…

读论文《Unpaired Unsupervised CT Metal ArtifactReduction》

论文题目&#xff1a;非配对无监督CT金属伪影还原 项目地址&#xff1a;GitHub - ChenBoYam/Metal-Artifact-Reduction: Eliminate metal artifacts from CT images Semi-supervised learning 重点应该就是怎么实现无监督吧 先看论文&#xff0c;再看代码 摘要&#xff1a;…