STM32--系统滴答SysTick

一、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  1msSysTick->LOAD = nus*SysTick_ms-1;//2.重装载值9000-1SysTick->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.mzph.cn/news/140664.shtml

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

相关文章

Notepad++,搜索窗口独立后,恢复

双击一下find result框&#xff0c;恢复到原来的模式。

Apipost IDEA插件如何使用

Apipost-Helper是由Apipost推出的IDEA插件&#xff0c;写完接口可以进行快速调试&#xff0c;且支持搜索接口、根据method跳转接口&#xff0c;还支持生成标准的API文档&#xff0c;注意&#xff1a;这些操作都可以在代码编辑器内独立完成&#xff0c;非常好用&#xff01;这里…

docker/ nvidia-docker

参考资料&#xff1a;https://www.cnblogs.com/zzcit/p/5845717.html 本文档说明下列系统下安装nvidia-docker Ubuntu Trusty 14.04 (LTS)Ubuntu Xenial 16.04 (LTS) 安装docker 更新apt源 更新安装包信息 sudo apt-get update sudo apt-get install apt-transport-http…

Selenium+Python自动化测试环境搭建

selenium python 自动化测试 —— 环境搭建 关于 selenium Selenium 是一个用于Web应用程序测试的工具。Selenium测试直接运行在浏览器中&#xff0c;就像真正的用户在操作一样。支持的浏览器包括IE(7、8、9)、Mozilla Firefox、Mozilla Suite等。 Selenium 框架底层使用JavaS…

独立站商品信息是怎么获取的呢

独立站商品信息的获取主要通过以下几种方式&#xff1a; 人工收集&#xff1a;卖家可以通过在各个电商平台、网站等渠道进行手动搜索和收集商品信息&#xff0c;包括商品名称、价格、描述、图片等&#xff0c;然后将其导入到自己的独立站中。使用采集工具&#xff1a;目前市面…

初阶JavaEE(17)Linux 基本使用和 web 程序部署

接上次博客&#xff1a;初阶JavaEE&#xff08;16&#xff09;博客系统&#xff08;Markdown编辑器介绍、博客系统功能、博客系统编写&#xff1a;博客列表页 、博客详情页、实现登录、实现强制登录、显示用户信息、退出登录、发布博客&#xff09;-CSDN博客 目录 Linux 基本…

PyCharm鼠标控制字体缩放

File->Settings->Keymap 右边搜索栏输入increase(放大)&#xff0c;可以看到下面出现increase Font Size(放大字体尺寸)&#xff0c;双击。 双击后出现几个选项&#xff0c;选择Add Mouse Shortcut,会出现一个页面给录入动作。 按住Ctrl同时鼠标向上滚动&#xff0c;该动…

[vim]Python编写插件学习笔记1 - 开始

0 环境 Windows 11 22H2gVim82 (D:/ProgramFiles/Vim)Python311 (D:/ProgramFiles/Python311)Vundle v0.10.2 1 Vim 支持 Python gVim82 默认配置中&#xff0c;使用的是 Python3.8。 但我的环境安装的是 Python3.11&#xff0c;且不是安装在默认路径下。虽然添加了 PATH 环…

Vite探索:构建、启程、原理、CSS艺术与插件魔法

文章目录 1 构建工具1.1 什么是构建工具1.2 主流构建工具1.3 vite相较于webpack的优势 2 vite启动项目初体验2.1 你必须要理解的vite脚手架和vite2.2 vite开箱即用2.3 vite的预加载2.4 vite配置文件处理细节2.5 vue环境变量配置 3 vite 原理篇3.1 vite是怎么让浏览器可以识别.v…

双十一“静悄悄”?VR购物拉满沉浸式购物体验

以往每年的双十一&#xff0c;都会因为电商购物狂欢而变得热闹非凡&#xff0c;而各大电商平台也会在这天推出各种促销活动。但是&#xff0c;近几年来&#xff0c;双十一正在变得“静悄悄”。一个原因是消费群体越发理性消费&#xff0c;更加重视商品本身的质量和体验&#xf…

java8函数式编程(Lambda表达式,Optional,Stream流)从入门到精通

