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.rhkb.cn/news/190425.html

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

相关文章

基于Qt 多线程(继承自QThread篇)

# 简介 我们写的一个应用程序,应用程序跑起来后一般情况下只有一个线程,但是可能也有特殊情况。比如我们前面章节写的例程都跑起来后只有一个线程,就是程序的主线程。线程内的操作都是顺序执行的。恩,顺序执行?试着想一下,我们的程序顺序执行,假设我们的用户界面点击有某…

JavaScript_动态表格_删除功能

1、动态表格_删除功能 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>动态表格_添加和删除功能</title><style>table{border: 1px solid;margin: auto;width: 100%;}td,th{text-align: …

网络渗透测试(被动扫描)

被动扫描 主要是指的是在目标无法察觉的情况下进行信息搜集。在Google上进行人名的搜素就是一次被动扫描。最经典的被动扫描技术就是"Google Hacking"技术。由于Google退出中国&#xff0c;暂时无法使用。在此介绍三个优秀的信息搜集工具 被动扫描范围 1.企业网络…

Kafka入门

kafka无疑是当今互联网公司使用最广泛的分布式实时消息流系统&#xff0c;它的高吞吐量&#xff0c;高可靠等特点为并发下的大批量实时请求处理提供了可靠保障。很多同学在项目中都用到过kafka&#xff0c;但是对kafka的设计原理以及处理机制并不是十分清楚。为了知其然知其所以…

k8s-docker二进制(1.28)的搭建

二进制文件-docker方式 1、准备的服务器 角色ip组件k8s-master1192.168.11.111kube-apiserver,kube-controller-manager,kube-scheduler,etcdk8s-master2192.168.11.112kube-apiserver,kube-controller-manager,kube-scheduler,etcdk8s-node1192.168.11.113kubelet,kube-prox…

Presentation Prompter 5.4.2(mac屏幕提词器)

Presentation Prompter是一款演讲辅助屏幕提词器软件&#xff0c;旨在帮助演讲者在公共演讲、主持活动或录制视频时更加流畅地进行演讲。以下是Presentation Prompter的一些特色功能&#xff1a; 提供滚动或分页显示&#xff1a;可以将演讲稿以滚动或分页的形式显示在屏幕上&a…

client-go controller-runtime kubebuilder

背景 这半年一直做k8s相关的工作&#xff0c;一直接触client-go controller-runtime kubebuilder&#xff0c;但是很少有文章将这三个的区别说明白&#xff0c;直接用框架是简单&#xff0c;但是出了问题就是黑盒&#xff0c;这不符合我的理念&#xff0c;所以这篇文章从头说起…

【Android】画面卡顿优化列表流畅度三之RecyclerView刷新机制notifyItemRangeInserted

经过长达一个多星期的反复渲染耗时记录&#xff0c;大致上有以下几个方面的地方可以优化&#xff1a; 列表组件RecyclerView刷新机制由notifyDataSetChanged()优化为notifyItemRangeInserted&#xff08;&#xff09;&#xff0c;后期有必要也会使用notifyItemRangeRemoved、n…

uniapp发行web页面在老版本浏览器打开一片空白

uniapp发行的web页面&#xff08;菜单->发行->网站-PC Web或手机H5&#xff09;&#xff0c;对于一些老的浏览器&#xff08;或内核&#xff09;&#xff0c;打开一片空白&#xff1b; 而在新版本的浏览器中打开却正常。这是因为那些版本较低的浏览器不支持ES6的语法和新…

mapboxGL中的底图切换

概述 底图切换&#xff0c;这么简单的功能还要写一篇文章&#xff1f;值得的&#xff0c;为什么这么说呢&#xff1f;因为mapboxGL的矢量底图有上百个&#xff0c;不同的底图用的样式、图层的名称、图层的内容、字体库、图标库都不一样&#xff0c;尤其是当地图上已经叠加了很…

vue 使用js new Map()优化多个if else 执行方法

前言 在实际开发中根据业务需求我们经常要判断情况&#xff0c;一个if 我们科技直接使用ES6就可以解决 经常会出现根据不同的条件执行不同的方法&#xff0c;这是就会有多个if else 看起不太美观也费劲 js new map &#xff08;&#xff09;就可以解决这个问题&#xff0c;它…

linux下搭建gperftools工具分析程序瓶颈

1. 先安装 unwind //使用root wget https://github.com/libunwind/libunwind/archive/v0.99.tar.gz tar -xvf v0.99.tar.gz cd libunwind-0.99 autoreconf --force -v --install ./configure make sudo make install2. 安装gperftools wget https://github.com/gp…

【无标题(PC+WAP)花卉租赁盆栽绿植类pbootcms站模板

(PCWAP)花卉租赁盆栽绿植类pbootcms网站模板 PbootCMS内核开发的网站模板&#xff0c;该模板适用于盆栽绿植网站等企业&#xff0c;当然其他行业也可以做&#xff0c;只需要把文字图片换成其他行业的即可&#xff1b; PCWAP&#xff0c;同一个后台&#xff0c;数据即时同步&…

纯c语言模拟栈和队列(初学必看)

一、栈(Stack) 1.栈的概念及其结构 栈是一种特殊的线性表&#xff0c;在栈这个结构里&#xff0c;越先存进去的数据越难取出来。 这个结构就像是一个只有一端有打开的容器&#xff0c;越先放进去的球越在底部&#xff0c;想要把底部的球拿出来&#xff0c;就必须先把前面的求…

【Pytest】跳过执行之@pytest.mark.skip()详解

一、skip介绍及运用 在我们自动化测试过程中&#xff0c;经常会遇到功能阻塞、功能未实现、环境等一系列外部因素问题导致的一些用例执行不了&#xff0c;这时我们就可以用到跳过skip用例&#xff0c;如果我们注释掉或删除掉&#xff0c;后面还要进行恢复操作。 1、skip跳过成…

Spring IOC - Bean的生命周期之实例化

在Spring启动流程文章中讲到&#xff0c;容器的初始化是从refresh方法开始的&#xff0c;其在初始化的过程中会调用finishBeanFactoryInitialization方法。 而在该方法中则会调用DefaultListableBeanFactory#preInstantiateSingletons方法&#xff0c;该方法的核心作用是初始化…

元核云亮相金博会,智能质检助力金融合规

11月初&#xff0c;第五届中新&#xff08;苏州&#xff09;数字金融应用博览会&#xff5c;2023金融科技大会在苏州国际博览中心举办&#xff0c;围绕金融科技发展热点领域及金融行业信息科技领域重点工作&#xff0c;分享优秀实践经验&#xff0c;探讨数字化转型路径与未来发…

蓝桥杯每日一题2023.11.8

题目描述 题目分析 对于输入的abc我们可以以a为年也可以以c为年&#xff0c;将abc,cab,cba这三种情况进行判断合法性即可&#xff0c;注意需要排序去重&#xff0c;所以考虑使用set 此处为纯模拟的写法&#xff0c;但使用循环代码会更加简洁。 方法一&#xff1a; #include&…

物联网AI MicroPython学习之语法 network网络配置模块

学物联网&#xff0c;来万物简单IoT物联网&#xff01;&#xff01; network介绍 模块功能&#xff1a; 用于管理Wi-Fi和以太网的网络模块参考用法&#xff1a; import network import time nic network.WLAN(network.STA_IF) nic.active(True) if not nic.isconnected():…

SplayTree高分测试用例

测试用例结果展示 覆盖率 变异得分 测试注意点 从SplayTree测起&#xff0c;然后再测SubSplayTree&#xff0c;因为前者调用后者。SplaySubTree的remove方法大部分内容需要通过反射才能测到。value和index在SplayTree当中都不是唯一的。一个index可能对应多个value。 不足之…