STM32-笔记10-手写延时函数(SysTick)

1、什么是SysTick

        Systick,即滴答定时器,是内核中的一个特殊定时器,用于提供系统级的定时服务。该定时器是一个24位的倒计数定时器‌。它从设定的初值(即重载值)开始计数,每经过一个系统时钟周期,计数值就减1,直到计数到0时,SysTick计数器会自动从RELOAD寄存器中重装初值并继续计数‌ 1  。如果中断使能,当计数到0时,还会触发中断‌ 1  。
        Systick定时器的主要功能包括实现简单的延时、生成定时中断以及进行精确定时和周期定时操作。此外,Systick定时器还可以被用于其他目的,例如作为操作系统的时基(如FreeRTOS),或者用于软件看门狗等系统调度操作。在STM32中,Systick通常以HCLK(AHB时钟)或HCLK/8作为运行时钟。

2、SysTick工作原理

        在使用Systick定时器进行延时操作时,可以设定初值并使能后,每经过一个系统时钟周期,计数值就减1。 当计数到0时,Systick计数器自动重装初值并继续计数,同时内部的COUNTFLAG标志会置位,触发中断 (如果中断使能)。这样,可以在中断处理函数中实现特定的延时逻辑。

3、SysTick寄存器介绍

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

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

SysTick当前数值寄存器(VAL)

 4、手写代码
#include "delay.h"

/**
  * @brief  微秒级延时
  * @param  nus 延时时长,范围:0~233015
  * @retval 无
  */
void delay_us(uint32_t nus)
{
    uint32_t temp;
    SysTick->LOAD = 72 * nus;                           /* 设置定时器重装值 */
    SysTick->VAL = 0x00;                                /* 清空当前计数值 */
    SysTick->CTRL |= 1 << 2;                            /* 设置分频系数为1分频 */
    SysTick->CTRL |= 1 << 0;                            /* 启动定时器 */
    do
    {
        temp = SysTick->CTRL;
    } while ((temp & 0x01) && !(temp & (1 << 16)));     /* 等待计数到0 */
    SysTick->CTRL &= ~(1 << 0);                         /* 关闭定时器 */
}

/**
  * @brief  毫秒级延时
  * @param  nms 延时时长,范围:0~4294967295
  * @retval 无
  */
void delay_ms(uint32_t nms)
{
    while(nms--)
        delay_us(1000);
}
 
/**
  * @brief  秒级延时
  * @param  ns 延时时长,范围:0~4294967295
  * @retval 无
  */
void delay_s(uint32_t ns)
{
    while(ns--)
        delay_ms(1000);
}

/**
  * @brief  重写HAL_Delay函数
  * @param  nms 延时时长,范围:0~4294967295
  * @retval 无
  */
void HAL_Delay(uint32_t nms)
{
    delay_ms(nms);
}
5、手写代码分析

关于函数delay_s(); = 1000*delay_ms(); = 1000*delay_us();之间的换算

等价于=>1s = 1000ms; 1ms = 1000us;

秒,毫秒之间的延迟函数只需要相互调用就好,重点是关于微秒的实现

下面这段代码是微妙的实现方法:

void delay_us(uint32_t nus)
{
    uint32_t temp;
    SysTick->LOAD = 72 * nus;                           /* 设置定时器重装值 */
    SysTick->VAL = 0x00;                                /* 清空当前计数值 */
    SysTick->CTRL |= 1 << 2;                            /* 设置分频系数为1分频 */
    SysTick->CTRL |= 1 << 0;                            /* 启动定时器 */
    do
    {
        temp = SysTick->CTRL;
    } while ((temp & 0x01) && !(temp & (1 << 16)));     /* 等待计数到0 */
    SysTick->CTRL &= ~(1 << 0);                         /* 关闭定时器 */
}

我们知道SysTick有三个寄存器,分别是CTRL、LOAD、VAL

SysTick启动对应的寄存器使用方法为:SysTick->LOAD

给相应的寄存器存它的意义,作用,使用=、|=、&=

= :直接赋值

|= :把某一位给它置1

