嵌入式开发十九:SysTick—系统定时器

news2025/2/25 17:03:45

         在前面实验中我们使用到的延时都是通过SysTick进行延时的。 我们知道,延时有两种方式:软件延时,即CPU 循环等待产生的,这个延时是不精确的。第二种就是滴答定时器延时,本篇博客就来介绍 STM32F4 内部 SysTick 系统定时器,通过一个简单的 LED 流水灯程序来讲述如何配置 SysTick 系统定时器实现精确延时。学习可以参考《STM32F3 与 F4 系列 Cortex M4 内核编程手册》 4.5 SysTick timer (STK) 章节或者参考库函数中 core_cm4.h 文件 。

目录

一、SysTick 定时器介绍

二、SysTick 定时器操作

2.1 SysTick 定时器寄存器

2.1.1 控制和状态寄存器:CTRL

2.1.2  重装载寄存器:LOAD

2.1.3 当前数值寄存器:VAL

2.1.4  校准数值寄存器:CALIB 

2.2 系统节拍定时器的工作原理

2.3 SysTick 定时器操作步骤

2.4  使用SysTick 定时器实现精准延时

2.4.1 实现1微秒延时

2.4.2 实现1毫秒延时

2.4.3 实现1秒延时

三、SysTick 定时实验

一、SysTick 定时器介绍

       SysTick 定时器也叫 SysTick 滴答定时器,它是 Cortex-M4 内核的一个外设, 被嵌入在 NVIC 中,用来产生SYSTICK异常(异常号:15)。它是一个 24 位向下递减的定时器,每计数一次所需时间为 1/SYSTICK,SYSTICK 是系统定时器时钟,它可以直接取自系统时钟,还可以通过系统时钟 8 分频后获取,本套程序中我们采用后者,即每计数一次所需时间为 1/(168/8)us,换句话说在 1us 的时间内会计数 21 次。当定时器计数到 0 时,将 从 LOAD 寄存器中自动重装定时器初值,重新向下递减计数,如此循环往复。如果开启 SysTick 中断的话,当定时器计数到 0,将产生一个中断信号。如下图所示,因此只要知道计数的次数就可以准确得到它的延时时间。 因为 SysTick 是属于 CM4 内核的外设,所以所有基于 CM4 内核的单片机都具有这个系统定时器,使得软件在 CM4 单片机中可以很容易的移植。系统定时器一般用于操作系统, 用于产生时基,维持操作系统的心跳。

如何计算延时时间?

       如果时钟源选择8分频后的即21MHZ,那么,1秒钟就会计数21000000次,(计数一次的时间就是:1/21000000),如此:如果想要定时1毫秒,就要计数21000次,定时1微秒,就要计数21次!

二、SysTick 定时器操作

        在 STM32F4 库函数中,并没有提供相应的 SysTick 定时器配置函数,我们要操作 SysTick 定时器就需要了解它的寄存器功能。其实 SysTick 定时器寄存器很 简单,只有 4 个,分别是 CTRL、LOAD、VAL、CALIB,在使用 SysTick 产生定时的时候, 只需要配置前三个寄存器,最后一个校准寄存器不需要使用。对应如下图所示:

2.1 SysTick 定时器寄存器

2.1.1 控制和状态寄存器:CTRL

CTRL 是 SysTick 定时器的控制及状态寄存器。其相应位功能如下:

注:CLKSOUTCE 位是用于选择 SysTick 定时器时钟来源:

  1. 如果该位为 1,表示其时钟是由系统时钟直接提供即 168M。
  2. 如果该位为 0,表示其时钟是由系统时钟八分频后提供即 168/8=21M。

2.1.2  重装载寄存器:LOAD

LOAD 是 SysTick 定时器的重装载数值寄存器。其相应位功能如下:

因为 STM32F4 的 SysTick 定时器是一个 24 位递减计数器,因此重装载寄存器中只使用到了低 24 位,即 bit0-bit23。当系统复位时,其值为 0。

2.1.3 当前数值寄存器:VAL

VAL 是 SysTick 定时器的当前数值寄存器。其相应位功能如下:

同样只有 bit0-bit24 有效,复位时值为 0。

2.1.4  校准数值寄存器:CALIB 

CALIB 是 SysTick 定时器的校准数值寄存器。其相应位功能如下:

此寄存器在定时实验中不需要使用,可以不用了解。

2.2 系统节拍定时器的工作原理

        当系统节拍定时器⼯作时,该定时器⾸先会从寄存器LOAD存储的值开始递减计数。当递减为0 后,寄存器CTRL的COUNTFLAG状态位会置1,同时会重装载寄存器LOAD预置的值。 当计数到0时,通过设置寄存器CTRL的TICKINT的值来产⽣异常(中断),或是⽆动作。

2.3 SysTick 定时器操作步骤

