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

HAL_Delay()在RTOS下失效?手把手教你用DWT实现us级精确延时(附STM32H743代码)

HAL_Delay()在RTOS下失效手把手教你用DWT实现us级精确延时附STM32H743代码在嵌入式开发中精确的延时控制往往是保证系统稳定性和实时性的关键。当我们在RTOS环境下使用STM32的HAL库时可能会遇到一个棘手的问题原本可靠的HAL_Delay()函数突然失效了。这种现象背后隐藏着RTOS与HAL库对SysTick资源的争夺而解决这个问题的钥匙就藏在Cortex-M内核中一个鲜为人知的外设——DWT(Data Watchpoint and Trace)中。本文将带你深入理解这一问题的根源并手把手教你如何利用DWT实现微秒级的高精度延时。不同于简单的代码移植我们会从原理出发让你真正掌握这种技术的精髓。无论你是正在为RTOS下的延时问题困扰还是单纯追求更高精度的定时控制这篇文章都将为你提供实用的解决方案。1. 为什么RTOS下HAL_Delay()会失效要理解这个问题我们需要先看看HAL_Delay()和RTOS是如何使用SysTick的。SysTick是Cortex-M内核中的一个24位递减计数器通常被用作系统的心跳节拍。HAL库对SysTick的依赖主要体现在三个方面HAL_Delay()函数的实现外设操作中的超时判断如I2C、SPI等HAL库内部的时间基准当RTOS介入后情况变得复杂起来。RTOS需要SysTick来提供系统时基用于任务调度和时间管理。这就导致了一个根本性的冲突两个关键系统组件都需要独占SysTick资源。更严重的问题出现在中断优先级上。RTOS通常会将SysTick中断设置为最低优先级以保证其他中断能够及时响应。考虑以下场景void int_a_IRQHandler(void) // 高优先级中断 { // 某些操作... HAL_Delay(10); // 调用HAL_Delay() // 更多操作... }在这种情况下由于int_a的中断优先级高于SysTickSysTick中断无法抢占当前中断。结果是SysTick计数器无法更新HAL_Delay()陷入死循环整个系统随之挂起。2. DWT被忽视的高精度计时利器DWT(Data Watchpoint and Trace)是Cortex-M内核中一个强大的调试组件但它的CYCCNT计数器功能却可以为我们所用。这个32位向上计数器记录的是内核时钟的周期数能提供极高的时间分辨率。DWT相比传统定时器的优势特性DWT(CYCCNT)硬件定时器SysTick计数器位数32位16/32位24位计数方向向上可配置向下占用资源无需要外设无最高精度时钟周期级依赖分频1ms级是否需要配置简单使能复杂配置简单配置从表格可以看出DWT在精度和资源占用方面都有明显优势。以STM32H743为例400MHz的主频意味着DWT能提供2.5ns的时间分辨率这是传统定时器难以企及的。DWT的工作原理CYCCNT是一个自由运行的32位计数器每次内核时钟触发时计数器加1计数器溢出后自动归零重新计数不需要中断参与纯硬件计数3. 基于DWT的精确延时实现现在让我们动手实现基于DWT的精确延时方案。我们需要重写HAL库中的三个关键函数HAL_InitTick()、HAL_GetTick()和HAL_Delay()。3.1 初始化DWT首先我们需要初始化DWT外设并启用CYCCNT计数器。这个过程只需要配置几个寄存器#define DWT_CR *(__IO uint32_t *)0xE0001000 #define DWT_CYCCNT *(__IO uint32_t *)0xE0001004 #define DEM_CR *(__IO uint32_t *)0xE000EDFC #define DEM_CR_TRCENA (1 24) #define DWT_CR_CYCCNTENA (1 0) HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority) { /* 使能DWT外设 */ DEM_CR | (uint32_t)DEM_CR_TRCENA; /* 清空CYCCNT计数器 */ DWT_CYCCNT (uint32_t)0u; /* 使能CYCCNT计数器 */ DWT_CR | (uint32_t)DWT_CR_CYCCNTENA; return HAL_OK; }注意这个初始化过程只需要在系统启动时执行一次之后CYCCNT就会自动运行。3.2 实现微秒级延时基于CYCCNT我们可以实现极高精度的延时函数。下面是微秒级延时的实现void CPU_TS_Tmr_Delay_US(uint32_t us) { uint32_t ticks; uint32_t told, tnow, tcnt 0; /* 计算需要的时钟周期数 */ ticks us * (GET_CPU_ClkFreq() / 1000000); told (uint32_t)DWT_CYCCNT; // 获取初始计数值 while(1) { tnow (uint32_t)DWT_CYCCNT; if(tnow ! told) { /* 处理计数器溢出情况 */ if(tnow told) { tcnt tnow - told; } else { tcnt UINT32_MAX - told tnow; } told tnow; /* 达到或超过所需延时则退出 */ if(tcnt ticks) break; } } }这个实现考虑了计数器溢出的情况确保在任何情况下都能正确计算经过的时间。3.3 兼容HAL库的延时函数为了保持与HAL库的兼容性我们需要重新实现HAL_GetTick()和HAL_Delay()uint32_t HAL_GetTick(void) { /* 将时钟周期数转换为毫秒 */ return ((uint32_t)DWT_CYCCNT / (GET_CPU_ClkFreq() / 1000)); } #define HAL_Delay(ms) CPU_TS_Tmr_Delay_US(ms*1000)4. 在STM32H743上的完整实现下面是在STM32H743平台上基于DWT的完整延时方案。我们将其分为头文件和源文件两部分。core_delay.h:#ifndef __CORE_DELAY_H #define __CORE_DELAY_H #include stm32h7xx_hal.h /* 获取CPU时钟频率 */ #define GET_CPU_ClkFreq() HAL_RCC_GetSysClockFreq() /* 是否在延时函数内部初始化DWT */ #define CPU_TS_INIT_IN_DELAY_FUNCTION 0 /* 函数声明 */ uint32_t CPU_TS_TmrRd(void); HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority); void CPU_TS_Tmr_Delay_US(uint32_t us); /* 宏定义 */ #define HAL_Delay(ms) CPU_TS_Tmr_Delay_US((ms)*1000) #define CPU_TS_Tmr_Delay_MS(ms) CPU_TS_Tmr_Delay_US((ms)*1000) #define CPU_TS_Tmr_Delay_S(s) CPU_TS_Tmr_Delay_MS((s)*1000) #endif /* __CORE_DELAY_H */core_delay.c:#include core_delay.h /* DWT寄存器定义 */ #define DWT_CR *(__IO uint32_t *)0xE0001000 #define DWT_CYCCNT *(__IO uint32_t *)0xE0001004 #define DEM_CR *(__IO uint32_t *)0xE000EDFC #define DEM_CR_TRCENA (1 24) #define DWT_CR_CYCCNTENA (1 0) /* 初始化DWT */ HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority) { /* 使能DWT外设 */ DEM_CR | (uint32_t)DEM_CR_TRCENA; /* 清空CYCCNT */ DWT_CYCCNT (uint32_t)0u; /* 使能CYCCNT */ DWT_CR | (uint32_t)DWT_CR_CYCCNTENA; return HAL_OK; } /* 读取当前计数器值 */ uint32_t CPU_TS_TmrRd(void) { return ((uint32_t)DWT_CYCCNT); } /* 微秒级延时 */ void CPU_TS_Tmr_Delay_US(uint32_t us) { uint32_t ticks; uint32_t told, tnow, tcnt 0; /* 如果需要在函数内部初始化DWT */ #if (CPU_TS_INIT_IN_DELAY_FUNCTION) HAL_InitTick(5); #endif /* 计算需要的时钟周期数 */ ticks us * (GET_CPU_ClkFreq() / 1000000); told (uint32_t)CPU_TS_TmrRd(); while(1) { tnow (uint32_t)CPU_TS_TmrRd(); if(tnow ! told) { if(tnow told) { tcnt tnow - told; } else { tcnt UINT32_MAX - told tnow; } told tnow; if(tcnt ticks) break; } } } /* 重定义HAL_GetTick */ uint32_t HAL_GetTick(void) { return ((uint32_t)DWT_CYCCNT / (GET_CPU_ClkFreq() / 1000)); }5. 实际应用中的注意事项虽然DWT方案非常强大但在实际应用中还是需要注意以下几点初始化时机确保在调用任何延时函数前已经初始化了DWT。最好的做法是在main()函数开始时调用HAL_InitTick()。计数器溢出虽然32位计数器在400MHz下需要约10.7秒才会溢出但在设计长时间延时时仍需考虑这一点。低功耗模式当CPU进入某些低功耗模式时内核时钟可能停止导致DWT计数器也停止。在这种情况下需要考虑替代方案。多核系统在STM32H7等多核芯片上每个核都有自己的DWT组件需要注意核间同步问题。调试影响DWT主要用于调试目的在某些调试场景下可能会被调试器重置需要考虑这种特殊情况。性能对比测试我们在STM32H743平台上对几种延时方式进行了测试结果如下延时方法最小延时平均误差CPU占用HAL_Delay()1ms±1ms高硬件定时器1us±0.5us中DWT方案0.1us±0.05us低从测试结果可以看出DWT方案在精度和CPU占用率方面都有明显优势。特别是在需要频繁短延时的场景中DWT几乎是不二之选。

