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

         在前面实验中我们使用到的延时都是通过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.mfbz.cn/a/753177.html

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

相关文章

浅谈API生态建设:API安全策略的6项原则

API作为连接系统与应用的桥梁&#xff0c;在助力实现高效业务流程的同时&#xff0c;也不可避免出现资产管理困难、敏感数据泄漏风险骤增等安全问题。前段时间&#xff0c;安全公司Fastly公布了一项重磅调查报告&#xff0c;报告中显示95%的企业在过去1年中遭遇过API安全问题。…

AXI接口简介

AXI接口&#xff0c;全称为Advanced eXtensible Interface&#xff0c;是ARM公司推出的一种高性能、低成本、可扩展的高速总线接口。AXI接口是ARM公司提出的AMBA&#xff08;Advanced Microcontroller Bus Architecture&#xff09;高级微控制器总线架构的一部分。2003年发布了…

简易电阻、电容和电感测量仪-FPGA

通过VHDL语言编写程序用于设计电阻、电容和电感测量仪&#xff0c;通过使用试验箱进行验证是否设计正确&#xff0c;资料获取到咸&#x1f41f;&#xff1a;xy591215295250 \\\或者联系wechat 号&#xff1a;comprehensivable 设计并制作--台数字显示的电阻、电容和电感参数测试…

07-border布局的另一个用处

07-border布局的另一个用处 实现如下的布局: 分析: 1.USERNAME和PASSWORD使用form 2.PASSWORD的文本框使用NewMultiLineEntry 布局1 USERNAME和PASSWORD作为一个form整体&#xff0c;使用border布局&#xff0c;form设置为top&#xff0c;文本框设置为center参数。 packa…

Postman 接口测试 安装使用教程

1 下载官网:https://www.postman.com/downloads/ 2 方便下载,特提供百度云网盘: 链接&#xff1a;Postman 3 windows10 安装&#xff0c;点击安装包 #自动安装&#xff0c;并打开 4 举例&#xff0c;比如豆瓣&#xff0c;get 查询时间&#xff0c;图片登 5 举例&#xff0…

HSRP热备份路由协议(VRRP虚拟路由冗余协议)配置以及实现负载均衡

1、相关原理 在网络中&#xff0c;如果一台作为默认网关的三层交换机或者路由器损坏&#xff0c;所有使用该网关为下一跳的主机通信必然中断&#xff0c;即使配置多个默认网关&#xff0c;在不重启终端的情况下&#xff0c;也不能彻底换到新网关。Cisco提出了HSRP热备份路由协…

传神论文中心|第14期人工智能领域论文推荐

在人工智能领域的快速发展中&#xff0c;我们不断看到令人振奋的技术进步和创新。近期&#xff0c;开放传神&#xff08;OpenCSG&#xff09;社区发现了一些值得关注的成就。传神社区本周也为对AI和大模型感兴趣的读者们提供了一些值得一读的研究工作的简要概述以及它们各自的论…

【干货】一文讲清楚社群裂变的主要模式和SOP流程

一、社群裂变的主要模式 社群裂变是一种依赖于现有成员的推广以吸引新成员的增长策略。以下是几种主要的社群裂变模式&#xff1a; 老带新裂变 定义&#xff1a;通过老用户带动新用户&#xff0c;同时给予某一方或双方奖励的一种裂变形式。 示例&#xff1a;任务宝活动&…

【精选】数据治理项目实施(合集)06——数据标准在数据治理中的落地实践

导读 本文对数据标准管理进行了深入探讨。重点介绍了数据标准的定义&#xff0c;实施路线和具体标准定义的内容&#xff0c;并总结了企业开展数据标准管理面临的常见问题&#xff0c;由于编写的水平和时间有限&#xff0c; 难免有所纸漏&#xff0c; 欢迎大家批评指正。 在现实…

填报高考志愿时,学校、专业和城市怎么选择呢?

我的观点是&#xff1a; 专业>城市>学校 专业是兴趣导向&#xff0c;符合自己的价值观&#xff0c;失去了这种驱动力的专业学习&#xff0c;会变得非常艰难的&#xff0c;而且没有竞争力&#xff0c;所以我的排序第一位是专业。 其次是城市&#xff0c;最好是一线城市&…

