stm32的中断分为 1.抢占优先级。 2.子优先级。
1.抢占优先级。抢占优先级高的中断,可以打断抢占优先级低的中断。
2.子优先级。抢占优先级相同的中断,子优先级高的可以优先执行。
其实,子优先级主要给出了一种响应的优先队列。假设中断的抢占优先级都相同。如果有多个相同抢占优先级的中断来了 ,那么他们不会互相打断,但是他们后续的排队会按照子优先级排队。也就是说,在第一个中断没有执行完的期间内,后续的最高级的子优先级是被安排到最高等待位处理的。
NVIC设置流程:
static void EXTI_NVIC_Config(void)
{
NVIC_InitTypeDef NVIC_InitStruct;
// 先设置中断优先级分组
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
NVIC_InitStruct.NVIC_IRQChannel = EXTI0_IRQn;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStruct);
}
void EXTI0_IRQHandler(void)
{
// 判断是否发生中断
// 与函数FlagStatus EXTI_GetFlagStatus(uint32_t EXTI_Line);功能相同
if (EXTI_GetITStatus(EXTI_Line0) != RESET)
{
LED_R_TOGGLE;
}
// 清除标志位,往EXTI_PR寄存器写1,与函数void EXTI_ClearFlag(uint32_t EXTI_Line)功能相同
// 之所有一个功能有两个一样的函数,是为了兼容旧的固件库
EXTI_ClearITPendingBit(EXTI_Line0);
}
stm32的中断可以分为系统异常10个(内核)和外部中断60个(外设)。NVIC是内核的外设,管理包括内核和片上外设所有的中断功能,在core_cm3.h和misc.h中。
NVIC的寄存器描述:
ISER:中断使能寄存器,对应60个外设的不可屏蔽中断,其中NVIC_ISER0的0~31位对应着中断向量表中的编号0~31,NVIC_ISER1对应着32~63,ISER2对应剩余位,其中还存在一些保留位,要想开启特定的中断,设置特定的位就可以。
ICER:中断清除寄存器,对应60个外设的不可屏蔽中断。与ISER类似,要想清除特定的中断,设置特定的位就可以。
ISPR:中断挂起寄存器,可挂起正在执行的中断,设置特定位。当置位此寄存器时,这个中断不会立即执行,而是等待可执行的时候再执行;比如高低级别的中断同时产生,CPU会自然的将低级别的中断挂起,当高优先级中断执行完毕后,再去处理低优先级中断,这个时候需要清除挂起位(使用ICPR),然后执行低级别中断。
ICPR:中断解除挂起寄存器,可以解除被挂起的中断。
IABR:中断激活标志寄存器(只读),可读取该寄存器判断当前执行的中断是哪个,中断执行完硬件清零。
IPR:中断优先级寄存器,用于中断分组。
STIR:软件触发中断寄存器,用于系统任务调度,编写SDK(不让别人看到代码)。
core_cm3.h中的NVIC结构体:
typedef struct
{
__IO uint32_t ISER[8]; /*!< Offset: 0x000 Interrupt Set Enable Register */
uint32_t RESERVED0[24];
__IO uint32_t ICER[8]; /*!< Offset: 0x080 Interrupt Clear Enable Register */
uint32_t RSERVED1[24];
__IO uint32_t ISPR[8]; /*!< Offset: 0x100 Interrupt Set Pending Register */
uint32_t RESERVED2[24];
__IO uint32_t ICPR[8]; /*!< Offset: 0x180 Interrupt Clear Pending Register */
uint32_t RESERVED3[24];
__IO uint32_t IABR[8]; /*!< Offset: 0x200 Interrupt Active bit Register */
uint32_t RESERVED4[56];
__IO uint8_t IP[240]; /*!< Offset: 0x300 Interrupt Priority Register (8Bit wide) */
uint32_t RESERVED5[644];
__O uint32_t STIR; /*!< Offset: 0xE00 Software Trigger Interrupt Register */
} NVIC_Type;
stm32设计了8个ISER寄存器,实际上只用到其中的3个,之所以设计这么多组,是为了后续内核和外设资源的升级来考虑的,中间有24个保留地址,总共是32个32位地址,所以ICER的偏移地址为0X80(每4个地址增加0X10),以此类推。
值得注意的是,设置中断优先级的寄存器是8位有效(ARM规定),实际上stm32只使用了高4位,忽略低4位。但是中断优先级寄存器IPR是32位的,因此,每8位寄存器为一个优先级数组IP,每个IPR寄存器表示4个IP优先级分组,如下图:
misc.h中实现了NVIC所有的功能函数:
// 优先级分组
void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup);
// NVIC初始化
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);
// 设置内核时钟来源,72M或72M/8=9M(8分频)
void SysTick_CLKSourceConfig(uint32_t SysTick_CLKSource);
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 a value of @ref IRQn_Type
(For the complete STM32 Devices IRQ Channels list, please
refer to stm32f10x.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 NVIC_Priority_Table */
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 NVIC_Priority_Table */
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;
/**
* @}
*/
/** @defgroup NVIC_Priority_Table
* @{
*/
/**
@code
The table below gives the allowed values of the pre-emption priority and subpriority according
to the Priority Grouping configuration performed by NVIC_PriorityGroupConfig function
============================================================================================================================
NVIC_PriorityGroup | NVIC_IRQChannelPreemptionPriority | NVIC_IRQChannelSubPriority | Description
============================================================================================================================
NVIC_PriorityGroup_0 | 0 | 0-15 | 0 bits for pre-emption priority
| | | 4 bits for subpriority
----------------------------------------------------------------------------------------------------------------------------
NVIC_PriorityGroup_1 | 0-1 | 0-7 | 1 bits for pre-emption priority
| | | 3 bits for subpriority
----------------------------------------------------------------------------------------------------------------------------
NVIC_PriorityGroup_2 | 0-3 | 0-3 | 2 bits for pre-emption priority
| | | 2 bits for subpriority
----------------------------------------------------------------------------------------------------------------------------
NVIC_PriorityGroup_3 | 0-7 | 0-1 | 3 bits for pre-emption priority
| | | 1 bits for subpriority
----------------------------------------------------------------------------------------------------------------------------
NVIC_PriorityGroup_4 | 0-15 | 0 | 4 bits for pre-emption priority
| | | 0 bits for subpriority
============================================================================================================================
当接收到两个中断,先比较主优先级(抢占优先级),再比较子优先级,如果均相等,则比较硬件中断编号。
中断编程的顺序:
1 注意:中断的使能有两扇大门,第一个是外设的中断使能,比如串口发送完成中断,则TCIE位要置1,这是一扇小门;然后要设置NVIC总开关,来接受外设的中断请求,这个大门就是NVIC的中断使能寄存器NVIC_ISER。
2 因为会存在多个中断,所以要设置优先级分组。
3 配置好优先级分组后,就要初始化NVIC结构体,包括中断源,主优先级,子优先级和中断使能。
typedef struct
{
uint8_t NVIC_IRQChannel; /*!< Specifies the IRQ channel to be enabled or disabled.
This parameter can be a value of @ref IRQn_Type
(For the complete STM32 Devices IRQ Channels list, please
refer to stm32f10x.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 NVIC_Priority_Table */
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 NVIC_Priority_Table */
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;
如果是ENABLE,则会根据上述信息配置相应的寄存器,如果是DISABLE,直接设置ICER清除中断使能。
4 编写中断服务函数