&= :把某一位给它置0

  • 为什么给定时器重装值是 72*nus ?

        因为这里选用设置的是72MHZ;分频系数是1分频的SysTick,所以是72*nus(nus是传递进来多少微妙的数值)

        如果选用设置的是72MHZ;分频系数是8分频的SysTick,就应该是72/8 = 9,是9*nus.

  • 那么为什么是72乘以微妙数呢?

        72MHZ = 72 000 000 HZ

        1S = 1000 MS = 1000 000 US

        72MHZ是指STM32微控制器的系统时钟频率‌。在STM32微控制器中,72MHz通常是系统时钟(SYSCLK)的频率,72MHZ表示每秒钟有72,000,000个时钟周期。

        所以1000 000 us= 71 000 000 HZ

        1us有72个时钟周期

        所以,重装值被赋值为72*nus

  • 为什么设置分频系数为1分频时是SysTick->CTRL |= 1 << 2;这种表现形式?

        CTRL是控制及状态寄存器,对应配置分频系数是位段2,要把位段2赋值为1,

        把CTRL赋值为1,向左移2位

  • 思考:启动定时器,怎么设置?

        读上述信息可以知道,定时器的启动和关闭是CTRL寄存器的ENABLE来管理,当ENABLE为1的时候启动定时器,复位值为0的时候关闭计时器。所以CTRL赋值为1,向左移0位,表示为:1<<0;

        所以设置为:SysTick->CTRL |= 1 << 0; // |= :把某一位给它置1

        关闭定时器就是:SysTick->CTRL &= ~(1 << 0); // &= :把某一位给它置0

        因为在关闭定时器的时候CTRL的倒数第三位,也就是开启定时器时向左移两位的位置,已经赋值为1了,现在要把这个位置赋值为0,可以使用与运算,1&0 = 0;原理,所以,先把CTRL赋值为1,向左移0位,然后取反,就搞出了一个倒数第三位是0的一个位,使用与运算,与原来CTRL的值进行与,就会把1置为0.

  • 为什么要使用do-while来进行循环?

        因为从启动滴答定时器开始,滴答定时器就在一直倒数,我们要等滴答定时器,数完,然后将定时器关闭,这样就完成了1us的延时,所以do-while语句就是一个等的操作。

  • do-while中具体怎么实现?

        首先,我们明白了do-while存在的意义,那么我们知道在SysTick中CTRL寄存器的位段16 COUNTFLAG的作用是 当SysTick数到0时,该位为1,所以我们只需要在while中判断COUNTFLAG什么时候为1就知道SysTick什么时候数完了。

while(!(SysTick->CTRL & (1 << 16))); //可以这么写,但是有点小错误还需要完善

  •  会出现什么错误呢?

        如果你只是单一的使用delay,那么不会出错,但是如果在很多地方使用了delay,可能会在其他地方被关掉了,所以还需要一个判断条件。需要判断你此时的定时器是正常的(还在开启的模式下)。

 do{
        temp = SysTick->CTRL;
    } while ((temp & 0x01) && !(temp & (1 << 16)));

        使用do-while多做一步,定义一个临时变量temp来承接SysTick->CTRL;的值,方便用来进行判断。

6、系统HAL_Delay()函数代码流程

在上述代码中可以看出来HAL库自带的delay函数最小只支持到ms级别(HAL_Delay();)

 可以在这里看到: __weak void HAL_Delay(uint32_t Delay)这条语句。

双击点开,看到该函数由于_weak void...是弱函数,可以重写的函数所以可以在delay.c文件中重写void HAL_Delay(uint32_t Delay);函数

在上面的图片中我们可以看到,Delay形参是有外界传过来的时间,也就是想要延迟多久的时间,最小单位是ms,uint32表示32位无符号整数,不能表示小数,所以Delay的值为整数。

在HAL_Delay函数的上下文中,HAL_GetTick()和tickstart都是调用HAL_GetTick()函数时获取的系统时钟滴答数(通常是以毫秒为单位的)。HAL_GetTick()函数返回一个无符号的32位整数,表示自系统启动以来的滴答数。用tickstart变量来承接HAL_GetTick();函数是当前系统时钟滴答数也就是刚进到这个函数时的时间。

后面在while子句(HAL_GetTick() - tickstart) < wait中,while函数不断循环,HAL_GetTick()函数不断被调用,此时这里的HAL_GetTick()函数就是每一次读完一轮数以后执行中断服务函数时的时间。

 

是SysTick的中断服务函数,思考:那么在什么时候会触发这个中断服务函数呢?