相关文章:

HAL_Delay()在RTOS下失效?手把手教你用DWT实现us级精确延时(附STM32H743代码)

HAL_Delay()在RTOS下失效?手把手教你用DWT实现us级精确延时(附STM32H743代码) 在嵌入式开发中,精确的延时控制往往是保证系统稳定性和实时性的关键。当我们在RTOS环境下使用STM32的HAL库时,可能会遇到一个棘手的问题&a…...

网易云音乐下载器技术深度解析:从API逆向到无损音乐库构建

网易云音乐下载器技术深度解析:从API逆向到无损音乐库构建 【免费下载链接】netease-cloud-music-dl Netease cloud music song downloader, with full ID3 metadata, eg: front cover image, artist name, album name, song title and so on. 项目地址: https://…...

Yjs协同编辑避坑指南:从ToDoList到Markdown编辑器的完整实现方案

Yjs协同编辑避坑指南:从ToDoList到Markdown编辑器的完整实现方案 在多人协作场景下,实时同步编辑的需求越来越普遍。无论是团队协作的待办事项管理,还是多人共同编辑的Markdown文档,如何确保数据一致性、解决冲突问题,…...

GLM-OCR模型与Dify平台结合:打造零代码智能OCR应用

GLM-OCR模型与Dify平台结合:打造零代码智能OCR应用 你是不是也遇到过这样的场景?每天都要处理一堆发票、合同或者名片,一张张手动录入信息,眼睛看花了不说,还特别容易出错。或者,你的业务系统里积压了大量…...

