首页 > 其他分享 >06. 系统滴答定时器

06. 系统滴答定时器

时间:2023-09-29 19:22:04浏览次数:29  
标签:定时器 HAL 滴答 us Delay void SysTick 06 uint32

一、SysTick定时器简介

  SysTick,即系统滴答定时器,是属于 CM3 内核中的一个外设,内嵌在 NVIC 中。系统定时器是一个 24bit 的向下递减的计数器,SysTick 的时钟源自 HCLK。当计数值减到 0 时,将从 RELOAD 寄存器中自动重装载定时初值,开始新一轮计数。只要不把它在 SysTick 控制及状态寄存器中的使能位清除,就永不停息。

  因为 SysTick 是属于 CM3 内核的外设,所以所有基于 CM3 内核的单片机都具有这个系统定时器,使得软件在 CM3 单片机中可以很容易的移植。系统定时器一般用于操作系统,用于产生时基,维持操作系统的心跳。

二、SysTick工作原理

Systick工作原理

每次 VAL 减到 0 时,VAL 自动从 LOAD 重载,开始新的一轮递减计数;

三、SysTick寄存器介绍

  SysTick 有4个寄存器。在使用 SysTick 产生定时的时候,只需要配置前三个寄存器,最后一个校准寄存器不需要使用。

3.1、SysTick控制及状态寄存器(CTRL)

SysTick控制及状态寄存器

3.2、SysTick重装载数值寄存器(LOAD)

SysTick重装载数值寄存器

3.3、SysTick当前数值寄存器(VAL)

SysTick当前数值寄存器

3.4、SysTick校准数值寄存器(CALIB)

SysTick校准数值寄存器

四、SysTick定时时间的计算

  SysTick 的时钟源自 HCLK ,它的计数器是向下递减计数的,计数一次的时间 \(T_{DEC}\)=1/HCLK,,假设配置系统时钟为 72MHZ,经过分频器 8 分频后,那么 SysTick 的时钟即为 9Mhz,也就是 SysTick 的计数器 VAL 每减 1,就代表时间过了 1/9us。

  SysTick 延迟初始化函数:

uint16_t g_frequency_us = 0;                                    // us延时倍乘数

void Delay_Init(uint8_t clock)
{
  SysTick->CTRL = 0;                                            // 清Systick状态
  HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK_DIV8);     // Systick使用内核时钟源8分频,因Systick的计数器最大值只有2^24
  g_frequency_us = clock / 8;                                   // 1us作为基础时基
}

  微秒级延迟函数:

void Delay_us(uint32_t us)
{
  uint32_t temp;
  
  SysTick->LOAD = us * g_frequency_us;                          // 延迟时间加载
  SysTick->VAL = 0x00;                                          // 清空计数器
  SysTick->CTRL |= 1<<0;                                        // 开始倒数
  
  do {
    temp = SysTick->CTRL;
  }while ((temp & 0x01) && !(temp & (1<<16)));                  // CTRL.ENABLE位必须为1,并等待时间到达
  
  SysTick->CTRL &= ~(1<<0);                                     // 关闭Systick
  SysTick->VAL = 0x00;                                          // 清空计数器
}

  毫秒级延迟函数:

void Delay_ms(uint32_t ms)
{
  uint32_t repeat = ms / 1000;
  uint32_t remain = ms % 1000;
  
  while (repeat)
  {
    Delay_us(1000 * 1000);                                      // 利用Delay_us()实现1000ms延时
    repeat--;
  }
  
  if (remain)
  {
    Delay_us(remain * 1000);                                    // 利用Delay_us(),实现尾数延迟(remain ms)
  }
}

不考虑超频的情况下,延迟的最大微秒数为 1.86s 左右,超频的情况下,延迟的最大微秒数为 1.04s 左右;

五、HAL库延时函数HAL_Delay

  HAL 库实现延时功能非常简单,首先定义了一个 32 位全局变量 uwTick,在 Systick 中断服务函数 SysTick_Handler 中通过调用 HAL_IncTick 实现 uwTick 值不断增加,也就是每隔 1ms 增加 uwTickFreq,而 uwTickFreq 默认是 1。而 HAL_Delay 函数在进入函数之后先记录当前 uwTick 的值,然后不断在循环中读取 uwTick 当前值,进行减运算,得出的就是延时的毫秒数。

/**
  * @brief This function provides minimum delay (in milliseconds) based
  *        on variable incremented.
  * @note In the default implementation , SysTick timer is the source of time base.
  *       It is used to generate interrupts at regular time intervals where uwTick
  *       is incremented.
  * @note This function is declared as __weak to be overwritten in case of other
  *       implementations in user file.
  * @param Delay specifies the delay time length, in milliseconds.
  * @retval None
  */
__weak void HAL_Delay(uint32_t Delay)
{
  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)
  {
  }
}
/**
  * @brief Provides a tick value in millisecond.
  * @note  This function is declared as __weak to be overwritten in case of other
  *       implementations in user file.
  * @retval tick value
  */
__weak uint32_t HAL_GetTick(void)
{
  return uwTick;
}
/**
  * @brief This function handles System tick timer.
  */
