【STM32F103】SysTick系统定时器延时函数

SysTick

SysTick是Cortex-M3内核中的一个外设,内嵌在NVIC中,叫系统定时器。

当处理器在调试期间被喊停时,SysTick也将暂停运作。

一共有四个寄存器,不过我们通常用前三个,不需要校准。下图出自《STM32F10xxx Cortex-M3编程手册》第237页。

CTRL寄存器

第一个CTRL寄存器可用的一共有四个位。

第0位是SysTick的使能为,为1则使能。

第1位是SysTick的异常请求标志位,为1则会触发异常也就是中断使能,Cortex-M3处理器专门为SysTick开出了一个异常类型,也就是说它也在中断向量表中。由于SysTick属于内核外设,因此并没有抢占优先级和响应优先级的概念,一般我们也不使用SysTick中断,但是非要的话也是可以的,我们需要去操作SHPR3这个寄存器,并且这个寄存器只能通过字节访问。

从上图可知这个寄存器的第24位到第31位是给SysTick使用的,不过在STM32F103中,有效的仅是第28位到第31位这高4位有效,因此拥有16位可编程优先级,数值越小优先级越高。

更具体的SysTick中断还需自行查阅资料。

第2位是时钟源选择位,为0则AHB/8,即系统时钟SYSCLK经过AHB预分频器进行8分频(72MHz/8=8MHz),为1则是AHB进行1分频(72MHz/1=72MHz)。

第16位是计数的标志位,如果上次处理器读取到计数器已经计到了0,那么将此为置为1,我们可以通过读取此位来得知一轮计数是否结束。

LOAD寄存器&VAL寄存器

第二个LOAD寄存器是重装寄存器,也就是说计数器记到0之后,会给计数器重新赋值,赋的值就是从这个寄存器取出的。

第三个VAL寄存器就是计数器了,是向下递减的计数器。时钟源每触发一次则记一次(减一次)数,到0则会发出异常请求(如果有设置的话),并且重装计数值。

我们可以知道,重装寄存器和计数器都是24位的,因此能记的最大次数就是2^24(16777216),最大数值为2^24-1(16777215,0xFFFFFF),要注意不能超出最大数值。

固件库函数实现延时效果

以SysTick开头的函数就两个,不过因为SysTick是内嵌到NVIC的,所以以NVIC_SysTick开头的函数还有两个,不过我们用不着,因此仅介绍两个函数就够实现延时效果了,实际上一个就够了。

SysTick_Config

我们使用这个函数就可以对SysTick初始化并且赋上重装寄存器的值。

我们固件库函数的内容比较简单,我们可以简单分析一下,也有助于加深理解。

这个函数需要一个参数,这个参数就是用来设置重装计数器的值的。

库函数的第一行就是用来检验这个参数是否合法的,因为我们之前分析过了,重装寄存器和计数器都是24位的,因此可以赋的最大数值就是16777215,0xFFFFFF。

可以看到第一行检验参数使用的宏定义也是符合我们分析的,其中宏定义中的宏定义SysTick_LOAD_RELOAD_Pos为0,也就是没有任何效果(我也不知道它存在的意义何在)。

库函数的第二行就是将参数赋给重装寄存器。

第三行设置中断优先级的,我们用不着可以不管它。

第四行是将计数器清零的。

第五行设置CTRL寄存器,我们可以看出库函数默认将CTRL寄存器的三个位置1,除了第16位都置1了,也就是说库函数默认使用AHB1分频(72MHz)作为时钟源,并且默认开启异常请求。

调用这个函数之后,我们就成功的让SysTick系统定时器开始运行了,时钟源每来一个脉冲,计数器就向下递减一个数,减到0之后再通过重装寄存器来给计数器赋值。

如果我们需要1us的延时函数,那么调用下面这段代码即可实现SysTick每计数一轮就是1us。

SysTick_Config(SystemCoreClock/1000000);

其中SystemCoreClock是一个宏定义,也就是AHB的大小。也就是说每秒时钟源都会有那么多次的脉冲,计数器也会记那么多个数,我们将这个数除10^6,得到的数就是每us的脉冲次数,这样就可以让SysTick记1us的时间了。

对于我们STM32F103来说写上72000000也是一样的,不过不便于移植修改,例如如果我们修改了处理器的主频,那么就需要对这个数值进行修改,但如果写的是宏定义的话则不需要修改(虽然一般没事也不会修改主频)。

不过目前为止我们还只是让SysTick启动了起来,我们该如何知道SysTick计数完了一轮呢。

我们可以通过查询CTRL寄存器的第16位来知道是否计数一轮,处理器一旦查询到了SysTick的计数器为0之后,就会将CTRL的第16位置1,因此我们开启SysTick之后,只需要使用whlie循环查询CTRL的第十六位即可。

当我们延时了我们想要的时间之后还需要将SysTick关闭,这时候只需要把CTRL寄存器的第0位使能位置0即可。