革新性3D点云标注工具:labelCloud的3大核心优势与高效实践指南

革新性3D点云标注工具:labelCloud的3大核心优势与高效实践指南 【免费下载链接】labelCloud 项目地址: https://gitcode.com/gh_mirrors/la/labelCloud 3D点云标注工具在计算机视觉领域扮演着关键角色,而labelCloud作为一款轻量级开源解决方案&a…...

WAN2.2文生视频效果展示:‘青花瓷纹样’提示词生成循环动画GIF(含导出设置)

WAN2.2文生视频效果展示:‘青花瓷纹样’提示词生成循环动画GIF(含导出设置) 想不想用一句话,就让静态的“青花瓷”纹样动起来,变成一段优雅的循环动画?今天,我们就来实测一下WAN2.2文生视频模型…...

Linux驱动开发核心知识体系:字符/块/网络设备驱动与内核机制解析

1. Linux驱动开发核心知识体系解析Linux驱动开发是嵌入式系统工程师进阶的必经之路,也是内核级软件工程能力的重要体现。本节内容并非泛泛而谈的概念罗列,而是基于多年一线驱动开发、内核模块维护及面试评估经验提炼出的技术要点。所有条目均对应真实工程…...

FRCRN效果实测:-5dB极低信噪比下关键词识别准确率提升曲线

FRCRN效果实测:-5dB极低信噪比下关键词识别准确率提升曲线 语音识别技术已经深入到我们生活的方方面面,从手机语音助手到智能家居控制,再到会议纪要自动生成。然而,一个始终困扰着用户体验的核心问题就是环境噪声。当你在嘈杂的街…...

WwiseUtil:游戏音频处理的技术突破与创新方案

WwiseUtil:游戏音频处理的技术突破与创新方案 【免费下载链接】wwiseutil Tools for unpacking and modifying Wwise SoundBank and File Package files. 项目地址: https://gitcode.com/gh_mirrors/ww/wwiseutil 在游戏开发领域,音频资源的高效管…...

墨语灵犀辅助C语言学习:代码解释、调试与基础概念问答

墨语灵犀辅助C语言学习:代码解释、调试与基础概念问答 你是不是也遇到过这样的情况?面对一段复杂的C语言代码,看了半天也理不清它的逻辑;或者程序编译通过了,但运行结果就是不对,对着屏幕干瞪眼&#xff0…...

