基于STM32的电机状态检测系统:从传感器选型到状态判断

基于STM32的电机状态检测系统:从传感器选型到状态判断
电机状态检测这个题目乍一看像是实验室里的毕设项目实际放到生产现场它就是设备预维护系统里最基础、也最关键的一环。我们遇到的大多数电机故障并不是某一瞬间突然发生的。轴承磨损、绕组老化、负载异常这些隐患在真正停机之前早就通过电流波动、温升、转速异常表现出来了。问题在于人不可能 24 小时盯着电机而普通电机的控制器也不会关心这些问题。STM32 单片机在这个场景里的角色就是一套很小的“边缘体检设备”它把电流、温度、转速这些模拟量采进来转换成可判断的状态量再通过串口上报给上位机或者直接触发本地报警。这篇文章会围绕一个完整的“基于 STM32 的电机状态检测”最小系统展开从传感器选型、硬件设计思路、ADC 采样与测速原理到状态判断逻辑、串口数据上报、常见工程坑位一步步说清楚。读完你能直接搭出一个可运行的样机也能知道这套方案在真实项目中要踩哪些雷。1. 为什么需要电机状态检测很多初学单片机的人会把“电机状态检测”理解为“测一下电机转没转”。这个理解太浅了。真实场景里电机状态检测要回答的是四类问题电机当前的电流是否在正常区间过流通常是负载异常或堵转的前兆。绕组或驱动器的温度是否在持续上升绝缘老化在早期并不会直接停机但温度曲线会给出信号。电机实际转速和期望转速是否有偏差转速骤降通常是机械卡阻或供电不足的表现。多台电机在产线上运行时如何把状态数据统一采集、统一预警传统做法是安排巡检人员定时检查或者等电机彻底停转后再维修。这两种方式的共同问题是被动——设备已经坏了损失已经造成。状态检测的意义在于把“事后维修”变成“事前维护”而实现这个能力并不需要昂贵的工业网关一块 STM32 就能把传感、判断、上报全部承担起来。从成本角度看这也是 STM32 方案最合适的切入点。工业上专用的状态检测模块往往价格不低而普通 STM32F103 系列芯片成本低、外设丰富、生态资料多非常适合作为电机状态检测的开发平台尤其适合设备数量多、预算有限的改造项目。2. 电机状态检测的核心概念与检测维度电机状态检测本质上是对电机的多个物理量做连续采样并通过阈值判断或趋势分析来评定电机当前的健康状态。最常见的检测维度有四个。2.1 电流检测电流是最直接反映电机负载的物理量。电机正常运行电流处在一个相对稳定的区间负载增加时电流上升堵转时电流会迅速冲到额定值的数倍。通过电流采样可以做到过流报警电流超过设定阈值时立即告警避免绕组烧毁。堵转识别电流突然升高且转速下降可以判定电机堵转。轻载/空载判断电流长期低于正常范围可能是皮带脱落或负载丢失。工程上常用的电流传感器有两种采样电阻法和霍尔电流传感器法。采样电阻适合小电流电路成本低但需要隔离霍尔电流传感器模块如 ACS712 系列把电流线性转换成电压使用简单适合教学和快速验证。2.2 温度检测温度反映电机绕组的发热情况。电机绝缘等级决定了它能承受的最高温度超过限值时寿命会急剧下降。温度检测通常用两种方式NTC 热敏电阻模拟信号通过分压电路接入 ADC成本最低但需要做非线性换算。DS18B20 数字温度传感器单总线协议直接输出数字温度代码成熟适合大多数场景。2.3 转速检测转速是判断机械状态的重要指标。常用的测速方案是霍尔传感器或光电编码器。让磁钢随转轴旋转霍尔传感器每经过一次就产生一个脉冲STM32 通过外部中断或定时器捕获脉冲再按固定时间窗口计算转速。转速数据的价值在于和电流数据配合判断。如果只有电流升高可能是负载增大如果电流升高同时转速下降基本可以判定堵转。2.4 电压检测电压检测用于判断供电是否正常。电机运行时电压跌落严重会导致转矩不足、转速下降电压过高则可能损坏驱动器。电压信号通常用电阻分压后接入 ADC。3. 系统总体架构与方案选型一个典型的 STM32 电机状态检测系统架构如下电机本体 ├── 电流传感器 (ACS712) → 模拟电压 → STM32 ADC ├── 温度传感器 (DS18B20) → 单总线 → STM32 GPIO ├── 霍尔测速模块 → 脉冲 → STM32 外部中断 └── 电源模块 → 电压分压 → STM32 ADC │ STM32 主控 ├── 蜂鸣器/继电器 → 本地报警 ├── OLED/LCD1602 → 本地显示 └── USART → 串口上报上位机3.1 主控选型推荐使用 STM32F103C8T6。它是 STM32 系列中最常见的入门芯片具备72MHz 主频足以完成多路 ADC 采样和状态判断3 个 USART、2 个 ADC、多个定时器外设资源够用标准库和 HAL 库资料极其丰富遇到问题很容易搜到解决方案。如果项目对功耗有要求可以换 STM32L 系列如果后续要接屏幕、做更复杂的 GUI可以考虑 STM32F407 系列。但从电机状态检测这个需求出发F103C8T6 性价比最高。3.2 传感器选型检测项推荐器件输出信号接入 STM32 的方式电流ACS712 电流传感器模块模拟电压ADC 采样温度DS18B20单总线数字信号GPIO 读取转速霍尔传感器 磁钢TTL 脉冲外部中断计数电压电阻分压模拟电压ADC 采样这套方案的特点是传感器无需额外信号调理电路模块化程度高BOM 简单容易复现。要注意的是 ACS712 模块输出的是以 VCC/2 为中点的电压信号零点不是 0V代码里必须减掉这个偏置。3.3 通信方案状态检测的最终价值要落到数据上报。项目中可以用 USART 串口把状态帧发送到 PC 端串口助手或用 USB 转 TTL 模块实现上位机显示。更完整的工程可以直接加 ESP8266 或 RS485 模块把数据接入物联网平台或组态软件。本文以串口上报为例思路可以平滑迁移。4. 硬件设计要点与传感器信号处理硬件部分听起来简单但真正容易踩坑的恰恰在这里。4.1 电源隔离电机是典型的强干扰源。电机启动瞬间电流可达正常工作电流的数倍会导致电源电压大幅跌落。如果单片机与电机共用一个电源轻则 ADC 采样值抖动严重重则单片机直接复位。在实际项目中应尽量做到单片机供电和电机驱动供电分开各自使用独立的电源模块若必须共地也要在电机电源端和单片机电源端之间加入足够容量的电解电容ACS712 模块供电电压建议用 5VSTM32 ADC 引脚耐压有限采样输出端要确认电平范围。4.2 ADC 采样的干扰问题电机运行时PWM 驱动产生的开关噪声会叠加到模拟信号上。如果直接把 ACS712 的输出接到 STM32 的 PA0读出到的电流波形会非常“毛躁”。解决方法有三个层次硬件上在信号线上并联 100nF 电容做低通滤波软件上对 ADC 采样值做多次平均或滑动滤波采样时刻避开 PWM 开关瞬间。对于 STM32F103 的 12 位 ADC典型做法是连续采样 10 次求平均能明显降低噪声影响。4.3 转速脉冲的处理霍尔传感器输出的脉冲信号在电机转速较高时频率可能达到几 kHz此时要考虑 STM32 外部中断是否能正确处理。一般电机转速不会超过数千 RPM假设每圈一个脉冲最大也就是几十 kHz用外部中断计数完全没有压力。但如果使用带减速比的电机减速比达到 1:30 甚至更高电机输出轴每圈对应的霍尔脉冲数会很多需要按减速比换算实际转速。这个细节很容易被忽略。4.4 电压检测电压检测用两个电阻分压即可。注意电阻分压网络要选择足够大的阻值避免分压电路本身消耗过多电流。分压后的电压不能超过 STM32 的 ADC 参考电压通常 3.3V否则会损坏引脚。5. STM32 软件设计从 ADC 采样到状态判断软件部分按功能划分为 ADC 采集模块、转速测量模块、状态判断模块和串口上报模块。下面以 HAL 库为例给出核心代码。5.1 ADC 多通道采样STM32F103C8T6 的 ADC1 可以采样多个通道PA0、PA1、PA2 分别接电流、电压信号。代码采用“每次切换通道并读取”的方式适合采样频率要求不高的系统。// 文件路径Src/adc.c #include adc.h #include main.h ADC_HandleTypeDef hadc1; void MX_ADC1_Init(void) { ADC_ChannelConfTypeDef sConfig {0}; __HAL_RCC_ADC1_CLK_ENABLE(); hadc1.Instance ADC1; hadc1.Init.ScanConvMode ADC_SCAN_DISABLE; hadc1.Init.ContinuousConvMode DISABLE; hadc1.Init.DiscontinuousConvMode DISABLE; hadc1.Init.ExternalTrigConv ADC_SOFTWARE_START; hadc1.Init.DataAlign ADC_DATAALIGN_RIGHT; hadc1.Init.NbrOfConversion 1; HAL_ADC_Init(hadc1); } uint16_t adc_read_channel(uint32_t channel) { ADC_ChannelConfTypeDef sConfig {0}; sConfig.Channel channel; sConfig.Rank ADC_REGULAR_RANK_1; sConfig.SamplingTime ADC_SAMPLETIME_55CYCLES_5; HAL_ADC_ConfigChannel(hadc1, sConfig); HAL_ADC_Start(hadc1); if (HAL_ADC_PollForConversion(hadc1, 100) HAL_OK) { return HAL_ADC_GetValue(hadc1); } return 0; }把电流传感器输出电压转换为实际电流值// 文件路径Src/current.c #include adc.h // ACS712 模块 5A 量程典型参数 #define ADC_REF_VOLTAGE 3.3f #define ADC_RESOLUTION 4095.0f #define SENSOR_ZERO_OFFSET 1.65f // 0A 时输出约 VCC/2 #define SENSOR_SENSITIVITY 0.185f // 单位 V/A float current_get_value(void) { float voltage, current; uint32_t sum 0; uint8_t i; // 多次采样求平均降低干扰 for (i 0; i 10; i) { sum adc_read_channel(ADC_CHANNEL_0); } voltage (sum / 10.0f) * ADC_REF_VOLTAGE / ADC_RESOLUTION; current (voltage - SENSOR_ZERO_OFFSET) / SENSOR_SENSITIVITY; return current; }这里的核心逻辑是先把 ADC 原始值换算成电压再按传感器零点和灵敏度换算成电流。如果不减掉 1.65V 的零点偏置电流为 0 时会算出一个很大的错误值。5.2 转速测量与 RPM 换算用霍尔传感器测速本质是对脉冲计数。STM32 用外部中断捕获脉冲上升沿然后以 1 秒为窗口统计脉冲数换算成 RPM。// 文件路径Src/speed.c #include main.h volatile uint32_t pulse_count 0; static uint32_t rpm_value 0; // 外部中断回调霍尔脉冲每来一次计数值加 1 void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { if (GPIO_Pin HALL_PIN_Pin) { pulse_count; } } // 定时器中断回调每 1 秒计算一次转速 void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { static uint32_t last_count 0; uint32_t current_count; uint32_t pulses_in_second; if (htim-Instance TIM2) { current_count pulse_count; pulses_in_second current_count - last_count; last_count current_count; // 假设每圈输出 1 个脉冲则 RPM 每秒脉冲数 * 60 // 若电机带减速比 gear_ratio则输出轴转速 pulses * 60 / gear_ratio rpm_value pulses_in_second * 60; } } uint32_t speed_get_rpm(void) { return rpm_value; }5.3 状态判断与报警逻辑采集到电流、温度和转速之后真正体现工程水平的是状态判断逻辑。如果只看单点阈值很容易误报警。比如电机启动瞬间电流会短暂超过正常运行值如果一超阈值就报警电机会频繁误报。更合理的做法是过流持续时间超过一定时间后才触发报警即“瞬时超限 延时确认”。堵转判断则要综合两个条件电流大于堵转阈值同时转速低于最低转速。单独看电流可能把启动过程误判为堵转单独看转速可能忽略供电不足造成的整体降速。// 文件路径Src/state.c #include current.h #include speed.h #include main.h #define CURRENT_ALARM_THRESHOLD 2.0f // 过流阈值单位 A #define TEMP_ALARM_THRESHOLD 75.0f // 超温阈值单位 ℃ #define RPM_LOW_THRESHOLD 50 // 最低允许转速单位 RPM #define OVERLOAD_CONFIRM_TIME 2000 // 过流确认时间单位 ms volatile uint8_t alarm_flag 0; static uint8_t motor_state STATE_NORMAL; static uint32_t overcurrent_start 0; void state_update(uint32_t tick_ms) { float current current_get_value(); uint16_t rpm speed_get_rpm(); uint8_t over_current 0; uint8_t over_temp 0; uint8_t stall 0; if (current CURRENT_ALARM_THRESHOLD) { if (overcurrent_start 0) { overcurrent_start tick_ms; } else if (tick_ms - overcurrent_start OVERLOAD_CONFIRM_TIME) { over_current 1; } } else { overcurrent_start 0; } if (temperature_read() TEMP_ALARM_THRESHOLD) { over_temp 1; } if ((current CURRENT_ALARM_THRESHOLD) (rpm RPM_LOW_THRESHOLD)) { stall 1; } if (stall) { motor_state STATE_STALL; } else if (over_current) { motor_state STATE_OVER_CURRENT; } else if (over_temp) { motor_state STATE_OVER_TEMP; } else { motor_state STATE_NORMAL; } alarm_flag (motor_state ! STATE_NORMAL); }状态机的优先级顺序是堵转 过流 超温 正常。堵转往往伴随过流和转速下降如果不优先处理上报的信息会失真。6. 串口通信与数据上报状态检测的结果只有通过通信上报到上位机才能形成真正的监控能力。这里用 STM32 的 USART1 做数据输出通过 USB 转 TTL 接到 PC 串口助手。为了让数据便于解析串口帧建议使用固定格式帧头(0xAA 0x55) 数据长度 电机状态 电流 转速 温度 校验和(CRC8 或累加和)HAL 库中先重定向 printf 到串口// 文件路径Src/usart.c #include usart.h #include stdio.h int fputc(int ch, FILE *f) { HAL_UART_Transmit(huart1, (uint8_t *)ch, 1, 10); return ch; }然后按固定协议发送状态帧void report_status(void) { uint8_t buf[16]; uint8_t len 0; uint8_t checksum 0; uint16_t current_raw; uint16_t rpm speed_get_rpm(); int16_t temp_raw; buf[len] 0xAA; buf[len] 0x55; buf[len] 8; // 数据区长度 buf[len] motor_state; // 状态字节 current_raw (int16_t)(current_get_value() * 100); temp_raw (int16_t)temperature_read(); buf[len] (current_raw 8) 0xFF; buf[len] current_raw 0xFF; buf[len] (rpm 8) 0xFF; buf[len] rpm 0xFF; buf[len] (temp_raw 8) 0xFF; buf[len] temp_raw 0xFF; for (uint8_t i 0; i len; i) { checksum buf[i]; } buf[len] checksum; HAL_UART_Transmit(huart1, buf, len, 100); }这种自行打包的协议在小型项目中足够用而且比 printf 输出美观字符串更利于上位机解析。如果你只是临时调试用 printf 直接打印状态信息也可以正式项目建议统一成协议帧。7. 完整程序主流程与运行验证把上述模块串起来后主函数的结构如下// 文件路径Src/main.c #include main.h #include adc.h #include usart.h #include timer.h #include current.h #include speed.h #include state.h extern uint8_t motor_state; int main(void) { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_ADC1_Init(); MX_USART1_UART_Init(); MX_TIM2_Init(); HAL_TIM_Base_Start_IT(htim2); printf(Motor Status Monitor Start\r\n); while (1) { state_update(HAL_GetTick()); report_status(); HAL_Delay(500); } }实际项目里建议把状态判断和上报的周期分开。状态判断可以快一些比如 100ms 一次串口上报或显示刷新可以 500ms 甚至 1s 一次。这样既保证了实时性又避免了串口数据过于拥挤。运行验证的方法很简单硬件上先不接电机上电后观察 ADC 电流值是否接近 0A温度是否接近室温。用手转动电机轴或接入电机观察霍尔脉冲是否有计数变化。串口助手中设置波特率 115200查看是否能收到完整的数据帧。人为给电机增加负载观察电流值是否上升把阈值临时调低验证报警逻辑是否触发。如果串口收不到数据优先检查波特率、Tx 引脚接线和串口助手是否选对了 COM 口。如果 ADC 读数异常先用万用表量传感器输出端的电压判断是硬件接线问题还是代码换算问题。8. 常见问题与排查方法从实际开发经验来看最容易出问题的几个点集中在供电、采样干扰、协议解析和阈值设置上。问题现象可能原因排查方式解决方案上电后单片机反复复位电机与单片机共用电源启动瞬间压降过大示波器看复位引脚波形分开供电或加大电源电容电流值跳变严重PWM 开关噪声叠加到传感器信号万用表测传感器输出电压是否稳定信号线加滤波电容软件多次采样求平均电流显示始终为 0零点偏置未减去或传感器供电异常检查 ACS712 输出端对地电压正常运行时应为 VCC/2 左右转速恒为 0霍尔传感器未接对、脉冲电平不匹配示波器看霍尔输出波形确认上拉电阻确认脉冲信号接入的是外部中断引脚转速值偏大或偏小没考虑减速比或每圈脉冲数计算错误手动转一圈统计中断次数按实际机械结构换算 RPM 公式串口乱码波特率不匹配、电平不兼容看串口助手和代码配置的波特率统一波特率检查 USB 转 TTL 模块额定电压温度始终不变DS18B20 上拉电阻缺失或引脚接错用逻辑分析仪看单总线波形添加 4.7kΩ 上拉电阻报警频繁触发阈值设置太贴近正常值观察正常状态下的电流变化范围将阈值设置为正常值上限的 1.2 倍以上9. 最佳实践与工程建议9.1 阈值不要写死在代码里把电流、温度、转速阈值做成可配置参数可以通过串口命令下发或保存在 Flash。这样设备部署到不同现场时不需要重新编译代码就能适配不同的电机。9.2 数据要留历史串口上报的数据如果只用于实时显示意义不大。建议上位机端把数据存入 CSV 文件或数据库这样才能观察温度随时间的变化趋势。温度缓升往往比瞬间超温更有诊断价值。9.3 报警一定要有确认机制单次采样超阈值就立刻报警很容易因为干扰产生误报。比较好的做法是采用“耐久计数”连续 N 次采样超过阈值后才触发报警避免瞬时尖峰造成误动作。9.4 保护动作要区分等级状态检测不只是发报警还要考虑保护动作。建议把状态分成三级提示某个参数轻微偏高仅上报警告参数明显异常点亮蜂鸣器并通知上位机停机参数达到危险值立即通过继电器切断电机电源。停机动作一定要保留人工复位机制不能电压恢复正常就自动重启否则会造成安全事故。9.5 安全边界涉及电机电源切断时必须强调软件控制的继电器只能作为辅助保护手段不能替代热继电器、熔断器等硬件保护。所有保护动作都要在测试环境验证并保留手动急停回路。9.6 调试效率工具对于 ADC 和 GPIO 的调试可以在 Keil 的 Debug 模式下添加变量到 Watch 窗口实时观察采样值和状态机变化。但要注意在 Debug 模式下 ADC 采样容易受调试接口影响如果发现数据异常先断开调试器再单独验证运行结果。10. 总结与后续学习方向基于 STM32 单片机的电机状态检测核心价值不在于“采集”本身而在于把多路传感器信号融合成可以决策的状态量。电流、温度、转速这三个维度单独看都有局限组合起来就能覆盖电机最常见的故障类型过载、堵转、过热、供电异常。这套思路不仅适用于电机抽水机、风扇、压缩机、传送带等旋转设备都可以用同样的框架来实现状态监测。如果你刚完成这个项目下一步可以从三个方向继续深入把通信方式从串口升级为 RS485 或无线模块让多台设备组成监测网络在传感器层面增加振动检测覆盖机械故障的早期诊断在上位机端引入数据存储和趋势曲线把“报警”升级为“预测”。电机状态检测是个典型的“硬件门槛不高、工程细节不少”的项目。把采样滤波、状态机、通信协议这些环节逐个做扎实再回头看你会发现这套代码框架能复用到很多工业控制场景里。建议先在测试环境把上述流程完整跑通再考虑接入真实电机和负载不要跳过硬件验证直接上线。

最新新闻

日新闻

周新闻

月新闻