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

STM32 HAL库实战:PWM输出在写Flash时如何避免舵机抖动?一个真实案例的两种解法

STM32 HAL库实战:PWM输出在写Flash时如何避免舵机抖动?一个真实案例的两种解法

在嵌入式开发中,PWM信号控制舵机是常见应用场景。但当系统需要执行Flash写入操作时,往往会遇到一个棘手问题:PWM波形异常导致舵机抖动。本文将深入分析问题根源,并提供两种经过验证的解决方案。

1. 问题现象与根源分析

最近在一个机器人控制项目中,我们使用STM32的TIM14定时器生成PWM信号驱动舵机。系统正常运行良好,但当按下按键触发Flash写入操作时,舵机会出现明显抖动。

通过逻辑分析仪捕获的波形显示,在Flash写入期间,PWM信号变成了20ms高电平和20ms低电平交替的异常波形。这种异常信号会导致舵机在目标位置附近不断抖动,严重影响系统稳定性。

问题根源在于:

  1. Flash写入操作通常需要关闭中断以保证数据完整性
  2. PWM的比较值更新是在定时器中断中完成的
  3. 中断关闭导致比较值无法更新,PWM波形"冻结"在当前状态
  4. 舵机将这种异常波形解读为无效指令,产生抖动

2. 解决方案一:轮询锁定低电平

第一种方法的核心思想是在关闭中断前,确保PWM输出锁定在低电平状态。这种方法适用于必须关闭中断的Flash操作场景。

2.1 实现步骤

  1. 等待低电平到来:通过轮询方式检测PWM引脚状态
  2. 设置比较值:当检测到低电平时,立即设置比较值为周期最大值
  3. 执行Flash操作:在保持低电平状态下安全地写入Flash

关键代码如下:

// 等待PWM输出变为低电平 while(HAL_GPIO_ReadPin(TIMCH_Buff[i].GPIOx, TIMCH_Buff[i].GPIO_Pin) != GPIO_PIN_RESET){} // 设置比较值为周期最大值,保持低电平 __HAL_TIM_SET_COMPARE(&TIMCH_Buff[i].htim, TIMCH_Buff[i].channel, 64000); // 关闭中断并执行Flash写入 __disable_irq(); Write_Flash_Buf(FLASH_RF_PIN_MODE_ADR,(uint8_t *) modebuff, sizeof(modebuff)); Write_Flash_Buf(FLASH_RF_PIN_DATA_ADR, Slave_re_Pindata_temp, sizeof(Slave_re_Pindata_temp)); __enable_irq();

2.2 定时器中断处理优化

为了配合这种方法,需要在定时器中断处理中添加特殊逻辑:

