当前位置: 首页 > news >正文

三 STM32F4使用Sys_Tick 实现微秒定时器和延时

更多细节参考这篇

1. 什么是时钟以及作用

1.1 什么是时钟

  1. 时钟是由电路产生的周期性的脉冲信号,相当于单片机的心脏

1.2 时钟对于STM32的作用

  1. 指令同步:cpu和内核外设使用时钟信号来进行指令同步
  2. 数据传输控制: 时钟信号控制数据在内部总线上的传输时机
  3. 外设操作:很多外设比如 GPIO USART ADC等需要时钟来控制频率和时序
  4. 节能管理: 调整时钟的频率,可以管理MCU的功耗,实现节能

2. 关于Sys_Tick 定时器

Sys_Tick 是 ARM Cortex-M4 内核的一部分, 他提供24位递减计数器, 可以用来生成周期性的中断,适合用来左滴答定时器或者提供时间基准

2.1 Sys_Tick 定时器配置步骤

  1. 首先初始化SysTick : 调用
    SysTick_Config(SystemCoreClock/1000 ) ;  //位与CMSIS 下的core_cm4.h 1760 行

函数来配置SysTick定时器的重载值
,该值基于系统时钟频率和中断频率所需的值来确定
我这里设置的是1ms中断一次(STM32F4 的系统时钟是100MHZ 一个时钟周期有 1 / 100 000 000 s 也就是10 ns ,实现1ms 需要 100 000 个 10ns )
2. 选择时钟源 : 选择SysTick的时钟源 , 一般选择系统时钟
2. 中断使能

extern volatile uint32_t SysTickUptime  ;
void SysTick_Handler(void)
{SysTickUptime++ ; 
}

2.2 使用 SysTick 实现毫秒级定时器以及延时

/* 毫秒级运行定时器 , 返回的是毫秒 
SysTickUptime 溢出时间大概49天 */
uint32_t millis(void) 
{return SysTickUptime ; 
}/* 毫秒级延时函数  */
void delay_ms(uint32_t ms)  
{uint32_t now_time = millis();while(millis() - now_time  < ms) { }  }

2.3 使用 SysTick 实现微秒级定时器以及延时

  1. 使用 SysTick 实现微秒级定时器以及延时 为什么不直接SysTick_Config(SystemCoreClock/1000000 ) ;来实现呢
  • 中断开销 : 如果SysTick定时设置成微妙产生一次中断 , 那么中断的频率会非常高,可能导致花大量的时间处理中断从而影响程序的执行效率。对于一个100MHz的系统时钟,这意味着每秒会有100万次中断,这对于任何系统来说都是不切实际的。
  • 中断优先级: 处理中断具有一定的优先级, 过高的中断频率可能会导致低优先级任务或者中断得不到及时的处理
  • 24位计数器限制: SysTick 是一个24位递减计数器, 这意味着最大的计数是2的24次方-1 , 如果系统时钟频率非常高,比如180MHz或更高,设置SysTick每微秒递减一次将导致它在很短的时间内溢出,限制了可以生成的最长定时周期。
  1. 读取当前SysTick 来计算微妙
  • 设置一个1us所需的滴答数
static uint32_t usTicks ;
// SystemCoreClock = 100 MHZ
usTicks = SystemCoreClock/1000000 ; //1us的滴答数 usTicks = 100 
  • 捕捉一致的读数
    循环读取SysTickUptime 和 SysTick-> VAL 的值, 直到他们在循环中两次读取之间保持一致。这是为了确保在读取的时候没有SysTick发生 ,以为如果读取 SysTick-> VAL 之后 , 而在 SysTick-> VAL 之前发生中断 , SysTickUptime 会递增, 而SysTick-> VAL 会重置
uint32_t  ms ,  cycle_cnt ;do{ms = SysTickUptime ; cycle_cnt = SysTick->VAL ; }while(ms != SysTickUptime ) ;
  • 计算微妙
 (ms * 1000 ) + ( ( (SystemCoreClock/1000)   - cycle_cnt )  / usTicks ) ;
1. 通过将ms(毫秒计数)* 1000 得到了系统启动以来的时间(以微妙为单位)
2. 计算 SystemCoreClock/1000 - cycle_cnt 得到自上次中断以来经过的时钟周期数 ,  SystemCoreClock/1000  是SysTick 定时器的重装值 , 表示1ms内的时钟周期数 , 从这个值减去 SysTick-> VAL 得到了自从上次中断以来经过的时钟周期数
3. 最后 将这个值除以 usTicks(每 微秒的时钟周期数) 将周期转换成微妙

最后 函数的返回值也就是自系统启动以来的总微秒