答案:SysTick是递减计数器,当计数器数到0的时候,就会触发一次中断(前提中断使能)

         故上述的while子句中HAL_GetTick()函数就是每一次读完一轮数以后执行中断服务函数时的时间。

        SysTick是递减计数器,HAL_GetTick() - tickstart) < wait也就是 (新获取的时间-最开始的时间)<设置想要的时间 ,在实际应用中,HAL_GetTick()的值在每次调用时都会增加(通常是因为SysTick定时器的中断服务例程会在每经历过1ms时增加它),所以HAL_GetTick() - tickstart的值最终会超过wait,从而退出while循环。

7、在main.c函数中查找系统HAL滴答定时器的初始化设置

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/942795.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【ETCD】【实操篇(十五)】etcd集群成员管理:如何高效地添加、删除与更新节点

etcd 是一个高可用的分布式键值存储&#xff0c;广泛应用于存储服务发现、配置管理等场景。为了确保集群的稳定性和可扩展性&#xff0c;管理成员节点的添加、删除和更新变得尤为重要。本文将指导您如何在etcd集群中处理成员管理&#xff0c;帮助您高效地维护集群节点。 目录 …

反应力场的生成物、反应路径分析方法

关注 M r . m a t e r i a l , \color{Violet} \rm Mr.material\ , Mr.material , 更 \color{red}{更} 更 多 \color{blue}{多} 多 精 \color{orange}{精} 精 彩 \color{green}{彩} 彩&#xff01; 主要专栏内容包括&#xff1a; †《LAMMPS小技巧》&#xff1a; ‾ \textbf…

GIT与github的链接(同步本地与远程仓库)

1.官网下载GIT Git - 安装 Git 2.GIT生成密钥 2.1 打开gitbash配置邮箱与用户名&#xff08;非初次使用GIT跳过这一步&#xff09; git config --global user.name "你的用户名" git config --global user.email "你的邮箱" 2.2 生成ssh密匙 1&#xff0…

从虚拟到现实:AI与AR/VR技术如何改变体验经济?

引言&#xff1a;体验经济的崛起 在当今消费环境中&#xff0c;产品与服务早已不再是市场竞争的唯一焦点&#xff0c;能够提供深刻感知和独特体验的品牌&#xff0c;往往更能赢得消费者的青睐。这种转变标志着体验经济的崛起。体验经济不仅仅是简单的买卖行为&#xff0c;而是通…

利用Python爬虫速卖通按关键字搜索AliExpress商品

在当今互联网时代&#xff0c;数据的价值不言而喻&#xff0c;尤其是在电子商务领域。对于从事市场研究、数据分析或者个人项目开发的人士来说&#xff0c;能够从电商平台如速卖通&#xff08;AliExpress&#xff09;获取商品数据是一项非常有用的技能。Python以其简洁明了的语…

qt QZipWriter详解

1、概述 QZipWriter是Qt框架中用于创建ZIP文件的类。它允许开发者将多个文件和目录压缩成一个ZIP文件&#xff0c;支持多种压缩算法&#xff0c;并且易于集成到现有的Qt项目中。通过QZipWriter&#xff0c;开发者可以轻松实现文件的压缩、管理压缩包中的文件等功能。 需要注意…

HarmonyOS NEXT 实战之元服务:静态案例效果---查看国内航班服务

背景&#xff1a; 前几篇学习了元服务&#xff0c;后面几期就让我们开发简单的元服务吧&#xff0c;里面丰富的内容大家自己加&#xff0c;本期案例 仅供参考 先上本期效果图 &#xff0c;里面图片自行替换 效果图1完整代码案例如下&#xff1a; Index代码 import { authen…

【Java】Jackson序列化案例分析

1.Jackson介绍 Jackson 是一个流行的 Java 库&#xff0c;用于处理 JSON 数据。它提供了高效的序列化和反序列化功能&#xff0c;能够将 Java 对象转换为 JSON 格式&#xff0c;反之亦然。 它由 FasterXML 开发和维护。Jackson 的设计目标是提供高效、灵活且易于使用的 JSON 处…

Java反射学习(2)(“反射“机制获取构造方法及内部信息(Constructor类))

目录 一、"Class"对象实例化的常见三种方式以及使用时机。 &#xff08;1&#xff09;源代码(编写)阶段——使用全限定类名.forName()。 &#xff08;2&#xff09;加载阶段——使用类名.class。 &#xff08;3&#xff09;运行阶段——使用对象.getClass()。 二、Ja…

洛谷 P1595 信封问题 C语言dp