OpenAI发布新模型CriticGPT:利用GPT优化GPT训练,RLHF实现超越人类能力!

目录 01 基于GPT-4&#xff0c;改进GPT-4 02 CriticGPT取得了哪些成果呢&#xff1f; 03 RLHF的上限不再是人类 近日&#xff0c;OpenAI突然发布了一个新模型&#xff01;这个模型基于GPT-4训练&#xff0c;旨在帮助下一代GPT的训练。 CriticGPT能够在代码挑错中找到超过75%…

golang生成RSA公钥和密钥

目录 场景 场景一&#xff1a;加密、解密 场景二&#xff1a;微信退款 场景三&#xff1a;SSL证书 为什么是.key和.pem格式的文件 生成密钥、公钥 密钥、公钥保存到文件中 第一个&#xff1a;保存密钥到文件里 第二个&#xff1a;保存公钥到文件里 场景 场景一&#…

ForkJoinPool浅析

一,概述 相比传统的线程池ExecuteService,ForkJoinPool的优势在于能采用分治算法、工作窃取算法高效利用CPU资源,如下图 Fork即拆分,Join即合并, 通过将大任务拆分成多个小任务,在多个线程中执行后,合并结果即可得到大任务的结果,经典的例子有归并排序、超大数组求和…

如何保护应用?可快速部署的WAF服务器分享

Web应用攻击是安全事件和数据泄露的主要原因。相关统计表明&#xff0c;超过四分之三的网络犯罪直指应用及其漏洞。为保护数量日益增长的应用安全&#xff0c;Web应用防火墙(WAF)因此而生。本文则聚焦于WAF服务器&#xff0c;了解它的性能与具体的实践应用。   新加坡网络安全…

Linux应急响应靶机 2

一、靶机介绍 应急响应靶机-Linux2 前景需要&#xff1a;看监控的时候发现webshell告警&#xff0c;领导让你上机检查你可以救救安服仔吗&#xff01;&#xff01; 1,提交攻击者IP 2,提交攻击者修改的管理员密码(明文) 3,提交第一次Webshell的连接URL(http://xxx.xxx.xxx.…

变“回锅肉”专场的《歌手2024》,是不是高开低走了?

《歌手2024》播出已经过半&#xff0c;似乎出现了高开低走的不妙趋势。 6月26日&#xff0c;《歌手》节目组官宣第八期节目的补位歌手为谭维维&#xff0c;曾主动“请战”的她再次回到了《歌手》舞台&#xff0c;实力歌手加入节目按理说是件好事&#xff0c;却意外并未受到观众…

每天写java到期末考试--复习集合与泛型--6.28

1、定义一个Student类,具有name、sex、age属性,具有getName、setName、getSex、setSex、 getAge、setAge方法和三个参数的构造方法 2、编写一个类,名字为ListDemo,在main方法中做以下工作: 定义一个可以保存Student类型对象的List类型对象list1,然后向list1中放入2个学生:new S…

Web渗透:php反序列化漏洞

反序列化漏洞&#xff08;Deserialization Vulnerability&#xff09;是一种在应用程序处理数据的过程中&#xff0c;因不安全的反序列化操作引发的安全漏洞&#xff1b;反序列化是指将序列化的数据&#xff08;通常是字节流或字符串&#xff09;转换回对象的过程&#xff0c;如…

松下的台灯值得入手吗?书客、飞利浦真实横评大分享!

我们都知道&#xff0c;无论是学习还是工作&#xff0c;都需要一个良好的照明环境&#xff0c;而台灯就是我们日常生活中非常重要的照明工具。它不仅能够提供额外的光线&#xff0c;还能减少眼睛疲劳&#xff0c;提高我们的工作和学习效率。 所以&#xff0c;选购一款合适的台…

240622_昇思学习打卡-Day4-ResNet50迁移学习

240622_昇思学习打卡-Day4-ResNet50迁移学习 我们对事物的认知都是一点一点积累出来的&#xff0c;往往借助已经认识过的东西&#xff0c;可以更好地理解和认识新的有关联的东西。比如一个人会骑自行车&#xff0c;我们让他去骑摩托车他也很快就能学会&#xff0c;比如已经学会…