文章目录 函数式编程Lambda表达式Stream流创建流中间操作终结操作注意事项 Optional创建对象消费值获取值过滤判断数据转换 方法引用高级用法基本数据类型优化并行流 函数式编程 不关心具体的对象&#xff0c;只关心数据参数和 具体操作 Lambda表达式 格式&#xff1a; () -&…

软考绩效域启迪论文

请点击↑关注、收藏&#xff0c;本博客免费为你获取精彩知识分享&#xff01;有惊喜哟&#xff01;&#xff01; 论干系人绩效域 XX年X月&#xff0c;我作为项目经理参与了XX省人力资源与社会保障厅事业单位人员信息滚轮系统的建设项目&#xff08;以下简称人社厅&#xff09;…

深度学习(生成式模型)——Classifier Guidance Diffusion

文章目录 前言问题建模条件扩散模型的前向过程条件扩散模型的反向过程条件扩散模型的训练目标 前言 几乎所有的生成式模型&#xff0c;发展到后期都需要引入"控制"的概念&#xff0c;可控制的生成式模型才能更好应用于实际场景。本文将总结《Diffusion Models Beat …

【TiDB】TiDB CLuster部署

目录 0 大纲 一 集群部署工具TiUP简介 1 TiUP 简介 2 TiUP使用 3 TiUP使用举例 二 TiDB Cluster安装配置需求 1 生产环境硬件需求 2 操作系统需求 三 TIDB部署 1 软硬件需求以及前置检查​编辑 2 安装TiUP 组件 ​3 集群拓扑文件 4 执行部署命令 &#xff08;1&…

[Hive] CTE 通用表达式 WITH关键字

在Hive中&#xff0c;CTE代表的是Common Table Expression&#xff08;通用表达式&#xff09;&#xff0c;这是一种SQL语句结构&#xff0c;使用WITH关键字定义的子句。 文章目录 CTE递归 CTE将多个CTE&#xff08;公共表表达式&#xff09;写在同一个SQL文件中 CTE CTE提供…

视频号小店怎么做?运营四步骤,快来学习!

大家好&#xff0c;我是电商糖果 2023年因为视频号小店的爆火&#xff0c;想尝试开店的朋友也不少。 但是因为自己是新手小白&#xff0c;对做电商方面了解的也并不多&#xff0c;再加上它是一个才出来一年多的电商平台。对它的很多规则和玩法并不清楚。 所以&#xff0c;这…

MoSe2 二硒化钼 CAS:12058-18-3 瑞禧分享

MoSe2二硒化钼 纯度:4N 99.99%-99.999% 英文名称:Molybdenum Selenide CAS&#xff1a;12058-18-3 分子式为MoSe2.分子量为253.86 灰色粉末,具有层状性质,具有半导体性质。 技术对接:高温高压真空熔炼,处理后进行热扩散 瓶装,1kg/瓶,外加铝复合薄膜真空包装 用途:科研,…

flutter实现视频播放

使用到的库是lecle_yoyo_player 详细请查看文档 main.dart代码如下&#xff1a; import package:flutter/material.dart; import package:lecle_yoyo_player/lecle_yoyo_player.dart;void main() > runApp(const MyApp());class MyApp extends StatefulWidget {const MyA…

如何实现 promise.map,限制 promise 并发数

实现一个带有并发限制的Promise.map函数&#xff0c;可以使用async/await和Promise的特性来管理并发数。 function promiseMap(array, mapper, concurrencyLimit) {return new Promise((resolve, reject) > {const results [];let currentIndex 0;let activeCount 0;asy…

竞赛选题 深度学习的口罩佩戴检测 - opencv 卷积神经网络 机器视觉 深度学习

文章目录 0 简介1 课题背景&#x1f6a9; 2 口罩佩戴算法实现2.1 YOLO 模型概览2.2 YOLOv32.3 YOLO 口罩佩戴检测实现数据集 2.4 实现代码2.5 检测效果 3 口罩佩戴检测算法评价指标3.1 准确率&#xff08;Accuracy&#xff09;3.2 精确率(Precision)和召回率(Recall)3.3 平均精…