我在高职教STM32——时钟系统与延时控制(2)

        大家好,我是老耿,高职青椒一枚,一直从事单片机、嵌入式、物联网等课程的教学。对于高职的学生层次,同行应该都懂的,老师在课堂上教学几乎是没什么成就感的。正因如此,才有了借助 CSDN 平台寻求认同感和成就感的想法。在这里,我准备陆续把自己花了很多心思的教学设计分享出来,主要面向广大师生朋友,单片机老鸟就略过吧。欢迎点赞+关注,各位的支持是本人持续输出的动力,多谢多谢!

        众所周知,衡量一款处理器的性能,最重要的一个指标就是主频,对于STM32来说也不例外。主频的背后其实是一套复杂的时钟系统,而这套系统关乎所有外设的工作。因此,在我们继续深入学习之前,有必要了解STM32时钟系统的脉络,进而才能理解所有跟时间有关的机制和配置。其实,一开始我们用到的delay延时功能就是通过配置时钟系统实现的,现在是时候对它一探究竟了。

【学习目标】

  1. 认识STM32的系统时钟树,理解时钟的产生过程;
  2. 了解系统时钟配置函数的实现脉络;
  3. 知道SysTick定时器的地位和作用;
  4. 了解SysTick寄存器的功能;
  5. 理解延时函数的实现原理

        与STM32时钟有关的信息量不小,为了不让篇幅太长,本章打算分两个部分来讲解,本文是第二部分。

二、SysTick系统定时器

2.1 SysTick的地位和作用

        SysTick系统定时器是Cortex-M3内核中的一个外设,它是一个24位的向下递减的计数器,STM32一上电这个计数器就开始工作,每计数一次的时间是1/HCLK或8/HCLK。当计数值递减到0的时候,SysTick系统定时器就产生一次中断,以此循环往复。

        由于SysTick属于Cortex-M3内核,那么所有基于该内核的单片机都具有这个系统定时器,使得软件可以很容易的移植。系统定时器一般用于操作系统的时基,以维持操作系统的心跳。没有操作系统的时候,也可以用于精确的延时,我们一直在用的delay延时就是通过配置这个寄存器实现的。

2.2 SysTick寄存器解读

        SysTick寄存器比较简单,也是我们为数不多的对寄存器的直接分析。请看图4,它有4个寄存器,一般只需要配置前3个就可以得到你想要的时长了,我们把它们的功能列在表1中。

图4 SysTick的4个寄存器
表1 SysTick寄存器功能表

三、延时函数的代码剖析

        解读了SysTick寄存器的功能,可能你还不清楚该如何配置它,现在我们就来分析delay延时的源码。读完源码,也许就豁然开朗了。

3.1 delay文件清单

        我们在创建工程模板的时候,就已经把delay.c和delay.h这一对文件加进了工程,我们现在再来看一下它们所在的目录,如图5所示。

图5 delay文件清单

3.2 delay.h文件源码

        这个文件的源码很简单,就声明了三个函数,如代码清单1所示。

//-------------------------------------------
// 代码清单1:delay.h
//-------------------------------------------#ifndef _DELAY_H
#define _DELAY_H#include "stm32f10x.h"//-------------------------------------------
// 函数声明
//-------------------------------------------
void delay init(void);    //延时初始化函数
void delay us(u32 nus);   //微秒级延时函数
void delay ms(ul6 nms);   //毫秒级延时函数#endif

3.3 delay.c文件源码

        为了增加代码的可读性,在下面的代码清单中,我们把原工程文件中与操作系统有关的部分都去掉了,这并不影响代码的运行。

        1)delay_init()函数源码

        如代码清单2所示,该函数执行延时初始化配置,选择HCLK/8作为SysTick定时器的时钟源,并确定得到1us和1ms所需的计数值。

//------------------------------------------------------
// 代码清单2:delay.c中的delay_init()函数
//------------------------------------------------------#include "delay.h"static u8  fac_us = 0;    //微秒延时倍乘数
static ul6 fac_ms = 0;    //毫秒延时倍乘数void delay_init(void)
{//sysTick定时器的时钟源为HCLK/8SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);//按系统时钟的1/8来计数,fac_us个脉冲就是1usfac_us = SystemCoreClock/8000000;//1ms就是1000usfac_ms = (u16)fac_us * 1000;
}

        首先用了 SysTick_CLKSourceConfig() 这个库函数来选择时钟源为HCLK/8。在时钟主线的分析中,已经确定了HCLK = 72MHz,那么8分频就是9MHz。那么为了得到精确的1us,就需要9个时钟源脉冲。接着,SystemCoreClock 这个宏就是系统时钟频率72MHz,除以8M得到的fac_us不就是9么。至于最后一行,就比较好理解了,1000个fac_us不就是1ms么。

        2)delay_us()函数源码

        如代码清单3所示,该函数将需要的微秒数nus换算成计数值填入相应的寄存器,使能后开始计时,计时过程中通过do…while循环不断关注使能位和计数标志位的变化,时间到了则退出循环,停止计数。

