STM32 SYSTick高精度延时功能代码实现

news2025/3/11 9:08:56

文章目录

  • 前言
  • 一、SYSTick定时器介绍
  • 二、SYSTick定时器和其他定时器的区别
  • 三、SYSTick定时器框图讲解
  • 四、HAL库中SYSTick配置代码讲解
  • 五、SYSTick实现高精度延时
  • 总结


前言

本篇文章将给大家讲解一下SYSTICK滴答定时器,以及讲解使用滴答定时器来实现高精度延时功能的代码。

一、SYSTick定时器介绍

SysTick定时器是嵌入式系统中常见的一个系统定时器,在ARM Cortex-M微控制器中广泛使用。下面是关于SysTick定时器的一些介绍:

用途: SysTick定时器通常被用作操作系统的时钟节拍(Tick)或者作为基本的定时器来执行周期性的任务。它可以提供一个精确的时间基准,用于定时器中断、延时函数的实现以及系统的时间管理。

定时器类型: SysTick定时器是一个24位向下计数器。它可以在一个范围内计数从最大值向0的时钟周期,然后在达到0时重新装载计数值,并触发一个中断(如果已使能)。

配置: 在STM32微控制器中,SysTick定时器可以通过设置相关的寄存器来配置。这些寄存器包括:

STK_CTRL:控制寄存器,用于使能或禁用SysTick定时器,选择时钟源和设置中断使能。
STK_LOAD:装载寄存器,用于设置初始的计数值。
STK_VAL:当前值寄存器,用于读取当前的计数值。
STK_CALIB:校准寄存器,用于存储SysTick定时器的校准值。

时钟源: SysTick定时器的时钟源可以选择为外部时钟或者系统时钟的一个分频。通常情况下,它与系统时钟同步,但也可以使用外部时钟来提供更灵活的配置选项。

中断: SysTick定时器可以在计数器溢出时触发中断。这种中断通常被用来实现操作系统的时钟节拍,或者用于周期性任务的执行。

应用: SysTick定时器广泛应用于嵌入式系统中,特别是在实时操作系统(RTOS)中用作系统时钟。它可以用来实现延时函数、精确的定时器中断、周期性任务的执行以及系统的时间管理。

二、SYSTick定时器和其他定时器的区别

1.SYSTick定时器是CPU内部的定时器,其他定时器是作为STM32的外部定时器。

之所以在处理器内增加一个定时器,是为了提高软件的可移植性。由于所有的 Cortex-M处理器都具有相同的SysTick定时器,为一种Cortex-M3/M4微控制器实现的OS也能适用于其他的Cortex-M3/M4微控制器
在这里插入图片描述
2.功能和用途:

SYSTick定时器通常用于实现系统的时间管理、时钟节拍以及简单的定时功能,如延时函数的实现等。
其他定时器(如TIM定时器)通常用于更复杂的定时和计时任务,例如PWM输出、捕获/比较模式、定时触发ADC转换等。

3.精度:

SYSTick定时器的精度通常受限于系统时钟频率,因此在一般情况下可能比较低。
其他定时器通常具有更高的精度,并且可以通过外部时钟源进行精确校准,因此适用于需要更精确时间控制的应用。

4.中断处理:

SYSTick定时器通常只能产生一个中断,用于系统的时钟节拍或简单的定时任务。
其他定时器可以配置多个中断触发条件,允许更灵活的中断处理和定时任务的执行。

5.寄存器和配置:

SYSTick定时器只有几个寄存器,配置相对简单。
其他定时器通常具有更多的寄存器和更复杂的配置选项,以支持各种不同的定时和计时功能。

6.外设依赖性:

SYSTick定时器不依赖于外部器件,因为它是CPU内部的一个特殊功能模块。
其他定时器通常依赖于外部时钟源和其他外部器件(例如计数输入、PWM输出引脚等)。

7.优先级:

由于SYSTick定时器是CPU内部的定时器,因此其中断处理通常具有较高的优先级。
其他定时器的中断处理优先级可能需要根据具体应用情况进行配置,并且可能不如SYSTick定时器的中断处理优先级高。

三、SYSTick定时器框图讲解

在这里插入图片描述
1.首先SYSTick根据处理器时钟或者参考时钟来减小计数

2.配置CTRL寄存器的第0位使能计数器,当前值寄存器在每个处理器时钟周期或参考时钟的上升沿都会减小。若计数减至0,它会从重加载寄存器中加载数值并继续
运行。

