超详细!必看!!STM32--系统滴答SysTick

news2024/11/27 10:21:51

一、SysTick是什么?

Systick定时器是一个24bit的倒计时(向下计数)定时器,功能就是实现简单的延时。
SysTick 是一种系统定时器,通常在嵌入式系统中使用。它是 ARM Cortex-M 处理器的一个特殊定时器,用于提供系统级的定时服务。SysTick 可以用于生成定时中断,以便执行特定的任务或进行系统级的时间跟踪。
例如:计数初值为100,经过一个时钟周期后,计数值减一,即99,98,97……1,0;计数至0后,又重新开始从100开始倒计数至0。​ 可以借此做精准延时。

二、SysTick框架图

因为SysTick是属于内核的一部分,其被捆绑在NVIC中,用于产生SYSTICK异常。
在这里插入图片描述

三、SysTick组成

​ SysTick包含四个寄存器,都是24位的寄存器,分别是:
(1) SysTick->CTRL

SysTick控制及状态寄存器 (-- 0xE000 E010

在这里插入图片描述

(2) SysTick->LOAD

SysTick重装载寄存器 – 0xE000 E014
在这里插入图片描述

(3) SysTick->VAL

SysTick当前值寄存器 – 0xE000 E018
在这里插入图片描述

(4) SysTick->CALIB

SysTick校准值寄存器 – 0xE000 E01C
在这里插入图片描述

四、SysTick时钟知识点

(1)首先明白频率(Hz)与时间(S)的转换。
●1Hz代表每秒周期震动1次, 60Hz代表每秒周期震动60次。假如滴答时钟的频率是72MHZ,72MHz表示每秒钟有72,000,000个时钟周期。那让滴答时钟计1次,时间过去了1/72μs,也就是一个时钟周期为1/72000000 s =1/72 us。
●定时1us,就需要72个时钟周期。
●定时1s,就需要72000个时钟周期。
(2)为什么需要装载预期值-1?
答:装载值就是装载的时钟周期个数。SysTick 定时器的计数是从 LOAD 装载值寄存器的值递减到零的,所以如果你希望实现 n 个时钟周期的延时,你需要将 LOAD 寄存器设置为 n - 1。如系统时钟频率为72MHz,经过8分频后,频率为9MHz。即1s震动9000 000个周期。所以装载值为8999 000,计数器从8999000减到0,总共经过 9000000 个时钟周期,则正好为1s的时间,即实现定时1s。
(3)为什么选择经过8分频的外部时钟,而不选择内部时钟?
答:选择使用外部时钟而不是内部时钟,是为了保证定时器的精度和稳定性。
内部时钟是由微控制器内部提供的时钟源,通常频率相对较低。在某些情况下,使用内部时钟作为SysTick的时钟源可能会导致定时器的溢出时间过长,无法满足精确的延时需求。
外部时钟,例如外部晶体振荡器或主芯片提供的外部时钟信号,具有较高的频率和稳定性。使用外部时钟作为SysTick的时钟源可以提供更高的精度和可靠性。对于需要较准确的延时操作或时间计量的应用,选择外部时钟是更好的选择。
因此,在该代码中选择使用外部时钟来配置SysTick定时器,以确保精确和稳定的延时功能。
(4)时钟源选择
--------库函数( SysTick_CLKSourceConfig(时钟源)):

●时钟源可选参数:
SysTick_CLKSource_HCLK_Div8 (经过8分频的外部时钟)
SysTick_CLKSource_HCLK (内部时钟)

●函数代码如下:

#define SysTick_CLKSource_HCLK_Div8    ((uint32_t)0xFFFFFFFB)   //经过8分频的外部时钟
#define SysTick_CLKSource_HCLK         ((uint32_t)0x00000004)   //内部时钟
#define IS_SYSTICK_CLK_SOURCE(SOURCE) (((SOURCE) == SysTick_CLKSource_HCLK) || \
                                       ((SOURCE) == SysTick_CLKSource_HCLK_Div8))
                                       
