三 STM32F4使用Sys_Tick 实现微秒定时器和延时
更多细节参考这篇
1. 什么是时钟以及作用
1.1 什么是时钟
- 时钟是由电路产生的周期性的脉冲信号,相当于单片机的心脏
1.2 时钟对于STM32的作用
- 指令同步:cpu和内核外设使用时钟信号来进行指令同步
- 数据传输控制: 时钟信号控制数据在内部总线上的传输时机
- 外设操作:很多外设比如 GPIO USART ADC等需要时钟来控制频率和时序
- 节能管理: 调整时钟的频率,可以管理MCU的功耗,实现节能
2. 关于Sys_Tick 定时器
Sys_Tick 是 ARM Cortex-M4 内核的一部分, 他提供24位递减计数器, 可以用来生成周期性的中断,适合用来左滴答定时器或者提供时间基准
2.1 Sys_Tick 定时器配置步骤
- 首先初始化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 实现微秒级定时器以及延时
- 使用 SysTick 实现微秒级定时器以及延时 为什么不直接SysTick_Config(SystemCoreClock/1000000 ) ;来实现呢
- 中断开销 : 如果SysTick定时设置成微妙产生一次中断 , 那么中断的频率会非常高,可能导致花大量的时间处理中断从而影响程序的执行效率。对于一个100MHz的系统时钟,这意味着每秒会有100万次中断,这对于任何系统来说都是不切实际的。
- 中断优先级: 处理中断具有一定的优先级, 过高的中断频率可能会导致低优先级任务或者中断得不到及时的处理
- 24位计数器限制: SysTick 是一个24位递减计数器, 这意味着最大的计数是2的24次方-1 , 如果系统时钟频率非常高,比如180MHz或更高,设置SysTick每微秒递减一次将导致它在很短的时间内溢出,限制了可以生成的最长定时周期。
- 读取当前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 什么是时钟 时钟是由电路产生的周期性的脉冲信号,相当于单片机的心脏 1.2 时钟对于STM32的作用 指令同步:cpu和内核外设使用时钟信号来进行指令同步数据传输控制: 时钟信号控制数据在内部总…...
唯创知音WT2003H系列MP3录音语音芯片:高精度ADC与DAC,强大IO驱动能力成就音频卓越
在音频领域里,高精度和强大的驱动能力一直是工程师们追求的目标。唯创知音的WT2003H系列MP3录音芯片恰好满足了这一需求,该芯片具备16 bit高精度的ADC及DAC功能,大功率的IO驱动能力,能够直接驱动64mA,为电子产品带来卓…...
记录Windows下安装redis的过程
开源博客项目Blog支持使用EasyCaching组件操作redis等缓存数据库,在继续学习开源博客项目Blog之前,准备先学习redis和EasyCaching组件的基本用法,本文记录在Windows下安装redis的过程。 虽然redis官网文档写着支持Linux、macOS、Windows等…...
7.5 Windows驱动开发:监控Register注册表回调
在笔者前一篇文章《内核枚举Registry注册表回调》中实现了对注册表的枚举,本章将实现对注册表的监控,不同于32位系统在64位系统中,微软为我们提供了两个针对注册表的专用内核监控函数,通过这两个函数可以在不劫持内核API的前提下实…...
NC56 XML 报文校验出错一例
好好的上线了、下午开完会告诉我有个凭证没法传入 NC 了。 请求报文如下: <?xml version"1.0" encodingUTF-8?> <ufinterface roottag"voucher" billtype"gl" replace"Y" receiver"10108" sender&q…...
STM32 ADC转换器、串口输出
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、ADC是什么?二、STM32的ADC2.1 认识STM32 ADC2.2转换方式2.3 为什么要校准?2.4 采样时间计算2.5 触发方式2.6 多通道采集解决方案2.7…...
[MySQL--基础]函数、约束
hello! 这里是欧_aita的频道。 今日语录:不管你觉得自己能做什么,或者你觉得你不能做什么,你都是对的。 祝福语:愿你的程序像太阳一样明亮,给世界带来温暖和光明。 大家可以在评论区畅所欲言,可以指出我的错误…...
企业数字化决策者深度分享
2023年11月18日,数聚股份应邀参加在台州椒江举办的数字中国企业峰会。本次会议中,诸多在企业数字化进程中做出重要贡献的高层管理者分享了各行各业极具引领性、创新性的数字化实践案例、产品和解决方案;数聚股份董事长陈庆华携其前瞻的数字化…...
JMeter压测常见面试问题
1、JMeter可以模拟哪些类型的负载? JMeter可以模拟各种类型的负载,包括但不限于Web应用程序、API、数据库、FTP、SMTP、JMS、SOAP / RESTful Web服务等。这使得JMeter成为一个功能强大且灵活的压力测试工具。 2、如何配置JMeter来进行分布式压力测试&a…...
使用opencv将sRGB格式的图片转换为DCI-P3格式【sRGB】【DCI-P3】
要将图像从 sRGB 格式转换为 DCI-P3 格式,您需要使用适当的线性转换矩阵。在 OpenCV 中,这通常涉及使用色彩转换函数,但 OpenCV 默认情况下不直接支持 sRGB 到 DCI-P3 的转换。因此,您需要手动计算并应用转换矩阵。 转换矩阵取决…...
【协议设计与实现】Linux环境下,如何从0开始设计并实现一个网络协议之一——需要考虑的因素
🐚作者简介:花神庙码农(专注于Linux、WLAN、TCP/IP、Python等技术方向)🐳博客主页:花神庙码农 ,地址:https://blog.csdn.net/qxhgd🌐系列专栏: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设计模式学习之【工厂模式】
文章目录 引言工厂方法模式简介定义与用途:实现方式: 使用场景优势与劣势工厂模式在spring中的应用电费计算示例(简单工厂模式)改善为方法工厂模式代码地址 引言 在软件开发的世界中,对象的创建可能是一个复杂且重复的…...
android 内存分析(待续)
/proc/meminfo memory状态解读 命令:adb shell cat /proc/meminfo内存分布log 查看方式 命令:adb shell cat /proc/meminfo 用途:可以整体的了解memory使用情况 我们说的可用memory一般以MemAvailable的数据为准。所以了解MemAvailable的组成可以帮助…...
2023-简单点-机器学习中的数值计算问题
上溢和下溢: 上溢:指数函数或对数函数的输入值过大,导致计算结果超出了计算机可以表示的最大值。例如,在softmax函数中,当输入的数值很大时,指数运算的结果可能非常大,导致上溢。 下溢&#x…...
Qt5的事件处理函数有哪些?
2023年11月29日,周三上午 通过查看QWidget的定义可知,事件处理函数有: bool event(QEvent *event) override;virtual void mousePressEvent(QMouseEvent *event);virtual void mouseReleaseEvent(QMouseEvent *event);virtual void mouseDou…...
Jmeter性能综合实战——签到及批量签到
提取性能测试的三个方面:核心、高频、基础功能 签 到 请 求 步 骤 1、准备工作: 签到线程组 n HTTP请求默认值 n HTTP cookie 管理器 n 首页访问请求 n 登录请求 n 查看结果树 n 调试取样器 l HTTP代理服务器 (1)创建线…...
04 # 第一个 TypeScript 程序
初始化项目以及安装依赖 新建 ts_in_action 文件夾 npm init -y安装好 typescript,就可以执行下面命令查看帮助信息 npm i typescript -g tsc -h创建配置文件,执行下面命令就会生成一个 tsconfig.json 文件 tsc --init使用 tsc 编译一个 js 文件 新…...
Android gradle 配置阿里镜像
要在Android Gradle中配置阿里镜像,可以按照以下步骤进行操作: 打开项目中的 build.gradle 文件。 在 build.gradle 文件中添加阿里镜像的地址,如下所示: buildscript {repositories {maven { url https://maven.aliyun.com/re…...
Arduino驱动DHT20温湿度传感器(温湿度传感器)
目录 1、传感器特性 2、硬件原理图 3、控制器和传感器连线图 4、驱动程序 DHT20温湿度传感器是DHT11的全新升级版。 DHT20采用全新的ASIC专用芯片、改进的MEMS半导体电容式湿度传感器元件和标准片上温度元件。所有传感器均经过工厂校准,具有低功耗、高精度和稳定性、响应…...
2026年,跨端框架到底怎么选?
跨平台开发长期面临“一次编码、多端运行”的理想与现实落差。开发者常陷入取舍困境:既要兼顾性能与体验,又要控制包体与维护成本,更要在 Android、iOS、HarmonyOS 甚至 Web 和小程序间保持一致。实际项目中,常见坑包括启动延迟、…...
【GUI-Agent】阶跃星辰 GUI-MCP 解读---()---HITL(Human In The Loop)贡
插件化架构 v3 版本最大的变化是引入了模块化插件系统。此前版本中集成在核心包里的原生功能,现在被拆分成独立的插件。 每个插件都是一个独立的 Composer 包,包含 Swift 和 Kotlin 代码、权限清单以及原生依赖。开发者只需安装实际用到的插件࿰…...
BepInEx完整指南:3分钟学会Unity游戏模组开发与插件注入
BepInEx完整指南:3分钟学会Unity游戏模组开发与插件注入 【免费下载链接】BepInEx Unity / XNA game patcher and plugin framework 项目地址: https://gitcode.com/GitHub_Trending/be/BepInEx BepInEx是Unity游戏模组开发的终极解决方案,作为一…...
IM系统核心不是聊天?深入剖析SpringBoot+Netty项目中关系链与群组模块的设计陷阱
IM系统核心不是聊天?深入剖析SpringBootNetty项目中关系链与群组模块的设计陷阱 当大多数人谈论即时通讯系统时,首先想到的是消息收发功能。然而,真正让微信、QQ等产品形成护城河的,并非简单的消息传输能力,而是其背后…...
【系统架构设计师】从理论到实践:构建质量属性效用树与场景化评估指南
1. 质量属性:架构设计的灵魂所在 作为系统架构设计师,我们每天都在和各种质量属性打交道。记得去年设计一个电商平台时,产品经理突然提出"双十一要能扛住10倍流量",那一刻我深刻体会到质量属性不是纸上谈兵的概念。质量…...
PUBG终极雷达:5分钟搭建免费战场信息可视化系统
PUBG终极雷达:5分钟搭建免费战场信息可视化系统 【免费下载链接】PUBG-maphack-map this is a working copy online-map from jussihi/PUBG-map-hack, use nodejs webserver instead of firebase. 项目地址: https://gitcode.com/gh_mirrors/pu/PUBG-maphack-map …...
JVM学习笔记(7) 第三部分 虚拟机执行子系统 第6章 类文件结构
文章目录第6章 类文件结构6.0 个人感悟6.1 概述6.2 无关性的基石6.3 Class类文件的结构6.3.1 魔数与版本号6.3.2 常量池6.3.3 访问标志6.3.4 类索引、父类索引与接口索引集合6.3.5 字段表集合6.3.6 方法表集合6.3.7 属性表集合代码编译的结果从本地机器码转变为字节码ÿ…...
Java Loom + R2DBC + VirtualThread三重奏:构建零阻塞数据库访问层(含GraalVM原生镜像适配方案)
第一章:Java Loom响应式编程转型的背景与核心价值长期以来,Java 的并发模型依赖线程(Thread)作为基本执行单元,但传统线程是重量级操作系统资源,受限于内核调度开销与内存占用(每个线程栈默认 1…...
PoeCharm实战指南:5步打造你的流放之路完美BD构建
PoeCharm实战指南:5步打造你的流放之路完美BD构建 【免费下载链接】PoeCharm Path of Building Chinese version 项目地址: https://gitcode.com/gh_mirrors/po/PoeCharm 还在为《流放之路》复杂的BD构建而头疼吗?PoeCharm作为一款专为中文玩家打…...
终极指南:如何高效使用Audio Slicer实现智能音频分割
终极指南:如何高效使用Audio Slicer实现智能音频分割 【免费下载链接】audio-slicer A simple GUI application that slices audio with silence detection 项目地址: https://gitcode.com/gh_mirrors/aud/audio-slicer 你是否曾为处理长音频文件而烦恼&…...