SysTick 定时器的操作可以分为 4 步:

  1. 设置 SysTick 定时器的时钟源。
  2. 设置 SysTick 定时器的重装初始值(如果要使用中断的话,就将中断使能打开)。
  3. 清零 SysTick 定时器当前计数器的值。
  4. 打开 SysTick 定时器。

2.4  使用SysTick 定时器实现精准延时

2.4.1 实现1微秒延时

void Sleep_us(uint32_t us)
{
  while(us--)
  {
     SysTick ->CTRL = (1 << 0);   //定时器使能第0位置1
     SysTick ->CTRL &= ~(1<<2);   //选择时钟源:第2位置0,选择外部时钟源,由系统时钟八分频后提供即 168/8=21M
     SysTick ->CTRL &= ~(1<<1);   //延时时间到无动作:第1位置0

     SysTick ->VAL = 0x0;        //当前数值寄存器初值赋0
     SysTick ->LOAD = 21;       //重装载数值寄存器的值,定时1微秒,所以是21

     while(!(SysTick ->CTRL & (1<<16)));  //死循环等待计数值减到0
     SysTick ->CTRL = ~(1<<0);    //关闭定时器,第0位置0
  }
 
}


//复用上述函数实现延时1秒
void Sleep_s(uint32_t s)
{
   while(s--)
  {
      Sleep_ms(1000);
 }
}

2.4.2 实现1毫秒延时

void Sleep_ms(uint32_t ms)
{
  while(ms--)
  {
     SysTick ->CTRL = (1 << 0);   //定时器使能第0位置1
     SysTick ->CTRL &= ~(1<<2);   //选择时钟源:第2位置0,选择外部时钟源,由系统时钟八分频后提供即 168/8=21M
     SysTick ->CTRL &= ~(1<<1);   //延时时间到无动作:第1位置0

     SysTick ->VAL = 0x0;        //当前数值寄存器初值赋0
     SysTick ->LOAD = 21000;       //重装载数值寄存器的值,定时1毫秒,所以是21000

     while(!(SysTick ->CTRL & (1<<16)));  //死循环等待计数值减到0
     SysTick ->CTRL = ~(1<<0);    //关闭定时器,第0位置0
  }
 
}

2.4.3 实现1秒延时

void Sleep_s(uint32_t s)
{
  while(s--)
  {
     SysTick ->CTRL = (1 << 0);   //定时器使能第0位置1
     SysTick ->CTRL &= ~(1<<2);   //选择时钟源:第2位置0,选择外部时钟源,由系统时钟八分频后提供即 168/8=21M
     SysTick ->CTRL &= ~(1<<1);   //延时时间到无动作:第1位置0

     SysTick ->VAL = 0x0;        //当前数值寄存器初值赋0
     SysTick ->LOAD = 21000000;       //重装载数值寄存器的值,定时1秒,所以是21000000

     while(!(SysTick ->CTRL & (1<<16)));  //死循环等待计数值减到0
     SysTick ->CTRL = ~(1<<0);    //关闭定时器,第0位置0
  }
 
}

1秒=1000毫秒=1000微秒。

三、SysTick 定时实验

利用 SysTick 产生 1s 的时基,LED 以 1s 的频率闪烁。

led.h文件

#ifndef __MYLED_H
#define __MYLED_H

void LED_Init(void);

#endif

led.c 文件

#include "stm32f4xx.h"                  // Device header
#include "myled.h"

/*开时钟  打开外设对应的时钟(查看参考手册,该外设挂在哪个数据总线上),对应GPIO在哪条总线开哪条
	GPIOF外设 挂在AHB1总线上,所以要打开AHB1的时钟,双击函数,右键->go to definition*/


void LED_Init(void)
{
    //第一步:使能GPIOF的时钟 
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE);//使能 GPIOF 时钟
	
   //第二步:GPIOF9,F10 初始化设置
   GPIO_InitTypeDef GPIO_InitStructure;
   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10;//LED0 和 LED1 对应 IO 口
   GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
   GPIO_Init(GPIOF, &GPIO_InitStructure);//初始化 GPIO

   //第三步:设置灯的初始状态
   GPIO_SetBits(GPIOF,GPIO_Pin_9 | GPIO_Pin_10);//GPIOF9,F10 设置高电平,灯灭
}

mydelay.h

#ifndef __MYLED_H
#define __MYLED_H

void LED_Init(void);

#endif

mydelay.c

#include "stm32f4xx.h"                  // Device header
#include "mydelay.h"

void My_Delay_us(uint32_t num)
{
    while(num--)
    {
        SysTick ->CTRL = (1 << 0);
    
        SysTick ->CTRL &= ~(1<<2);
    
        SysTick ->CTRL &= ~(1<<1);
    
        SysTick ->VAL = 0x0;
    
        SysTick ->LOAD = 21;
    
        while(!(SysTick ->CTRL & (1<<16)));
        SysTick ->CTRL = ~(1<<0);
    }
}

