目录
系统定时器Systick:属于Cortex-M内核的外设,嵌套在NVIC中。24位,只能递减,计数器每计数一次的时间为1/SYSCLK,减到0时产生systick中断,以此循环往复。
系统定时器一般用于操作系统,用于产生时基,维持操作系统的心跳。
主要头文件:core_cm4.h。
Systick是24位的,重装载寄存器也为24位,递减计数器也是24位,所以它们最大可为2的24次方。
counter(当前值)在时钟的驱动下,从reload(初值)开始往下递减计数到0,产生中断和COUNTFLAG标志置1。然后又从reload值开始重新递减计数,如此循环。
对于Systick控制及状态寄存器,即STK_CTRL。
位段 | 名称 | 类型 | 复位值 | 描述 |
16 | COUNTFLAG | R | 0 | 如果在上次读取本寄存器后, SysTick 已经计到了 0,则该位为 1。如果读取该位,该位将自动清零 |
2 | CLKSOURCE | R/W | 0 | 0=外部时钟源(STCLK) 1=内核时钟(FCLK) |
1 | TICKINT | R/W | 0 | 1=SysTick倒数计数到0时产生SysTick异常请求 0=数到 0 时无动作 |
0 | ENABLE | R/W | 0 | SysTick 定时器的使能位 |
对于Systick重装载数值寄存器,即STK_LOAD。
位段 | 名称 | 类型 | 复位值 | 描述 |
23:0 | RELOAD | R/W | 0 | 当递减计数至0时,将被重装载的值 |
对于Systick当前数值寄存器,即STK_VAL。
位段 | 名称 | 类型 | 复位值 | 描述 |
23:0 | CURRENT | R/W | 0 | 读取时返回当前倒计数值,写它则使之清零 |
Systick定时时间计算
1)一个计数循环的时间,跟reload和CLK有关。
2)CLK:72M或9M,有CTRL寄存器配置。
3)RELOAD:24位,用户自己配置。
t=reload*(1/clk)
clk=72M时,t=(72)*(1/72M)=1us
clk=72M时,t=(72000)*(1/72M)=1ms
根据固件库文件core_cm3.h查看Systick结构体
typedef struct
{
__IO uint32_t CTRL; //偏移: 0x00 SysTick控制及状态寄存器
__IO uint32_t LOAD; //偏移: 0x04 SysTick重装载寄存器
__IO uint32_t VAL; //偏移: 0x08 SysTick当前数值寄存器
__I uint32_t CALIB; //偏移: 0x0C SysTick校准寄存器
} SysTick_Type;
根据固件库文件core_cm3.h查看Systick配置
/* SysTick Reload Register Definitions */
#define SysTick_LOAD_RELOAD_Pos 0 //位置
#define SysTick_LOAD_RELOAD_Msk (0xFFFFFFul << SysTick_LOAD_RELOAD_Pos) //置1
static __INLINE void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority)
{
if(IRQn < 0) { //系统内核
SCB->SHP[((uint32_t) (IRQn) & 0xF)-4] = ((priority << (8 - __NVIC_PRIO_BITS)) & 0xff); }
else { //系统外设
NVIC->IP[(uint32_t)(IRQn)] = ((priority << (8 - __NVIC_PRIO_BITS)) & 0xff); }
}
static __INLINE uint32_t SysTick_Config(uint32_t ticks)
{
//判断tick的值是否大于2^24,如果大于,则不符合规则
if (ticks > SysTick_LOAD_RELOAD_Msk) return (1);
//初始化reload寄存器的值
SysTick->LOAD = (ticks & SysTick_LOAD_RELOAD_Msk) - 1;
//配置中断优先级,配置为1<<4-1=15,默认为最低的优先级
NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1);
//配置count计数器的值
SysTick->VAL = 0;
//配置Systick的时钟为72M
//使能中断
//使能Systick
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |
SysTick_CTRL_TICKINT_Msk |
SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */
return (0); /* Function successful */
}
STM32里面无论是内核还是外设都是使用4个二进制位来表示中断优先级。
中断优先级的分组对内核和外设同样适用。当比较的时候,只需要把内核的中断优先级的四个位按照外设的中断优先级来分组解析即可,即人为的分出抢占优先级和子优先级。
书写一个微秒的延时函数(基于systick)
/**
* @bieaf 微秒延时函数
* @detail 注意:由于指令执行需要时间, 实际的延时精度约为1微秒
*
* @param unsigned int Delay 延时的微秒
*/
void delay_us(unsigned int Delay)
{
uint32_t tickstart = SysTick->VAL; ///<获取当前tick
uint32_t tickNum = 0;
uint32_t tickMax = SysTick->LOAD + 1;
uint32_t delay_usvalue = (tickMax / 1000) * Delay; ///<计算一共需要延时的tick
while(1)
{
uint32_t cur_tick = SysTick->VAL;
if (cur_tick > tickstart) ///<进行了一次重载
{
tickNum = tickstart + (tickMax - cur_tick);
}
else ///<未进行过重载
{
tickNum = tickstart - cur_tick;
}
if (tickNum > delay_usvalue) ///<达到延时的tick数
{
return;
}
}
}