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

news2024/10/5 19:19:48

        大家好,我是老耿,高职青椒一枚,一直从事单片机、嵌入式、物联网等课程的教学。对于高职的学生层次,同行应该都懂的,老师在课堂上教学几乎是没什么成就感的。正因如此,才有了借助 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/8
    SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);
    //按系统时钟的1/8来计数,fac_us个脉冲就是1us
    fac_us = SystemCoreClock/8000000;
    //1ms就是1000us
    fac_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;           //计数值清0
    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;    //清空计数器
}

        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;                //计数值清0
    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;    //清空计数器
}

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

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

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

相关文章

Java增加线程后kafka仍然消费很慢

文章目录 一、问题分析二、控制kafka消费速度属性三、案例描述 一、问题分析 Java增加线程通常是为了提高程序的并发处理能力&#xff0c;但如果Kafka仍然消费很慢&#xff0c;可能的原因有&#xff1a; 网络延迟较大&#xff1a;如果网络延迟较大&#xff0c;即使开启了多线…

嵌入式学习——硬件(UART)——day55

1. UART 1.1 定义 UART&#xff08;Universal Asynchronous Receiver/Transmitter&#xff0c;通用异步收发器&#xff09;是一种用于串行通信的硬件设备或模块。它的主要功能是将数据在串行和并行格式之间进行转换。UART通常用于计算机与外围设备或嵌入式系统之间的数据传输。…

掌握高效实用的VS调试技巧

&#x1f525; 个人主页&#xff1a;大耳朵土土垚 1.编程常见的错误 1.1编译型错误 编程编译型错误是指在编译代码时发现的错误。编译器在编译过程中会检查代码是否符合语法规范和语义要求&#xff0c;如果发现错误会产生编译错误。 直接看错误提示信息&#xff08;双击&#…

阿里云邮件推送邮件发送失败的问题排查解决

阿里云邮件推送为何失败&#xff1f;解决邮件推送失败的步骤指南&#xff01; 即便是功能强大的阿里云邮件推送服务&#xff0c;也可能在实际使用中遇到邮件发送失败的问题。AokSend将详细介绍如何排查和解决阿里云邮件推送邮件发送失败的问题。 阿里云邮件推送&#xff1a;验…

ode45的例程|MATLAB例程|四阶龙格库塔定步长节微分方程

ode45自己编的程序和测试代码 模型 模拟一个卫星绕大行星飞行的轨迹计算。 结果 轨迹图如下: 源代码 以下代码复制到MATLAB上即可运行,并得到上面的图像: % ode45自己编的程序和测试代码 % Evand©2024 % 2024-7-2/Ver1 clear;clc;close all; rng(0); % 参数设定…

ruoyi mybatis pagehelper 分页优化(自定义limit位置)clickhouse 外部数据源

例如加入clickhouse的分页时发现extends 不生效 则可以添加 startPage();registerDialectAlias("clickhouse", PageMySqlDialectPlus.class);List<MyMonitorlog> list monitorlogService.selectMonitorlogList(monitorlog);主要是需要注册 registerDialectAl…

JAVA 快递100wms工具类

快递wms工具类 import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.google.gson.Gson; import com.kuaidi100.sdk.api.QueryTrack; import com.kuaidi100.sdk.api.Subscribe; import com.kuaidi100.sdk.contant.ApiInfoConstant; import c…

为什么说牛企查查企业超好用?

步入职场的职场人士&#xff0c;经济相关专业的学生&#xff0c;都有查企业的需求&#xff0c;市面上查企业的软件平台那么多&#xff0c;每个功能都不怎么一样。 有的便宜&#xff0c;但是信息不全。有的信息还可以&#xff0c;但是会员费又很贵&#xff0c;让我这个打工人没…

图像增强方法汇总OpenCV+python实现【第一部分:常用图像增强方法】

图像增强方法汇总OpenCVpython实现【第一部分】 前言常用的图像增强方法1. 旋转&#xff08;Rotation&#xff09;&#xff1a;2. 平移&#xff08;Translation&#xff09;&#xff1a;3. 缩放&#xff08;Scaling&#xff09;&#xff1a;4. 剪切变换&#xff08;Shear Trans…

Java:JDK、JRE和JVM 三者关系

文章目录 一、JDK是什么二、JRE是什么三、JDK、JRE和JVM的关系 一、JDK是什么 JDK&#xff08;Java Development Kit&#xff09;&#xff1a;Java开发工具包 JRE&#xff1a;Java运行时环境开发工具&#xff1a;javac&#xff08;编译工具&#xff09;、java&#xff08;运行…

