SysTick系统定时器(二)

发布于 2022-12-11  92 次阅读


SysTick寄存器介绍

SysTick—系统定时器有4个寄存器,简要介绍如下。在使用SysTick产生定时的时候,只需要配置前三个寄存器,最后一个校准寄存器不需要使用。

SysTick系统定时器(二)插图
寄存器名称寄存器描述
CTRLSysTick控制及状态寄存器
LOADSysTick重装载数值寄存器
VALSysTick当前数值寄存器
CALIBSysTick校准数值寄存器
 SysTick寄存器汇总
位段名称类型复位值描述
16COUNTFLAGR/W0如果在上次读取本寄存器后, SysTick 已经计到 了 0,则该位为 1。如果读取改位,该位将自动清零
2CLKSOURCER/W0时钟源选择位;0=外部时钟源(STCLK) 8分频;1=内核时钟(FCLK) 1分频
1TICKINTR/W01=SysTick 倒数计数到 0 时产生 SysTick异常请 求
0=数到 0 时无动作。也可以通过读取COUNTFLAG标志位来确定计数器是否递减到0
0ENABLER/W0SysTick 定时器的使能位
 SysTick控制及状态寄存器
位段名称类型复位值描述
23:0RELOADR/W0当倒数计数至零时,将被重装载的值
SysTick 重装载数值寄存器
位段名称类型复位值描述
23:0CURRENTR/W0读取时返回当前倒计数的值,写它则使之清零,同时还会清除在SysTick控制及状态寄存器中的COUNTFLAG 标志
SysTick当前数值寄存器
位段名称类型复位值描述
31NOREFR0NOREF flag. Reads as zero. Indicates that a separate reference clock is provided. The frequency of this clock is HCLK/8
30SKEWR1Reads as one. Calibration value for the 1 ms inexact timing is not known because TENMS is not known. This can affect the suitability of SysTick as a software real time clock
23:0TENMSR0Indicates the calibration value when the SysTick counter runs on HCLK max/8 as external clock. The value is product dependent, please refer to the Product Reference Manual, SysTick Calibration Value section. When HCLK is programmed at the maximum frequency, the SysTick period is 1ms. If calibration information is not known, calculate the calibration value required from the frequency of the processor clock or external clock.
SysTick校准数值寄存器

初始化延迟函数

void delay_init(uint16_t sysclk)
{
SysTick->CTRL = 0; /*清 Systick 状态,以便下一步重设,如果这里开了中断会关闭其中断*/
/* SYSTICK 使用内核时钟源 8 分频,因 systick 的计数器最大值只有 2^24 */
HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK_DIV8);
g_fac_us = sysclk / 8; /*g_fac_us 为全局变量作为 1us 的基础时基 
因为72Mhz/8 = 9;则一次计数需要1/9000000s,所以需要循环9次 1*9/9000000hz = 1/1000000hz = 1us;
*/
}

延时1us

SysTick 是 MDK 定义了的一个结构体(在 core_m3.h 里面),里面包含 CTRL、 LOAD、VAL、 CALIB 等 4 个寄存器,各位定义如上4张表所示

/**
* @brief 延时 nus
* @param nus: 要延时的 us 数.
* @note 注意: nus 的值,不要大于 1864135us(最大值即 2^24/g_fac_us @g_fac_us = 9)
* @retval 无
*/
void delay_us(uint32_t nus)
{
uint32_t temp;
SysTick->LOAD = nus * g_fac_us; /* 时间加载 */
SysTick->VAL = 0x00; /* 清空计数器 */
SysTick->CTRL |= 1 << 0 ; /* 开始倒数 */
do
{
temp = SysTick->CTRL;
} while ((temp & 0x01) && !(temp & (1 << 16)));
/* CTRL.ENABLE 位必须为 1, 并等待时间到达,CTRL第16位为1则跳出循环 */
SysTick->CTRL &= ~(1 << 0) ; /* 关闭 SYSTICK */
SysTick->VAL = 0X00; /* 清空计数器 */
}

延时1ms

/**
* @brief 延时 nms
* @param nms: 要延时的 ms 数 (0< nms <= 65535)
* @retval 无
*/
void delay_ms(uint16_t nms)
{
/*这里用 1000,是考虑到可能有超频应用,如 128Mhz 时,delay_us 最大只能延时 1048576us 左右*/
uint32_t repeat = nms / 1000;
uint32_t remain = nms % 1000;
while (repeat)
{
delay_us(1000 * 1000); /* 利用 delay_us 实现 1000ms 延时 */
repeat--;
}
if (remain)
{
delay_us(remain * 1000); /* 利用 delay_us, 把尾数延时(remain ms)给做了 */
}
}

该函数其实就是多次调用 delay_us 函数,来实现毫秒级延时的。做一些处理,使得调用 delay_us 函数的次数减少,这样时间会更加精准

HAL 库延时函数 HAL_Delay

HAL 库提供的延时函数,只能实现简单的毫秒级别延时,没有实现 us 级别延时。
我们看看 HAL 库的 HAL_Delay 函数原定义:

__weak void HAL_Delay(uint32_t Delay) /* HAL 库的延时函数,默认延时单位 ms */
{
uint32_t tickstart = HAL_GetTick();
uint32_t wait = Delay;
/* Add a freq to guarantee minimum wait */
if (wait < HAL_MAX_DELAY)
{
wait += (uint32_t)(uwTickFreq);
}
while ((HAL_GetTick() - tickstart) < wait)
{ }
}

点击统计


白日梦想家