void SysTick_CLKSourceConfig(uint32_t SysTick_CLKSource)   //时钟源选择库函数
{
  /* Check the parameters */
  assert_param(IS_SYSTICK_CLK_SOURCE(SysTick_CLKSource));
  if (SysTick_CLKSource == SysTick_CLKSource_HCLK)
  {
    SysTick->CTRL |= SysTick_CLKSource_HCLK;
  }
  else
  {
    SysTick->CTRL &= SysTick_CLKSource_HCLK_Div8;
  }
}

--------寄存器

SysTick->CTRL &=~(1<<2); //选择外部时钟,必须清零默认是1内核时钟
SysTick->CTRL |=(1<<2); //选择内核时钟。

在这里插入图片描述

(4)延时范围
●如系统时钟频率为72MHz,经过8分频后为9MHz。1s的时钟周期个数为9000 000,1ms的时钟周期个数为9000,1us的时钟周期个数为9。
●VAL寄存器以及LOAD寄存器都是24位的,它的最大值是1111 1111 1111 1111 1111 1111,转化乘十进制后是16777215。即装载的最大十周周期个数为16777215。
级别的定时器,一次最大定时时长为:16777215 / 9000000 s。
毫秒级别的定时器,一次最大的定时时长16777215/9000 ms,也就是1864.135毫秒,由于对于毫秒只能取整,也就是1864毫秒。
微秒级别的定时器,一次最大定时时长是16777215/9=1864135 us。
这就是Systick定时器循环一次所能达到的最大定时时长。也就是装载值的最大范围。当然也可以通过循环嵌套来实现更长时间的定时。

五、SysTick两种功能

(1)查询方式延时功能:
只需要定时器工作一个周期,也就是从重装载值减到0的一个过程,执行一次后需要关闭定时器,不然它还会不停的从重装载值减到0然后又从重装载值减到0无限循环。

实现功能:实现us、ms级别的延时函数。
伪代码:

实现系统的us延时(参数)
{
   1.选择时钟 建议选择经过8分频后的外部时钟。
   2.写入重装载值,设为预期值-13.禁止中断。
   4.清空计数器。
   5.使能计数器。
   6.等待时间到达,等待标志位置17.关闭计数器。
   8.清空计数器。
}

具体代码:

//  uint32_t SystemCoreClock         = SYSCLK_FREQ_72MHz;        /*!< System Clock Frequency (Core Clock) */
void delay_init()
{
 	SysTick->CTRL &=~(1<<2); //1.选择外部时钟,必须清零。默认是1,为内核时钟。
	//SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);	 // 1.选择外部时钟  HCLK/8 
	s_fac_num=SystemCoreClock/8;				    //选择的经过8分频的外部时钟,所以要将系统时钟72Mhz/8。此时频率为9MHz。1s震动9 000 000 次。
	us_fac_num=Clock_Div8_after/1000000;            //1us 震动9次。1s=1000 000 us.
	ms_fac_num=(u16)fac_us*1000;					//1个ms需要的systick时钟数 。
}	
void delay_us(u32 nus)
{		
	u32 temp;	    	 
	SysTick->LOAD=nus*us_fac_num-1; 					//2.写入装载值  	
	SysTick->CTRL &=~(0x01 <<1);	              //3.禁止中断
	SysTick->VAL=0x00;        					//4.清空计数器(当前值)这里大家一定要注意,必须使得当前寄存器的值VAL等于0! SysTick->VAL  = (0x00);只有当VAL值为0时,计数器自动重载RELOAD。下面同理。
	SysTick->CTRL |=(0x01<<0);	//5.使能计数器,开始倒数。
	while( (SysTick->CTRL&(1<<16)) ==0);//6.等待时间到达   
	SysTick->CTRL&=~(0x01<<0);	//7.关闭计数器
	SysTick->VAL =0X00;      	//8.清空计数器(当前值) 
}