3.另外一个寄存器为 SysTick 校准值寄存器。它为软件提供了校准信息。由于 CMSISCore 提供了一个名为 SystemCoreClock 的软件变量(CMSIS 1.2及之后版本可用,CMSIS 1.1或之前版本则使用变量 SystemFrequency),因此它就未使用SysTick 校准值寄存器。系统初始化函数 SystemInit()函数设置了该变量,而且每次系统时钟配置改变时都要对其进行更新这种软件手段比利用SysTick 校准值寄存器的硬件方式更灵活。

四、HAL库中SYSTick配置代码讲解

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
滴答定时器配置代码:

__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks)
{
  if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk)
  {
    return (1UL);                                                   /* Reload value impossible */
  }

  SysTick->LOAD  = (uint32_t)(ticks - 1UL);                         /* set reload register */
  NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); /* set Priority for Systick Interrupt */
  SysTick->VAL   = 0UL;                                             /* Load the SysTick Counter Value */
  SysTick->CTRL  = SysTick_CTRL_CLKSOURCE_Msk |
                   SysTick_CTRL_TICKINT_Msk   |
                   SysTick_CTRL_ENABLE_Msk;                         /* Enable SysTick IRQ and SysTick Timer */
  return (0UL);                                                     /* Function successful */
}

下面是对这段代码的配置流程的讲解:

1.参数检查:

if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk)
{
  return (1UL);  /* Reload value impossible */
}

这一部分首先检查传入的 ticks 参数是否超过了SysTick定时器的重装载寄存器(LOAD寄存器)的最大值。如果超过了,说明无法设置这么大的重载值,函数返回1表示配置失败。否则,继续执行后续的配置步骤。

2.设置重载寄存器:

SysTick->LOAD  = (uint32_t)(ticks - 1UL);  /* set reload register */

这一行代码设置SysTick定时器的重载寄存器,确定计数器计数到多少时触发一次SysTick中断。ticks - 1 是因为计数器是从零开始计数的。

3.设置中断优先级:

NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL);  /* set Priority for Systick Interrupt */

这里设置了SysTick定时器的中断优先级。NVIC_SetPriority 是一个用于设置中断优先级的CMSIS(Cortex Microcontroller Software Interface Standard)函数。__NVIC_PRIO_BITS 表示中断优先级位的数量,通常由硬件定义。这里将SysTick中断的优先级设置为最低,即最高数值。

4.清零计数器寄存器:

SysTick->VAL   = 0UL;  /* Load the SysTick Counter Value */

这一行代码清零SysTick定时器的计数器寄存器,确保计数器从零开始计数。

5.配置并启用SysTick定时器:

SysTick->CTRL  = SysTick_CTRL_CLKSOURCE_Msk |
                 SysTick_CTRL_TICKINT_Msk   |
                 SysTick_CTRL_ENABLE_Msk;  /* Enable SysTick IRQ and SysTick Timer */

这一行代码配置并启用SysTick定时器。具体配置包括:

SysTick_CTRL_CLKSOURCE_Msk:选择SysTick定时器的时钟源,通常选择处理器时钟。
SysTick_CTRL_TICKINT_Msk:使能SysTick定时器中断。
SysTick_CTRL_ENABLE_Msk:启用SysTick定时器。

返回配置结果:

   return (0UL);  /* Function successful */

如果上述配置步骤都成功执行,函数返回0,表示配置成功。

五、SYSTick实现高精度延时

创建systick.c和systick.h来管理高精度延时的代码。

systick.c

#include "systick.h"

//us级延时
void udelay(int us)
{
	uint32_t told = SysTick->VAL;
	uint32_t tnow;
	
	uint32_t load = SysTick->LOAD;
	
	/* LOAD+1个时钟对应1ms
	 * n us对应 n*(load+1)/1000个时钟
   */
	uint32_t ticks = us*(load+1)/1000;
	
	uint32_t cnt = 0;
	
	while (1)
	{
		tnow = SysTick->VAL;
		if (told >= tnow)
			cnt += told - tnow;
		else
			cnt += told + load + 1 - tnow;
		
		told = tnow;
		if (cnt >= ticks)
			break;
	}	
}

//ms级延时
void mdelay(int ms)
{
	for (int i = 0; i < ms; i++)
		udelay(1000);	
}

//获取系统上电到现在经过了多少ns
uint64_t system_get_ns(void)
{
	uint64_t ns = HAL_GetTick(); /* ms */
	ns = ns*1000000;

	uint32_t tnow = SysTick->VAL;	
	uint32_t load = SysTick->LOAD;
	
	uint64_t cnt;
	
	cnt = load+1-tnow; /* 没有考虑tnow等于0的情况 */
	
	ns += cnt * 1000000 / (load+1) ;
	return ns;	
}


systick.h

