news 2026/9/4 9:20:13

stm32F103C8T6标准库DWT基础应用1

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
stm32F103C8T6标准库DWT基础应用1

目录

  • 1.DWT介绍
  • 2. DWT精度
  • 3.DWT 精确延时功能
  • 4. DWT相关寄存器
    • 4.1 DEMCR
    • 4.2 DWT_CYCCNT
    • 4.3 CYCCNTENA
    • 4.4 寄存器总结
  • 5. DWT宏定义编写
  • 6. DWT模块代码
    • 6.1 DWT初始化
    • 6.2 获取当前时间戳
    • 6.3 节拍数转换成对应的时间
    • 6.4 us延时
    • 6.5 ms延时
    • 6.6 s延时

1.DWT介绍

在Cortex-M里面有一个外设叫DWT(DataWatchpoint andTrace),是用于系统调试及跟踪,它有一个32位的寄存器叫CYCCNT,它是一个向上的计数器,记录的是内核时钟运行的个数,内核时钟跳动一次,该计数器就加1,精度非常高,决定内核的频率是多少。

2. DWT精度

例如本教程是基于F103系列,内核时钟是72M,那精度就是1/72M=14ns,而程序的运行时间都是微秒级别的,所以14ns的精度是远远够的。

假设内核频率为72M,内核跳一次的时间大概为1/72M=14ns(最长能记录的时间为:
60s=2的32次方/72000000)。

如果是H7这种400M主频的芯片,那它的计时精度高达1/400M=2.5ns。
如果是i.MXRT1052这种高速的处理器,假设内核频率为528M,内核跳一次的时间
大概为1/528M=1.9ns,(最长能记录的时间为:8.13s=2的32次方/528000000)。
当CYCCNT溢出之后,会清0重新开始向上计数。

3.DWT 精确延时功能

要实现延时的功能,总共涉及到三个寄存器:DEMCR、DWT_CTRL、DWT_CYCCNT,分别用于开启DWT功能、开启CYCCNT及获得系统时钟计数值。
详细内容出自文献《DDI0337Hcortexm3_r2p0_trm》与《CM3权威指南CnR2》等

4. DWT相关寄存器

4.1 DEMCR

想要使能DWT外设,需要由另外的内核调试寄存器DEMCR的位24控制,写1使能。
DEMCR的地址是:OxEOOOEDFC。关于该寄存器的详情见图DEMCR的位24写1使能。

4.2 DWT_CYCCNT

使能DWT_CYCCNT寄存器之前,先清0。其基地址是OxE0001004,复位默认值是0,
可读写类型。所以往0xE0001004这个地址写0,就将DWT_CYCCNT清0了。

4.3 CYCCNTENA

它是DWT控制寄存器(DWT_CTRL)的第一位,其基地址为:OxE0001000,写1使能,则启用CYCCNT计数器,否则CYCCNT计数器将不会工作。

4.4 寄存器总结

想要使用DWT的时候需要将 DEMCR寄存器的第24位写1使能。
想要查看计数的值,去看DWT_CYCCNT寄存器里面计数的值。
如果想要开始计数,DWT 控制寄存器 DWT_CTRL 的第 0 位 CYCCNTENA 置 1,开启 CYCCNT 硬件自增计数。

5. DWT宏定义编写

/*DWT时间戳相关寄存器定义*/#defineDEMCR(*(uint32_t*)(0xE000EDFC))#defineDWT_CTRL(*(uint32_t*)(0xE0001000))#defineDWT_CYCCNT(*(uint32_t*)(0xE0001004))#defineDEMCR_TRCENA(1<<24)#defineDWT_CTRL_CYCCNTENA(1<<0)

外设叫DWT(Data Watchpoint and Trace,数据观察点与跟踪单元),该外设有一个32位的寄存器叫CYCCNT,
它是一个向上的计数器,记录的是内核时钟运行的个数,
内核每一个时钟周期时间大概为1/72M=14ns(最长能记录的时间约为:60s = 2的32次方 /72000000),
当CYCCNT溢出之后,自动清零,重新开始向上计数。

开关1 DEMCR:调试异常与监控控制寄存器 (寄存器地址:0xE000EDFC) DEMCR_TRCENA:管理第24位使能(DWT工作) 开关2 DWT_CTRL:控制寄存器 (寄存器地址:0xE0001000) DWT_CTRL_CYCCNTENA:管理第0位(计数器工作) DWT_CYCCNT:DWT 周期计数器寄存器 (寄存器地址:0xE0001004) 存放计数值,CPU每一个时钟周期自动+1。(使用前需要软件手动清零) 使能CYCCNT计数的操作步骤: 1、先使能DWT外设准备,这个由内核调试寄存器DEMCR的位24控制,写1使能 2、使能CYCCNT计数器之前,先清0。 3、使能CYCCNT计数器,这个由DWT_CTRL的位0控制,写1使能

6. DWT模块代码

6.1 DWT初始化