void delay_ms(u32 nus)
{		
	u32 temp;	    	 
	SysTick->LOAD=nus*ms_fac_num-1; 					//2.写入装载值  	
	SysTick->CTRL &=~(0x01 <<1);	              //3.禁止中断
	SysTick->VAL=0x00;        					//4.清空计数器(当前值)这里大家一定要注意,必须使得当前寄存器的值VAL等于0! SysTick->VAL  = (0x00);只有当VAL值为0时,计数器自动重载RELOAD。下面同理。
	SysTick->CTRL |=(0x01<<0);	//5.使能计数器,开始倒数。
	while( (SysTick->CTRL&(1<<16)) ==0);//6.等待时间到达   
	SysTick->CTRL&=~(0x01<<0);	//7.关闭计数器
	SysTick->VAL =0X00;      	//8.清空计数器(当前值) 
}

(2)中断功能:
利用中断,一定时间进一次中断,以此来实现一个时间片轮询的操作方式。这时候,就需要计数器一直计数了,所以不能计数完成后就关闭计数器了。

实现功能:每过一次设定的ms发送一次’123456’。
伪代码:

系统滴答的初始化
{
   1.选择外部滴答的时钟源。
   2.配置系统滴答的重装载值,设为预期值-13.使能中断。
   4.当前值清零--清空计数器。
   5.设置优先级。
   6.使能NVIC响应。
   7.使能计数器。
}
中断服务函数
{
	1.检测标志与清除标志;
	2.执行操作。
}

具体代码:

#include "SysTick.h"
u16 SysTick_us;
u16 SysTick_ms;
/*******************************
函数名:SysTick_Init
函数功能:初始化系统滴答,选择外部时钟
函数形参:u32 sysclk 系统时钟72(MHZ)
函数返回值:void
备注:开启1ms中断
********************************/
void SysTick_ms_Init(u32 nus) //72HZ
{	
	SysTick->CTRL &=~(1<<2); //1.选择外部时钟,必须清零。默认是1,为内核时钟。
	SysTick_s=SystemCoreClock/8;           //9000 000     1s  //外部时钟8分频
	SysTick_us=SysTick_s/1000 000;           //9     1us  
	SysTick_ms=SysTick_s/1000;            //9 000  1ms
	
	SysTick->LOAD = nus*SysTick_ms-1;//2.重装载值9000-1
	SysTick->CTRL |=(0x01<<1);   //3.使能中断 SysTick倒数计数到0时产生SysTick异常(中断)请求 */
	SysTick->VAL=0;              //4.清空计数器,清标志位
	NVIC_SetPriority(SysTick_IRQn,NVIC_EncodePriority(7-2,1,2));  // 5.设置中断优先级
	NVIC_EnableIRQ(SysTick_IRQn);                                 //6.使能NVIC响应
	SysTick->CTRL |=1<<0;   //7.使能计数器


/*   步骤5、6也可以用结构体来配置优先级以及使能NVIC响应。
	NVIC_InitTypeDef NVIC_InitStructure; //结构体重命名
	NVIC_InitStructure.NVIC_IRQChannel = SysTick_IRQn;  //选择通道(要中断的对象)
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  //设置抢占优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;  //设置响应优先级
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //通道使能
	NVIC_Init(&NVIC_InitStructure);  //根据以上参数初始化NVIC寄存器	
*/		
}
void SysTick_Handler(void)
{
	if((SysTick->CTRL & 0x1 << 16))//检测标志位,也是清除标志位
	{	
		SysTick->VAL=0;              //清空计数器,清标志位
		printf("123456\r\n");
	}
}

主函数:

int main()
{
   NVIC_SetPriorityGrouping(7-2); //设置优先级分组。抢占2bit,响应2bit。
   SysTick_ms_Init(1); //实现1ms打印一次'123456'
}

六、附录:

上述函数中,为什么SysTick的时钟频率需要经过8分频系统时钟?
在这里插入图片描述
答:因为在时钟树框图中,Cortex系统时钟需要系统时钟经过8分频。

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

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

相关文章

Kvaser CAN硬件在Top Dutch Solar的遥测系统中发挥重要作用