//------------------------------------------------------------
// 代码清单3:delay_us()函数
//------------------------------------------------------------void delay_us(u32 nus)
{u32 temp;SysTick->LOAD = nus*fac_us;    //时间装载SysTick->VAL = 0x00;           //计数值清0SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;    //开始倒数计时do{temp = SysTick->CTRL;}while((temp&0x01)&&!(temp&(1<<16)));    //等待时间到达SysTick->CTRL &= SysTick_CTRL_ENABLE_Msk;    //关闭计数SysTick->VAL = 0x00;    //清空计数器
}

        3)delay_ms()函数源码

        该函数与 delay_us() 函数的构造是一致的,如代码清单4所示,就是在装载计数器初值时不一样。使用这个函数需要特别注意,由于SysTick->LOAD寄存器是24位的,所以有nms <= 0xffffff*8*1000/HCLK。按照HCLK = 72MHz来计算,nms的最大值为1864。

//------------------------------------------------------------
// 代码清单4:delay_ms()函数
//------------------------------------------------------------void delay_ms(u16 nms)    //注意:nms<1864
{u32 temp;SysTick->LOAD = (u32)nms*fac_ms;    //时间装载SysTick->VAL = 0x00;                //计数值清0SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;    //开始倒数计时do{temp = SysTick->CTRL;}while((temp&0x01)&&!(temp&(1<<16)));    //等待时间到达SysTick->CTRL &= SysTick_CTRL_ENABLE_Msk;    //关闭计数SysTick->VAL = 0x00;    //清空计数器
}

(第二部分完,共两部分)

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

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

相关文章

WPS中制作甘特图的详细教程

网上没几个详细说怎么在WPS中制作甘特图的&#xff0c;我自己整理了一下详细教程&#xff0c;最终效果如下图所示&#xff1a; 1.写好需要展示的项目相关信息&#xff0c;如下图所示&#xff1a; #####这个进度的百分比渐变效果这样设置就行了 2.现在我们需要计算已用时间和剩…

docker安装ElasticSearchKibana

本文参考以下两篇文章 ✅ElasticSearch&Kibana 部署 云效 Thoughts 企业级知识库 (aliyun.com) docker安装ElasticSearch&Kibana - 飞书 安装elasticsearch 使用docker下载es&#xff1a; docker pull elasticsearch:8.13.0 挂载配置 创建挂在文件目录 mkdir…

AI大模型:解锁未来职业竞争力的金钥匙

AI元年&#xff1a;大模型的革新力量 随着ChatGPT的震撼登场&#xff0c;2023年被标记为AI元年&#xff0c;大模型以其前所未有的影响力&#xff0c;重塑我们的日常生活和工作方式。从日常的问答对话到复杂的编程辅助&#xff0c;乃至创意图像生成&#xff0c;AI大模型展现出超…

嵌入式Linux系统编程 — 6.4 信号集

目录​​​​​​​ 1 信号集概念 2 sigemptyset、sigfillset初始化信号集 3 sigaddset、sigdelset向信号集中添加/删除信号 4 sigismember函数测试信号是否在信号集中 1 信号集概念 在Linux系统中&#xff0c;信号集&#xff08;signal set&#xff09;用于表示一组信号…

对标GPT-4o!不锁区、支持手机、免费使用,Moshi来啦!

7月4日凌晨&#xff0c;法国知名开源AI研究实验室Kyutai在官网发布了&#xff0c;具备看、听、说多模态大模型——Moshi。 Moshi功能与OpenAI在5月14日展示的最新模型GPT-4o差不多&#xff0c;可以听取人的语音提问后进行实时推理回答内容。但GPT-4o的语音模式要在秋天才能全面…

确认下单:购物车页面点击 去结算 按钮发起两个请求trade(显示购物车的商品信息和计算商品的总金额)findUserAddressList

文章目录 1、确认下单&#xff1a;购物车页面点击去结算1.1、在OrderController类中创建 trade 方法1.2、在CartController类中创建 checkedCartInfos1.3、CartServiceImpl 实现 checkedCartInfos的业务功能1.4、在service-cart-client模块下定义远程openFeign接口1.5、在SpzxO…

再次登榜,深兰科技荣膺全球独角兽企业500强

6月27&#xff5e;28日&#xff0c;《2024全球独角兽企业500强》榜单发布&#xff0c;深兰科技凭借在AI产业赋能和产品出海方面的出色表现&#xff0c;继2023年之后再次登榜。 《2024全球独角兽企业500强》评委会介绍&#xff0c;本届榜单的产生&#xff0c;是由“全球独角兽企…

flutter开发实战-Charles抓包设置,dio网络代理

flutter开发实战-Charles抓包设置 在开发过程中抓包&#xff0c;可以看到请求参数等数据&#xff0c;方便分析问题。flutter上使用Charles抓包设置。dio需要设置网络代理。 一、dio设置网络代理 在调试模式下需要抓包调试&#xff0c;所以需要使用代理&#xff0c;并且仅用H…