if(HAL_GPIO_ReadPin(timch->GPIOx, timch->GPIO_Pin) == GPIO_PIN_SET) { // 高电平状态:正常更新比较值 timch->count =__HAL_TIM_GET_COMPARE(&timch->htim, timch->channel) + (4864+Buf[rps[timch->rpspin].mode]-2048); timch->count = (timch->count>TIM_PERIOD) ? (timch->count-TIM_PERIOD) : timch->count; __HAL_TIM_SET_COMPARE(&timch->htim, timch->channel, timch->count); } else { // 低电平状态:设置比较值为周期最大值 __HAL_TIM_SET_COMPARE(&timch->htim, timch->channel, 64000); }

提示:这种方法需要精确计算等待低电平的超时时间,避免系统死锁。

3. 解决方案二:定时器启停控制

第二种方法不需要关闭中断,而是通过控制定时器的启停来保证PWM输出稳定性。这种方法更适合对中断响应要求不高的场景。

3.1 实现步骤

  1. 等待低电平到来:同样通过轮询检测PWM引脚状态
  2. 停止定时器输出:在低电平时停止PWM输出
  3. 执行Flash操作:此时PWM引脚将保持最后状态(低电平)
  4. 恢复定时器输出:操作完成后重新启动PWM

关键代码如下:

// 等待PWM输出变为低电平 while(HAL_GPIO_ReadPin(TIMCH_Buff[i].GPIOx, TIMCH_Buff[i].GPIO_Pin) != GPIO_PIN_RESET){} // 停止定时器输出(保持当前低电平) HAL_TIM_OC_Stop_IT(&TIMCH_Buff[i].htim, TIMCH_Buff[i].channel); // 执行Flash写入(无需关闭中断) Write_Flash_Buf(FLASH_RF_PIN_MODE_ADR,(uint8_t *) modebuff, sizeof(modebuff)); Write_Flash_Buf(FLASH_RF_PIN_DATA_ADR, Slave_re_Pindata_temp, sizeof(Slave_re_Pindata_temp)); // 重新启动定时器输出 HAL_TIM_OC_Start_IT(&TIMCH_Buff[i].htim, TIMCH_Buff[i].channel);

3.2 方案优势对比

特性方案一(轮询锁定)方案二(定时器启停)
中断状态需要关闭中断保持中断开启
系统响应性较差(中断关闭期间)较好
实现复杂度中等(需修改中断处理)简单
适用场景必须关闭中断的Flash操作常规Flash操作
资源占用需要轮询等待只需一次启停操作

4. 工程实践建议

在实际项目中选择解决方案时,需要考虑以下因素:

  1. 系统实时性要求

    • 如果系统对中断响应要求高,优先考虑方案二
    • 如果Flash操作必须关闭中断,则选择方案一
  2. PWM信号特性

    • 对于高频PWM信号,轮询等待低电平可能耗时较长
    • 低频信号(如舵机控制)更适合方案一
  3. 代码可维护性

    • 方案二实现更简洁,后期维护成本低
    • 方案一需要对定时器中断有更深入的理解
  4. 异常处理

    • 为轮询等待添加超时机制,避免死锁
    • 在定时器启停前后添加状态检查

5. 深入理解:STM32定时器工作机制

要彻底解决这个问题,需要理解STM32定时器的几个关键机制:

  1. 输出比较模式

    • TIM_OCMODE_TOGGLE模式下,当计数器值与比较值匹配时,输出引脚电平翻转
    • 比较值更新通常发生在定时器中断中
  2. 自动重装载预加载

    • TIM_AUTORELOAD_PRELOAD_ENABLE可以确保周期值更改无毛刺
    • 但对比较值的即时更新没有同样效果
  3. 中断与DMA

    • 定时器更新事件可以触发中断或DMA请求
    • Flash操作期间中断关闭会影响这些机制

理解这些底层机制,有助于我们在类似问题上快速找到解决方案。

http://www.jsqmd.com/news/679481/

相关文章:

  • 别扔!手把手教你用U盘和Telnet救活WD MyCloud Gen2变砖(保姆级图文教程)
  • 从一条CAN报文说起:深入理解J1939多帧传输(BAM/TP.DT)的底层逻辑与抓包分析
  • 全面掌控英雄联盟游戏体验:基于LCU API的智能自动化工具集深度解析
  • 收藏|2026最新版大语言模型(LLM)系统化学习路线,小白程序员都适用
  • DataGrip连接MySQL报错‘无效时区’?5分钟搞定配置并解锁它的SQL智能补全
  • CN3392 PFM 升压型双节锂电池充电控制集成电路
  • 强化学习核心算法与工程实践全解析
  • 2026年泥浆压滤机租赁排行:河道泥浆固化机/河道清淤压滤机/泥浆脱水机/湖泊清淤泥浆固化机/电厂脱硫专用压滤机/选择指南 - 优质品牌商家
  • Cadence IC617实战:手把手教你用Virtuoso仿真共源级放大器(含电阻负载分析)
  • 别再让IT团队管车了!聊聊车企搭建VSOC(车辆安全运营中心)必须独立的5个坑
  • 【电池-超级电容器混合存储系统】单机光伏电池-超级电容混合储能系统的能量管理系统附Simulink仿真
  • AI Agent Harness Engineering 辅助创意设计:从 Midjourney 到自主设计
  • 计算机毕业设计:Python农产品电商数据可视化分析大屏 Flask框架 数据分析 可视化 机器学习 数据挖掘 大数据 大模型(建议收藏)✅
  • VSCode集成ChatGPT提升开发效率全指南
  • 保姆级教程:在Ubuntu 20.04上搞定arm-linux-gnueabi交叉编译环境(含libmpfr.so.4报错解决方案)
  • CN3862 具有太阳能最大功率点跟踪功能的降压型 4A 两节锂电池充电管理集成电路
  • 别再只测距了!用HC-SR04+STM32做个智能防撞小车(附完整代码)
  • 别再死记硬背了!一张图帮你搞懂SRv6里那些‘End.X’、‘End.DT4’指令到底在干啥
  • 【电磁】两个不同介电常数的区域2D FDTD研究附Matlab代码
  • Buildroot启动报错‘/dev/console找不到’?手把手教你排查mdev与设备节点问题
  • 从AUTOSAR标准看VCU/MCU/BMS开发:为什么说软件定义汽车时代,架构先行?
  • 别再只盯着RSSI测距了!手把手教你用Python+蓝牙信标搭建一个简易的室内指纹定位系统
  • 28BYJ48步进电机驱动实战:从接线到代码的完整指南(附避坑技巧)
  • 如何5分钟告别百度网盘提取码困扰:智能获取工具完全指南
  • 【地质】一维层状模型大地电磁测深 (MT) 和可控源音频大地电磁测深 (CSAMT) 正演计算研究附Matlab代码
  • 2026免费GEO工具,AI搜索优化一步到位
  • 2026年权威软件检测机构名录:北京软件评测功能测试性能、北京软件项目验收测试、北京软件验收测试、北京验收测试选择指南 - 优质品牌商家
  • 别再只盯着PSNR了!用Python实战对比MSE、SSIM、UQI,手把手教你选对图像相似度指标
  • CN3863 具有太阳能最大功率点跟踪功能的降压型 4A 三节锂电池充电管理集成电路
  • 手把手教你用Python脚本+ROS,让ORB-SLAM3跑通自己的USB双目摄像头(含标定)