1、简介
Cortex‐M3 处理器内部包含了一个简单的定时器。因为所有的 CM3 芯片都带有这个定时器,软件在不同 CM3 器件间的移植工作得以化简。该定时器的时钟源可以是内部时钟,或者是外部时钟。不过,STCLK
的具体来源则由芯片设计者决定,因此不同产品之间的时钟频率可能会大不相同,你需要查找芯片的器件手册来决定选择什么作为时钟源。
Cortex-M3 的内核中包含一个 SysTick 时钟。SysTick 为一个 24 位递减计数器,SysTick 设定初值并使能后,每经过 1 个系统时钟周期,计数值就减 1。计数到 0 时,SysTick 计数器自动重装初值并继续计数,同时内部的 COUNTFLAG
标志会置位,触发中断 (如果中断使能情况下)。
2、SysTick 包含的寄存器
STM32 中的 Systick 部分内容属于 NVIC 控制部分,一共有 4 个寄存器,名称和地址分别是:
STK_CSR 0xE000E010 -- 控制寄存器
STK_LOAD 0xE000E014 -- 重载寄存器
STK_VAL 0xE000E018 -- 当前值寄存器
STK_CALRB 0xE000E01C -- 校准值寄存器
STK_CSR
控制寄存器:寄存器内有 4 个位具有意义
第 0 位:ENABLE,Systick 使能位(0:关闭 Systick 功能;1:开启 Systick 功能)
第 1 位:TICKINT,Systick 中断使能位(0:关闭 Systick 中断;1:开启 Systick 中断)
第 2 位:CLKSOURCE,Systick 时钟源选择(0:使用 HCLK/8 作为 Systick 时钟;1:使用 HCLK 作为 Systick 时钟)
第 16 位:COUNTFLAG,Systick 计数比较标志,如果在上次读取本寄存器后,SysTick 已经数到了0,则该位为1。如果读取该位,该位将自动清零。
STK_LOAD
重载寄存器:
Systick
是一个递减的定时器,当定时器递减至0 时,重载寄存器中的值就会被重装载,继续开始递减。STK_LOAD
重载寄存器是个24 位的寄存器最大计数0xFFFFFF。STK_VAL
当前值寄存器:
也是个24 位的寄存器,读取时返回当前倒计数的值,写它则使之清零,同
时还会清除在 SysTick 控制及状态寄存器中的COUNTFLAG
标志。STK_CALRB
校准值寄存器:
位31 NOREF:= 1
没有外部参考时钟(STCLK
不可用),= 0
外部参考时钟可用
位30 SKEW:= 1 校准值不是准确的1ms
,= 0校准值是准确的1ms
3、代码:
那基于 STM32F10x V3.5.0
库如何操作 Systick
定时器呢?
STM32 的内核库已经提供了这个功能,只要配置 SysTick_Config()
即可实现。SysTick_Config
的参数,其实就是一个时钟次数,叫 systick
重装寄存器的值。意思就是我要多少个1/fosc
时间后中断一下。
#include "bsp_cpu.h"
static void BSP_CoreClockInit(void);
void BSP_CPUInit(void)
{
BSP_CoreClockInit();
}
static void BSP_CoreClockInit(void)
{
SysTick_Config(SystemCoreClock / 100); //10ms
//SysTick_Config(720000); //10ms
}
void SysTick_Handler(void)
{
static uint8_t i=0;
i++;
if(i > 50)
{
i = 0;
BSP_LedTurn();
}
}
SystemCoreClock / 100
代表的是时钟次数,即放入重装载寄存器中的值,每计时一个数需要 1/72000000s 的时间,那么计SystemCoreClock / 100
(SystemCoreClock 为 72M)个数的时间就是 10ms,通过在中断中设置标志位达到 systick 定时中断的功能。
void delay_us(u32 nus)
{
u32 temp;
SysTick->LOAD = 9*nus;
SysTick->VAL=0X00;//清空计数器
SysTick->CTRL=0X01;//使能,减到零是无动作,采用外部时钟源
do
{
temp=SysTick->CTRL;//读取当前倒计数值
}while((temp&0x01)&&(!(temp&(1<<16))));//等待时间到达
SysTick->CTRL=0x00; //关闭计数器
SysTick->VAL =0X00; //清空计数器
}
void delay_ms(u16 nms)
{
u32 temp;
SysTick->LOAD = 9000*nms;
SysTick->VAL=0X00;//清空计数器
SysTick->CTRL=0X01;//使能,减到零是无动作,采用外部时钟源
do
{
temp=SysTick->CTRL;//读取当前倒计数值
}while((temp&0x01)&&(!(temp&(1<<16))));//等待时间到达
SysTick->CTRL=0x00; //关闭计数器
SysTick->VAL =0X00; //清空计数器
}
分析:delay_us
中 9*nus
的意义
假设外设频率为 9M,也就是经过 8 分频,那么计数 9 次是 1us,乘以 9 的意义就是参数的时间对应的次数,也就是重装载值,delay_ms
同理。