void SysTick_Handler(void)
{
  HAL_IncTick();
}
/**
  * @brief This function is called to increment  a global variable "uwTick"
  *        used as application time base.
  * @note In the default implementation, this variable is incremented each 1ms
  *       in SysTick ISR.
  * @note This function is declared as __weak to be overwritten in case of other
  *      implementations in user file.
  * @retval None
  */
__weak void HAL_IncTick(void)
{
  uwTick += uwTickFreq;
}

  但是,HAL 库的延时函数在中断服务函数中使用 HAL_Delay 会引起混乱(虽然一般禁止在中断中使用延时函数),因为它是通过中断方式实现,而 Systick 的中断优先级是最低的,所以在中断中运行 HAL_Delay 会导致延时出现严重误差。

  HAL 库的 ms 级别的延时函数 __weak void HAL_Delay(uint32_t Delay);它是弱定义函数,所以用户可以自己重新定义该函数。

标签:定时器,HAL,滴答,us,Delay,void,SysTick,06,uint32
From: https://www.cnblogs.com/kurome/p/17737188.html

相关文章

  • 玩一玩“baichuan2”,很强的中文开源模型,2060s即可流畅运行!
    OpenAIChatGPT出来后,热闹了好一阵子!先是一波大厂闭源PK。然后Meta不按套路出牌,直接放出来开源的Llama1-2 后来就百花齐放了。但是外国的模型默认情况下中文支持都不好。另外很多开源模型,最简单的对话都一塌糊涂。今天来玩一个不错的中文开源模型。先来简......
  • Postman06-前置代码块
    pre-requestscript在发送测试请求之前所要执行的代码常用于设置域名、IP,保存多个请求共用的数据等......
  • 力扣刷题笔记-06 N字形变换
    06N字形变换不要混日子,小心日子把你混了对于题目的理解比如说,我给一个字符串,LEETCODE,行数为3,然后按照N字形排列,就是下面这个排列方式。排列完之后正常读取,结果就是LCETOEED。这叫做N字形变换。这个例子里给的行数就是3,往下排三行,然后往右往上走。chatGPT思路边界情况/特......
  • ARC063F Snuke's Coloring 2
    Day\(4!\)。首先容易找到周长为\(2(w+1)\)和\(2(h+1)\)的矩形,所以答案下界是\(2(\max(w,h)+1)\)。考虑按照整个矩形中心坐标,将矩形分成\(4\)个子矩形,观察到若有矩形完全包含于其中一个子矩形,则其周长必不超过\(2\max(w,h)\),必然不是最优解。所以最优解一定被直线\(2x=......
  • P6066 [USACO05JAN] Watchcow S
    prologue这个题这么水的一个板子题。analysis这个题目我们正反建两条边,在跑欧拉回路的时候,看这个边是不是被走过,走过就不走,跳过这个边。如果没走,就走这条边并且标记这个边走过了。codetime#include<bits/stdc++.h>usingnamespacestd;#definelllonglong#definerlr......
  • 506_杂牌手柄游戏不适配?Steam这项功能其实就能解决
    这是一篇原发布于2020-03-2812:37:00得益小站的文章,备份在此处。前言市场上游戏手柄虽多,但PC游戏中做到能够适配的似乎也只有Xbox、PS、SwitchPro等大厂发布的手柄。即使游戏中有着手柄按键设置,但无法完美显示XYAB键、按键命名混乱一直是游戏玩家的硬伤。配置效果对比轶哥测......
  • P1060 [NOIP2006 普及组] 开心的金明
    P1060[NOIP2006普及组]开心的金明简单的01背包问题点击查看代码#include<bits/stdc++.h>usingnamespacestd;intf[30005];intmain(){ intn,m; cin>>n>>m; for(inti=1;i<=m;i++){ intv,p; cin>>v>>p; for(intj=n......
  • Standard E-96 series Resistance Value code (for 0603≤±1% marking)
     ValueCodeValueCodeValueCodeValueCode10001178253164956273102021822632450576741050318727332515907510704191283405260476110051962934853619771130620030357546347811507205313655564979118082103237456......
  • 【原】S27KL0642DPBHV023、S27KL0642DPBHV020、S27KL0642DPBHA020、S27KL0642DPBHI020
    一、概述S27KL0642DPBHV023、S27KL0642DPBHV020、S27KL0642DPBHA020、S27KL0642DPBHI020伪静态随机存储器(PSRAM)HyperRAM™是具备HyperBus™接口的高速CMOS自刷新DRAM。其存储阵列的内部结构类似于DRAM,而外在行为则与SRAM相似。(明佳达供求库存)DRAM阵列需要定期刷新以保持数......
  • MySQL实战实战系列 06 全局锁和表锁 :给表加个字段怎么有这么多阻碍?
    今天我要跟你聊聊MySQL的锁。数据库锁设计的初衷是处理并发问题。作为多用户共享的资源,当出现并发访问的时候,数据库需要合理地控制资源的访问规则。而锁就是用来实现这些访问规则的重要数据结构。 根据加锁的范围,MySQL里面的锁大致可以分成全局锁、表级锁和行锁三类。今天这......