STM32--系统滴答SysTick

news2024/11/16 23:34:37

一、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)
(3)时钟源选择—库函数( SysTick_CLKSourceConfig(时钟源)):

#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)重装载值—库函数( SysTick_Config(装载值))
SysTick_Config(72000) ;滴答定时器的参数是72000即计数72000。使用这个函数不需要预期值-1。直接设为预期值即可。(因为我们使用72M的时钟频率,即1s计数72M=72000000次,那1ms计数72000次,所以计数值为72000)

static __INLINE uint32_t SysTick_Config(uint32_t ticks)
{ 
  if (ticks > SysTick_LOAD_RELOAD_Msk)  return (1);            /* Reload value impossible */
                                                               
  SysTick->LOAD  = (ticks & SysTick_LOAD_RELOAD_Msk) - 1;      /* set reload register */
  NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1);  /* set Priority for Cortex-M0 System Interrupts */
  SysTick->VAL   = 0;                                          /* Load the SysTick Counter Value */
  SysTick->CTRL  = SysTick_CTRL_CLKSOURCE_Msk | 
                   SysTick_CTRL_TICKINT_Msk   | 
                   SysTick_CTRL_ENABLE_Msk;                    /* Enable SysTick IRQ and SysTick Timer */
  return (0);                                                  /* Function successful */
}

