首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >如何计算中断函数的执行时间

如何计算中断函数的执行时间

作者头像
云深无际
发布2025-01-02 14:26:46
发布2025-01-02 14:26:46
9560
举报
文章被收录于专栏:云深之无迹云深之无迹

上面理论一通,再来点调试技巧。我们需要知道这个函数到底耗时不?

最简单可以使用使用GPIO来计算,将MCU的功耗和IO引脚关联起来分析 不仅可以计算时间还可以计算功耗。

使用一个 GPIO 引脚来记录中断函数的开始和结束时间。

  1. 在中断函数的开头将一个 GPIO 引脚置高。
  2. 在中断函数的结尾将这个 GPIO 引脚置低。
  3. 用示波器或逻辑分析仪测量 GPIO 的高电平持续时间,即为中断函数的执行时间。
代码语言:javascript
复制
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
    if (htim == &htim2) {
        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET); // GPIO 引脚置高

        // 中断任务
        AD7682_Read_4_ADC_Value(ADC_Value_u16_inter);
        IIR_50HZ_Norch_Filter(...);
        applyIIRFilter(...);

        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET); // GPIO 引脚置低
    }
}

也可以利用 MCU 自带的定时器硬件,在中断函数中记录时间戳。

  1. 在中断开始时读取定时器的计数值( TIMx->CNT)。
  2. 在中断结束时再次读取计数值。
  3. 两次计数值的差值乘以定时器时钟周期,即为中断函数的执行时间。
代码语言:javascript
复制
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
    if (htim == &htim2) {
        uint32_t start_time = __HAL_TIM_GET_COUNTER(&htim3); // 获取定时器开始计数值

        // 中断任务
        AD7682_Read_4_ADC_Value(ADC_Value_u16_inter);
        IIR_50HZ_Norch_Filter(...);
        applyIIRFilter(...);

        uint32_t end_time = __HAL_TIM_GET_COUNTER(&htim3); // 获取定时器结束计数值

        uint32_t elapsed_ticks = (end_time >= start_time) ? 
                                 (end_time - start_time) : 
                                 ((htim3.Init.Period - start_time) + end_time + 1);

        float elapsed_time = elapsed_ticks * (1.0f / HAL_RCC_GetPCLK1Freq()); // 转换为秒
    }
}

一作差就可以了

不需要外部硬件,完全依赖 MCU 内部资源。可以精确计算运行时间。

需要占用一个定时器。这是什么狗屁话,我直接使用。定时器频率和计数溢出可能需要额外的处理,再说吧。

也可以使用 SysTick 定时器(系统滴答定时器)来记录时间。这个MCU都有,不会浪费捏。

  1. 在中断开始时读取 SysTick 的计数值(SysTick->VAL)。
  2. 在中断结束时再次读取 SysTick 的计数值。
  3. 两次计数值的差值乘以 SysTick 的时钟周期,即为中断函数的执行时间。
代码语言:javascript
复制
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
    if (htim == &htim2) {
        uint32_t start_time = SysTick->VAL; // 记录开始时间

        // 中断任务
        AD7682_Read_4_ADC_Value(ADC_Value_u16_inter);
        IIR_50HZ_Norch_Filter(...);
        applyIIRFilter(...);

        uint32_t end_time = SysTick->VAL; // 记录结束时间

        uint32_t elapsed_ticks = (start_time >= end_time) ?
                                 (start_time - end_time) :
                                 (SysTick->LOAD - end_time + start_time);

        float elapsed_time = elapsed_ticks * (1.0f / HAL_RCC_GetSysClockFreq()); // 转换为秒
    }
}

SysTick 分辨率受限于其时钟频率。如果中断执行时间较长,可能会导致 SysTick 溢出,需要额外处理。这个目前还不知道咋办

还有自带的调试内核,这个时比较高级的技巧,值得重点学习。

  1. 启用 ARM Cortex-M 的 DWT(数据观察和跟踪单元)。
  2. 在中断开始和结束时记录 DWT 的计数值。
  3. 通过计数差值和时钟频率计算执行时间。
代码语言:javascript
复制
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
    if (htim == &htim2) {
        DWT->CYCCNT = 0; // 重置 DWT 计数器
        uint32_t start_cycles = DWT->CYCCNT; // 开始时计数值

        // 中断任务
        AD7682_Read_4_ADC_Value(ADC_Value_u16_inter);
        IIR_50HZ_Norch_Filter(...);
        applyIIRFilter(...);

        uint32_t end_cycles = DWT->CYCCNT; // 结束时计数值

        uint32_t elapsed_cycles = end_cycles - start_cycles;
        float elapsed_time = elapsed_cycles * (1.0f / SystemCoreClock); // 转换为秒
    }
}

其实Keli有个调试组件,Event Recorder

有这个功能,更简单,加个代码就行

在CMSIS里面打开

然后重定向

其实也是使用的DWT

再说吧

安富莱有着详细的教程。代码,三分写,气氛调,不是啥好活。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-01-02,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 云深之无迹 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档