#ifndef __SYSTICK_H__
#define __SYSTICK_H__

#include "main.h"

void udelay(int us);

void mdelay(int ms);

uint64_t system_get_ns(void);

#endif


  1. udelay(int us)
    这个函数实现了微秒级延时。其原理是利用SysTick定时器进行精确计时。首先,获取当前SysTick计数器的值 told,然后计算出需要延时的时钟周期数 ticks,接着在一个循环中不断获取当前计数器的值 tnow,并计算经过的时钟周期数 cnt。当经过的时钟周期数达到了延时所需的时钟周期数 ticks 时,跳出循环,延时结束。

  2. mdelay(int ms)
    这个函数实现了毫秒级延时,它通过多次调用微秒级延时函数来实现。每次调用 udelay(1000) 即相当于延时了1毫秒。

  3. system_get_ns(void)
    这个函数用于获取系统上电到当前时刻经过的纳秒数。首先,获取系统运行时间的毫秒数 ns,然后通过当前SysTick计数器的值 tnow 和 SysTick加载值 load 计算出当前经过的时钟周期数 cnt,进而将其转换为纳秒数并加到系统运行时间上,最终返回总的纳秒数。

总结

本篇文章主要讲解了SYSTick的概念,寄存器配置和使用,并且使用SYSTick实现了高精度延时,大家可以自己写代码实验验证一下正确性。

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

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

相关文章

【51单片机】DS18B20(江科大)

一、DS18B20温度传感器 1.DS18B20介绍 DS18B20是一种常见的数字温度传感器,其控制命令和数据都是以数字信号的方式输入输出,相比较于模拟温度传感器,具有功能强大、硬件简单、易扩展、抗干扰性强等特点 测温范围 :- 55℃到125℃ 通信接口:1-Wire(单总线) 其它特征:可形成…

复旦TravelPlanner让大语言模型挑战旅程规划

引言&#xff1a;探索语言智能的新疆界——旅行规划 在人工智能的发展历程中&#xff0c;规划一直是核心追求之一。然而&#xff0c;由于缺乏人类水平规划所需的多种认知基础&#xff0c;早期的AI代理主要集中在受限的环境中。随着大语言模型&#xff08;LLMs&#xff09;的出…

[ai笔记5] 个人AI资讯助手实战

欢迎来到文思源想的ai空间&#xff0c;这是技术老兵重学ai以及成长思考的第5篇分享&#xff0c;也是把ai场景化应用的第一篇实操内容&#xff01; 既然要充分学习和了解ai&#xff0c;自然少不了要时常看看ai相关资讯&#xff0c;所以今天特地用字节的“扣子”做了一个ai的资讯…

ChatGPT高效提问—prompt实践

ChatGPT高效提问—prompt实践 ​ 探索prompt在实际生活中的各种应用&#xff0c;旨在帮助理解和掌握如何将之前学到的prompt基础和技巧应用到具体实践中&#xff0c;从而在各个领域实现人工智能的价值。 ​ 通过生动的案例&#xff0c;发现并挖掘ChatGPT和prompt的无穷潜力。…

亚马逊云科技AI应用 SageMaker 新突破,机器学习优势显著

&#xff08;声明&#xff1a;本篇文章授权活动官方亚马逊云科技文章转发、改写权&#xff0c;包括不限于在 亚马逊云科技开发者社区、知乎、自媒体平台、第三方开发者媒体等亚马逊云科技官方渠道&#xff09; Amazon SageMaker是一种机器学习服务&#xff0c;帮助开发人员快速…

《MySQL 简易速速上手小册》第7章:MySQL监控和日志分析(2024 最新版)

文章目录 7.1 配置和使用 MySQL 监控工具7.1.1 基础知识7.1.2 重点案例&#xff1a;使用 Python 和 Prometheus 监控 MySQL 性能7.1.3 拓展案例 1&#xff1a;自动化 MySQL 慢查询日志分析7.1.4 拓展案例 2&#xff1a;实时警报系统 7.2 解读 MySQL 日志文件7.2.1 基础知识7.2.…

JAVA设计模式之命令模式详解

命令模式 1 命令模式介绍 命令模式(command pattern)的定义: 命令模式将请求&#xff08;命令&#xff09;封装为一个对象&#xff0c;这样可以使用不同的请求参数化其他对象&#xff08;将不同请求依赖注入到其他对象并且能够支持请求&#xff08;命令&#xff09;的排队执行…

Java中的IO介绍

本章内容 一 、File概念 File可以代表一个目录或者一个文件&#xff0c;并不能代表文件的内容 文件和流的区别&#xff1a;File关注的是文件本身的特征&#xff0c;如名称、路径、修改时间、大小。 流关注的是文件的内容。 二、File基本的操作 常见构造方法 | File(String p…