Top Dutch Solar Racing&#xff08;荷兰顶级太阳能赛车队&#xff09;是2023年Bridgestone World Solar Challenge&#xff08;普利司通世界太阳能挑战赛&#xff09;的参赛车队之一&#xff0c;其赛车上搭载的Kvaser Ethercan HS是为基于Wifi的实时遥测系统捐赠的。Kvaser Me…

读写分离(基于mycat)和全同步复制

一、mycat实现读写分离&#xff08;VIP机制&#xff09; &#xff08;一&#xff09;配置主从复制 &#xff08;二&#xff09;部署mycat 1、安装Java 2、下载mycat安装包 3、解压mycat包 4、设置变量环境 5、启动mycat &#xff08;三&#xff09;客户端连接数据库 1、安装…

初冬喜事:星融元成都办事处开业啦!

立冬过去不久&#xff0c;我国大部分地区气温就随双十一打了五折。寒冬时分吃火锅温暖身心&#xff0c;红火的锅底也为生活增添不少喜气&#xff0c;今天就有一桩喜事——星融元成都办事处开业啦&#xff01; 星融元成都办事处位于成都市高新区锦城大道666号奥克斯广场C座2007…

【LeetCode】挑战100天 Day11(热题+面试经典150题)

【LeetCode】挑战100天 Day11&#xff08;热题面试经典150题&#xff09; 一、LeetCode介绍二、LeetCode 热题 HOT 100-132.1 题目2.2 题解 三、面试经典 150 题-133.1 题目3.2 题解 一、LeetCode介绍 LeetCode是一个在线编程网站&#xff0c;提供各种算法和数据结构的题目&…

9种高效提速的transformer魔改版本

Transformer目前已经成为人工智能领域的主流模型&#xff0c;应用非常广泛。然而Transformer中注意力机制计算代价较高&#xff0c;随着序列长度的增加&#xff0c;这个计算量还会持续上升。 为了解决这个问题&#xff0c;业内出现了许多Transformer的魔改工作&#xff0c;以优…

(.htaccess文件特性)[MRCTF2020]你传你呢 1

题目环境&#xff1a; 不难看出是一道文件上传漏洞 上传一句话木马文件burpsuite进行抓包<?php eval($_POST[shell]);?> 命名为PHP文件格式 Repeater进行重放 尝试了其它后缀进行绕过都没有成功 通过 application/x-php内容类型&#xff0c;可以看出被识别出是PHP文件&…

【C++】类和对象(3)--初始化列表(再谈构造函数)

