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

news2024/11/29 22:56:10

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 header

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
}

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;                         //输出频率为2MHz
    GPIO_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.coloradmin.cn/o/1348432.html

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

相关文章

小兔鲜儿 uniapp - SKU 模块

目录 存货单位(SKU)​ 插件市场​ 下载 SKU 插件​ 使用 SKU 插件​ 插件类型问题​ 核心业务​ 渲染商品规格​ 打开弹窗交互​ 渲染被选中的值​ 存货单位(SKU)​ SKU 概念 存货单位(Stock Keeping Unit&a…

【教学类-43-11】 20231231 3*3宫格数独提取单元格坐标数字的通用模板(做成2*2=4套、3*2=6套)

背景需求: 1、以前做单元格填充,都是制作N个分开的单元格 (表格8) 2、这次做五宫格数独的Word模板,我图方便,就只用了一个大表格,第六行第六列隐藏框线,看上去就是分开的&#xff…

Linux | 解决问题Ubuntu重启无法进入系统以及网络无法连接【图文详解】

Ubuntu18.04重启无法进入系统,重开后如图 一直在加载系统内核4.15.0-213-generic,无法加载 错误原因 原本的系统是Ubuntu16.04,使用命令升级到Ubuntu18.04版本,升级重启后,远程无法连接! 错误解决 第一步:进入GRUB…

ZigBee案例笔记 - 无线点灯

文章目录 无线点灯实验概述工程关键字工程文件夹介绍Basic RF软件设计框图简单说明工程操作Basic RF启动流程Basic RF发送流程Basic RF接收流程 无线点灯案例无线点灯现象 无线点灯实验概述 ZigBee无线点灯实验(即Basic RF工程),由TI公司提供…

neovim调试linux内核过程中索引不到对应头文件问题

大家好,我叫徐锦桐,个人博客地址为www.xujintong.com,github地址为https://github.com/jintongxu。平时记录一下学习计算机过程中获取的知识,还有日常折腾的经验,欢迎大家访问。 一、环境 neovim–0.9.4 mason的clang…

中小微医院机构云服务(云HIS)平台源码

云HIS(Cloud-Based Healthcare Information System)重新定义了HIS,目标是为中小型医疗卫生机构提供优质经济的医疗卫生信息化产品及服务;是以健康档案为主线、以电子病历为核心、以云计算技术为基础的医疗卫生系统。云HIS作为基于…

GoogleNetv1:Going deeper with convolutions更深的卷积神经网络

文章目录 GoogleNetv1全文翻译论文结构摘要1 引言2 相关工作3 动机和高层考虑稀疏矩阵 4 结构细节引入1x1卷积核可以减少通道数 5 GoogleNet6 训练方法7 ILSVRC 2014 分类挑战赛设置和结果8 ILSVRC 2014检测挑战赛设置和结果9 总结 论文研究背景、成果及意义论文图表 GoogleNet…

【小沐学Python】Python实现免费天气预报获取(OpenWeatherMap)

文章目录 1、简介1.1 工具简介1.2 费用1.3 注册1.4 申请key 2、接口说明2.1 One Call 3.02.2 Current Weather and Forecasts collection2.2.1 API 调用2.2.2 API 参数 2.3 Historical Weather collection2.4 Weather Maps collection2.5 Other weather APIs 3、接口测试3.1 例…

无监督学习(下)

1.高斯混合模型(GMM) (1)简单概念 高斯混合模型是一种概率模型,它假定实例是由多个参数未知的高斯分布的混合生成的。从单个高斯分布生成的所有实例都形成一个集群,通常看起来像一个椭圆。每个集群都可以由不同的椭圆形状,大小,密…

【C# 技术】 C# 常用排序方式——自定义数据排序

C# 常用排序方式——自定义数据排序 前言 在最近的项目中经常会对C#中的数据进行排序,对于基本数据类型,其排序方式比较简单,只需要调用内置算法即可实现,但对于自定义数据类型以及自定义排序规则的情况实现起来就比较麻烦&…

美团到店终端从标准化到数字化的演进之路

总第580篇 | 2023年第032篇 本文整理自美团技术沙龙第76期《大前端研发协同效能提升与实践》。前端团队在产研多角色协同形式上存在不同阶段,而大前端多技术栈在各阶段都有其独特的实践,同时又有类似的演进路线。本文从到店终端团队移动端和前端技术栈持…

最详细GIT学习笔记

1. Git简介 1.1. Git介绍 Git(读音为/gɪt/) 是一个开源的分布式版本控制系统,可以有效、高速地处理从很小到非常大的项目版本管理。 Git 是 Linus Torvalds 为了帮助管理 Linux 内核开发而开发的一个开放源码的版本控制软件。 1.2. 主流的版本控制器 Git(分布式…

金融帝国实验室(Capitalism Lab)官方正版游戏『2024新年特卖优惠』

「金融帝国实验室」(Capitalism Lab)Enlight 官方正版游戏「2024新年特卖」 ■优惠时限:2024.01.01~01.31 ■游戏开发商:Enlight Software Ltd. 请您认准以下官方正版游戏购买链接:支持“支付宝&am…

【数据结构-单链表】(C语言版本)

今天分享的是数据结构有关单链表的操作和实践(图解法,图变化更利于理解) 记录宗旨📝: 眼(脑)过千遍,不如手过一遍。 我们都知道单链表是一种常见的链表数据结构,由一系列…

【Delphi】IOS上架踩坑记 - 2024年第一天

目录 一、前言: 二、IOS程序上架网址 三、踩坑记 1. 关于版本中的 CFBundleIdentifier 参数(Transporter 提示) 2. IOS APP 程序图标要求(Transporter 提示) 3. 关于版本中的 CFBundleShortVersionString 参数&a…

小波理论与应用:理解小波

1 简介 来自源的信号通常处于时域。例如正弦信号、生物医学信号等。任何时域信号都可以使用数学变换进行处理或变换到频域(谱域)。傅里叶变换是一种流行或著名的变换,它将时域信号转换为频域信号,而不失一般性。 在绘制时域信号…

智能客服系统要素分析:提升客户满意度与工作效率的关键要素

智能客服系统是企业建立完善服务框架的重要工具。市面上存在着形态各异的各种客服系统,如何选择一款最适合自己企业的产品是很多采购人员想知道的问题。事实上,不同的智能客服系统之间的主要功能并未存在太大的区别,它们往往会在一些亮点功能…

m系列mac配置Tomcat

配置上走了些弯路 翻了不少博客各有各的说法,此说明是本人亲自尝试,电脑是m芯片mbp如果不是mac系统,勿跟风尝试 一、下载和安装Tomcat 1.下载 首先,打开Tomcat官网:https://tomcat.apache.org,选择Downlo…

oracle 9i10g编程艺术-读书笔记1

根据书中提供的下载代码链接地址,从github上找到源代码下载地址。 https://github.com/apress下载好代码后,开始一段新的旅行。 设置 SQL*Plus 的 AUTOTRACE 设置 SQL*Plus 的 AUTOTRACE AUTOTRACE 是 SQL*Plus 中一个工具,可以显示所执行…

计算机网络物理层 习题答案及解析

2-1 下列选项中,不属于物理层接口规范定义范畴的是( D )。 A. 引脚功能 B. 接口形状 C. 信号电平 D. 传输媒体 【答案】D 【解析】 2-2 某网络在物理层规定,信号的电平范围为- 15V~15V , 电线长…