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滴答定时器的初始化设置

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

“AI+Security”系列第4期(一)之“洞” 见未来:AI 驱动的漏洞挖掘新范式

在数字化浪潮下&#xff0c;安全漏洞问题日益严峻&#xff0c;成为各行业发展的重大挑战。近日&#xff0c;“AISecurity” 系列第 4 期线下活动于北京成功举办&#xff0c;聚焦 “洞” 见未来&#xff1a;AI 驱动的漏洞挖掘新范式&#xff0c;汇聚了安全领域的众多专家。 本次…

LeetCode 热题 100_LRU 缓存(35_146_中等_C++)(哈希表 + 双向链表)(构造函数声明+初始化列表=进行变量初始化和赋值)

LeetCode 热题 100_LRU 缓存&#xff08;35_146&#xff09; 题目描述&#xff1a;输入输出样例&#xff1a;题解&#xff1a;解题思路&#xff1a;代码实现&#xff08;思路一&#xff08;哈希表 双向链表&#xff09;&#xff09;&#xff1a;部分代码解读 题目描述&#xf…

攻防世界 PHP2

开启场景 访问 /index.php&#xff0c;页面无变化 访问 /index.phps index.php 和 index.phps 文件之间的主要区别在于它们的文件扩展名。 index.php&#xff1a;这是一个标准的 PHP 文件&#xff0c;通常用于编写 PHP 代码。当用户访问 index.php 文件时&#xff0c;Web 服务器…

AI应用-本地模型实现AI生成PPT(简易版)

文章目录 前言技术栈效果展示 一、实现思路二、实现步骤1.本地安装marp-cli2.后端实现3.前端实现 三、代码地址及说明 前言 在许多项目中&#xff0c;生成 PPT 是常见的需求&#xff0c;尤其在教育和报告展示中。传统的生成 PPT 的方法需要手动创建&#xff0c;而使用生成模型…

项目2路由交换

背景 某学校为满足日常教学生活需求&#xff0c;推动数字校园的建设&#xff0c;学校有办公楼和学生宿舍楼和服务器集群三块区域&#xff0c;请合理规划IP地址和VLAN&#xff0c;实现企业内部能够互联互通现要求外网能通过公网地址访问服务器集群&#xff0c;学生和老师能正常…

快速掌握Haproxy原理架构

文章目录 一、原理架构二、无负载均衡三、四层负载均衡的工作流程四、七层负载均衡工作流程五、基础属性mode 属性retries 属性maxconn 属性clitimeout 属性servtimeout 属性states uri 属性 一、原理架构 四层tcp代理&#xff1a;Haproxy仅在客户端和服务器之间双向转发流量&…

02、并发编程的三大特性

并发编程有三大特性分别是&#xff0c;原子性&#xff0c;可见性&#xff0c;有序性。会产生这些特性的根本原因是现在的服务器都是多CPU多核心数的&#xff0c;每个CPU都有自己单独的一套缓存和pc系统&#xff0c;而且程序在运行时按照JMM的规范&#xff0c;它们是需要先把数据…

企业数字化转型和人工智能(AI)之间的关系

企业数字化转型和人工智能&#xff08;AI&#xff09;之间的关系可以被理解为 “驱动与支撑” 的关系&#xff1a;AI 是数字化转型的重要技术驱动力&#xff0c;而数字化转型为 AI 的应用提供了场景和数据支持。两者相辅相成&#xff0c;共同推动企业向智能化发展。 数字化转型…

STM32和精准的型号STM32F03C8T6 ——ADC通道数目区别

注意表达方式的区别 5&#xff0e;STM32芯片内部集成的&#xff08;12&#xff09;位ADC是一种逐次逼近型模拟数字转换器&#xff0c;具 有&#xff08;18&#xff09;个通道&#xff0c;可测量&#xff08;16&#xff09;个外部和(2)个内部信号源。 书上原话&#xff1a;STM32…

【项目构建】Gradle入门

本文适用&#xff1a; 不知道什么是项目构建&#xff0c;可以了解下Ant&#xff0c;Maven&#xff0c;Gradle的区别。知道什么是项目构建&#xff0c;了解Ant&#xff0c;Maven&#xff0c;可以看到Gradle是怎么做的。知道什么是项目构建&#xff0c;了解Ant&#xff0c;Maven&…

