SysTick寄存器介绍
SysTick—系统定时器有4个寄存器,简要介绍如下。在使用SysTick产生定时的时候,只需要配置前三个寄存器,最后一个校准寄存器不需要使用。
寄存器名称 | 寄存器描述 |
CTRL | SysTick控制及状态寄存器 |
LOAD | SysTick重装载数值寄存器 |
VAL | SysTick当前数值寄存器 |
CALIB | SysTick校准数值寄存器 |
位段 | 名称 | 类型 | 复位值 | 描述 |
16 | COUNTFLAG | R/W | 0 | 如果在上次读取本寄存器后, SysTick 已经计到 了 0,则该位为 1。如果读取改位,该位将自动清零 |
2 | CLKSOURCE | R/W | 0 | 时钟源选择位;0=外部时钟源(STCLK) 8分频;1=内核时钟(FCLK) 1分频 |
1 | TICKINT | R/W | 0 | 1=SysTick 倒数计数到 0 时产生 SysTick异常请 求 0=数到 0 时无动作。也可以通过读取COUNTFLAG标志位来确定计数器是否递减到0 |
0 | ENABLE | R/W | 0 | SysTick 定时器的使能位 |
位段 | 名称 | 类型 | 复位值 | 描述 |
23:0 | RELOAD | R/W | 0 | 当倒数计数至零时,将被重装载的值 |
位段 | 名称 | 类型 | 复位值 | 描述 |
23:0 | CURRENT | R/W | 0 | 读取时返回当前倒计数的值,写它则使之清零,同时还会清除在SysTick控制及状态寄存器中的COUNTFLAG 标志 |
位段 | 名称 | 类型 | 复位值 | 描述 |
31 | NOREF | R | 0 | NOREF flag. Reads as zero. Indicates that a separate reference clock is provided. The frequency of this clock is HCLK/8 |
30 | SKEW | R | 1 | Reads 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:0 | TENMS | R | 0 | Indicates 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. |
初始化延迟函数
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)
{ }
}
Comments NOTHING