5步高效下载B站视频:打造个人专属资源库的完整方案

5步高效下载B站视频:打造个人专属资源库的完整方案 【免费下载链接】BilibiliDown (GUI-多平台支持) B站 哔哩哔哩 视频下载器。支持稍后再看、收藏夹、UP主视频批量下载|Bilibili Video Downloader 😳 项目地址: https://gitcode.com/gh_mirrors/bi/B…...

directADC:AVR微控制器高精度低抖动ADC驱动库

1. directADC 库概述&#xff1a;面向 AVR 平台的高级 ADC 控制方案directADC 是一个专为 Atmel AVR 系列微控制器&#xff08;如 ATmega328P、ATmega2560、ATtiny85 等&#xff09;设计的轻量级、高精度 ADC 控制库。它并非对标准<avr/io.h>中ADCSRA/ADMUX寄存器操作的简…...

《Claude Code 从入门到精通》试读篇:Claude Code 是什么?你可能从第一步就用错了

本文是《Claude Code 从入门到精通》合集的试读篇阅读时长&#xff1a;约8分钟 难度&#xff1a;★☆☆☆☆ 适合人群&#xff1a;完全没用过或刚接触 Claude Code 的开发者 学完之后&#xff1a;你会知道 Claude Code 的真实定位&#xff0c;以及它在你日常工作里该怎么用你大…...

深入解析差错控制技术:从奇偶校验到循环冗余校验的实战应用

1. 为什么我们需要差错控制技术&#xff1f; 想象一下你正在给朋友发送一条重要消息&#xff1a;"明天下午3点会议室见"。如果传输过程中某个比特位出错&#xff0c;消息变成"明天下午8点会议室见"&#xff0c;后果可能很严重。这就是差错控制技术存在的意…...

libfixmath嵌入式定点数学库原理与实战

1. libfixmath&#xff1a;跨平台定点数学库深度解析1.1 定点运算的工程必要性在资源受限的嵌入式系统中&#xff0c;浮点运算单元&#xff08;FPU&#xff09;并非标配。以Cortex-M0/M0/M3等主流MCU为例&#xff0c;其硬件FPU支持极为有限甚至完全缺失。此时若直接调用标准C库…...

专栏简介:21天学会基于 Linux 的 NPU 固件开发

目录 专栏简介:21天学会基于 Linux 的 NPU 固件开发 🚀 专栏背景 🎯 适合人群 💡 专栏特色 📚 专栏目录 第一阶段:基础筑基(4 周) 第 1 章:NPU 技术全景与开发环境搭建 第 2 章:Linux 内核与固件交互机制 第 3 章:NPU 指令集与微架构探秘 第二阶段:核…...

51单片机温湿度检测报警

目录 具体实现功能 设计介绍 51单片机简介 资料内容 原理图和PCB&#xff08;AD19&#xff09; 仿真实现&#xff08;protues8.7&#xff09; 程序&#xff08;Keil5&#xff09; 全部资料 资料获取 具体实现功能 由51单片机DHT11温湿度传感器LCD1602液晶显示按键模块…...

Boost串口通信实战:从基础配置到异步读写优化

1. 串口通信基础与Boost.Asio简介 串口通信作为嵌入式系统和物联网设备中最基础的通信方式之一&#xff0c;至今仍在工业控制、传感器数据采集等领域广泛应用。相比网络通信&#xff0c;串口的优势在于硬件简单、协议直接&#xff0c;特别适合短距离、点对点的数据传输场景。我…...

Redis的设计与实现(6)-压缩列表

压缩列表 (ziplist) 是列表键和哈希键的底层实现之一.当一个列表键只包含少量列表项, 并且每个列表项要么就是小整数值, 要么就是长度比较短的字符串, 那么 Redis 就会使用压缩列表来做列表键的底层实现. 当一个哈希键只包含少量键值对, 并且每个键值对的键和值要么就是小整数值…...

OpenClaw配置备份方案:GLM-4.7-Flash环境迁移与快速恢复

OpenClaw配置备份方案&#xff1a;GLM-4.7-Flash环境迁移与快速恢复 1. 为什么需要配置备份&#xff1f; 上周我的主力开发机突然硬盘故障&#xff0c;不得不紧急更换设备。当我准备在新电脑上重新部署OpenClaw时&#xff0c;突然意识到一个严重问题——过去三个月精心调试的…...

小白专属!Qwen2.5-7B离线推理,一步步教你搭建环境