至此,我们就可以完成us级的延时函数了,具体可以参考下面的代码,如果要实现ms和s级别的延时函数,可以调用10^3次和10^6次us的延时函数。其中ms延时可以修改传给SysTick_Config的参数,将原本的SystemCoreClock/1000000修改为SystemCoreClock/1000即可,但是s延时就不能用类似的方法了,因为超过了计数器可以记的最大值,但可以通过调用10^3次ms延时来实现。

void delay_us(uint32_t us){//SysTick_Config(72000000/1000000);         //不便移植SysTick_Config(SystemCoreClock/1000000);    //固件库函数初始化+设置重装值while(us--){while(!((SysTick->CTRL)&(SysTick_CTRL_COUNTFLAG))); //不断查询计数标志位}SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk;    //关闭SysTick
}

SysTick_CLKSourceConfig

第二个函数就是这个用来修改时钟源的函数了,一般我们就使用库函数默认的AHB,不过想要修改的话也是可以事后改掉的。

使用AHB1分频(72MHz)为时钟源就传入SysTick_CLKSource_HCLK。

使用AHB8分频(8MHz)为时钟源就传入SysTick_CLKSource_HCLK_Div8。

LED闪烁&延时函数

#include "stm32f10x.h"                  // Device headervoid delay_us(uint32_t us){//SysTick_Config(72000000/1000000);         //不便移植SysTick_Config(SystemCoreClock/1000000);    //固件库函数初始化+设置重装值while(us--){while(!((SysTick->CTRL)&(SysTick_CTRL_COUNTFLAG))); //不断查询计数标志位}SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk;    //关闭SysTick
}void delay_ms(uint32_t ms){while(ms--) delay_us(1000);        
}void delay_s(uint32_t s){while(s--) delay_ms(1000);
}int main(void){RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);    //打开GPIO口的外设时钟GPIO_InitTypeDef itd;               itd.GPIO_Mode=GPIO_Mode_Out_PP;                         //设置为推挽输出模式itd.GPIO_Pin=GPIO_Pin_0;                                //指定0号引脚itd.GPIO_Speed=GPIO_Speed_2MHz;                         //输出频率为2MHzGPIO_Init(GPIOA,&itd);                                  //初始化while(1){                                               //LED闪烁GPIO_ResetBits(GPIOA,GPIO_Pin_0);                   //设置低电平delay_s(1);                                         //延时一秒GPIO_SetBits(GPIOA,GPIO_Pin_0);                     //设置高电平delay_s(1);}
}

 接线&效果

参考:

《STM32F103xx固件函数库用户手册》

《STM32F10xxx Cortex-M3编程手册》

《STM32库开发实战指南(基于STM32F103)》

《ARM Cortex-M3嵌入式原理及应用(基于STM32F103微控制器)》

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

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

相关文章

关于SIC 的Know-how

SiC的分类和用途 根据电阻率不同,SiC衬底晶片可分为导电型和半绝缘型。 SiC衬底晶片主要用来做成高压功率器件和高频功率器件。其中,导电型SiC衬底晶片经过SiC外延后(SiC基SiC外延片),主要应用于制造耐高温、耐高压的…

72内网安全-域横向CSMSF联动及应急响应知识

拿到才行,拿不到就是多余的 案例一MSF&CobaltStrike 联动 Shell 有一些功能可能cs或者msf强大一些,他们两个可以相互调用,在真实情况下也是可以cs和msf同时启动的, cs移交给msf .创建Foreign监听器 “Listeners”“Add”…

蓝桥杯一维差分 | 算法基础

⭐简单说两句⭐ ✨ 正在努力的小新~ 💖 超级爱分享,分享各种有趣干货! 👩‍💻 提供:模拟面试 | 简历诊断 | 独家简历模板 🌈 感谢关注,关注了你就是我的超级粉丝啦! &…

Python-docx 深入word源码 带有序号的段落无法设置段后、段前距离、间距等段落属性

如果使用p doc.add_paragraph(内容, styleList Number)来创建序号段落,会发现设置序号段落之间的段前、段后以及段落间距无法生效。后来将docx库生成的word文档打开后发现段落的设置出现问题,如下图红框所示,将该选项去掉即可使段落间距属性…

【AIGC-图片生成视频系列-4】DreamTuner:单张图像足以进行主题驱动生成

目录 一. 项目概述 问题: 解决: 二. 方法详解 a) 整体结构 b) 自主题注意力 三. 文本控制的动漫角色驱动图像生成的结果 四. 文本控制的自然图像驱动图像生成的结果 五. 姿势控制角色驱动图像生成的结果 2023年的最后一天,发个文记录…

迈向通用异常检测和理解:大规模视觉语言模型(GPT-4V)率先推出

PAPERCODEhttps://arxiv.org/pdf/2311.02782.pdfhttps://github.com/caoyunkang/GPT4V-for-Generic-Anomaly-Detection 图1 GPT-4V在多模态多任务异常检测中的综合评估 在这项研究中,我们在多模态异常检测的背景下对GPT-4V进行了全面评估。我们考虑了四种模式&#…