/** * @brief 初始化 DWT 计数器 * @param 无 * @retval 使用DWT延时函数之前,必须调用本函数 */voidDWT_Init(void){/* 1.先使能DWT设备准备 */DEMCR|=(uint32_t)DEMCR_TRCENA;/* 2.DWT CYCCNT寄存器清0 */DWT_CYCCNT=(uint32_t)0U;//使能CYCCNT计数器之前,先清0。/* 使能Cortex-M DWT CYCCNT 寄存器 */DWT_CTRL|=(uint32_t)DWT_CTRL_CYCCNTENA;}

6.2 获取当前时间戳

/** * @brief 获取当前的时间戳 * @param 无 * @retval 当前时间戳,即DWT_CYCCNT寄存器的值 */uint32_tDWT_GetTick(void){return(uint32_t)DWT_CYCCNT;}

6.3 节拍数转换成对应的时间

/** * @brief 节拍数转化时间间隔(微秒单位) * @param tick: 需要转换的节拍数 * @param frequency: 内核时钟频率 * @retval 当前时间戳,即DWT_CYCCNT寄存器的值 */uint32_tDWT_TickToMicrosecond(uint32_ttick,uint32_tfrequency){return(uint32_t)1000000.0/frequency*tick;}


传入的tick=3600,代表需要累计走过 3600 个 CPU 内核时钟节拍
DWT‑CYCCNT 寄存器每个内核时钟周期自动 + 1;当DWT->CYCCNT − start这个差值累加到 3600 时,硬件层面真实流逝时间就是 50μs(CPU 主频 72MHz 条件下)。

这里的tick = `DWT->CYCCNT − start周期差值,只是用户只需要传递节拍数

CYCCNT和us互相转换:
1/SystemCoreClock*CYCCNT(s) = 1000/SystemCoreClock*CYCCNT(ms)
= 1000 000/SystemCoreClock*CYCCNT(us)= (x)us

6.4 us延时

/** * @brief DWT计数实现精确延时,32位计数器 * @param time : 延迟长度,单位1 us * @retval 无 * @note 无 */voidDWT_DelayUs(__IOuint32_ttime){/* 将微秒转化为对应的时钟计数值*/uint32_ttick_duration=time*(SystemCoreClock/1000000);uint32_ttick_start=DWT_GetTick();/* 刚进入时的计数器值 */while(DWT_GetTick()-tick_start<tick_duration);}

tick_duration= time * (SystemCoreClock / 1000000) ;

  • time:输入,单位微秒 us
  • SystemCoreClock:内核时钟,单位Hz
  • tick_duration:输出,DWT 需要的节拍数(就是DWT->CYCCNT‑start要达到的差值)

完整流程(72MHz,time=50)

  1. time=50,计算:tick_duration = 50 * (SystemCoreClock/1000000)tick_duration = 3600
  2. tick_start = DWT->CYCCNT;,假设此刻寄存器读到 12400,tick_start =12400
  3. while 判断:(DWT->CYCCNT - tick_start) < 3600
    • 差值不到 3600:循环继续等待,CYCCNT 硬件持续 + 1
    • 差值 ≥3600:退出 while,延时完成

6.5 ms延时

/** * @brief DWT计数实现精确延时,32位计数器 * @param time : 延迟长度,单位1 ms * @retval 无 */voidDWT_DelayMs(__IOuint32_ttime){for(uint32_ti=0;i<time;i++){DWT_DelayUs(1000);}}

6.6 s延时

/** * @brief DWT计数实现精确延时,32位计数器 * @param time : 延迟长度,单位1 s * @retval 无 */voidDWT_DelayS(__IOuint32_ttime){for(uint32_ti=0;i<time;i++){DWT_DelayMs(1000);}}
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/3 8:15:51

开源投屏工具Scrcpy实战:电脑控制安卓/iOS,实现低延迟跨屏操作

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/3 8:14:48

专业工具箱GAOT:集成化工具集的价值、安全获取与深度定制指南

简介&#xff1a;本资源为GAOT&#xff08;Genetic Algorithm Optimization Toolbox&#xff09;遗传算法通用工具箱&#xff0c;面向高校科研人员、工程优化从业者及智能算法初学者&#xff0c;旨在降低遗传算法编程门槛&#xff0c;快速实现函数优化、参数调优与组合优化等典…

作者头像 李华
网站建设 2026/9/3 8:12:34

2026年电赛新手必看:核心器件清单、选购指南与分阶段备赛策略

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/3 8:12:06

EnvHarness:把智能体训练从静态测试集带向自适应环境

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/3 8:10:00

基于STA-ResNet的深度学习信道估计:从注意力机制到工程实现

简介&#xff1a;本资源是面向通信工程与人工智能交叉领域研究者及高年级本科生的深度学习信道估计实践项目&#xff0c;聚焦5G/6G无线系统中多径衰落、时变信道下的高精度CSI估计难题。项目完整实现STA-ResNet模型——融合空间注意力&#xff08;捕获多天线/多径空间特征&…

作者头像 李华