STM32F1 - 中断优先级

Interrupt Priority

  • 1> STM32F103ZET6异常向量表
  • 2> 中断优先级寄存器NVIC_IPRx
  • 3> 中断优先级分组
  • 4> 例程:设置EXTI4中断优先级
  • 5> 例程:设置SysTick中断优先级
  • 6> 为什么不能用NVIC_Init()设置Systick优先级?
  • 7> 函数NVIC_EncodePriority()


1> STM32F103ZET6异常向量表

1

中断数量:70个

STM32F103ZET6有70个中断 = 60外设中断 + 10个系统中断;

问题来了:
70个中断中除了复位、NMI、硬件错误3个的中断优先级是固定的,
其他67个中断都可以改变,如何管理配置这些中断的优先级呢?


2> 中断优先级寄存器NVIC_IPRx

// core.cm3.h文件
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;   

NVIC的中断优先级寄存器,有240个,位宽为8位,
每个中断都由一个8位来控制,也就是能控制240个中断,
STM32F103ZET6只有70个中断,够够的。

 uint8_t  IP[240]; 

31

STM32F103只使用优先级控制寄存器IPn的高4位[7:4]


3> 中断优先级分组

通过配置SCB中AIRCR中[10~8]3位来确定IP中高4位的分组模式;
3

高抢占优先级,可以【打断】低抢占优先级程序;
子优先级没有抢占功能,同一抢占级中,高子优先级的先执行;

// misc.h文件中:#define NVIC_PriorityGroup_0         ((uint32_t)0x700) /*!< 0 bits for pre-emption priority4 bits for subpriority */
#define NVIC_PriorityGroup_1         ((uint32_t)0x600) /*!< 1 bits for pre-emption priority3 bits for subpriority */
#define NVIC_PriorityGroup_2         ((uint32_t)0x500) /*!< 2 bits for pre-emption priority2 bits for subpriority */
#define NVIC_PriorityGroup_3         ((uint32_t)0x400) /*!< 3 bits for pre-emption priority1 bits for subpriority */
#define NVIC_PriorityGroup_4         ((uint32_t)0x300) /*!< 4 bits for pre-emption priority0 bits for subpriority */

4> 例程:设置EXTI4中断优先级

第1步:
先设置优先级分组模式,一般主程序中设置1次;

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);		// 中断优先级分组

第2步:
设置具体中断的抢占优先级,子优先级;

NVIC_InitTypeDef NVIC_tmp;NVIC_tmp.NVIC_IRQChannel = EXTI4_IRQn;			// 外部中断
NVIC_tmp.NVIC_IRQChannelPreemptionPriority = 0; // 抢占优先级
NVIC_tmp.NVIC_IRQChannelSubPriority = 0;		// 子优先级
NVIC_tmp.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_tmp);

5> 例程:设置SysTick中断优先级

第1步:
先设置优先级分组模式,一般主程序中设置1次;

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);		// 中断优先级分组

第2步:
设置具体中断的抢占优先级,子优先级;

NVIC_SetPriority(SysTick_IRQn, NVIC_EncodePriority(NVIC_PriorityGroup_2, 0, 0));

6> 为什么不能用NVIC_Init()设置Systick优先级?

uint8_t NVIC_IRQChannel; 是无符号的成员变量,而SysTick_IRQn是【-1】,
并且也有注释,NVIC_IRQChannel这个结构体成员用于STM32的外设,
SysTick属于CPU部分,所以要调用NVIC_SetPriority();

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) */// 省略其他成员定义} NVIC_InitTypeDef;

7> 函数NVIC_EncodePriority()

函数功能:

根据优先级分组,抢占优先级,子优先级,生成优先级数字,
给NVIC_SetPriority() 函数用

// core_cm3.h
/*** @brief  Encode the priority for an interrupt*  * @param  PriorityGroup    The used priority group* @param  PreemptPriority  The preemptive priority value (starting from 0)* @param  SubPriority      The sub priority value (starting from 0)* @return                  The encoded priority for the interrupt** Encode the priority for an interrupt with the given priority group,* preemptive priority value and sub priority value.* In case of a conflict between priority grouping and available* priority bits (__NVIC_PRIO_BITS) the samllest possible priority group is set.** The returned priority value can be used for NVIC_SetPriority(...) function* 返回值用于NVIC_SetPriority();*/
static __INLINE uint32_t NVIC_EncodePriority (uint32_t PriorityGroup, uint32_t PreemptPriority, uint32_t SubPriority)
{uint32_t PriorityGroupTmp = (PriorityGroup & 0x07);          /* only values 0..7 are used          */uint32_t PreemptPriorityBits;uint32_t SubPriorityBits;PreemptPriorityBits = ((7 - PriorityGroupTmp) > __NVIC_PRIO_BITS) ? __NVIC_PRIO_BITS : 7 - PriorityGroupTmp;SubPriorityBits     = ((PriorityGroupTmp + __NVIC_PRIO_BITS) < 7) ? 0 : PriorityGroupTmp - 7 + __NVIC_PRIO_BITS;return (((PreemptPriority & ((1 << (PreemptPriorityBits)) - 1)) << SubPriorityBits) |((SubPriority     & ((1 << (SubPriorityBits    )) - 1))));
}