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

06. 系统滴答定时器

时间:2023-07-25 20:13:52浏览次数:39  
标签:定时器 HAL 滴答 us Delay void SysTick 06 uint32

一、SysTick定时器简介

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

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

二、SysTick工作原理

img

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

三、SysTick寄存器介绍

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

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

img

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

img

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

img

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

img

四、SysTick定时时间的计算

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

  SysTick 延迟初始化函数:

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

/*******************************************************************************
 * @brief       : 延迟初始化函数
 * @param       : clock: 系统时钟频率,单位为MHz
 * @return      : None
 * @author      : Sakura
 * @date        : 2023/7/11
 *******************************************************************************
 * @description : None
 ******************************************************************************/
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作为基础时基
}

  微秒级延迟函数:

/*******************************************************************************
 * @brief       : 微秒级延迟函数
 * @param       : us: 要延迟的微秒数
 * @return      : None
 * @author      : Sakura
 * @date        : 2023/7/11
 *******************************************************************************
 * @description : 系统时钟频率为72MHz时,最大延迟时间为1.86s
                  系统时钟频率超频为128MHz时,最大延迟时间为1.04s
 ******************************************************************************/
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;                                                          // 清空计数器
}

  毫秒级延迟函数:

/*******************************************************************************
 * @brief       : 毫秒级延迟函数
 * @param       : ms: 要延迟的毫秒数
 * @return      : None
 * @author      : Sakura
 * @date        : 2023/7/11
 *******************************************************************************
 * @description : None
 ******************************************************************************/
void Delay_ms(uint32_t ms)
{
  uint32_t repeat = ms / 1000;                                                  // 考虑到超频情况,delay_us()最大延迟时间为1.04s
  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)
  }
}

五、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)
{
  /* USER CODE BEGIN SysTick_IRQn 0 */

  /* USER CODE END SysTick_IRQn 0 */
  HAL_IncTick();
  /* USER CODE BEGIN SysTick_IRQn 1 */

  /* USER CODE END SysTick_IRQn 1 */
}
/**
  * @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/17580883.html

相关文章

  • 左神算法-基础06-前缀树&贪心算法
    左神算法-基础06-前缀树&贪心算法介绍前缀树何为前缀树?如何生成前缀树?例子:一个字符串类型的数组arr1,另一个字符串类型的数组arr2。arr2中有哪些字符,是arr1中出现的?请打印。arr2中有哪些字符,是作为arr1中某个字符串前缀出现的?请打印。arr2中有哪些字符,是作为arr1中某个......
  • LeetCode 406. 根据身高重建队列
    classSolution{public:structnode{intval;intpre;node*next;node(inta,intb,node*c){val=a;pre=b;next=c;}};voidinsert(node*&head,int......
  • oracle数据库临时表空间损坏,报错ORA-01116,ORA-01110 ,ORA-27041,ORA-06512的解决方式
     打脚本的时候报错:ORA-01116:打开数据库文件203时出错ORA-01110:数据文件203:'/u01/app/oracle/oradata/temp02.dbf'ORA-27041:无法打开文件Linux-x86_64Error:2:NosuchfileordirectoryAdditionalinformation:3ORA-06512:在line9  是我们环境的临时表空间......
  • 2023-06 服务器行业产品趋势
    06-07赛迪顾问《2022-2023年中国服务器市场研究年度报告》发布,数据显示,宝德品牌在中国ARM架构服务器市场销售规模排名第一位 06-22英特尔(Intel)官方宣布,美国能源部阿拉贡国家实验室已经完成基于英特尔CPU及GPU的新一代超算“Aurora”的安装工作,今年晚些时候上线后将提供超过2e......
  • 左神算法-基础06-图
    左神算法-基础06-图图的存储方式邻接表邻接矩阵如何表达图?生成图?//图的节点publicclassNode{publicintvalue;//入度publicintin;//出度publicintout;publicArrayList<Node>nexts;publicArrayList<Edge>edges;......
  • list agg cause ORA-06502 PL/SQL: numeric or value error
    http://www.idb-stock.net/idb/2011/07/05/204.htmlora-06502错误主要是指数据字或值错误,包括以下子类型:字符到数据值的转换错误、字符串缓冲区太小、数值精度太高等。对空集合的调用,会报ora-06502错误declaretypecnt_typistableofnumberindexbybinary_integer;v_c......
  • CF506E Mr. Kitayuta's Gift 思考--zhengjun
    妙妙题。首先可以有一个\(O(kn^2)\)的dp,但是显然不行。但是,发现其中的大多数转移都浪费在自环上了,所以考虑不要这个东西。这个dp一共有三种转移:左右端点一起向内移动一格;左端点或右端点单独移动;左右端点都不动。所以考虑加一维\(k\)表示走了\(k\)次转移1......
  • ORA-10635:无效的段或表空间类型
    错误信息【汉】ORA-10635:无效的段或表空间类型【英】ORA-10635:Invalidsegmentortablespacetype例在正常运行的Oracle数据库中,执行收缩段(表)报错。版本Oracle【11.2.0.3.0】、【11.2.0.1.0】、【11.2.0.4.0】原因无法收缩段,因为Oracle在收缩前检测到,段(表)不在自动段空间管理......
  • centos7 安装 minio RELEASE.2021-06-17
    1、下载执行包wgethttps://dl.min.io/server/minio/release/linux-amd64/archive/minio.RELEASE.2021-06-17T00-10-46Z2、创建数据、日志文件夹mkdir-p/data/project/minio/data/mkdir-p/data/project/minio/log/touch/data/project/minio/log/minio.log3、授......
  • android 不让系统休眠后会禁用我们的定时器
    Android不让系统休眠对定时器的影响在Android开发中,我们经常使用定时器来执行一些重复性的任务或者进行定时操作。然而,当设备进入休眠状态时,系统会尝试最大限度地节省电量,这就可能导致我们的定时器无法按预期工作。本文将探讨Android系统不允许休眠对定时器的影响,并提供一些解决方......