java栈--数据结构

前言 java实现数据结构栈&#xff1a;用顺序表存储的栈和数组存储的栈。 本文源代码网址&#xff1a;https://gitee.com/zfranklin/java/tree/master/dataStructure/src/com/njupt/stack https://gitee.com/zfranklin/java/tree/master/dataStructure/src/com/njupt/stack 栈…

2.5.2 文件结构、目录及存取

文章目录 文件结构文件目录存取 文件结构 文件结构是文件的组织形式。从用户角度观察到的结构是逻辑结构&#xff0c;从机器实现存储的角度观察&#xff0c;看到的是物理结构。 逻辑结构 有结构的记录式文件&#xff1a;文件中记录的长度都相同&#xff0c;称为定长记录。文件…

Highcharts 饼图:数据可视化利器

Highcharts 饼图&#xff1a;数据可视化利器 引言 在数据可视化的领域中&#xff0c;饼图作为一种经典且直观的图表类型&#xff0c;被广泛应用于各种行业和场景中。Highcharts&#xff0c;作为一个功能强大且易于使用的JavaScript图表库&#xff0c;为我们提供了创建交互式和…

关于科研中使用linux服务器的集锦

文章目录 常用的linux命令下载COCO2017数据集 常用的linux命令 一个文件移动到另一个目录下的命令是&#xff1a;mv -v ./old_name ./new_name 如果目标文件夹中已经有同名文件或文件夹&#xff0c;mv 会覆盖它们&#xff08;除非使用了 -i 选项来提示确认&#xff09;。 使用…

<项目代码>YOLO Visdrone航拍目标识别<目标检测>

项目代码下载链接 &#xff1c;项目代码&#xff1e;YOLO Visdrone航拍目标识别&#xff1c;目标检测&#xff1e;https://download.csdn.net/download/qq_53332949/90163918YOLOv8是一种单阶段&#xff08;one-stage&#xff09;检测算法&#xff0c;它将目标检测问题转化为一…

linux命令中cp命令-rf与-a的差别

在Linux系统中&#xff0c;cp 命令用于复制文件和目录。cp -rf 和 cp -a 都常用于递归复制目录及其内容&#xff0c;但它们在功能和行为上存在一些差别&#xff1a; 1. 选项含义 cp -rf&#xff1a; -r&#xff08;recursive&#xff09;&#xff1a;表示递归复制。当源文件是…

java内存马

java内存马 idea 2024.1.2专业版 jdk1.8.0_181 tomcat 8.5.82 默认有java基础&#xff0c;Javassist&#xff0c;Jsp&#xff0c;JavaEE都会一点 更新ing 文章目录 java内存马0. 一些基础1. filter型内存马2. Servlet型内存马3. listener型内存马4. Tomcat特有的Valve内存马…

【ORB-SLAM3:相机针孔模型和相机K8模型】

在ORB-SLAM3中&#xff0c;相机的建模是 SLAM 系统的核心之一&#xff0c;因为它直接影响到如何处理和利用图像数据进行定位和地图构建。ORB-SLAM3 支持不同的相机模型&#xff0c;其中包括针孔模型和鱼眼模型&#xff08;K8 模型&#xff09;。下面分别介绍这两种模型。 相机…

undefined reference to `vtable for错误

QT构建报错&#xff1a; D:\code\QGraphicsScaleTest\main.cpp:-1: error: undefined reference to vtable for ResizableSvgViewVS编译报错&#xff1a; 1>main.obj : error LNK2001: 无法解析的外部符号 "public: virtual struct QMetaObject const * __cdecl Resi…

[手机Linux] 七,NextCloud优化设置

安装完成后在个人设置里发现很多警告&#xff0c;一一消除。 只能一条一条解决了。 关于您的设置有一些错误。 1&#xff0c;PHP 内存限制低于建议值 512 MB。 设置php配置文件&#xff1a; /usr/local/php/etc/php.ini 把里面的&#xff1a; memory_limit 128M 根据你自…