目录 一 引入 二 初始化列表概念 三 初始化列表特性 1 引用和const 2 混合使用 3 自定义成员情况 四 初始化列表中的初始化顺序 五 总结 一 引入 构造函数体赋值 class Date { public:Date(int year, int month, int day){_year year;_month month;_day day;} priv…

TSINGSEE青犀视频平台EasyCVR自定义可视化页面一览

视频监控TSINGSEE青犀视频平台EasyCVR能在复杂的网络环境中&#xff0c;将分散的各类视频资源进行统一汇聚、整合、集中管理&#xff0c;在视频监控播放上&#xff0c;视频安防监控汇聚平台可支持1、4、9、16个画面窗口播放&#xff0c;可同时播放多路视频流&#xff0c;也能支…

数据结构—队列的实现

前言&#xff1a;上次我们已经学习了数据结构中一个重要的线性表—栈&#xff0c;那么我们这一次就来学习另外一个重要的线性表—队列。 目录&#xff1a; 一、 队列的概念 二、 队列的实现&#xff1a; 1.队列的创建 三、 队列的操作 1.初始化队列 2.队尾入队列 3.队头出队列…

KOSMOS-G-图像文本结合控制生成

文章目录 摘要引言算法多模态语言建模图像解码器对齐微调instruction 实验结论 论文&#xff1a; 《Kosmos-G: Generating Images in Context with Multimodal Large Language Models》 github&#xff1a; https://github.com/microsoft/unilm/tree/master/kosmos-g 摘要 当…

朋友过生日送什么葡萄酒好呢

现在葡萄酒不但是活跃气氛、制造仪式感的酒精饮品&#xff0c;也是朋友之间礼尚往来的最佳礼品。有人问&#xff0c;朋友过生日送什么葡萄酒好呢&#xff1f;云仓酒庄的品牌雷盛红酒LEESON分享人们觉得红葡萄似乎太严肃&#xff0c;白葡萄酒颜色又太清淡&#xff0c;送一款什么…

pip安装到哪里

可以这样证明&#xff1a;

《QT从基础到进阶·二十六》绘制多个图形项(QGraphicsRectItem,QGraphicsLineItem,QGraphicsPolygonItem)

这个demo用QT实现了对多个图形项的绘制&#xff0c;包括矩形的绘制&#xff0c;直线的绘制和多边形的绘制&#xff0c;是之前一章中绘制矩形的增强版&#xff0c;之前一章节关于矩形的绘制可以参考&#xff1a;《QT从基础到进阶十五》用鼠标绘制矩形&#xff08;QGraphicsView、…

远程登录Linux方法(Linux平台相互远程;Windows远程登录Linux、远程编码、文件传输;无法远程登录的问题解决;c程序的编译)

在实际使用Linux系统过程中我们不可避免的需要远程登录Linux&#xff0c;这是因为未来大家使用Linux服务器的时候你所对应的那台Linux服务器不一定提供界面(服务器可能在外地)。本篇将会介绍远程登录Linux的方法。 文章目录 1. SSH介绍2. Linux平台相互远程及文件传输2.1 Linux…

准备搞OpenStack了,先装一台最新的Ubuntu 23.10

正文共&#xff1a;1113 字 25 图&#xff0c;预估阅读时间&#xff1a;2 分钟 依稀记得前面发了一篇Ubuntu的安装文档&#xff08;66%的经验丰富开发者和69%的学生更喜欢的Ubuntu的安装初体验&#xff09;&#xff0c;当时安装的是20.04.3的版本&#xff0c;现在看来已经是非常…

C语言数据结构-----栈和队列(概念,代码实现及简单练习)

前言 本篇主要介绍栈和队列的相关知识&#xff0c;练习以及代码实现。 代码主要展示部分功能的实现。完整代码在gitee上查看。 链接: 栈和队列的完整代码实现 文章目录 前言1.栈1.1 栈的概念及结构1.2 栈的实现1.3 栈的代码实现1.3.1 栈的初始化1.3.2 栈顶插入1.3.3 栈顶删除1…

若依框架修改包名报错

1.首先看下报错截图 启动GateWay 2.这个是因为 我改了里面的包名就是下面 ruoyi改成screen爆了上面的问题 3.那么关键的来了&#xff0c;我测了下 改了core不管启动gateway还是modules里面任何一个都会爆打不开工具类的问题 &#xff0c;我看了其他pom也没有引用core&#xff…

功能强大的国产API管理神器 Eolink,亲测好用

前言 大家好&#xff0c;我是小月&#xff0c;今天给大家讲讲最近很火的Eolink&#xff0c;一款功能强大且非常实用的国产 API管理工具。在我们日常的前端、后端开发测试过程中经常会用到API&#xff0c;特别是在大型项目中API管理工具也就必不可少。工欲善其事必先利其器&…

[模版总结] - 树的基本算法1 - 遍历

树结构定义 一种非线性存储结构&#xff0c;具有存储“一对多”关系的数据元素集合 种类 General Tree TrieB/B 树二叉树 满/完满/完全二叉树 完美BT : 除了叶子结点外所有节点都有两个字节点&#xff0c;每一层都完满填充完全BT&#xff1a; 除最后一层以外其他每一层都完美…

FaceBook登录提示密码错误的原因及解决方法

下面这一种类型的提示密码错误&#xff0c;大家首先能够想到的可能就是本身的账号密码有错误&#xff0c;但这个只代表其一。有一种情况的话&#xff0c;他可能根本不是账号或者密码的错误&#xff0c;他仅仅是因为注册的地方和登录的地方不太一样&#xff0c;也会造成这样的结…