目录
1. 简介
2. SysTick功能框图
3. SysTick寄存器
3.1 SysTick控制及状态寄存器
3.2 SysTick重装载数值寄存器
3.3 SysTick当前数值寄存器
3.4 SysTick校准数值寄存器
4. SysTick定时时间计算
5. SysTick寄存器结构体
6. 写一个us级延时函数
7. 写一个ms级延时函数
8. 完整代码
1. 简介
SysTick—系统定时器是属于 CM3 内核中的一个外设,内嵌在 NVIC 中。系统定时器是一个 24bit的向下递减的计数器,计数器每计数一次的时间为 1/SYSCLK,一般我们设置系统时钟 SYSCLK等于 72M。当重装载数值寄存器的值递减到 0 的时候,系统定时器就产生一次中断,以此循环往复。
因为 SysTick 是属于 CM3 内核的外设,所以所有基于 CM3 内核的单片机都具有这个系统定时器,使得软件在 CM3 单片机中可以很容易的移植。系统定时器一般用于操作系统,用于产生时基,维持操作系统的心跳。
2. SysTick功能框图
counter在时钟的驱动下,从reload初值开始往下递减计数到0,产生中断和置位COUNTFLAG标志。然后又从reload值考试重新递减计数,如此循环。
3. SysTick寄存器
3.1 SysTick控制及状态寄存器
位段 | 名称 | 类型 | 复位值 | 描述 |
16 | COUNTFLAG | R/W | 0 | 如果在上次读取本寄存器后, SysTick已经计到了 0,则该位为 1 |
2 | CLKSOURCE | R/W | 0 | 时钟源选择位, 0=AHB/8, 1=处理器时钟AHB |
1 | TICKINT | R/W | 0 | 1=SysTick倒数计数到0时产生SysTick异常请求,0=数到0时无动作。也可以通过读取COUNTFLAG标志位来确定计数器是否递减到0 |
0 | ENABLE | R/W | 0 | SysTick 定时器的使能位 |
3.2 SysTick重装载数值寄存器
位段 | 名称 | 类型 | 复位值 | 描述 |
23:0 | RELOAD | R/W | 0 | 当倒数计数至零时,将被重装载的值 |
3.3 SysTick当前数值寄存器
位段 | 名称 | 类型 | 复位值 | 描述 |
23:0 | CURRENT | R/W | 0 | 读取时返回当前倒计数的值,写它则使之清 |
3.4 SysTick校准数值寄存器
位段 | 名称 | 类型 | 复位值 | 描述 |
31 | NOREF | R | 0 | 1=没有外部参考时钟(STCLK 不可用),0=外部参考时钟可用 |
30 | SKEW | R | 1 | 1=没有外部参考时钟(STCLK 不可用),0=校准值是准确的10ms |
23:0 | TENMS | R | 0 | 10ms 的时间内倒计数的格数。芯片设计者应该通过 Cortex-M3 的输入信号提供该数值。若该值读回零,则表示无法使用校准功能 |
4. SysTick定时时间计算
(1)t:一个计数循环的时间,跟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
5. SysTick寄存器结构体
在固件库文件:core_cm3.h中定义:
typedef struct
{
__IO uint32_t CTRL; /*!< Offset: 0x00 SysTick Control and Status Register 控制及状态寄存器*/
__IO uint32_t LOAD; /*!< Offset: 0x04 SysTick Reload Value Register 重装载数值寄存器 */
__IO uint32_t VAL; /*!< Offset: 0x08 SysTick Current Value Register 当前数值寄存器 */
__I uint32_t CALIB; /*!< Offset: 0x0C SysTick Calibration Register 校准寄存器 */
} SysTick_Type;
#if 0
// 这个 固件库函数 在 core_cm3.h中
static __INLINE uint32_t SysTick_Config(uint32_t ticks)
{
// reload 寄存器为24bit,最大值为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);
// 配置 counter 计数器的值
SysTick->VAL = 0;
// 配置systick 的时钟为 72M
// 使能中断
// 使能systick
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |
SysTick_CTRL_TICKINT_Msk |
SysTick_CTRL_ENABLE_Msk;
return (0);
}
#endif
6. 写一个us级延时函数
// couter 减1的时间 等于 1/systick_clk
// 当counter 从 reload 的值减小到0的时候,为一个循环,如果开启了中断则执行中断服务程序,
// 同时 CTRL 的 countflag 位会置1
// 这一个循环的时间为 reload * (1/systick_clk)
void SysTick_Delay_Us( __IO uint32_t us)
{
uint32_t i;
SysTick_Config(SystemCoreClock/1000000);
for(i=0;i<us;i++)
{
// 当计数器的值减小到0的时候,CRTL寄存器的位16会置1
while( !((SysTick->CTRL)&(1<<16)) );
}
// 关闭SysTick定时器
SysTick->CTRL &=~SysTick_CTRL_ENABLE_Msk;
}
7. 写一个ms级延时函数
void SysTick_Delay_Ms( __IO uint32_t ms)
{
uint32_t i;
SysTick_Config(SystemCoreClock/1000);
for(i=0;i<ms;i++)
{
// 当计数器的值减小到0的时候,CRTL寄存器的位16会置1
// 当置1时,读取该位会清0
while( !((SysTick->CTRL)&(1<<16)) );
}
// 关闭SysTick定时器
SysTick->CTRL &=~ SysTick_CTRL_ENABLE_Msk;
}
8. 完整代码
#include "bsp_SysTick.h"
#include "core_cm3.h"
#include "misc.h"
static __IO u32 TimingDelay;
/**
* @brief 启动系统滴答定时器 SysTick
* @param 无
* @retval 无
*/
void SysTick_Init(void)
{
/* SystemFrequency / 1000 1ms中断一次
* SystemFrequency / 100000 10us中断一次
* SystemFrequency / 1000000 1us中断一次
*/
// if (SysTick_Config(SystemFrequency / 100000)) // ST3.0.0库版本
if (SysTick_Config(SystemCoreClock / 100000)) // ST3.5.0库版本
{
/* Capture error */
while (1);
}
}
/**
* @brief us延时程序,10us为一个单位
* @param
* @arg nTime: Delay_us( 1 ) 则实现的延时为 1 * 10us = 10us
* @retval 无
*/
void Delay_us(__IO u32 nTime)
{
TimingDelay = nTime;
// 使能滴答定时器
SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;
while(TimingDelay != 0);
}
/**
* @brief 获取节拍程序
* @param 无
* @retval 无
* @attention 在 SysTick 中断函数 SysTick_Handler()调用
*/
void TimingDelay_Decrement(void)
{
if (TimingDelay != 0x00)
{
TimingDelay--;
}
}
#if 0
// 这个 固件库函数 在 core_cm3.h中
static __INLINE uint32_t SysTick_Config(uint32_t ticks)
{
// reload 寄存器为24bit,最大值为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);
// 配置 counter 计数器的值
SysTick->VAL = 0;
// 配置systick 的时钟为 72M
// 使能中断
// 使能systick
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |
SysTick_CTRL_TICKINT_Msk |
SysTick_CTRL_ENABLE_Msk;
return (0);
}
#endif
// couter 减1的时间 等于 1/systick_clk
// 当counter 从 reload 的值减小到0的时候,为一个循环,如果开启了中断则执行中断服务程序,
// 同时 CTRL 的 countflag 位会置1
// 这一个循环的时间为 reload * (1/systick_clk)
void SysTick_Delay_Us( __IO uint32_t us)
{
uint32_t i;
SysTick_Config(SystemCoreClock/1000000);
for(i=0;i<us;i++)
{
// 当计数器的值减小到0的时候,CRTL寄存器的位16会置1
while( !((SysTick->CTRL)&(1<<16)) );
}
// 关闭SysTick定时器
SysTick->CTRL &=~SysTick_CTRL_ENABLE_Msk;
}
void SysTick_Delay_Ms( __IO uint32_t ms)
{
uint32_t i;
SysTick_Config(SystemCoreClock/1000);
for(i=0;i<ms;i++)
{
// 当计数器的值减小到0的时候,CRTL寄存器的位16会置1
// 当置1时,读取该位会清0
while( !((SysTick->CTRL)&(1<<16)) );
}
// 关闭SysTick定时器
SysTick->CTRL &=~ SysTick_CTRL_ENABLE_Msk;
}
/*********************************************END OF FILE**********************/
#ifndef __SYSTICK_H
#define __SYSTICK_H
#include "stm32f10x.h"
void SysTick_Init(void);
void Delay_us(__IO u32 nTime);
#define Delay_ms(x) Delay_us(100*x) //单位ms
void SysTick_Delay_Us( __IO uint32_t us);
void SysTick_Delay_Ms( __IO uint32_t ms);
#endif /* __SYSTICK_H */
STM32学习笔记_时光の尘的博客-CSDN博客