/* 微秒级计数函数  */
uint32_t  micros ( void )  
{uint32_t  ms ,  cycle_cnt ;do{ms = SysTickUptime ; cycle_cnt = SysTick->VAL ; }while(ms != SysTickUptime ) ;return (ms * 1000 ) + ( ( (SystemCoreClock/1000)   - cycle_cnt )  / usTicks ) ;}/* 微秒级延时函数  */
void delay_us(uint32_t us)  
{uint32_t now_time = micros();while(micros() - now_time  < us) { }     
}

这里的关键是SysTick是递减计数的 , 并在到达零时重置和触发中断 cycle_cnt 变量存储的时从前的计数器值到下一个零点的周期数 , 这个值要用 SysTick定时器的重载值减去 才是已经过去的时钟周期数

3. 完整代码

3.1 Delay.h

#ifndef DELAY_H
#define DELAY_H
#include "stm32f4xx.h"void Delay_Init(void);uint32_t millis(void)  ; //毫秒级运行定时器
uint32_t micros(void)  ; //微秒级运行定时器 void delay_ms(uint32_t ms) ; //毫秒级延时函数 
void delay_us(uint32_t us) ; //毫秒级延时函数 #endif

3.1 Delay.c

#include "stm32f4xx.h" 
#include "Delay.h"
#include "stm32f4xx_it.h"static uint32_t usTicks ;
volatile uint32_t SysTickUptime  = 0  ; //systick 每1ms 中断一次 void Delay_Init(void)
{ SysTick_Config(SystemCoreClock/1000 ) ; /*  这里的系统时钟是100mhz,一个时钟周期有 1 / 100 000 000 s   也就是一个时钟周期有 10ns 我们需要计数到1ms,也就是100 000个周期,也就是100 000个10ns所以 SystemCoreClock/1000 1ms 开启systick中断一次*/usTicks = SystemCoreClock/1000000 ; //1us的滴答数 usTicks = 100 
}/* 毫秒级运行定时器 , 返回的是毫秒 
SysTickUptime 溢出时间大概49天 */
uint32_t millis(void) 
{return SysTickUptime ; 
}/* 毫秒级延时函数  */
void delay_ms(uint32_t ms)  
{uint32_t now_time = millis();while(millis() - now_time  < ms) { }  }/* 微秒级计数函数  */
uint32_t  micros ( void )  
{uint32_t  ms ,  cycle_cnt ;do{ms = SysTickUptime ; cycle_cnt = SysTick->VAL ; }while(ms != SysTickUptime ) ;return (ms * 1000 ) + ( ( (SystemCoreClock/1000)   - cycle_cnt )  / usTicks ) ;}/* 微秒级延时函数  */
void delay_us(uint32_t us)  
{uint32_t now_time = micros();while(micros() - now_time  < us) { }     
}/*举个简单的例子理解一下 假如 我们这里选择 100mhz  此时SysTickUptime = 100 表示自系统启动以来已经过了100ms在某一时刻,我们调用micros函数,SysTick->VAL当前的值是50000(表示自上次SysTick中断以来已经过了50000个周期)那么此时是多少毫秒呢 
也就是计算 SysTickUptime * 1000 + (1000000 - SysTick->VAL) / usTicks
(1000000 - SysTick->VAL) / usTicks 表示走过的50000个周期 有少个usTicks 1个usTicks 也就是1us*/

3.3 void SysTick_Handler(void)

位于
在这里插入图片描述

相关文章:

三 STM32F4使用Sys_Tick 实现微秒定时器和延时

更多细节参考这篇 1. 什么是时钟以及作用 1.1 什么是时钟 时钟是由电路产生的周期性的脉冲信号&#xff0c;相当于单片机的心脏 1.2 时钟对于STM32的作用 指令同步&#xff1a;cpu和内核外设使用时钟信号来进行指令同步数据传输控制&#xff1a; 时钟信号控制数据在内部总…...

唯创知音WT2003H系列MP3录音语音芯片:高精度ADC与DAC,强大IO驱动能力成就音频卓越

在音频领域里&#xff0c;高精度和强大的驱动能力一直是工程师们追求的目标。唯创知音的WT2003H系列MP3录音芯片恰好满足了这一需求&#xff0c;该芯片具备16 bit高精度的ADC及DAC功能&#xff0c;大功率的IO驱动能力&#xff0c;能够直接驱动64mA&#xff0c;为电子产品带来卓…...

记录Windows下安装redis的过程

开源博客项目Blog支持使用EasyCaching组件操作redis等缓存数据库&#xff0c;在继续学习开源博客项目Blog之前&#xff0c;准备先学习redis和EasyCaching组件的基本用法&#xff0c;本文记录在Windows下安装redis的过程。   虽然redis官网文档写着支持Linux、macOS、Windows等…...

7.5 Windows驱动开发:监控Register注册表回调