void My_Delay_ms(uint32_t num)
{
    while(num--)
    {
        My_Delay_us(1000);
    }
}


void My_Delay_s(uint32_t num)
{
    while(num--)
    {
        My_Delay_ms(1000);
    }
}

main.c文件

#include "stm32f4xx.h"                  // Device header
#include "stdio.h"
#include "mydelay.h"
#include "myled.h"

int main(void)
{
    LED_Init();
    
    while(1)
    {
        My_Delay_ms(1000);           //延时1秒
        GPIO_ToggleBits(GPIOF,GPIO_Pin_9 | GPIO_Pin_10);
    }
}

实验现象:

     两个灯每隔一秒闪烁一次。

至此,我们的本次的学习就结束了。通过以上几个实验,相信对串口通信有了深入的理解,这一节我们就讲解到这里,希望能对大家的开发有帮助。 如有兴趣,感谢点赞、关注、收藏,若有不正地方,还请各位大佬多多指教!

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

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

相关文章

如何手撸一个自有知识库的RAG系统

RAG通常指的是"Retrieval-Augmented Generation"&#xff0c;即“检索增强的生成”。这是一种结合了检索&#xff08;Retrieval&#xff09;和生成&#xff08;Generation&#xff09;的机器学习模型&#xff0c;通常用于自然语言处理任务&#xff0c;如文本生成、问…

硬件开发笔记(二十):AD21导入外部下载的元器件原理图库、封装库和3D模型

若该文为原创文章&#xff0c;转载请注明原文出处 本文章博客地址&#xff1a;https://hpzwl.blog.csdn.net/article/details/139707771 长沙红胖子Qt&#xff08;长沙创微智科&#xff09;博文大全&#xff1a;开发技术集合&#xff08;包含Qt实用技术、树莓派、三维、OpenCV…

一文读懂分布式系统CAP理论与BASE理论概念