题目描述 某人写了 n 封信和 n 个信封&#xff0c;如果所有的信都装错了信封。求所有信都装错信封共有多少种不同情况。 输入格式 一个信封数 n&#xff0c;保证 n≤20。 输出格式 一个整数&#xff0c;代表有多少种情况。 输入输出样例 输入 #1 2 输出 #1 1 输入 #2 3 输…

【LuaFramework】服务器模块相关知识

目录 一、客户端代码 二、本地服务器代码 三、解决服务器无法多次接收客户端消息问题 一、客户端代码 连接本地服务器127.0.0.1:2012端口&#xff08;如何创本地服务器&#xff0c;放最后说&#xff09;&#xff0c;连接成功后会回调 协议号Connect是101&#xff0c;其他如下…

解决Ascend上vllm运行时出现urllib3.exceptions.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED]

背景 尝试使用vllm模型&#xff0c;脚本代码如下&#xff1a; from vllm import LLM, SamplingParamsprompts ["Hello, my name is","The president of the United States is","The capital of France is","The future of AI is", …

【卷积神经网络】常用评价指标总结

评估指标 概述 该评价指标适合分类任务与目标检测&#xff0c;主要用于评估模型的性能。该文章对相关指标进行总结&#xff0c;同时对输出的图片进行学习分析 混淆矩阵的组成 TP&#xff08;True Positives&#xff0c;真正例&#xff09;&#xff1a;实际为正例&#xff0c;…

HarmonyOS NEXT 的技术发展和市场趋势:打造1+8+N的万物互联新世界

随着5G、AI、物联网等技术的飞速发展&#xff0c;全球智能设备和操作系统的竞争也日益激烈。在这一背景下&#xff0c;华为推出的HarmonyOS NEXT正逐渐成为智能设备生态中一个重要的参与者&#xff0c;其独特的18N战略布局以及跨设备、跨平台的互联互通理念&#xff0c;正在塑造…

免费 IP 归属地接口

免费GEOIP&#xff0c;查询IP信息&#xff0c;支持IPV4 IPV6 ,包含国家地理位置&#xff0c;维度&#xff0c;asm,邮编 等&#xff0c;例如 例如查询1.1.1.1 http://geoip.91hu.top/?ip1.1.1.1 返回json 对象

以太网通信--读取物理层PHY芯片的状态

PHY芯片通过MDIO接口进行读写&#xff0c;框图如下所示&#xff1a; 原理很简单&#xff0c;就是按照时序将PHY芯片的指定寄存器信息读出或者写入。 MDC时钟需要输出到PHY芯片&#xff0c;一般不低于80MHz。 MDIO是双向接口&#xff0c;FPGA读出状态信息时为输入&#xff0c;FP…

Docker服务发现新纪元:探索Consul的无限魅力

作者简介&#xff1a;我是团团儿&#xff0c;是一名专注于云计算领域的专业创作者&#xff0c;感谢大家的关注 •座右铭&#xff1a; 云端筑梦&#xff0c;数据为翼&#xff0c;探索无限可能&#xff0c;引领云计算新纪元个人主页&#xff1a;团儿.-CSDN博客 目录 前言&…

OpenHarmony-6.IPC/RPC组件

IPC/RPC组件机制 1.基本概念 IPC&#xff1a;设备内的进程间通信&#xff08;Inter-Process Communication&#xff09;。 RPC&#xff1a;设备间的进程间通信&#xff08;Remote Procedure Call&#xff09;。 IPC/RPC用于实现跨进程通信&#xff0c;不同的是前者使用Binder驱…

0.机顶盒晶晨s905l3b芯片--刷入第三方系统+安卓9 root教程+armbian写入EMMC教程

机顶盒s905l3b芯片刷第三方系统安卓9 root教程刷armbian写入EMMC教程 声明&#xff1a; 由于固件、软件、镜像等持续更新&#xff0c;本文仅代表当前所使用版本的流畅安装记录。行文略长&#xff0c;关键代码处会配以截图展示&#xff0c;请自行对比是否存在差异导致安装失败…

视频监控平台:Liveweb视频汇聚融合平台智慧安防视频监控应用方案

Liveweb是一款功能强大、灵活部署的安防视频监控平台&#xff0c;支持多种主流标准协议&#xff0c;包括GB28181、RTSP/Onvif、RTMP等&#xff0c;同时兼容海康Ehome、海大宇等厂家的私有协议和SDK接入。该平台不仅提供传统安防监控功能&#xff0c;还支持接入AI智能分析&#…