STM32电机状态检测系统实战:ADC采样与转速测量完整教程

📅 发布时间:2026/9/1 1:24:07
STM32电机状态检测系统实战:ADC采样与转速测量完整教程
先问一个很实际的问题做单片机项目时你是怎么判断电机“现在转得正不正常”的很多初学者做电机类项目只会给电机通电让它转起来然后发现转速不对、电流偏大、电机发烫却完全不知道问题出在哪一步。要解决这个问题就需要给电机加一套“体检系统”实时检测它的电压、电流、转速和温度再让 STM32 根据这些数据判断电机当前处于什么状态。这篇教程就围绕“STM32 单片机电机状态检测”这个主题展开。我会从硬件方案选型开始讲然后给出基于 STM32 的 ADC 多通道采集、电机参数计算、状态判断的完整代码最后补充常见问题的排查思路和工程实践建议。无论是做毕业设计、课程设计还是准备电赛、蓝桥杯嵌入式项目这套思路都可以直接复用。1. 电机状态检测到底要检测什么1.1 什么是电机状态检测电机状态检测简单说就是通过传感器和单片机实时获取电机运行过程中的关键物理量然后判断电机是否处于正常工作状态。电机不是只要通电就会好好转的。它可能遇到这些情况电源电压跌落电机力矩不足转速下降。电机堵转电流急剧上升绕组发热。负载变化导致电流波动、转速不稳定。电机轴承磨损振动异常噪音增大。长时间运行导致温度过高可能烧毁绕组。如果不做状态检测这些隐患只能在电机彻底损坏之后被发现。而做好状态检测就能提前感知异常及时停机或报警。1.2 状态检测的核心参数一个比较完整的电机状态检测系统通常关注以下几个参数参数检测方式反映的问题电源电压电阻分压 ADC供电是否正常工作电流采样电阻 / 电流传感器 ADC是否过流、堵转转速霍尔传感器 / 编码器 / 红外对射是否失速、停转温度NTC 热敏电阻 / DS18B20是否过热振动振动传感器如 SW-420机械故障对于入门项目优先做“电压 电流 转速”三合一检测既能覆盖大部分异常情况硬件成本也不高。温度可以作为扩展项。1.3 为什么用 STM32 做这个项目很多人会问“51 单片机不也能做 ADC 检测吗为什么选 STM32”51 单片机确实可以做但 STM32 的优势很明显STM32 的 ADC 是 12 位分辨率精度远高于 51 单片机常用的 8 位/10 位 ADC。STM32 支持多通道扫描可以同时采集电压、电流、温度等多路信号。STM32 主频高可以跑更复杂的滤波算法比如滑动平均滤波、卡尔曼滤波入门可以先不做。STM32 外设丰富可以一边采集 ADC一边输出 PWM 控制电机还能通过串口、CAN、OLED 显示屏和人交互。做毕业设计或项目开发时STM32 的工程资料和参考代码更多遇到问题更容易解决。所以基于 STM32 做电机状态检测既是学习单片机外设的好例子也是一个具有工程价值的完整项目。2. 硬件设计与方案选型2.1 系统整体架构整个电机状态检测系统的硬件可以分成四个部分电机驱动部分STM32 输出 PWM通过驱动芯片如 L298N、TB6612、DRV8833或 MOS 管驱动电机。信号采集部分电压采样电路、电流采样电路、转速传感器。主控部分STM32 最小系统板负责 ADC 采集、数据处理、逻辑判断。人机交互部分OLED 显示屏显示数据按键设置阈值蜂鸣器报警串口输出调试信息。结构图可以用文字表述大致是这样的电机 ← 驱动电路 ← STM32 PWM 输出 ↑ ↑ 传感器信号 → 信号调理电路 → STM32 ADC 输入 ↓ OLED / 串口 / 蜂鸣器2.2 电压检测方案电机工作电压通常是 5V、12V 或 24V。STM32 的 ADC 输入范围一般是 0~3.3V所以不能直接把电源电压接到 ADC 引脚。最常用的方案是电阻分压Vmotor ---[R1]------[R2]--- GND | ADC引脚选择 R1 和 R2 的比例让分压后的电压落在 0~3.3V 范围内。比如检测 12V 电压可以取 R1 30KR2 10K分压比是 10 / (30 10) 0.25。12V × 0.25 3V在 ADC 量程内。需要注意的是分压电阻的精度会影响测量结果工程上最好用 1% 精度的电阻。2.3 电流检测方案电流检测常见有两种思路方法一采样电阻法在电机供电回路中串联一个低阻值采样电阻比如 0.1Ω。电流流过采样电阻时会产生压降通过运放放大后送到 ADC。这个方案在直流电机项目中非常常用。核心公式是U I × R如果电流是 1A采样电阻是 0.1Ω压降就是 0.1V。这个电压比较小通常需要用运放放大后送入 ADC。方法二ACS712 电流传感器模块ACS712 是 Allegro 公司生产的霍尔电流传感器不需要串联采样电阻可以直接把电流转换为电压输出。使用很方便模块输出接 ADC 引脚就能采集。ACS712 有不同量程常见的有 5A、20A、30A 版本。用 ACS712 的话代码里要按模块的灵敏度做换算。2.4 转速检测方案转速检测是电机状态检测里比较有意思的部分。常用方案方案原理优点缺点霍尔传感器A3144电机轴上贴磁铁霍尔传感器感知磁场变化非接触耐用需要贴磁铁红外对射模块电机轴上装遮光片每转一圈遮挡一次简单低成本容易受环境光干扰光电编码器输出两路正交脉冲可以测方向精度高成本较高电机自带霍尔输出有些电机内部集成霍尔信号线直接读取脉冲不是所有电机都有入门推荐用“霍尔传感器 小磁铁”或者在转轴上贴一个黑白相间的码盘配合红外对射然后使用 STM32 的定时器输入捕获或外部中断统计脉冲数。转速的计算思路每分钟转速 每秒脉冲数 × 60 / 每转脉冲数比如每转产生 1 个脉冲1 秒内数到 10 个脉冲那么转速就是 10 × 60 / 1 600 RPM。3. 环境准备与工程搭建3.1 硬件清单器件说明STM32 开发板推荐 STM32F103C8T6 最小系统板性价比高直流电机12V 直流减速电机或普通直流电机电机驱动模块TB6612 或 L298NACS712 电流传感器5A 或 20A 量程均可OLED 显示屏0.96 寸 SSD1306I2C 接口蜂鸣器模块有源蜂鸣器低电平触发或高电平触发按模块而定电阻若干做分压用杜邦线、面包板接线用3.2 软件环境我用的是比较通用的开发环境组合Keil MDK5也可以使用 STM32CubeIDESTM32CubeMX用于生成初始化代码STM32 标准外设库或者 HAL 库都可以本文示例以 HAL 库为主如果你已经安装了 Keil5但是还没有添加 STM32 芯片支持包需要先在 STM32 官网下载对应芯片的 Pack 包或者在 Keil 的 Pack Installer 里在线安装。安装完成后才能新建 STM32 工程。版本相关的提醒不同版本的 HAL 库在 API 名称上基本一致但个别参数可能有差异。本文代码以最常见的 STM32F1 系列 HAL 库为例如果你用的是其他系列注意检查 ADC 时钟配置和引脚定义。3.3 新建工程的整体思路这个项目里用到的 STM32 外设主要有外设用途GPIO控制电机驱动方向引脚、蜂鸣器TIM输出 PWM 控制电机速度ADC采集电压、电流信号TIM 外部中断测转速I2C驱动 OLED 显示USART串口打印调试信息在 CubeMX 里你需要做以下配置选择芯片型号比如 STM32F103C8T6。配置时钟树将系统主频设置为 72MHz。配置 ADC1启用两个或三个通道。配置一个定时器输出 PWM。配置另一个定时器或外部中断引脚用于转速脉冲计数。配置 I2C1 用于 OLED。配置 USART1 用于串口调试。4. 核心原理与数据处理4.1 ADC 采样原理STM32 的 ADC 是逐次逼近型 ADC。它将模拟电压转换为一个 12 位的数字值范围是 0~4095。转换公式ADC值 输入电压 / 参考电压 × 4096反过来从 ADC 值算回电压输入电压 ADC值 × 参考电压 / 4096如果参考电压是 3.3V那么输入电压 ADC值 × 3.3 / 4096示例ADC值 2048 → 输入电压 2048 × 3.3 / 4096 1.65V多通道采集时STM32 可以配置为扫描模式在通道之间按顺序轮询。缺点是每次只能读一个通道的结果必须等待转换完成后再启动下一次转换。4.2 数据处理为什么要滤波ADC 采集到的原始数据往往带有噪声原因是电机运行时电刷会产生火花引入电磁干扰。如果不做任何处理ADC 数值会在真实值附近剧烈跳动导致电压电流显示不准、误报警。最简单的处理方法是滑动平均滤波。核心思路是维护一个长度为 N 的数组每次采集到新值就放入数组末尾去掉最前面的值然后求平均。滑动平均滤波的优点算法简单计算量小适合 STM32。能有效抑制周期性噪声。实时性较好。4.3 电机状态判断逻辑采集到电压、电流、转速之后不能只看单个数据还需要综合判断。常用的判断逻辑如果 电流 过流阈值 状态 过流 / 堵转 否则如果 转速 失速阈值 状态 失速 / 停转 否则如果 电压 欠压阈值 状态 欠压 否则 状态 正常运行这里要注意优先级。比如电机堵转时转速为 0电流很大。此时如果先判断转速会得到“停转”结论但根本原因是堵转。所以应该先判断电流是否过大再判断转速是否过低。判断逻辑需要添加“连续多次满足条件才确认异常”的防抖机制。比如电流连续 5 次超过阈值才认为真的过流了。这样可以避免瞬时波动导致的误判。5. 完整实战STM32 电机状态检测系统下面进入本教程的核心部分。我会按照实际开发流程从 CubeMX 配置到代码编写一步步走。5.1 项目硬件接线先明确接线方式。这里以 STM32F103C8T6 为例模块STM32 引脚电机驱动 PWMAPA0TIM2_CH1电机驱动 AIN1PA1电机驱动 AIN2PA2ACS712 输出PA4ADC1_IN4电源分压输出PA5ADC1_IN5OLED SCLPB6OLED SDAPB7霍尔传感器信号PB0外部中断蜂鸣器PB1串口 TXPA9串口 RXPA10注意默认直流电机驱动中的方向引脚逻辑请根据你实际使用的驱动模块调整。TB6612 与 L298N 的方向控制引脚电平定义可能不同。5.2 STM32CubeMX 关键配置在 CubeMX 中逐步完成以下设置。RCC 配置选择 HSE外部高速时钟为 Crystal/Ceramic Resonator。时钟树将 HCLK 设置为 72MHzAPB1 分频为 36MHzAPB2 分频为 72MHz。ADC 时钟不要超过 14MHz所以 ADC 分频选择 PCLK2/6。ADC1 配置开启通道 4PA4开启通道 5PA5扫描模式Enable多通道必须打开连续转换Disable这里我们用软件触发单次转换采样时间设置为 55.5 Cycles 或更大保证采样精度注意如果使用 HAL 库多通道 ADC 还可以使用 DMA 模式。本文为了降低初学难度先使用“连续采样 软件切换通道”的方式。TIM2 配置Channel1PWM Generation CH1预分频 PSC72-1得到 1MHz 计数频率自动重装载 ARR9999得到 100Hz PWM你也可以根据电机驱动要求调整初始占空比50%GPIO 配置PA1、PA2输出用于控制电机方向PB0外部中断模式上升沿触发用于转速脉冲计数PB1输出用于控制蜂鸣器I2C1 配置开启 I2C默认 100kHz 即可。USART1 配置异步模式115200-8-N-15.3 编写代码CubeMX 生成的代码已经完成了底层初始化。我们只需要在用户代码区域补充业务逻辑。5.3.1 定义全局变量和数据结构/* USER CODE BEGIN PV */ #define ADC_SAMPLE_TIMES 10 typedef enum { MOTOR_STOP 0, MOTOR_RUNNING, MOTOR_OVER_CURRENT, MOTOR_STALL, MOTOR_UNDER_VOLTAGE } MotorState; MotorState motor_state MOTOR_STOP; uint16_t adc_buffer[ADC_SAMPLE_TIMES][2]; uint8_t adc_index 0; float motor_voltage 0.0f; float motor_current 0.0f; volatile uint32_t pulse_count 0; volatile uint8_t speed_timer_flag 0; float motor_speed_rpm 0.0f; /* USER CODE END PV */5.3.2 启动外部中断和定时器在主函数中初始化外设后需要启动外部中断和用于测速的定时器。这里用 SysTick 来产生 1 秒的时基每秒计算一次转速。int main(void) { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_ADC1_Init(); MX_TIM2_Init(); MX_I2C1_Init(); MX_USART1_UART_Init(); /* USER CODE BEGIN 2 */ HAL_TIM_PWM_Start(htim2, TIM_CHANNEL_1); HAL_ADC_Start(hadc1); // 使能外部中断用于霍尔传感器脉冲计数 HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET); HAL_NVIC_EnableIRQ(EXTI0_IRQn); OLED_Init(); OLED_Clear(); __HAL_TIM_SET_COMPARE(htim2, TIM_CHANNEL_1, 5000); // 初始占空比50% HAL_UART_Transmit(huart1, (uint8_t*)Motor Detect System Start\r\n, 27, 100); /* USER CODE END 2 */ while (1) { // 主循环逻辑 Motor_Task(); HAL_Delay(50); } }注意OLED_Init()是 SSD1306 显示屏驱动函数具体实现取决于你使用的 OLED 库这里不做展开。如果你不用 OLED可以把显示部分去掉只保留串口输出。5.3.3 ADC 多通道采样函数/* 获取指定ADC通道的值 */ uint16_t ADC_GetChannelValue(uint32_t channel) { ADC_ChannelConfTypeDef sConfig {0}; uint16_t value 0; sConfig.Channel channel; sConfig.Rank ADC_REGULAR_RANK_1; sConfig.SamplingTime ADC_SAMPLETIME_55CYCLES_5; if (HAL_ADC_ConfigChannel(hadc1, sConfig) ! HAL_OK) { return 0; } HAL_ADC_Start(hadc1); if (HAL_ADC_PollForConversion(hadc1, 10) HAL_OK) { value HAL_ADC_GetValue(hadc1); } HAL_ADC_Stop(hadc1); return value; }这段代码的核心思路是每次读取之前把 ADC 切换到指定通道。虽然效率不高但对于电机状态检测这种低速场景完全够用。5.3.4 滑动平均滤波/* 滑动平均滤波data是历史缓冲区new_value是新采样值n是缓冲区长度 */ uint16_t MovingAverage(uint16_t *data, uint16_t new_value, uint8_t n) { uint32_t sum 0; uint8_t i 0; for (i 0; i n - 1; i) { data[i] data[i 1]; } data[n - 1] new_value; for (i 0; i n; i) { sum data[i]; } return (uint16_t)(sum / n); }这里需要注意sum使用uint32_t避免 ADC 值求和时溢出。ADC 12 位最大值 409510 次累加最大 40950在 uint32_t 范围内但养成用更大类型存储求和结果的习惯是好的。5.3.5 电压和电流换算#define VREF 3.3f #define ADC_RES 4096.0f // 分压电阻参数R130KR210K #define VOLTAGE_DIVIDER_RATIO (30.0f 10.0f) / 10.0f // ACS712 灵敏度使用 5A 量程模块时约为 185mV/A #define ACS712_SENSITIVITY 0.185f #define ACS712_ZERO_OFFSET 2.5f float ADC_To_Voltage(uint16_t adc_value) { return (float)adc_value * VREF / ADC_RES; } float Cal_Voltage(uint16_t adc_value) { float v_adc ADC_To_Voltage(adc_value); return v_adc * VOLTAGE_DIVIDER_RATIO; } float Cal_Current(uint16_t adc_value) { float v_adc ADC_To_Voltage(adc_value); return (v_adc - ACS712_ZERO_OFFSET) / ACS712_SENSITIVITY; }ACS712 模块在零电流时输出电压大约是 VCC/22.5V电流为正时电压升高为负时电压降低。所以电流 (实际电压 - 2.5V) / 灵敏度。注意ACS712 的灵敏度与模块量程有关5A 模块约为 185mV/A20A 模块约为 100mV/A30A 模块约为 66mV/A。如果你的模块是别的量程需要查模块数据手册。5.3.6 转速计算转速测量使用外部中断统计霍尔脉冲数每秒读取一次。void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { if (GPIO_Pin GPIO_PIN_0) { pulse_count; } } void Speed_Calculate(void) { if (speed_timer_flag 1) { speed_timer_flag 0; // 假设每转1个脉冲如果你的电机每转多个脉冲需要调整除数 motor_speed_rpm (float)(pulse_count * 60); pulse_count 0; } }这里用 SysTick 中断设置speed_timer_flag每 1 秒置 1。在SysTick_Handler中增加void SysTick_Handler(void) { /* USER CODE BEGIN SysTick_IRQn 0 */ static uint32_t tick_count 0; tick_count; if (tick_count 1000) // 1秒 { tick_count 0; speed_timer_flag 1; } /* USER CODE END SysTick_IRQn 0 */ HAL_IncTick(); }需要注意pulse_count是 volatile 变量在中断中累加在主循环中读取清零这样在高速计数时可以减少主循环被打断的影响。5.3.7 电机状态判断void Motor_State_Update(void) { if (motor_current 1.5f) // 过流阈值按实际电机调整 { motor_state MOTOR_OVER_CURRENT; } else if (motor_speed_rpm 100.0f) // 失速阈值 { motor_state MOTOR_STALL; } else if (motor_voltage 10.5f) // 欠压阈值 { motor_state MOTOR_UNDER_VOLTAGE; } else { motor_state MOTOR_RUNNING; } }5.3.8 主任务函数void Motor_Task(void) { uint16_t voltage_adc 0; uint16_t current_adc 0; char msg[64]; // 采集电流通道PA4 current_adc ADC_GetChannelValue(ADC_CHANNEL_4); current_adc MovingAverage(adc_buffer[0][0], current_adc, ADC_SAMPLE_TIMES); // 采集电压通道PA5 voltage_adc ADC_GetChannelValue(ADC_CHANNEL_5); voltage_adc MovingAverage(adc_buffer[0][1], voltage_adc, ADC_SAMPLE_TIMES); // 换算物理量 motor_voltage Cal_Voltage(voltage_adc); motor_current Cal_Current(current_adc); // 计算转速 Speed_Calculate(); // 更新状态 Motor_State_Update(); // 串口打印 sprintf(msg, V:%.2fV I:%.2fA Speed:%.0fRPM State:%d\r\n, motor_voltage, motor_current, motor_speed_rpm, motor_state); HAL_UART_Transmit(huart1, (uint8_t*)msg, strlen(msg), 100); // 异常报警 if (motor_state MOTOR_OVER_CURRENT || motor_state MOTOR_STALL) { HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_SET); // 蜂鸣器响 } else { HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_RESET); // 蜂鸣器关 } }5.4 编译与下载在 Keil 中完成编译后使用 ST-Link 下载程序。下载时选择 ST-Link Debugger如果出现下载失败常见原因是芯片没有连接好。ST-Link 驱动没装好。Keil 中 Flash Download 配置里没有选择正确的 Flash 算法。使用 ST-Link Utility 也可以下载但日常开发建议在 Keil 里直接 F8 下载配合调试功能更高效。5.5 预期运行结果程序下载成功后打开串口助手波特率设为 115200能够看到类似下面的输出V:12.10V I:0.35A Speed:1200RPM State:2 V:12.08V I:0.38A Speed:1198RPM State:2 V:12.11V I:1.20A Speed:900RPM State:1 V:12.09V I:1.80A Speed:50RPM State:1这里 State 的含义值含义0电机停止1过流/堵转2正常运行3失速4欠压正常运行时电压稳定在电源电压附近电流较小转速稳定在一个值。用手捏住电机轴模拟堵转电流迅速上升串口输出的 State 会变为过流状态蜂鸣器报警。6. 常见问题与排查思路6.1 ADC 采集值跳动很大问题现象常见原因解决思路ADC 数值不稳定上下跳动几十甚至几百电机干扰、采样时间过短增加采样时间改用滑动平均滤波ADC 数值整体偏高参考电压不稳定检查 VREF 引脚供电使用独立 3.3V 基准某一通道数据为零通道配置错误检查通道号是否对应正确引脚6.2 电机不转问题现象常见原因解决思路电机完全不动PWM 没有输出检查 TIM 配置是否正确确认占空比不是 0电机嗡嗡响但不转驱动方向引脚电平错误检查 AIN1、AIN2 的高低组合电机电压不足电源功率不够使用独立电机电源不要用 STM32 USB 供电6.3 转速显示为 0问题现象常见原因解决思路转速一直是 0霍尔传感器信号没接对检查霍尔传感器输出脚是否接在 PB0转速偶尔跳变磁铁离霍尔传感器太远调整磁铁和霍尔传感器的距离转速偏大或偏小每转脉冲数设置不对确认电机每转产生几个脉冲调整除法因子6.4 OLED 不显示问题现象常见原因解决思路OLED 黑屏I2C 地址不对确认 SSD1306 地址是 0x3C 还是 0x3DOLED 显示乱码接线接触不良检查 SCL、SDA 是否接反程序卡在等待标志位I2C 总线被占用重新上电检查超时设置6.5 电流显示负值如果 ACS712 在没有电流时输出低于 2.5V电流计算会得到负数。解决方法是给模块增加一个校准步骤float current_offset 0.0f; void Current_Calibration(void) { uint16_t adc_value ADC_GetChannelValue(ADC_CHANNEL_4); float v_adc ADC_To_Voltage(adc_value); current_offset v_adc; } float Cal_Current_Calibrated(uint16_t adc_value) { float v_adc ADC_To_Voltage(adc_value); return (v_adc - current_offset) / ACS712_SENSITIVITY; }在电机启动前调用一次校准函数把零电流时的输出电压记录为偏移量。7. 最佳实践与工程建议7.1 电源设计电机启动瞬间电流很大如果和 STM32 共用一个电源会导致单片机复位或 ADC 采集异常。正确的做法是电机电源和逻辑电源分开。两个电源共地。电机电源加大电容减少启动瞬间电压跌落。如果要用一个电源给全系统供电建议选择功率足够的电源并在电机电源输入端并联一个大电容和一个 0.1uF 小电容。7.2 采样稳定性工程中提升 ADC 采样稳定性的常用方法在 ADC 引脚对地并联一个 0.1uF 滤波电容或 10nF 电容。采样时间尽量长一点比如 55.5 Cycles 或 239.5 Cycles。软件上使用滑动平均滤波不建议使用简单的单次采样。对于要求更高的场景可以考虑 DMA 采样模式加环形缓冲区。7.3 阈值不要写死电机参数会随着负载、电源电压变化把阈值写死在代码里不利于项目扩展。建议在文件开头用宏定义集中管理阈值。通过按键或串口指令在线修改阈值。关键阈值保存到 Flash 或 EEPROM掉电不丢失。例如#define OVER_CURRENT_THRESHOLD 1.5f #define STALL_SPEED_THRESHOLD 100.0f #define UNDER_VOLTAGE_THRESHOLD 10.5f这样后续调整参数只需要修改宏定义。7.4 状态显示要直观不要只在串口输出状态码建议在 OLED 上显示对应的文字状态方便现场调试。比如运行正常电流过大电机堵转电压偏低同时可配合不同颜色的 LED 或蜂鸣器声音频率做区分。7.5 添加保护动作真正的电机保护系统不能只报警还需要自动停机。在检测到过流或堵转时应立即关闭 PWM 输出否则电机可能烧毁。if (motor_state MOTOR_OVER_CURRENT || motor_state MOTOR_STALL) { HAL_TIM_PWM_Stop(htim2, TIM_CHANNEL_1); // 也可以直接设置占空比为0 __HAL_TIM_SET_COMPARE(htim2, TIM_CHANNEL_1, 0); } else { HAL_TIM_PWM_Start(htim2, TIM_CHANNEL_1); }7.6 调试信息分级开发阶段可以通过串口输出所有调试信息比如 ADC 原始值、滤波后的值、计算后的物理量、状态判断结果。但在实际项目部署时应减少无用的日志输出避免大量串口打印占用 CPU 时间。8. 总结与学习路线到这里一个基于 STM32 的电机状态检测系统就完整落地了。回顾一下完成的工作理解了电机状态检测的常见参数和应用场景。掌握了电压分压采集、电流传感器、霍尔测速的硬件方案。在 STM32F103 上配置了 ADC 多通道采集。添加了滑动平均滤波提高了数据稳定性。实现了电压、电流、转速的物理量换算。编写了电机状态判断逻辑和报警保护功能。通过串口和 OLED 实时显示电机运行状态。如果你是用 51 单片机做类似项目原理也相通只是 ADC 精度和代码组织上要适当调整。接下来想继续深入可以从这几个方向选一个学习 PID 闭环控制把状态检测和电机调速结合起来。学习 CAN 总线通信把状态数据上传到上位机或车载网络。学习 FreeRTOS把 ADC 采集、数据显示、状态判断放到不同任务中运行。学习无刷直流电机BLDC控制用 STM32 检测反电动势实现电机换相。电机状态检测是嵌入式开发中一个很典型的多外设综合项目它把 GPIO、定时器、ADC、中断、串口、显示全都串起来了。做完这个项目你对 STM32 的整体掌握程度会上一个台阶。建议自己动手把硬件搭起来亲手改一遍代码观察不同工况下的数据变化这比只看文章理解得深刻得多。