news 2026/1/11 5:18:48

简单理解:计算高电平时间(当前重载值 - 第一个上升沿值) + (重载值 * (溢出次数-1)) + 下降沿值

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
简单理解:计算高电平时间(当前重载值 - 第一个上升沿值) + (重载值 * (溢出次数-1)) + 下降沿值

以下是对注释对应的高电平时间计算逻辑的详细解析表格及核心说明,该逻辑适用于嵌入式定时器捕获模式(测量信号高电平持续时间,兼容 XT 系列 / STM32 等 MCU),核心解决 “高电平跨定时器溢出” 的计算问题:

计算项(注释拆解)语法 / 变量说明核心功能含义适用场景与示例
当前重载值定时器自动重载寄存器值(XT 系列:XT_GPTM0->CRR;STM32:htim->Instance->ARR定时器计数的最大值(如 16 位定时器默认65535),计数到该值后溢出归零是计算 “不完整周期计数” 的基准,所有跨溢出场景都需基于该值拆分计算
第一个上升沿值全局变量(volatile uint16_t,如G_RisingEdgeCnt信号高电平起始点的定时器捕获值(上升沿触发时锁存的计数值)高电平的 “起点标记”,由定时器捕获中断赋值(如G_RisingEdgeCnt = GPTM_GetCaptureCompare0(...)
(当前重载值 - 第一个上升沿值)无符号整数减法表达式计算 “从第一个上升沿到定时器第一次溢出” 的计数值(起点到溢出的高电平计数)例:CRR=65535,上升沿值 = 50000 → 结果 = 15535(50000~65535 共 15535 次计数)
溢出次数全局变量(volatile uint16_t,如G_OverFlowCnt高电平持续期间,定时器发生溢出的总次数(由溢出中断累加)高电平跨 N 个完整定时器周期时,溢出次数 = N+1(如跨 1 个完整周期,溢出次数 = 2)
(溢出次数 - 1)整数减法表达式计算高电平期间 “完整的定时器周期数”(排除首尾不完整周期)例:溢出次数 = 3 → 完整周期数 = 2(即 0~65535 重复 2 次)
(重载值 * (溢出次数 - 1))乘法表达式计算 “完整溢出周期” 对应的总计数(高电平在完整周期内的计数)例:CRR=65535,溢出次数 = 3 → 65535 * 2 = 131070(2 个完整周期的总计数)
下降沿值全局变量(volatile uint16_t,如G_FallingEdgeCnt信号高电平结束点的定时器捕获值(下降沿触发时锁存的计数值)高电平的 “终点标记”,由定时器捕获中断赋值(需配置为 “下降沿捕获” 或 “双边沿捕获”)
整体计算逻辑高电平计数 = (CRR - 上升沿值) + (CRR*(溢出次数-1)) + 下降沿值拆分高电平为 3 段计数求和:起点→第一次溢出 + 完整溢出周期 + 最后溢出→下降沿解决 “高电平持续时间> 定时器单次计数周期” 的计算误差,确保跨溢出场景下结果准确

核心补充说明(逻辑原理、场景与代码)

1. 为什么需要这样拆分计算?

定时器是 “循环计数”(0→CRR→0→CRR...),若高电平持续时间超过 1 个定时器周期(即发生溢出),直接用下降沿值 - 上升沿值会得到错误结果(无符号减法借位导致)。通过 “拆分三段” 可覆盖所有场景:

  • 第一段:上升沿(起点)→ 第一次溢出(不完整周期);
  • 第二段:多次完整溢出周期(若有);
  • 第三段:最后一次溢出→下降沿(终点,不完整周期)。
2. 典型示例(直观理解)

假设:

  • 定时器配置:16 位(CRR=65535),时钟 = 1MHz(1μs / 次计数);
  • 高电平起点(上升沿):G_RisingEdgeCnt=50000
  • 高电平期间溢出 2 次(G_OverFlowCnt=3);
  • 高电平终点(下降沿):G_FallingEdgeCnt=20000

计算过程:

高电平计数 = (65535 - 50000) + (65535*(3-1)) + 20000 = 15535 + (65535*2) + 20000 = 15535 + 131070 + 20000 = 166605 次计数

实际高电平时间 = 166605 μs = 166.605 ms(与物理时间完全一致)。

3. 无溢出场景的兼容性

若高电平未溢出(G_OverFlowCnt=1),公式自动简化为:

高电平计数 = (CRR - 上升沿值) + 0 + 下降沿值

因无溢出时下降沿值 > 上升沿值,根据无符号整数模运算特性:(CRR - 上升沿值) + 下降沿值 = 下降沿值 - 上升沿值 + CRR?→ 此处需注意:无溢出时需单独判断优化!若G_OverFlowCnt=1,直接用下降沿值 - 上升沿值即可(例:上升沿 = 10000,下降沿 = 30000 → 30000-10000=20000 次计数,正确)。完整代码中需增加判断,避免冗余计算:

if (G_OverFlowCnt == 1) { G_HighLevelCnt = G_FallingEdgeCnt - G_RisingEdgeCnt; // 未溢出,直接相减 } else { G_HighLevelCnt = (XT_GPTM0->CRR - G_RisingEdgeCnt) + (XT_GPTM0->CRR*(G_OverFlowCnt-1)) + G_FallingEdgeCnt; // 跨溢出计算 }
4. 关键前提(代码配置要求)

要使该公式生效,需满足 3 个核心配置:

配置项要求说明
定时器捕获模式通道配置为 “双边沿捕获”(上升沿 + 下降沿都触发捕获),或分别配置上升沿、下降沿捕获通道
中断使能使能 “捕获中断”(获取上升沿 / 下降沿值)和 “溢出中断”(累加溢出次数)
全局变量修饰上升沿值、下降沿值、溢出次数、高电平计数均需加volatile(避免编译器优化)
5. 完整代码片段(结合中断与计算)
// 全局变量(volatile 不可少) volatile uint32_t G_HighLevelCnt = 0; // 高电平总计数(32位避免溢出) volatile uint16_t G_RisingEdgeCnt = 0; // 上升沿捕获值(高电平起点) volatile uint16_t G_FallingEdgeCnt = 0; // 下降沿捕获值(高电平终点) volatile uint16_t G_OverFlowCnt = 0; // 溢出次数 volatile uint8_t G_CaptureFlag = 0; // 捕获标志:0=未捕获上升沿,1=已捕获上升沿 // 定时器0中断服务程序(捕获中断+溢出中断) void GPTM0_IRQHandler(void) { // 1. 捕获中断(通道0,双边沿触发) if (GPTM_GetIntStatus((XT_GPTM_TypeDef*)XT_GPTM0, GPTM_INT_CC0) == SET) { if (G_CaptureFlag == 0) { // 第一次捕获:上升沿(高电平起点) G_RisingEdgeCnt = GPTM_GetCaptureCompare0((XT_GPTM_TypeDef*)XT_GPTM0); G_OverFlowCnt = 0; // 重置溢出次数 G_CaptureFlag = 1; // 标记已捕获上升沿 } else { // 第二次捕获:下降沿(高电平终点) G_FallingEdgeCnt = GPTM_GetCaptureCompare0((XT_GPTM_TypeDef*)XT_GPTM0); // 核心计算:高电平时间(处理跨溢出) if (G_OverFlowCnt == 1) { G_HighLevelCnt = G_FallingEdgeCnt - G_RisingEdgeCnt; // 未溢出 } else { G_HighLevelCnt = (XT_GPTM0->CRR - G_RisingEdgeCnt) + (XT_GPTM0->CRR * (G_OverFlowCnt - 1)) + G_FallingEdgeCnt; // 跨溢出 } G_CaptureFlag = 0; // 重置标志,等待下一次测量 } GPTM_ClearIntPendingBit((XT_GPTM0, GPTM_INT_CC0); // 清除捕获中断标志 } // 2. 溢出中断(更新事件中断) if (GPTM_GetIntStatus((XT_GPTM_TypeDef*)XT_GPTM0, GPTM_INT_UEV) == SET) { if (G_CaptureFlag == 1) { // 已捕获上升沿,才累加溢出次数 G_OverFlowCnt++; } GPTM_ClearIntPendingBit((XT_GPTM_TypeDef*)XT_GPTM0, GPTM_INT_UEV); // 清除溢出中断标志 } } // 主程序:换算高电平实际时间 void main(void) { GPTM_Init(); // 初始化:GPTM0通道0双边沿捕获,使能捕获+溢出中断(省略配置) _EINT(); // 使能全局中断 uint32_t timer_clk = 1000000; // 定时器时钟=1MHz(1μs/次) float high_level_time; // 高电平时间(单位:ms) while(1) { if (G_HighLevelCnt != 0) { // 换算为实际时间:计数次数 / 时钟频率(Hz)= 秒 → 转毫秒 high_level_time = (float)G_HighLevelCnt / timer_clk * 1000; printf("高电平时间:%.2f ms\n", high_level_time); // 打印结果 G_HighLevelCnt = 0; // 清零,等待下一次测量 } } }
6. 跨平台兼容性(XT 系列 vs STM32)

该计算逻辑的核心是 “定时器计数原理”,与具体 MCU 无关,仅需替换寄存器 / 函数命名:

功能项XT 系列(示例)STM32(HAL 库示例)
自动重载值XT_GPTM0->CRRhtim1.Instance->ARR
读取捕获值GPTM_GetCaptureCompare0(XT_GPTM0)HAL_TIM_ReadCapturedValue(&htim1, TIM_CHANNEL_0)
捕获中断标志GPTM_INT_CC0TIM_IT_CC1(通道 1 为例)
溢出中断标志GPTM_INT_UEVTIM_IT_UPDATE

总结

该注释对应的公式是嵌入式高电平时间测量的核心逻辑,核心价值是:

  1. 解决 “高电平跨定时器溢出” 的计算误差,覆盖所有时长场景;
  2. 基于定时器自动重载值拆分计数,确保结果精准;
  3. 需配合 “双边沿捕获 + 溢出中断” 的硬件配置,及volatile修饰的全局变量,才能正常工作。

实际使用时,需根据 MCU 型号调整寄存器 / 函数命名,并在无溢出时优化计算(直接相减),提升效率。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/1/3 2:11:32

情感計算與社會化代理:重塑人機交互的未來

情感計算與社會化代理:重塑人機交互的未來引言:情感智能的時代來臨在人工智能迅猛發展的今天,傳統的計算系統專注於邏輯推理與數據處理,卻往往忽略了人類交流中最核心的要素——情感。情感計算(Affective Computing&am…

作者头像 李华
网站建设 2025/12/31 16:55:49

【区块链+PHP开发秘籍】:掌握这4种接口模式,轻松实现数据上链

第一章:PHP与区块链数据上链的核心逻辑在现代分布式应用开发中,PHP作为广泛应用的服务器端脚本语言,正逐步被集成到区块链技术生态中,实现关键业务数据的安全上链。其核心逻辑在于利用PHP构建可信数据结构,并通过智能合…

作者头像 李华
网站建设 2025/12/31 16:55:43

PHP微服务如何扛住百万级并发?服务网格集成全链路解析

第一章:PHP微服务高并发挑战与架构演进随着互联网业务规模的持续扩张,传统单体PHP应用在面对高并发请求时暴露出性能瓶颈与扩展性不足的问题。为应对流量激增、提升系统可用性,PHP后端架构逐步向微服务化演进,将复杂系统拆分为多个…

作者头像 李华
网站建设 2025/12/31 16:54:01

YOLOv8排行榜功能:公开模型性能横向对比

YOLOv8排行榜与镜像环境:高效开发与科学选型的双重革新 在自动驾驶感知系统需要实时识别上百个动态目标,工业质检产线每分钟处理数千张高清图像的今天,目标检测模型不仅要比“谁更准”,还得比“谁更快、更稳、更容易用”。YOLO系列…

作者头像 李华
网站建设 2025/12/31 16:53:30

卷积神经网络深度探索

本系列课程从卷积神经网络的基础概念出发,通过理论与实践相结合的方式,深入探讨卷积层、汇聚层、批量规范化、残差网络等核心组件及其在LeNet、AlexNet、VGG、NiN、GoogLeNet、ResNet和DenseNet等经典模型中的应用,旨在提升开发者在图像处理和…

作者头像 李华