Spring Cloud微服务网关Zuul基础入门使用

一、概述 Zuul是从设备和网络到后端应用程序所有请求的后门&#xff0c;为内部服务提供可配置的对外URL到服务的映射关系&#xff0c;基于JVM的后端路由器。具有一下的功能&#xff1a; 认证与授权压力测试金丝雀测试动态路由负载削减静态相应处理主动流量管理 其底层是基于…

屏幕字体种类介绍

[ Script and font support in Windows ] [Windows 中的脚本和字体支持&#xff3d; 在Windows 2000 以前&#xff0c;Windows 的每个主要版本都会添加对新脚本的文本显示支持。本文介绍了每个主要版本中的更改。 Since before Windows 2000, text-display support for new scr…

ARM PAC/BTI/MTE三剑客精讲与实战

一、PAC指针认证精讲与实战 思考 1、什么是栈溢出攻击&#xff1f;什么是代码重用攻击&#xff1f;区别与联系&#xff1f; 2、栈溢出攻击的软&硬件缓解技术有哪些&#xff1f;在TF-A&OPTEE上的应用&#xff1f; 3、什么是ROP攻击&#xff1f;对ROP攻击的缓解技术&…

【医学大模型 知识增强】SMedBERT:结构化语义知识 + 医学大模型 = 显著提升大模型医学文本挖掘性能

SMedBERT&#xff1a;结构化语义知识 医学大模型 显著提升医学文本挖掘任务性能 名词解释结构化语义知识预训练语言模型医学文本挖掘任务 提出背景具体步骤提及-邻居混合注意力机制实体嵌入增强实体描述增强三元组句子增强 提及-邻居上下文建模域内词汇权重学习领域自监督任务…

Swift Combine 有序的异步操作 从入门到精通十二

Combine 系列 Swift Combine 从入门到精通一Swift Combine 发布者订阅者操作者 从入门到精通二Swift Combine 管道 从入门到精通三Swift Combine 发布者publisher的生命周期 从入门到精通四Swift Combine 操作符operations和Subjects发布者的生命周期 从入门到精通五Swift Com…

论文阅读-面向公平性的分布式系统负载均衡机制

摘要 当一组自利的用户在分布式系统中共享多个资源时&#xff0c;我们面临资源分配问题&#xff0c;即所谓的负载均衡问题。特别地&#xff0c;负载均衡被定义为将负载分配到分布式系统的服务器上&#xff0c;以便最小化作业响应时间并提高服务器的利用率。在本文中&#xff0…

【客户端】聊聊卸载安装测试、新安装测试和覆盖安装测试(持续更新中)

程序安装一般会有&#xff1a;全新安装、卸载安装、覆盖安装这几种&#xff0c;那么安装渠道和方式就非常的多样化了。iOS可以商店安装、文件安装&#xff0c;安卓有商店安装、渠道安装、APK安装 等等。 一、不同安装方式 通常来说&#xff0c;大部分用户都会走到覆盖安装&…

微信小程序(四十二)wechat-http拦截器

注释很详细&#xff0c;直接上代码 上一篇 新增内容&#xff1a; 1.wechat-http请求的封装 2.wechat-http请求的拦截器的用法演示 源码&#xff1a; utils/http.js import http from "wechat-http"//设置全局默认请求地址 http.baseURL "https://live-api.ith…

【ES】--Elasticsearch的分词器详解

目录 一、前言二、分词器原理1、常用分词器2、ik分词器模式3、指定索引的某个字段进行分词测试3.1、采用ts_match_analyzer进行分词3.2、采用standard_analyzer进行分词三、如何调整分词器1、已存在的索引调整分词器2、特别的词语不能被拆开一、前言 最近项目需求,针对客户提…

SSM+SpringBoot框架

单例bean是线程安全的吗 AOP Spring事务失效 第四种&#xff0c;在方法内部使用&#xff0c;需要用代理类调用此方法 bean生命周期 bean的循环依赖 SpringMVC执行流程 、 SpringBoot自动配置原理 Spring常见注解 MyBatis执行流程 MyBatis延迟加载 MyBatis缓存

算法刷题:复写零

复写零 .习题链接题目描述算法原理初始值步骤1步骤2我的答案: . 习题链接 复写零 题目描述 给你一个长度固定的整数数组 arr &#xff0c;请你将该数组中出现的每个零都复写一遍&#xff0c;并将其余的元素向右平移。 注意&#xff1a;请不要在超过该数组长度的位置写入元素…