SysTick定时器和NVIC中断优先级管理
Systick定时器简介
Systick定时器,是一个简单的定时器,对于ST的CM3,CM4,CM7内核芯片,都有Systick定时
Systick定时器常用来做延时,或者实时系统的心跳时钟。这样可以节省MCU资源,不用浪费一个定时器。比如UCOS中,分时复用,需要一个最小的时间戳,一般在STM32+UCOS系统中,都采用Systick做UCOS心跳时钟。
Systick定时器就是系统滴答定时器,一个24 位的倒计数定时器,计到0 时,将从RELOAD 寄存器中自动重装载定时初值。只要不把它在SysTick 控制及状态寄存器中的使能位清除,就永不停息,即使在睡眠模式下也能工作。
SysTick定时器被捆绑在NVIC中,用于产生SYSTICK异常(异常号:15)。Systick中断的优先级也可以设置。
4个Systick寄存器
CTRL SysTick 控制和状态寄存器
LOAD SysTick 自动重装载除值寄存器
VAL SysTick 当前值寄存器
CALIB SysTick 校准值寄存器
四个寄存器的定义函数
1 | typedef struct |
SysTick库函数
Systick时钟源有两种选择选择:SYSTICK_CLKSOURCE_HCLK和SYSTICK_CLKSOURCE_HCLK_DIV8
1 |
|
初始化systick,时钟为HCLK,并开启中断
1 | __STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks) //systick定时器经过多少个ticks周期发生中断 |
不带OS的系统延时
systick的频率为HCLK,fac_us=SYSCLK,
systick运行1us,要跑fac_us(SYSCLK)个节拍。
1 | static u32 fac_us=0; //us延时倍乘数 |
NVIC中断优先级管理
CM4/CM7 内核支持256个中断,其中包含了16个内核中断和240个外部中断,并且具有256级的可编程中断设置。STM32F42xx/STM32F43xx则总共有97个中断。10个内核中断,87个可屏蔽中断。
STM32具有16级可编程的中断优先级,而我们常用的就是这些可屏蔽中断。
《STM32F中文参考手册》中搜索向量表可以找到相应的中断说明。
中断管理方法
首先,对STM32中断进行分组,组0~4。同时,对每个中断设置一个抢占优先级和一个响应优先级值。分组配置是在寄存器SCB->AIRCR中配置:
组 | AIRCR[10:8] | IP bit[7:4]分配情况 | 分配结果 |
---|---|---|---|
0 | 111 | 0:4 | 0位抢占优先级,4位响应优先级 |
1 | 110 | 1:3 | 1位抢占优先级,3位响应优先级 |
2 | 101 | 2:2 | 2位抢占优先级,2位响应优先级 |
3 | 100 | 3:1 | 3位抢占优先级,1位响应优先级 |
4 | 011 | 4:0 | 4位抢占优先级,0位响应优先级 |
抢占优先级 & 响应优先级区别:
高优先级的抢占优先级是可以打断正在进行的低抢占优先级中断的。
抢占优先级相同的中断,高响应优先级不可以打断低响应优先级的中断。
抢占优先级相同的中断,当两个中断同时发生的情况下,哪个响应优先级高,哪个先执行。
如果两个中断的抢占优先级和响应优先级都是一样的话,则看哪个中断先发生就先执行;
举例
假定设置中断优先级组为2,然后设置
中断3(RTC中断)的抢占优先级为2,响应优先级为1。
中断6(外部中断0)的抢占优先级为3,响应优先级为0
中断7(外部中断1)的抢占优先级为2,响应优先级为0。
那么这3个中断的优先级顺序为:中断7>中断3>中断6。
中断优先级分组函数
1 | void HAL_NVIC_SetPriorityGrouping(uint32_t PriorityGroup) |
IO引脚复用和映射管理与配置
STM32F4 系列微控制器 IO 引脚通过一个复用器连接到内置外设或模块。该复用器一次只允 许一个外设的复用功能(AF)连接到对应的 IO 口。
这样可以确保共用同一个 IO 引脚的外设之 间不会发生冲突。 每个 IO 引脚都有一个复用器,该复用器采用 16 路复用功能输入(AF0 到 AF15),可通过 GPIOx_AFRL(针对引脚 0-7)和 GPIOx_AFRH(针对引脚 8-15)寄存器对这些输入进行配置,每四位控制一路复用:
端口复用映射示意图
AFRL复用功能低位寄存器
AFRH复用功能高位寄存器
复用功能映射配置
)
端口复用为复用功能配置过程
-以PA9,PA10配置为串口1为例
① 首先,我们要使用 IO 复用功能,必须先打开对应的 IO 时钟和复用功能外设时钟,这里 我们使用了 GPIOA 以及 USART1,所以我们需要使能 GPIOA 和 USART1 时钟。方法如下:
1 | __HAL_RCC_GPIOA_CLK_ENABLE(); //使能 GPIOA 时钟 |
② 其次,我们在 GIPOx_MODER 寄存器中将所需 IO(对于串口 1 是 PA9,PA10)配置为复用 功能(ADC 和 DAC 设置为模拟通道)。
④ 最后,我们需要配置 GPIOx_AFRL 或者 GPIOx_AFRH 寄存器,将 IO 连接到所需的 AFx。 对于 PA9,PA10 复用为 USART1 的发送接收引脚,可知都需要连接 AF7。 上面三步,在我们 HAL 库中是通过 HAL_GPIO_Init 函数来实现的,参考代码如下:
1 | __HAL_RCC_GPIOA_CLK_ENABLE(); //使能GPIOA时钟 |
对于 GPIO 初始化结构体成员变量 Alternate 的取值范围,在 HAL 库中有详细定义,取值范围如下
1 |
|