BikeDNA(二) OSM数据的内在分析1

BikeDNA(二) OSM数据的内在分析1 该笔记本分析给定区域的 OSM 自行车基础设施数据的质量。 质量评估是“内在的”,即仅基于一个输入数据集,而不使用外部信息。 对于将 OSM 数据与用户提供的参考数据集进行比较的外在质量评估&…

mysql原理--optimizer trace表的神器功效

1.概述 设计 MySQL 的大叔提出了一个 optimizer trace 的功能,这个功能可以让我们方便的查看优化器生成执行计划的整个过程,这个功能的开启与关闭由系统变量 optimizer_trace 决定。 如果想打开这个功能,必须首先把 enabled 的值改为 on &am…

力扣回溯算法-电话号码的字母组合

力扣第17题,电话号码的字母组合 题目 给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。 给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。 .电话号码的字母组合 示例: 输入:“2…

lv14 注册字符设备 3

1 注册字符设备 1.1 结构体介绍 struct cdev {struct kobject kobj;//表示该类型实体是一种内核对象struct module *owner;//填THIS_MODULE,表示该字符设备从属于哪个内核模块const struct file_operations *ops;//指向空间存放着针对该设备的各种操作函数地址str…

2023-12-17 LeetCode每日一题(使用最小花费爬楼梯)

2023-12-17每日一题 一、题目编号 746. 使用最小花费爬楼梯二、题目链接 点击跳转到题目位置 三、题目描述 给你一个整数数组 cost ,其中 cost[i] 是从楼梯第 i 个台阶向上爬需要支付的费用。一旦你支付此费用,即可选择向上爬一个或者两个台阶。 你…

宠物猫的饲养技术,可爱猫的秘密世界

一、教程描述 从来没有养过猫的朋友,在你猫咪来你家之前,最基本的准备工作需要做好,比如清洁消毒屋子,为猫咪准备好猫砂、猫砂盆、猫粮(不要去超市买猫粮),以及一个柔软的窝。满三个月的小猫要…

Linux 安装 mysql 【使用 tar.gz | tar.xz安装包-离线安装】

一、以tar.xz压缩包为安装源 网址:https://downloads.mysql.com/archives/community/ 二、解压压缩包 首先,将压缩包从windows传输到linux上 解压到/usr/local下,并且将解压的目录名称改为mysql tar -xvf /tmp/mysql-8.1.0-linux-glibc2.2…

【JVM】一文掌握JVM垃圾回收机制

作为Java程序员,除了业务逻辑以外,随着更深入的了解,都无法避免的会接触到JVM以及垃圾回收相关知识。JVM调优是一个听起来很可怕,实际上很简单的事。 感到可怕,是因为垃圾回收相关机制都在JVM的C++层实现,我们在Java开发中看不见摸不着;而实际很简单,是因为它说到底,也…

[密码学]ECC加密

椭圆曲线加密 Ellipse Curve Cryptography 椭圆曲线上的离散对数问题 Ellipse Curve Discrete logarithm Problem 椭圆曲线 注意积分公式的分母,椭圆曲线由此得名。这种曲线和椭圆一点不像。 离散对数: yg^x mod p,对于给定的g,x,p求y很容易&#…

操作系统期末复习

分段存储管理方式 某采用段式存储管理的系统为装入主存的一个作业建立了如下段表: 段号 段长 主存起始地址 0 660 210 1 140 3300 2 100 90 3 580 1237 4 960 1959 (1)计算该作业访问[0,432],[1&am…

什么是缓存、为什么要用缓存、缓存分类、缓存测试、缓存更新、缓存设计考虑点、缓存测试点

一、缓存 缓存是一种将数据存储在高速缓存中的技术,它可以提高应用程序的性能和响应速度。 二、 为什么要用缓存 1. 高性能(主要目的) 查询耗时,但变化少,又有很多读请求情况下,可以将查询结果放到缓存中。减少对数据库的压力&…

Python实现【亚马逊商品】数据采集

前言 亚马逊公司,是美国最大的一家网络电子商务公司,位于华盛顿州的西雅图 是网络上最早开始经营电子商务的公司之一,亚马逊成立于1994年 今天教大家用Python批量采集亚马逊平台商品数据(完整代码放在文末) 地址&#…

应对服务器CPU占用持续性变高的解决办法

​  在服务器的使用过程中,高CPU使用率是一个常见的问题,一般是由于遇到大量流量,进程需要更多时间来执行或通过网络发送和接收大量网络数据包时,CPU使用率可能会急剧增加,严重时可能会影响到网络的性能和稳定性。因…

保护Word或Excel的几种方法,总有一种满足你的需求

你已经在Microsoft Word或Excel中创建了一个重要或机密文件,你希望将其保密或至少保持安全。也许你想确保只有你和某些人可以阅读或编辑它。也许你想限制某人可以对文件进行的修改类型。你甚至可以向读者保证这是最终版本。如果你知道在Word和Excel中使用哪些工具以及它们是如…