CAP理论 Cap理论又被称作布鲁尔定理(Brewers theorem),它指出对于一个分布式系统来说,不可能同时满足如下三点: 一致性(Consistency) 可用性(Availability) 分区容错性(Partition tolerance)(以实际效果而言,分区相当于对通信的时限要求。系统如果不能在时限内达…

windows 系统根据端口查找进程,杀死进程

在启动项目时&#xff0c;往往设置的端口被占用&#xff0c;这时需要杀死端口所占用的进程&#xff0c;然后再重启项目。 netstat -ano | findstr :8085 taskkill /F /PID 25184 杀死进程后&#xff0c;再执行命令 netstat -ano | findstr :8085 进行查看端口占用情况

B树(数据结构篇)

数据结构之B树 B-树(B-tree) 概念&#xff1a; B-树是一个非二叉树的多路平衡查找树(数据有序)&#xff0c;是一颗所有数据都存储在树叶节点上的树&#xff0c;不一定存储具体的数据&#xff0c;也可以是指向包含数据的记录的指针或地址 对于**阶为M(子节点数量在2和M之间)*…

嵌入式数据库_2.嵌入式数据库的一般架构

嵌入式数据库的架构与应用对象紧密相关&#xff0c;其架构是以内存、文件和网络等三种方式为主。 1.基于内存的数据库系统 基于内存的数据库系统中比较典型的产品是每个McObject公司的eXtremeDB嵌入式数据库&#xff0c;2013年3月推出5.0版&#xff0c;它采用内存数据结构&…

Ansys Mechanical|学习方法

Ansys Mechanical是Ansys的旗舰产品之一&#xff0c;涉及的学科体系全面丰富&#xff0c;包括的力学分支主要有理论力学&#xff0c;振动理论&#xff0c;连续介质力学&#xff0c;固态力学&#xff0c;物理力学&#xff0c;爆炸力学及应用力学等。 在自媒体及数字经济飞速发展…

Samtec制造理念系列一 | 差异变量的概念

【摘要/前言】 制造高端电子产品是非常复杂精密的过程。制作用于演示或原型的一次性样品可能具有挑战性&#xff0c;但真正的挑战在于如何以盈利的方式持续生产。 这就是Samtec风险投资研发工程总监Aaron Tucker在一次关于生产高密度微小型连接器的挑战的演讲中所强调的观点。…

使用QMainWindow、QMenuBar,QToolBar文本编辑器界面布局设置

使用QMainWindow、QMenuBar&#xff0c;QToolBar设计一个文本编辑器的界面 菜单 菜单输入处输入 文件$F ,呈现文件(F),快捷键AltF ,打开文件菜单 添加工具栏 在窗体空白处&#xff0c;右键添加工具栏 Action工具 在Designer界面下方 批量定义action 拖入到menu和 toolBar中 Too…

Docker 拉取镜像失败处理 配置使用代理拉取

解决方案 1、在 /etc/systemd/system/docker.service.d/http-proxy.conf 配置文件中添加代理信息 2、重启docker服务 具体操作如下&#xff1a; 创建 dockerd 相关的 systemd 目录&#xff0c;这个目录下的配置将覆盖 dockerd 的默认配置 代码语言&#xff1a;javascript 复…

阿里云API文档有哪些实用功能?如何使用?

阿里云API安全性如何保障&#xff1f;阿里云API怎么实现自动化&#xff1f; 阿里云作为全球领先的云计算服务提供商&#xff0c;提供了广泛的API接口&#xff0c;以满足各类用户的需求。阿里云API文档不仅详尽&#xff0c;而且易于使用&#xff0c;AokSend将详细介绍阿里云API…

事务的实现机制

一、基础概念 事务&#xff08;Transaction&#xff09;是访问和更新数据库的程序执行单元&#xff1b;事务中可能包含一个或多个sql语句&#xff0c;这些语句要么都执行&#xff0c;要么都不执行。作为一个关系型数据库&#xff0c;MySQL支持事务&#xff0c; 事务&#xff…

关于IntelliJ IDEA 2024.1版本更新的问题

希望文章能给到你启发和灵感&#xff5e; 感谢支持和关注&#xff5e; 阅读指南 序幕一、基础环境说明1.1 硬件环境1.2 软件环境 二、起因三、解决四、总结 序幕 近期&#xff0c;IntelliJ IDEA 推出了全新2024版本&#xff0c;相信很多编程的爱好者或者刚接触编程的小伙伴都会…

【Linux】关于在华为云中开放了端口后仍然无法访问的问题

已在安全组中添加规则: 通过指令: netstat -nltp | head -2 && netstat -nltp | grep 8080 运行结果: 可以看到服务器确实处于监听状态了. 通过指令 telnet 公网ip port 也提示: "正在连接xxx.xx.xx.xxx...无法打开到主机的连接。 在端口 8080: 连接失败"…

【2024最新华为OD-C/D卷试题汇总】[支持在线评测] 最长的指定瑕疵度的元音子串(100分) - 三语言AC题解(Python/Java/Cpp)

&#x1f36d; 大家好这里是清隆学长 &#xff0c;一枚热爱算法的程序员 ✨ 本系列打算持续跟新华为OD-C/D卷的三语言AC题解 &#x1f4bb; ACM银牌&#x1f948;| 多次AK大厂笔试 &#xff5c; 编程一对一辅导 &#x1f44f; 感谢大家的订阅➕ 和 喜欢&#x1f497; &#x1f…

【windows|007】DHCP服务详解

&#x1f341;博主简介&#xff1a; &#x1f3c5;云计算领域优质创作者 &#x1f3c5;2022年CSDN新星计划python赛道第一名 &#x1f3c5;2022年CSDN原力计划优质作者 ​ &#x1f3c5;阿里云ACE认证高级工程师 ​ &#x1f3c5;阿里云开发者社区专家博主 &#x1f48a;交流社…

IDEA配置maven,热部署,生命周期和插件,maven工程的聚合和继承

1.maven配置 先来说maven配置 首先到官网下载 https://mvnrepository.com/search?qmaven 解压就可以 然后解压完会生成一个apache-maven-3.3.9的文件 我们配置一下阿里云的镜像仓库 D:\maven\apache-maven-3.3.9\conf 我的是这个&#xff0c;你们的和我不一样&#xff0c…

Talk|香港科技大学冯宸:高效自主的大尺度场景空中覆盖与重建

本期为TechBeat人工智能社区第601期线上Talk。 北京时间6月19日(周三)20:00&#xff0c;香港科技大学冯宸博士生—冯宸的Talk已经准时在TechBeat人工智能社区开播&#xff01; 他与大家分享的主题是: “高效自主的大尺度场景空中覆盖与重建”&#xff0c;他围绕团队在利用无人机…

【C++题解】1324 - 扩建鱼塘问题

问题&#xff1a;1324 - 扩建鱼塘问题 类型&#xff1a;分支问题 题目描述&#xff1a; 有一个尺寸为 mn 的矩形鱼塘&#xff0c;请问如果要把该鱼塘扩建为正方形&#xff0c;那么它的面积至少增加了多少平方米&#xff1f; 输入&#xff1a; 两个整数 m 和 n 。 输出&…

AI 已经在污染互联网了。。赛博喂屎成为现实

大家好&#xff0c;我是程序员鱼皮。这两年 AI 发展势头迅猛&#xff0c;更好的性能、更低的成本、更优的效果&#xff0c;让 AI 这一曾经高高在上的技术也走入大众的视野&#xff0c;能够被我们大多数普通人轻松使用&#xff0c;无需理解复杂的技术和原理。 其中&#xff0c;…