在笔者前一篇文章《内核枚举Registry注册表回调》中实现了对注册表的枚举&#xff0c;本章将实现对注册表的监控&#xff0c;不同于32位系统在64位系统中&#xff0c;微软为我们提供了两个针对注册表的专用内核监控函数&#xff0c;通过这两个函数可以在不劫持内核API的前提下实…...

NC56 XML 报文校验出错一例

好好的上线了、下午开完会告诉我有个凭证没法传入 NC 了。 请求报文如下&#xff1a; <?xml version"1.0" encodingUTF-8?> <ufinterface roottag"voucher" billtype"gl" replace"Y" receiver"10108" sender&q…...

STM32 ADC转换器、串口输出

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、ADC是什么&#xff1f;二、STM32的ADC2.1 认识STM32 ADC2.2转换方式2.3 为什么要校准&#xff1f;2.4 采样时间计算2.5 触发方式2.6 多通道采集解决方案2.7…...

[MySQL--基础]函数、约束

hello! 这里是欧_aita的频道。 今日语录:不管你觉得自己能做什么&#xff0c;或者你觉得你不能做什么&#xff0c;你都是对的。 祝福语&#xff1a;愿你的程序像太阳一样明亮&#xff0c;给世界带来温暖和光明。 大家可以在评论区畅所欲言&#xff0c;可以指出我的错误&#xf…...

企业数字化决策者深度分享

2023年11月18日&#xff0c;数聚股份应邀参加在台州椒江举办的数字中国企业峰会。本次会议中&#xff0c;诸多在企业数字化进程中做出重要贡献的高层管理者分享了各行各业极具引领性、创新性的数字化实践案例、产品和解决方案&#xff1b;数聚股份董事长陈庆华携其前瞻的数字化…...

JMeter压测常见面试问题

1、JMeter可以模拟哪些类型的负载&#xff1f; JMeter可以模拟各种类型的负载&#xff0c;包括但不限于Web应用程序、API、数据库、FTP、SMTP、JMS、SOAP / RESTful Web服务等。这使得JMeter成为一个功能强大且灵活的压力测试工具。 2、如何配置JMeter来进行分布式压力测试&a…...

使用opencv将sRGB格式的图片转换为DCI-P3格式【sRGB】【DCI-P3】

要将图像从 sRGB 格式转换为 DCI-P3 格式&#xff0c;您需要使用适当的线性转换矩阵。在 OpenCV 中&#xff0c;这通常涉及使用色彩转换函数&#xff0c;但 OpenCV 默认情况下不直接支持 sRGB 到 DCI-P3 的转换。因此&#xff0c;您需要手动计算并应用转换矩阵。 转换矩阵取决…...

【协议设计与实现】Linux环境下,如何从0开始设计并实现一个网络协议之一——需要考虑的因素

&#x1f41a;作者简介&#xff1a;花神庙码农&#xff08;专注于Linux、WLAN、TCP/IP、Python等技术方向&#xff09;&#x1f433;博客主页&#xff1a;花神庙码农 &#xff0c;地址&#xff1a;https://blog.csdn.net/qxhgd&#x1f310;系列专栏&#xff1a;TCP/IP协议&…...

【前端】JS实现SQL格式化

sqlFormatter sql-formatter - npm (npmjs.com) const sqlFormatter require(/utils/sqlFormatter)let sql select count(1) as cnt from t_user where id < 7;// 格式化 // let sqlF sqlFormatter.format(sql);let sqlF sqlFormatter.format(sql, {language:mysql,})…...

java设计模式学习之【工厂模式】

文章目录 引言工厂方法模式简介定义与用途&#xff1a;实现方式&#xff1a; 使用场景优势与劣势工厂模式在spring中的应用电费计算示例&#xff08;简单工厂模式&#xff09;改善为方法工厂模式代码地址 引言 在软件开发的世界中&#xff0c;对象的创建可能是一个复杂且重复的…...

android 内存分析(待续)

/proc/meminfo memory状态解读 命令&#xff1a;adb shell cat /proc/meminfo内存分布log 查看方式 命令&#xff1a;adb shell cat /proc/meminfo 用途:可以整体的了解memory使用情况 我们说的可用memory一般以MemAvailable的数据为准。所以了解MemAvailable的组成可以帮助…...

2023-简单点-机器学习中的数值计算问题

上溢和下溢&#xff1a; 上溢&#xff1a;指数函数或对数函数的输入值过大&#xff0c;导致计算结果超出了计算机可以表示的最大值。例如&#xff0c;在softmax函数中&#xff0c;当输入的数值很大时&#xff0c;指数运算的结果可能非常大&#xff0c;导致上溢。 下溢&#x…...

Qt5的事件处理函数有哪些?

2023年11月29日&#xff0c;周三上午 通过查看QWidget的定义可知&#xff0c;事件处理函数有&#xff1a; bool event(QEvent *event) override;virtual void mousePressEvent(QMouseEvent *event);virtual void mouseReleaseEvent(QMouseEvent *event);virtual void mouseDou…...

