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

从示波器波形到单片机代码:一次搞定霍尔电机信号里的‘杂波’滤波与速度计算

从示波器波形到单片机代码:一次搞定霍尔电机信号里的‘杂波’滤波与速度计算

当你在调试一个不知名的霍尔电机时,示波器上那些看似规律的方波中隐藏着令人头疼的高频杂波。这些15.3kHz的干扰信号会让你的转速计算偏离实际值数千倍。本文将带你完整经历一次从波形异常发现、问题分析到最终解决方案落地的工程实践。

1. 霍尔电机信号基础与异常发现

霍尔电机通过内置的霍尔传感器输出方波信号,通常每个磁极会对应一个完整的方波周期。在理想情况下,这些信号应该是干净整齐的方波,但实际上我们常常会遇到各种干扰。

使用示波器观察信号时,我发现:

  • 基础信号频率:约85Hz(对应电机转速5100r/min)
  • 叠加的高频噪声:15.3kHz的周期性干扰
  • 干扰幅度:达到基础信号幅度的30%

关键测量数据对比表

测量方式测得频率换算转速(r/min)实际转速(r/min)
转速表-51005100
原始信号85Hz51005100
干扰信号15.3kHz918,000不适用

注意:干扰信号的频率换算转速明显不合理,表明这是需要滤除的噪声

2. 杂波分析与滤波器设计

高频干扰的来源可能是电机驱动电路的开关噪声、电源纹波或电磁辐射。针对15.3kHz的干扰,我们需要设计一个低通滤波器,保留有用的转速信号(<1kHz),滤除高频噪声。

2.1 滤波器类型选择

考虑两种常见方案:

  1. RC低通滤波器
    • 优点:简单、成本低
    • 缺点:对陡峭截止需求响应一般
  2. LC低通滤波器
    • 优点:截止特性更陡峭
    • 缺点:体积大、成本高

基于本应用的需求,选择RC滤波器完全足够。

2.2 RC参数计算

截止频率公式:

f_c = 1 / (2πRC)

设计目标:

  • 保留信号:<1kHz
  • 滤除信号:>10kHz
  • 选择截止频率:2kHz(兼顾保留有用信号和滤除干扰)

常用电阻值选择360Ω,计算所需电容:

C = 1 / (2π × 360 × 2000) ≈ 220nF

实际选用:

  • 电阻:360Ω
  • 电容:220nF(标称值最接近计算值)

3. 硬件滤波实现与验证

将设计的RC滤波器接入信号线路后,重新用示波器观察波形变化:

滤波前后波形对比

特性滤波前滤波后
上升时间<100ns~2μs
高频噪声明显(15.3kHz)基本消除
信号幅度5V4.8V(轻微衰减)
波形完整性方波有毛刺较干净的正弦化边缘

虽然滤波后的上升沿变得稍缓,但对转速测量应用完全可接受。关键是没有了高频干扰,转速计算将更准确。

4. 单片机测速算法实现

4.1 测量原理

霍尔电机通常有多个极对,每个极对会产生两个边沿(上升沿和下降沿)。假设电机有3个极对,则:

  • 每转产生6个边沿
  • 测量两个边沿的时间间隔×3=每转时间

4.2 代码实现关键

使用STM32的定时器捕获功能实现:

// 定时器捕获初始化 void TIM1_Capture_Init(uint16_t prescaler, uint16_t reload) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_ICInitTypeDef TIM_ICInitStructure; // 时基配置 TIM_TimeBaseStructure.TIM_Period = reload - 1; TIM_TimeBaseStructure.TIM_Prescaler = prescaler - 1; TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure); // 输入捕获配置 TIM_ICInitStructure.TIM_Channel = TIM_Channel_2; TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; TIM_ICInitStructure.TIM_ICFilter = 0x01; // 轻微滤波 TIM_ICInit(TIM1, &TIM_ICInitStructure); // 启用中断 TIM_ITConfig(TIM1, TIM_IT_CC2 | TIM_IT_Update, ENABLE); TIM_Cmd(TIM1, ENABLE); }

4.3 转速计算

在捕获中断中计算转速:

void TIM1_CC_IRQHandler(void) { static uint32_t last_capture = 0; uint32_t current_capture; if (TIM_GetITStatus(TIM1, TIM_IT_CC2) != RESET) { current_capture = TIM_GetCapture2(TIM1); // 计算周期(考虑定时器溢出) uint32_t period = (current_capture > last_capture) ? (current_capture - last_capture) : (0xFFFF - last_capture + current_capture); // 保存当前值供下次使用 last_capture = current_capture; // 计算转速(r/min) // 假设3个极对,每个极对2个边沿,所以乘以6 float rpm = (60.0f * SystemCoreClock) / (period * prescaler * 6); // 更新全局转速变量 motor_rpm = (uint32_t)rpm; TIM_ClearITPendingBit(TIM1, TIM_IT_CC2); } }

5. 转向判断实现

霍尔电机的转向可以通过多个霍尔信号的相位关系判断。典型的三相霍尔信号在正反转时会有不同的边沿顺序:

正转序列

  1. 霍尔A上升沿
  2. 霍尔B上升沿
  3. 霍尔C上升沿

反转序列

  1. 霍尔A上升沿
  2. 霍尔C上升沿
  3. 霍尔B上升沿

实现代码片段:

void EXTI_IRQHandler(void) { static uint8_t last_state = 0; uint8_t current_state = (HALL_A_PIN << 2) | (HALL_B_PIN << 1) | HALL_C_PIN; if (current_state != last_state) { // 判断转向逻辑 if ((last_state == 0b100 && current_state == 0b110) || (last_state == 0b110 && current_state == 0b010) || (last_state == 0b010 && current_state == 0b011) || (last_state == 0b011 && current_state == 0b001) || (last_state == 0b001 && current_state == 0b101) || (last_state == 0b101 && current_state == 0b100)) { motor_direction = FORWARD; } else if (...) { // 反向判断逻辑 motor_direction = REVERSE; } last_state = current_state; } EXTI_ClearITPendingBit(HALL_A_EXTI_LINE | HALL_B_EXTI_LINE | HALL_C_EXTI_LINE); }

6. 系统优化与误差处理

在实际应用中,还需要考虑以下优化:

  1. 软件滤波:对连续几次测量结果进行中值滤波

    #define MEDIAN_FILTER_SIZE 5 uint32_t speed_buffer[MEDIAN_FILTER_SIZE]; uint32_t median_filter(uint32_t new_value) { static uint8_t index = 0; uint32_t temp_buffer[MEDIAN_FILTER_SIZE]; // 更新缓冲区 speed_buffer[index++] = new_value; if (index >= MEDIAN_FILTER_SIZE) index = 0; // 复制并排序 memcpy(temp_buffer, speed_buffer, sizeof(speed_buffer)); bubble_sort(temp_buffer, MEDIAN_FILTER_SIZE); return temp_buffer[MEDIAN_FILTER_SIZE/2]; }
  2. 异常处理:检测信号丢失或异常

    • 设置超时机制,长时间无信号变化视为停止
    • 检测信号占空比异常(如持续高/低电平)
  3. 校准功能

    • 通过已知转速校准极对数参数
    • 存储校准值到Flash,避免每次上电重新校准
http://www.cnnetsun.cn/news/2902297.html

相关文章:

  • VS2013下用Halcon12实现相机采集、二维码识别与界面显示三线程协同运行
  • 从MoeCTF到NSSCTF:CTF新手如何高效刷题并建立自己的解题知识库(Reverse/Web方向)
  • DLSS Swapper完整指南:免费工具轻松管理游戏DLSS版本,提升游戏性能体验
  • TMS320F28377D RAM运行程序全解析:从CMD文件配置到内存布局优化,让你的算法飞起来
  • 深入解析Mesen:如何用C++/C构建跨平台NES模拟器的技术架构
  • 保姆级教程:用STM32CubeMX和HAL库搞定ADC采集光照传感器(附完整代码)
  • 公司防泄密软件怎么选?拒绝硬核监视式管理
  • 嵌入式开发避坑指南:汽车ECU刷写中Flash Driver的RAM地址分配与安全设计要点
  • 猫抓插件终极指南:三步轻松捕获网页视频音频和图片资源
  • 保姆级拆解:CODESYS 3.5.19 Robotics例程里,PickAndPlace的坐标变换到底是怎么玩的?
  • Java计算机毕设之基于 SpringBoot 的师生家教对接管理系统(完整前后端代码+说明文档+LW,调试定制等)
  • CH32V307实战:用TIM4驱动舵机,保姆级代码解析与调试心得
  • 储能电站维保智能预判实测:依托巡检数据测算损耗,实在Agent如何让OM成本骤降35%?
  • NewJob:终极招聘神器!3秒识别有效职位,求职效率提升300%
  • 别再死记H7/g6了!用SolidWorks出工程图时,如何根据加工方式快速确定公差值?
  • 5G消息使用率不足10%,谷歌用电话反诈为其找到新出路
  • Linux命令-php(PHP语言的命令行接口)
  • feishu-doc-export:企业级飞书文档批量导出解决方案的技术实现与应用实践
  • MCF5445x嵌入式SoC:高集成度设计在工业控制与网络存储中的应用
  • 别再只用Python了!用LabVIEW+ONNX工具包,5分钟搞定你的第一个图像分类模型
  • 大疆与影石创新:中美市场诉讼不断,运动相机竞争白热化
  • ST官方开发板uboot启动菜单extlinux.conf配置详解(以STM32MP15为例)
  • STC8H外部中断INT0/INT3保姆级配置教程(附Keil补丁避坑指南)
  • 告别混乱图层管理:ArcMap数据加载全攻略(从本地Shapefile到数据库Geodatabase)
  • 告别会员限制:LX Music桌面版如何让你免费畅享全网音乐
  • 文本生成3D模型:零建模门槛的端到端实践指南
  • IwaraDownloadTool技术解析:浏览器脚本的视频下载解决方案
  • Transformer模型在金融风险建模中的创新应用
  • 飞书文档批量导出终极指南:3步完成企业知识库自动化备份
  • 交通护驾,重构道路运输安全管理新范式