专利优先权是什么

专利优先权&#xff1a;定义、分类与重要性 在专利的世界中&#xff0c;专利优先权是一个至关重要的概念。它不仅是专利申请人权益的保障&#xff0c;更是确保创新成果得到及时和充分保护的重要工具。 一、专利优先权的定义 专利优先权是指专利申请人就其发明创造第一次在某…

CTF常用sql注入(一)联合注入和宽字节

0x01 前言 给自己总结一下sql注入的常用姿势吧&#xff0c;记录一下学习 0x02 联合 联合注入的关键词是union SQL的union联合注入原理是联合两个表进行注入攻击&#xff0c;使用union select关键词来进行联合查询。 那么为什么我们在题目中一般是只写一个呢 因为 $sql &quo…

java-数据结构与算法-02-数据结构-02-链表

文章目录 1. 概述2. 单向链表3. 单向链表&#xff08;带哨兵&#xff09;4. 双向链表&#xff08;带哨兵&#xff09;5. 环形链表&#xff08;带哨兵&#xff09;6. 习题E01. 反转单向链表-Leetcode 206E02. 根据值删除节点-Leetcode 203E03. 两数相加-Leetcode 2E04. 删除倒数…

基于C++实现的EventLoop与事件驱动编程

一&#xff0c;概念介绍 事件驱动编程&#xff08;Event-Driven&#xff09;是一种编码范式&#xff0c;常被应用在图形用户界面&#xff0c;应用程序&#xff0c;服务器开发等场景。 采用事件驱动编程的代码中&#xff0c;通常要有事件循环&#xff0c;侦听事件&#xff0c;…

封装stater时配置导入配置类提示功能

提示功能如下 使用注解导入配置属性时添加依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-configuration-processor</artifactId><optional>true</optional></dependency>

孕产妇健康管理信息平台,多家医院产科广泛运用,系统稳定,功能齐全 产科管理系统源码,三甲医院产科电子病历系统成品源代码

孕产妇健康管理信息平台&#xff0c;多家医院产科广泛运用&#xff0c;系统稳定&#xff0c;功能齐全 产科管理系统源码&#xff0c;三甲医院产科电子病历系统成品源代码 女性生育过程会面临许多的困难和问题&#xff0c;需要经常性地前往医院做详细的身心检查&#xff0c;在…

IDEA 一键部署Docker

以部署示例服务&#xff08;sevnce-demo&#xff09;为例。 配置服务器 地址、账号、密码根据实际情况填写 配置镜像仓库 地址、账号、密码根据实际情况填写 编写Dockerfile 在sevnce-demo根目录下右键&#xff0c;选择创建Dockerfile。 # 基础镜像 FROM sevnce-registry.c…

C++:求梯形面积

梯形面积 已知上底15厘米&#xff0c;下底25厘米&#xff0c;问梯形面积值是多少&#xff1f; #include<iostream> using namespace std; int main() {//梯形的面积公式&#xff08;上底下底&#xff09; 高 2//上底变量、下底变量int s,d,h,m;s15;d25;h 2*150 * 2/s ;…

Day04-jenkins-docker

Day04-jenkins-docker 9. 案例06: 基于docker的案例实现静态代码9.1 整体流程9.2 步骤与环境1) 步骤2) 环境 9.3 详细步骤1&#xff09;代码准备2&#xff09;书写dockerfile3&#xff09;准备私有仓库4&#xff09;创建jenkins任务5&#xff09;web节点上启动对应的docker容器…

信息打点web篇---前端js打点

前言 欢迎来到我的博客 个人主页:北岭敲键盘的荒漠猫-CSDN博客 本文主要整理前端js代码的打点思路 本文只为学习安全使用&#xff0c;切勿用于非法用途。 一切未授权的渗透行为都是违法的。 前端js打点概念与目的 javascript文件属于前端语言&#xff0c;也就是说他的代码都…

taoCMS v3.0.2 文件上传漏洞(CVE-2022-23880)

前言 CVE-2022-23880是一个影响taoCMS v3.0.2的任意文件上传漏洞。攻击者可以利用此漏洞通过上传特制的PHP文件在受影响的系统上执行任意代码。 漏洞细节 描述: 在taoCMS v3.0.2的文件管理模块中存在任意文件上传漏洞。攻击者可以通过上传恶意的PHP文件来执行任意代码。 影响…

谷粒商城笔记-03-分布式基础概念

文章目录 一&#xff0c;微服务二&#xff0c;集群、分布式三&#xff0c;远程调用四&#xff0c;负载均衡五&#xff0c;服务注册、服务发现、注册中心六&#xff0c;配置中心七&#xff0c;服务熔断、服务降级1&#xff0c;服务熔断2&#xff0c;服务降级3&#xff0c;区别 八…