Jmeter性能综合实战——签到及批量签到

提取性能测试的三个方面&#xff1a;核心、高频、基础功能 签 到 请 求 步 骤 1、准备工作&#xff1a; 签到线程组 n HTTP请求默认值 n HTTP cookie 管理器 n 首页访问请求 n 登录请求 n 查看结果树 n 调试取样器 l HTTP代理服务器 &#xff08;1&#xff09;创建线…...

04 # 第一个 TypeScript 程序

初始化项目以及安装依赖 新建 ts_in_action 文件夾 npm init -y安装好 typescript&#xff0c;就可以执行下面命令查看帮助信息 npm i typescript -g tsc -h创建配置文件&#xff0c;执行下面命令就会生成一个 tsconfig.json 文件 tsc --init使用 tsc 编译一个 js 文件 新…...

Android gradle 配置阿里镜像

要在Android Gradle中配置阿里镜像&#xff0c;可以按照以下步骤进行操作&#xff1a; 打开项目中的 build.gradle 文件。 在 build.gradle 文件中添加阿里镜像的地址&#xff0c;如下所示&#xff1a; buildscript {repositories {maven { url https://maven.aliyun.com/re…...

Arduino驱动DHT20温湿度传感器(温湿度传感器)

目录 1、传感器特性 2、硬件原理图 3、控制器和传感器连线图 4、驱动程序 DHT20温湿度传感器是DHT11的全新升级版。 DHT20采用全新的ASIC专用芯片、改进的MEMS半导体电容式湿度传感器元件和标准片上温度元件。所有传感器均经过工厂校准,具有低功耗、高精度和稳定性、响应…...

eNSP-Cloud(实现本地电脑与eNSP内设备之间通信)

说明&#xff1a; 想象一下&#xff0c;你正在用eNSP搭建一个虚拟的网络世界&#xff0c;里面有虚拟的路由器、交换机、电脑&#xff08;PC&#xff09;等等。这些设备都在你的电脑里面“运行”&#xff0c;它们之间可以互相通信&#xff0c;就像一个封闭的小王国。 但是&#…...

基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销&#xff0c;平衡网络负载&#xff0c;延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...

Caliper 配置文件解析:config.yaml

Caliper 是一个区块链性能基准测试工具,用于评估不同区块链平台的性能。下面我将详细解释你提供的 fisco-bcos.json 文件结构,并说明它与 config.yaml 文件的关系。 fisco-bcos.json 文件解析 这个文件是针对 FISCO-BCOS 区块链网络的 Caliper 配置文件,主要包含以下几个部…...

如何理解 IP 数据报中的 TTL?

目录 前言理解 前言 面试灵魂一问&#xff1a;说说对 IP 数据报中 TTL 的理解&#xff1f;我们都知道&#xff0c;IP 数据报由首部和数据两部分组成&#xff0c;首部又分为两部分&#xff1a;固定部分和可变部分&#xff0c;共占 20 字节&#xff0c;而即将讨论的 TTL 就位于首…...

Maven 概述、安装、配置、仓库、私服详解

目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...

python报错No module named ‘tensorflow.keras‘

是由于不同版本的tensorflow下的keras所在的路径不同&#xff0c;结合所安装的tensorflow的目录结构修改from语句即可。 原语句&#xff1a; from tensorflow.keras.layers import Conv1D, MaxPooling1D, LSTM, Dense 修改后&#xff1a; from tensorflow.python.keras.lay…...

Caliper 负载(Workload)详细解析

Caliper 负载(Workload)详细解析 负载(Workload)是 Caliper 性能测试的核心部分,它定义了测试期间要执行的具体合约调用行为和交易模式。下面我将全面深入地讲解负载的各个方面。 一、负载模块基本结构 一个典型的负载模块(如 workload.js)包含以下基本结构: use strict;/…...

Proxmox Mail Gateway安装指南:从零开始配置高效邮件过滤系统

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐&#xff1a;「storms…...

9-Oracle 23 ai Vector Search 特性 知识准备

很多小伙伴是不是参加了 免费认证课程&#xff08;限时至2025/5/15&#xff09; Oracle AI Vector Search 1Z0-184-25考试&#xff0c;都顺利拿到certified了没。 各行各业的AI 大模型的到来&#xff0c;传统的数据库中的SQL还能不能打&#xff0c;结构化和非结构的话数据如何和…...

软件工程 期末复习

瀑布模型&#xff1a;计划 螺旋模型&#xff1a;风险低 原型模型: 用户反馈 喷泉模型:代码复用 高内聚 低耦合&#xff1a;模块内部功能紧密 模块之间依赖程度小 高内聚&#xff1a;指的是一个模块内部的功能应该紧密相关。换句话说&#xff0c;一个模块应当只实现单一的功能…...