小白专属&#xff01;Qwen2.5-7B离线推理&#xff0c;一步步教你搭建环境 1. 前言&#xff1a;为什么选择Qwen2.5-7B&#xff1f; Qwen2.5-7B是阿里最新开源的大语言模型&#xff0c;相比前代版本有了显著提升。它特别适合中文场景&#xff0c;能帮你完成各种文本生成任务&am…...

DRAM命令真值表实战指南:如何正确理解L/H/V/X信号(DDR4为例)

DRAM命令真值表实战指南&#xff1a;如何正确理解L/H/V/X信号&#xff08;DDR4为例&#xff09; 在嵌入式系统开发中&#xff0c;DRAM的正确配置和操作是确保系统稳定性的关键。本文将深入解析DDR4 DRAM命令真值表中L&#xff08;低电平&#xff09;、H&#xff08;高电平&…...

translategemma-4b-it实战落地:与Notion API联动实现笔记截图自动翻译归档

translategemma-4b-it实战落地&#xff1a;与Notion API联动实现笔记截图自动翻译归档 1. 项目背景与价值 你有没有遇到过这样的情况&#xff1a;阅读英文资料时截取了大量有价值的截图&#xff0c;但时间一长就忘记了内容&#xff0c;或者需要分享给团队时还要手动翻译&…...

BepInEx新手故障诊断与解决方案完全指南

BepInEx新手故障诊断与解决方案完全指南 【免费下载链接】BepInEx Unity / XNA game patcher and plugin framework 项目地址: https://gitcode.com/GitHub_Trending/be/BepInEx 一、环境配置故障诊断&#xff1a;游戏启动无响应或闪退问题 影响范围说明 影响程度&…...

嵌入式机器人3-DOF运动学计算库:轻量级前向/逆向解算

1. 项目概述 Kinematics 是一个面向嵌入式机器人系统的轻量级运动学计算工具包&#xff0c;专为资源受限的微控制器平台&#xff08;如基于 AVR 或 ARM Cortex-M0 的 Arduino 兼容开发板&#xff09;设计。其核心目标并非替代工业级机器人控制库&#xff0c;而是提供一套 可直…...

告别依赖烦恼:在Kylin V10桌面版一键部署Qt 5.12.3开发环境(附离线包制作方法)

告别依赖烦恼&#xff1a;在Kylin V10桌面版一键部署Qt 5.12.3开发环境&#xff08;附离线包制作方法&#xff09; 在团队协作开发中&#xff0c;开发环境的标准化部署一直是个令人头疼的问题。特别是当项目需要迁移到国产化平台时&#xff0c;如何快速、高效地为整个团队搭建统…...

基于范德华外延氮化物剥离转印的研究

基于范德华外延氮化物剥离转印的研究 摘要 第三代半导体氮化物材料(GaN、AlN、InN及其合金)因其优异的物理性能在光电器件和功率电子领域具有重要应用。然而,氮化物异质外延面临的晶格失配与热失配问题,以及难以从生长衬底上剥离转移的困境,严重制约了其在柔性电子和异质…...

热键冲突排查完全指南:从症状到解决方案的系统方法论

热键冲突排查完全指南&#xff1a;从症状到解决方案的系统方法论 【免费下载链接】hotkey-detective A small program for investigating stolen hotkeys under Windows 8 项目地址: https://gitcode.com/gh_mirrors/ho/hotkey-detective 问题诊断&#xff1a;识别热键冲…...

Ostrakon-VL-8B入门指南:5类典型失败提问模式纠正(模糊/歧义/超范围/多跳/隐含)

Ostrakon-VL-8B入门指南&#xff1a;5类典型失败提问模式纠正&#xff08;模糊/歧义/超范围/多跳/隐含&#xff09; 你是不是也遇到过这种情况&#xff1a;给一个看起来很聪明的AI模型上传了一张图片&#xff0c;问了一个自己觉得很简单的问题&#xff0c;结果它要么答非所问&…...

DTIIA 9.1.1、角形传动滚筒头架(槽钢)

图示 【主视图】 【侧视图】 【俯视图】 【Tip】滚筒与支架连接的紧固件&#xff08;螺栓&#xff09;已包括在本部件内。 组成 见下面 标准图 “120JA1072Q” 参数 &#xff08;结合下面3张表&#xff09; 【Y】传动滚筒中心 到 中间架焊接角钢 &#xff08;带面角度&#…...