电机的分类

1.按工作电源种类划分 2.按结构特点分类 3.按启动与运行方式分类 4.按转子结构分类 5.按用途分类 6.按运转速度分类 其他文章介绍了主流电机的原理和使用&#xff1a; 直流电机介绍-CSDN博客 步进电机(STM3228BYJ-48)-CSDN博客 待更新........

使用elasticsearch完成多语言搜索的三种方式

文档目标&#xff1a; 基于elasticsearch&#xff0c;实现不同语言搜索特定语言的文档数据&#xff1b;比如输入中文的内容&#xff0c;搜索中文文档数据&#xff0c;输入英文搜索英文文档数据&#xff0c;日韩文类似 方案概述&#xff1a; 方式一&#xff1a;不同的语言使用不…

Chirp信号生成(FPGA、基于cordic IP核)

一、Chirp生成模块介绍 采用Verilog 生成Chirp&#xff0c;实现输入使能电平&#xff0c;模块输出Chirp信号&#xff0c;Chirp信号频率范围&#xff0c;时间宽度&#xff0c;连续Chirp信号数量可配置。 二、模块例化方法示例 parameter FL d20_000 ; parameter FH…

如何在忘记密码的情况下重置Realme手机?

欢迎阅读我们关于如何在有或没有密码的情况下重置Realme手机的综合指南。无论您是忘记了密码&#xff0c;还是只是需要将设备恢复到出厂设置&#xff0c;我们都会为您提供所需的专业提示和技术专长。 发现分步说明、专家提示和行之有效的方法&#xff0c;轻松重新控制您的 Rea…

如何搭建10万个H100 GPU的集群:电力、并行化、网络拓扑与成本优化

引言 在现代人工智能的发展中&#xff0c;构建大规模GPU集群是提升计算能力的关键手段。今天我们探讨如何搭建一个包含10万个H100 GPU的集群。这个项目不仅涉及巨大的资本支出&#xff0c;还面临电力供应、并行化处理、网络拓扑结构以及可靠性和恢复等多方面的挑战。通过深入分…

zabbix 配置企业微信告警

1、申请一个企业微信&#xff0c; 官网链接 2、群内申请一个机器人 下载电脑版企业微信&#xff0c;登录后&#xff0c;在要接收群消息的群里&#xff0c;点击右上角三个点&#xff0c;添加机器人后&#xff0c;保存机器人的webhook地址 上传应用logo&#xff0c;填写应用名称…

破解电脑卡顿难题,将数据优化,5分钟提升运行速度

当电脑变得缓慢且反应迟钝时&#xff0c;工作效率和娱乐体验都会大打折扣。而电脑卡顿是由于系统资源占用过多、磁盘空间不足等原因引起的。因此&#xff0c;我们经常需要寻找优化措施&#xff0c;提升电脑的运行速度。文章整理了4个优化方法&#xff0c;帮助你破解卡顿难题&am…

5月1日起,《碳排放权交易管理暂行条例》正式施行

2024年5月1日&#xff0c;《碳排放权交易管理暂行条例》&#xff08;以下简称《条例》&#xff09;正式施行&#xff0c;作为我国应对气候变化领域的第一部专门法规&#xff0c;《条例》首次以行政法规的形式明确了碳排放权市场交易制度。 作为碳排放权交易市场的重要补充&…

将KVM虚拟机迁移为Virtualbox虚拟机

1、在KVM宿主机上把qcow2格式磁盘转成vdi格式 [rootkvm ~]# cd /kvm-data [rootkvm kvm-data]# qemu-img convert -f qcow2 wind30.qcow2 -O vdi wind30.vdi 注&#xff1a;把vdi转qcow2命令qemu-img convert -f vdi wind30.vdi -O qcow2 wind30.qcow2 2、把转换成功vdi磁盘…

蓝桥杯开发板STM32G431RBT6高阶HAL库学习FreeRtos——新建工程

一、介绍 ​ 蓝桥杯嵌入式使用的单片机是STM32G431RBT6,内核ARM Cortex - M4,MCU+FPU,170MHz/213DMIPS,高达128KB Flash,32KB SRAM,其余的外设就不多介绍了,参照数据芯片数据手册 ​ CT117E-M4开发板资源:微控制器STM32G431RBT6、一路USB转串口、2.4寸TFT-LCD、4个功…