(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延时(参数)
{
   1.选择时钟 建议选择经过8分频后的外部时钟
   2.写入重装载值,设为预期值-13.清空计数器
   4。打开计数器
   5.等待时间到达,等待标志位置1
   6.关闭计数器
   7.清空计数器
}

具体代码:

//  uint32_t SystemCoreClock         = SYSCLK_FREQ_72MHz;        /*!< System Clock Frequency (Core Clock) */
void delay_init()
{
 
	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; 					//2.写入装载值  		 
	SysTick->VAL=0x00;        					//3.清空计数器(当前值)这里大家一定要注意,必须使得当前寄存器的值VAL等于0! SysTick->VAL  = (0x00);只有当VAL值为0时,计数器自动重载RELOAD。下面同理。
	SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ;	//4.打开计数器,开始倒数,使能  
	do
	{
		temp=SysTick->CTRL;
	}while((temp&0x01)&&!(temp&(1<<16)));		//5.等待时间到达   
	SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk;	//6.关闭计数器
	SysTick->VAL =0X00;      				    //7.清空计数器(当前值) 
}
void delay_ms(u16 nms)
{	 		  	  
	u32 temp;		   
	SysTick->LOAD=(u32)nms*ms_fac_num;				//时间加载(SysTick->LOAD为24bit)
	SysTick->VAL =0x00;							//清空计数器(当前值)
	SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ;	//开始倒数  
	do
	{
		temp=SysTick->CTRL;
	}while((temp&0x01)&&!(temp&(1<<16)));		//等待时间到达   
	SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk;	//关闭计数器
	SysTick->VAL =0X00;       					//清空计数器	  	    
} 

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

实现功能:每过1ms发送一次123456。

伪代码:

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

具体代码:

#include "SysTick.h"
u16 SysTick_us;
u16 SysTick_ms;
/*******************************
函数名:SysTick_Init
函数功能:初始化系统滴答,选择外部时钟
函数形参:u32 sysclk 系统时钟72(MHZ)
函数返回值:void
备注:开启1ms中断
********************************/
void SysTick_Init(u32 sysclk) //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 = SysTick_ms;//2.重装载值9000
	SysTick->VAL=0;    //3.清空计数器,清标志位
	SysTick->CTRL |=1<<1;   //4.使能中断 SysTick倒数计数到0时产生SysTick异常(中断)请求 */

/*-----------------------配置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寄存器	
	
	//NVIC_SetPriority(SysTick_IRQn,NVIC_EncodePriority(7-2,1,2));  // 5.配置NVIC控制器
	//NVIC_EnableIRQ(SysTick_IRQn);    
	SysTick->CTRL |=1<<0;   //6.使能定时器
}

void SysTick_Handler(void)
{
	if((SysTick->CTRL & 0x1 << 16))//检测标志位,也是清除标志位
	{
		printf("123456\r\n");
	}
}

六、附录:

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

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

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

相关文章

基于樽海鞘群算法优化概率神经网络PNN的分类预测 - 附代码

基于樽海鞘群算法优化概率神经网络PNN的分类预测 - 附代码 文章目录 基于樽海鞘群算法优化概率神经网络PNN的分类预测 - 附代码1.PNN网络概述2.变压器故障诊街系统相关背景2.1 模型建立 3.基于樽海鞘群优化的PNN网络5.测试结果6.参考文献7.Matlab代码 摘要&#xff1a;针对PNN神…

微信聊天,收到二维码图片就自动帮你提取出来的方法

10-3 如果你是二维码收集的重度用户&#xff0c;那我非常推荐你好好阅读本文&#xff0c;也许可以帮你解决你的问题&#xff0c;比如做网推的人&#xff0c;需要常年混迹在各种微信群&#xff0c;那如何在各个微信群中收集到群友分享出来的二维码&#xff0c;并且要立即保存出…

Pyside6/PYQT6如何实现无边框设计,解决无边框窗口无法移动的问题

文章目录 💢 问题 💢💯 解决方案 💯🍔 准备工作🐾 操作步骤🐾 窗口无边框🐾 窗口透明🐾 实现窗口可移动⚓️ 相关链接 ⚓️💢 问题 💢 有时候我们需要一个无边框的UI设计来实现/美化一些功能,如:制作一个桌面时钟,进度条展示等,要实现无边框其实很简…

基于springboot实现桥牌计分管理系统项目【项目源码】计算机毕业设计

基于springboot实现桥牌计分管理系统演示 JAVA简介 JavaScript是一种网络脚本语言&#xff0c;广泛运用于web应用开发&#xff0c;可以用来添加网页的格式动态效果&#xff0c;该语言不用进行预编译就直接运行&#xff0c;可以直接嵌入HTML语言中&#xff0c;写成js语言&#…

Liunx命令汇总

一.用户相关命令 1.1账号管理 创建用户&#xff1a; useradd &#xff08;选项&#xff09; 用户名用户口令&#xff1a; passwd &#xff08;选项&#xff09; 用户名修改用户&#xff1a; usermod 选项 用户名删除用户&#xff1a; userdel &#xff08;选项&#xff09; 用…

SpringBootWeb案例——Tlias智能学习辅助系统(3)——登录校验

前一节已经实现了部门管理、员工管理的基本功能。但并没有登录&#xff0c;就直接访问到了Tlias智能学习辅助系统的后台&#xff0c;这节来实现登录认证。 目录 登录功能登录校验(重点)会话技术会话跟踪方案一 Cookie&#xff08;客户端会话跟踪技术&#xff09;会话跟踪方案二…

微信支付服务商消费者投诉及时处理与商户违规及时通知,支持多服务商

大家好&#xff0c;我是小悟 微信直连商户处理消费者投诉的功能解决了很多商户对于投诉处理不及时而导致商户号出现异常的问题&#xff0c;可以说解决了实实在在的问题。 很多小伙伴私信说自己是服务商角色&#xff0c;也需要微信支付服务商处理消费者投诉的功能&#xff0c;…

ablation study

文章目录 ablation study1、消融实验思想是什么&#xff1f;2、消融实验意义3、消融实验应用场景举例 ablation study 1、消融实验思想是什么&#xff1f; “消融实验”&#xff08;ablation study&#xff09;通常指的是通过逐步移除系统的一部分来评估该系统的贡献。这种方法…

分享一下关于“vcruntime140_1.dll丢失的5种解决方法

今天我来给大家分享一下关于“vcruntime140_1.dll丢失的5种修复方法”的分享。首先&#xff0c;我们来了解一下vcruntime140_1.dll丢失的原因。 病毒感染&#xff1a;病毒或恶意软件可能损坏或删除vcruntime140_1.dll文件。 系统更新或软件安装&#xff1a;在进行系统更新或安…

使用.net 构建 Elsa Workflow

对接过蓝凌OA 也基于泛微OA数据库原型重新研发上线过产品&#xff0c;自研的开源的也上线过 每个公司对OA流程引擎介绍 都不一样的&#xff0c; 比如Elsa 这款微软MVP开源组件&#xff0c;基于跨平台开发的技术含量高&#xff0c;专门做OA的同行推过对应文章。 直接看怎么用吧。…

JavaScript逆向之Hook技术

Hook技术&#xff1a; 背景&#xff1a; ​ 在js逆向的过程种&#xff0c;当我们遇到加密参数&#xff0c;可以使用关键字全局搜素&#xff0c;跟栈&#xff0c;还有一种就是hook技术。跟栈就是比较麻烦&#xff0c;需要我们一个个找&#xff0c;hook技术就比较厉害了&#x…

Unity 使用INI文件存储数据或配置参数预设

法1&#xff1a;调用外部Capi库 具体使用&#xff1a; public class Ini{//读取INI文件需要调用C的APP[System.Runtime.InteropServices.DllImport("kernel32")]private static extern long WritePrivateProfileString(string section, string key, string val, st…

【数据结构初阶】顺序表

各位读者老爷好&#xff0c;又见面了哈&#xff01;鼠鼠我呀现在基于C语言浅浅介绍一下数据结构初阶中的顺序表&#xff0c;希望对你有所帮助&#xff01; 目录 1.线性表 2.顺序表 2.1概念即结构 2.2动态顺序表接口的实现 2.2.1定义顺序表 2.2.2初始化 2.2.3销毁 2.2…

kubenetes-容器运行时接口CRI

一、CRI 容器运行时&#xff08;Container Runtime&#xff09;&#xff0c;运行于Kubernetes&#xff08;K8s&#xff09; 集群的每个节点中&#xff0c;负责容器的整个生命周期。其中Docker是目前应用最广的。随着容器云的发展&#xff0c;越来越多的容器运行时涌现。 为了解…

UE特效案例 —— 角色刀光

目录 一&#xff0c;环境配置 二&#xff0c;场景及相机设置 三&#xff0c;效果制作 刀光制作 地裂制作 击打地面炸开制作 一&#xff0c;环境配置 创建默认地形Landscape&#xff0c;如给地形上材质需确定比例&#xff1b;添加环境主光源DirectionalLight&#xff0c;设…

电路综合-基于简化实频的SRFT集总参数切比雪夫低通滤波器设计

电路综合-基于简化实频的SRFT集总参数切比雪夫低通滤波器设计 6、电路综合-基于简化实频的SRFT微带线切比雪夫低通滤波器设计中介绍了使用微带线进行切比雪夫滤波器的设计方法&#xff0c;在此对集总参数的切比雪夫响应进行分析。 SRFT集总参数切比雪夫低通滤波器综合不再需要…

C语言——打印1000年到2000年之间的闰年

闰年&#xff1a; 1、能被4整除不能被100整除 2、能被400整除 #define _CRT_SECURE_NO_WARNINGS 1#include<stdio.h> int main() {int year;for(year 1000; year < 2000; year){if((year%4 0) && (year%100!0) || (year%400 0)){printf("%d ",ye…

算法之双指针

双指针算法的作用 双指针算法是一种使用2个变量对线性结构(逻辑线性/物理线性)&#xff0c;进行操作的算法&#xff0c;双指针可以对线性结构进行时间复杂度优化&#xff0c;可以对空间进行记忆或达到某种目的。 双指针算法的分类 1.快慢指针 2.滑动窗口 3.左右指针 4.前后指…

Keil文本对齐

摘要&#xff1a;通常我们写代码的时候&#xff0c;尤其是缩进和{}的使用&#xff0c;很多都需要自己手动去调整&#xff0c;如果有一个自动格式化代码的工具&#xff0c;每次编辑完代码&#xff0c;然后一键给将代码格式化&#xff0c;即省时又美观。为了解决这个问题&#xf…

红黑树,AVLTree树(平衡二叉树)迭代器原理讲解

红黑树&#xff0c;AVLTree树底层实现逻辑都是平衡二叉树&#xff08;AVLTree高度平衡&#xff0c;红黑树以某种规则平衡&#xff09;&#xff0c;但终究不像链表的迭代器那样逻辑简单。 简单叙述以下&#xff0c;二叉树上面迭代器的运行逻辑&#xff0c;根据下面的图&#xff…