
做无刷直流电机驱动的这些年我被问得最多的问题主要有两个一是“电机堵转了怎么检测”二就是“怎么算当前转速”。很多刚入手BLDC的朋友在网上找《永磁无刷直流电机技术》这类资料翻开转速计算那一章看到一堆微分方程、等效电路和坐标变换就开始头疼最后直接拿公式硬套结果转速读数怎么都不对。实际上工程中计算转速并没有那么玄。核心思路就一句话把位置变化或者反电动势规律换算成每分钟转数。这篇文章我打算把这个事彻底讲透——先说反电动势和转速的关系再分别讲有霍尔传感器和无传感器两种场景下的转速计算方案然后给一套可以落到STM32上的测速代码最后把我在现场踩过的坑一并列出来。无论你做的是水泵、散热风扇、电动工具还是无人机动力这套思路都通用。1. 转速计算的物理基础先搞懂转速藏在哪个环节1.1 反电动势是转速的天然传感器很多新手以为转速是“给定电压除以某个系数”算出来的其实没那么直接。无刷直流电机的转子是永磁体转动时转子磁场会切割定子线圈线圈里就会感应出一个电压这个电压方向和外部驱动电压刚好相反所以叫反电动势。你可以用手拧一个电机感受一下电机没通电的时候用手转轴电机三根线之间能测到电压转速越快电压越高这就是反电动势。反电动势的大小和转速直接挂钩近似满足这个关系E Ke × n其中E是相反电动势幅值单位Vn是机械转速单位rpmKe是反电动势系数单位V/rpm。不同电机Ke不一样但同一台电机内部是固定的。换句话说只要我能测到反电动势就能估计出转速。这也是所有无感无刷电机转速估算的物理基础。理解了这一层很多东西就通了。比如堵转的时候转子不转反电动势为零外部电压几乎全部压在绕组电阻上电流会迅速飙高。所以堵转保护和转速计算本质上是一件事的两面都在反电动势上做文章。1.2 方波驱动下的端电压方程与简化估算有传感器或者开环控制时转速还可以从端电压方程粗算。方波驱动六步换相下任意时刻有两相绕组导通母线电压U除了加在绕组电阻和电感上还要减去功率管的导通压降。忽略换相瞬间的电感效应后稳定运行时近似有U ≈ 2 × I × R 2 × ΔU E其中I是相电流R是单相绕组电阻ΔU是单个功率管的导通压降。反电动势E约等于U减去电阻压降和管压降。再结合E Ke × n就能反推转速n (U - 2IR - 2ΔU) / Ke这套公式的最大问题在于负载变大时I会变化IR这一项误差很大而且Ke随温度也会漂移。我实测过低压大电流的直流电机上用这个公式估算转速轻载和堵转工况下误差可以到30%以上。所以它只能用来做一个粗略的速度指示不能拿来当闭环控制的反馈量。真正做转速闭环时要么用传感器直接测位置事件要么用反电动势过零事件来推算。下面两部分就分别说这两条路。2. 有霍尔传感器时三种实测转速的可行方案霍尔传感器装在电机的定子或转子附近转子磁场扫过时霍尔输出电平翻转。三个霍尔组合起来一个机械周期内会产生6次状态变化正好对应六步换相的6个扇区。所以霍尔信号天然就是转速脉冲源而且自带位置信息。2.1 换相中断时间间隔法T法这是我最推荐新手先用的方法原理特别简单记下相邻两次换相事件的时间间隔Δt根据每次换相对应多少机械角度直接换算出转速。无刷直流电机每转一圈换相次数是6p其中p是极对数。比如常见的2极电机1对极一圈换相6次4极电机2对极一圈换相12次。相邻两次换相之间的时间间隔Δt对应的转速是n 10 / (p × Δt)这里的Δt单位是秒。如果用微秒做单位公式变成n 10000000 / (p × Δt_us)举个例子帮助验证2极电机p1如果相邻两次换相间隔1ms也就是0.001秒那么n 10 / (1 × 0.001) 10000rpm。实际中1ms一次换相已经很快了这个量级是合理的。4极电机p2同样间隔1msn 10 / (2 × 0.001) 5000rpm因为一圈换相次数翻倍同样的时间间隔意味着转得慢一半。T法的优势是低速时很准。转速越低换相间隔越长定时器计数越多相对误差越小。我调过一台低速水泵转速只有120rpm2极电机换相间隔约83ms定时器计数误差只有几个微秒算出来转速非常稳定。需要注意一个容易混淆的细节如果三个霍尔都接进中断任何一路霍尔沿都触发那每次触发间隔就是60度电角度用上述公式。但如果你只取一路霍尔信号的上升沿相邻两个上升沿之间是一个完整的电周期对应机械角度360/p度公式要改成n 60 / (p × Δt)。2.2 固定窗口脉冲计数法M法M法的思路是固定一个时间窗口T在这个窗口内数一共发生了多少次换相事件m然后用频率换算转速。换相频率f_c和转速的关系是f_c p × n / 10所以n 10 × m / (p × T)举例窗口T 0.1秒2极电机窗口内数到16次换相那么n 10 × 16 / (1 × 0.1) 1600rpm。M法在高速时精度很高因为转速越高窗口内脉冲数越多数数的量化误差占比越小。但低速时就露馅了。2极电机转速100rpm时每秒换相次数只有10次0.1秒窗口内平均只有1个脉冲有可能数到0个、1个、2个算出来的转速可能在0到2000rpm之间跳完全没法用。所以工程上有个流传很广的经验M法适合测高速T法适合测低速。如果转速范围很宽那就得上M/T法。2.3 M/T法取长补短的工程折中M/T法的做法很巧妙窗口时间T只作为参考实际计数区间从窗口内第一个换相脉冲开始到最后一个完整脉冲结束。记录这个实际时间T_m和里面完整的脉冲数m然后n 10 × m / (p × T_m)这样不管是高速还是低速脉冲数和时间跨度都是同步变化的低速时脉冲虽然少但时间跨度也等比例变长误差不会像M法那样爆掉。硬件上一般用定时器的门控方式实现软件里也可以用DMA记录时间戳来算。我在实际项目里做霍尔测速通常直接按T法处理就够了。因为BLDC霍尔信号本身就是换相事件6步换相一次中断天然就是T法的时间点。只有当电机极对数特别多、换相频率非常高导致中断过于频繁时我会切到M法降低CPU负载。2.4 霍尔方案的硬件与接线细节霍尔测速看着简单硬件上如果没处理好测速数据一样稀烂。霍尔传感器绝大多数是开漏输出必须接上拉电阻阻值常用1k到10k。上拉太小功耗大上拉太大边沿变缓容易造成误触发。我一般取4.7k配合10nF左右的电容做RC滤波效果不错。传感器到控制板的连线如果较长建议加一级施密特触发器或者用带施密特输入的MCU引脚防止信号在阈值附近来回抖动产生毛刺。电机内部的高压逆变桥是主要噪声源布线时霍尔信号线和功率线尽量分开走不要平行靠太近。3. 无传感器方案从反电动势过零倒推转速不少应用为了省掉霍尔传感器或者因为在压缩机、油泵这种高温高压环境里霍尔容易退磁失效会做无感方波控制。这时转速的获取全靠反电动势。3.1 过零检测的原理与常用电路方波驱动下每一时刻有一相悬空不导通。悬空相的端电压等于中性点电压加上这一相的反电动势。反电动势过零的时刻悬空相的端电压就等于中性点电压。所以检测思路是把悬空相的端电压和中性点电压做比较交叉点就是反电动势过零点。工程上常用一个比较器把悬空相端电压和虚拟中性点电压通常简单取母线电压的一半比较输出一个方波给MCU的捕获引脚。关键问题是采样时机。PWM导通区间里中性点电位受斩波影响会上下跳直接比较会得到一堆噪声。正确做法是只在PWM关断区间采样也就是通常说的同步采样。软件里用PWM定时器的计数中断来同步在PWM计数器到周期值或零点的时刻去读比较器输出准确度会高很多。3.2 过零间隔与转速的换算三相正弦反电动势在一个电周期内会产生6个过零点正好对应6个换相扇区相邻两个过零事件之间的电角度是60度。因此如果测得相邻两次过零事件间隔Δt_zero公式和有霍尔时的换相中断间隔法一致n 10 / (p × Δt_zero)这个结论很关键如果你做的无感方波控制已经能稳定换相那转速计算只需要在每次过零中断里做一次除法而已并不需要额外加任何传感器。换相时机也要用到过零信号。反电动势过零点和应该换相的点之间相差30度电角度。既然相邻过零事件间隔对应60度电角度那从过零到换相的延迟时间就是Δt_zero的一半。换句话说测到过零后定时器延迟Δt_zero/2再执行换相。实际项目中有人只检测一路比较器输出认为相邻两次过零之间隔一个电周期直接套上面的公式就会差6倍。用三个比较器做完整六步过零检测或者只检测单相但按180度电周期换算是自己要在软件里明确的事情搞混了转速会错得离谱。3.3 启动阶段的特殊处理与转速开环切换无感方案在零速和极低速时有个天然缺陷反电动势幅值和转速成正比转速太低时反电动势被PWM噪声吞没过零检测根本没法用。所以几乎所有无感方波都跑三段式启动第一步是转子定位。给定一个固定电压矢量并保持一段时间让转子转到已知位置附近。 第二步是开环加速。按照程序设定的加速度曲线将换相频率逐步提高转子在同步力矩下跟着加速。 第三步是切换闭环。当反电动势幅值足够大、过零检测稳定后把换相来源从程序给定切换到过零检测结果。开环阶段没有真正的“测速”转速本质上就是你程序给的脉冲频率机械转速只是近似跟随。切换瞬间如果程序里的估计转速和实际转速偏差太大会看到电流尖峰甚至失步。我在调一个无感风扇电机时就是切换点转速设得太低反电动势还没建立起来就切闭环结果电机反复抖动。后来把切换转速提高到额定转速的30%问题才解决。4. 实操演示STM32霍尔测速代码与滤波处理理论说完了给一份能直接落地的霍尔测速代码。我用的芯片是STM32F103这套逻辑换到其他MCU上一样适用核心思路不变。4.1 定时器与中断配置思路测速需要一个稳定时间基准。我把TIM2配置成1MHz计数频率也就是1微秒加1这样测时间间隔的精度是us级。对绝大多数风扇、水泵、电动工具的应用来说这个精度完全够。如果电机极对数多、转速高时间间隔可能短到几十微秒建议把计数频率提到10MHz或者改用专用输入捕获通道。三个霍尔信号分别接PA0、PA1、PA2配置为外部中断上升沿和下降沿都要触发。无论哪一路霍尔变化都进入同一个处理函数。霍尔状态读取放在中断里读取三个引脚的组合值用来判断当前扇区。4.2 换相中断测速核心代码#define POLE_PAIRS 2 // 极对数4极电机这里填2 #define TIM2_FREQ 1000000UL // 1MHz 1us volatile uint32_t hall_timestamp 0; volatile uint32_t hall_interval 0; // 相邻换相事件间隔单位us volatile uint16_t hall_state 0; volatile float speed_rpm 0.0f; uint16_t get_hall_state(void) { uint16_t a GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0) ? 1 : 0; uint16_t b GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_1) ? 1 : 0; uint16_t c GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_2) ? 1 : 0; return (a 2) | (b 1) | c; } void hall_trigger_isr(void) { uint32_t now TIM2-CNT; // 计算与上一次换相事件的时间间隔注意无符号减法不怕计数器回绕 hall_interval now - hall_timestamp; hall_timestamp now; hall_state get_hall_state(); } void EXTI0_IRQHandler(void) { if (EXTI_GetITStatus(EXTI_Line0) ! RESET) { EXTI_ClearITPendingBit(EXTI_Line0); hall_trigger_isr(); } } void EXTI1_IRQHandler(void) { if (EXTI_GetITStatus(EXTI_Line1) ! RESET) { EXTI_ClearITPendingBit(EXTI_Line1); hall_trigger_isr(); } } void EXTI2_IRQHandler(void) { if (EXTI_GetITStatus(EXTI_Line2) ! RESET) { EXTI_ClearITPendingBit(EXTI_Line2); hall_trigger_isr(); } }中断里只做减法、存状态不做浮点运算这样中断时间可以压到极短。转速换算放到主循环或者1ms速度环里void speed_calculate(void) { uint32_t interval hall_interval; if (interval 0) { // 转速 10000000 / (极对数 * 间隔us) speed_rpm 10000000.0f / (POLE_PAIRS * interval); } // 低速保护换相间隔超过250ms认为转速异常或已经停止 if (interval 250000UL) { speed_rpm 0.0f; } }对2极电机来说间隔250ms对应的转速是10000000 / (1 × 250000) 40rpm低于这个值我直接按0处理。阈值根据你自己的最低工作转速来调。4.3 一阶低通滤波与转速平滑hall_interval每次更新都会跳动直接拿速度反馈做闭环电流声会很吵。我习惯加一阶低通滤波#define SPEED_FILTER_ALPHA 0.2f static float speed_filtered 0.0f; void speed_filter(void) { speed_filtered (1.0f - SPEED_FILTER_ALPHA) * speed_filtered SPEED_FILTER_ALPHA * speed_rpm; }滤波系数取多大要看控制周期。我一般把转速换算和滤波放在1ms定时中断里跑alpha取0.15到0.3之间。取小了转速环响应慢取大了低速时速度波动大。先按0.2起步观察启动和突变负载下的表现再微调。这里有个小经验滤波不要关在速度环外面否则相位滞后会让环路震荡。我见过有人为了读数好看把滤波系数做到0.01结果0到额定转速的阶跃响应慢了快一秒电机一加载就掉速。滤波是为了抗干扰不是把真实变化也抹掉。5. 转速不准、乱跳、失效常见问题与排查建议转速算不准很多时候不是公式错了而是信号源头就有问题。我把这些年遇到过的典型故障整理成一张速查表方便你现场对照。5.1 霍尔换相间隔忽长忽短现象是转速显示有规律地上下波动比如周期性的“高-低-高-低”而你确认负载没有突变。这种情况大概率是霍尔位置安装不对称或者磁钢充磁不均匀导致6个换相区间不是严格的60度电角度。排查方法开环给一个固定占空比不要闭环用示波器抓三路霍尔波形测量6个区间的时间长度。如果某个区间明显偏长或偏短就是机械装配问题。霍尔本身也可能贴歪逐颗检查安装位置。软件层面能做一些补偿建立一张区间误差表每检测到一个区间就修正一次时间间隔。这个方法我在批量化产品里用过能把测速波动从±15%压到±3%以内。但治本的办法还是把霍尔装准软件补偿始终是补救措施。5.2 极对数搞错的倍数灾难极对数填错是新手最容易犯的错而且表现很隐蔽。常见错误是把“极数”当成“极对数”填比如4极电机应该是p2有人填成4转速显示直接翻倍。一个特别实用的判定方法用手匀速转动电机轴一整圈观察一路霍尔信号出现几个完整方波周期。一个完整周期对应一对极这个数就是极对数。这个方法我从没踩过空不管什么品牌什么型号都适用。如果转速显示正好是实际值的2倍、3倍、6倍优先检查极对数别急着调滤波和控制器。5.3 过零检测信号受PWM噪声污染无感方案最容易翻车的点就是这里。PWM开关瞬间端电压上会叠加极高的dv/dt尖峰比较器输出频繁毛刺转速计算和换相全乱。我的做法是软硬结合硬件上在比较器输入端加RC低通截止频率取PWM频率的1/10到1/5。比如PWM 20kHzRC截止频率做到2k到4k既能滤掉开关毛刺又不会让反电动势过零信号产生太大相移。软件上再做消抖处理检测到过零后拉一个最小间隔比如2us内的重复翻转全部忽略。最常见的问题是RC时间常数取得过大。有人想彻底滤干净用了一个截止频率几百Hz的RC结果过零信号滞后到离谱换相点全偏电机高速时直接失步。记住滤波的目标是抑制开关噪声不是把反电动势信号也滤掉。5.4 堵转、电压跌落和负载突变时的转速保护堵转时转速为零但电流很大。如果你的代码只在转速环里判断堵转转速到零后要等若干周期才能反应过来这段期间电流可能已经烧了。正确做法是转速和电流联合判断转速低于阈值且电流高于阈值立刻封锁PWM并报故障。电压跌落是另一个容易被忽视的场景。电池供电的设备转速很高时突然大电流拉载母线电压可能瞬间掉几伏导致转速跟着掉。如果代码里只根据给定电压估算转速这种工况下转速反馈会严重失真。用霍尔或反电动势实测的话电压跌落只是让转速真实下降反馈本身不会错但要注意欠压保护阈值别设得太高否则启动瞬间就触发误保护。负载突变时转速环还没来得及反应速度会先掉下去再拉回来。我在滤波器和PID参数上花过不少时间最终经验是速度环带宽不要追求过高给负载变化留一点余量电流环的限制反而更重要。转速计算本身只要稳定、不跳变剩下的交给控制参数去调节。6. 个人经验与几个延伸建议回头再看转速计算这件事基本逻辑就是“位置信号换时间时间换转速”。有霍尔就数霍尔边沿无传感器就数反电动势过零。公式都很简单真正决定现场调试顺不顺畅的是信号质量、极对数参数和滤波策略这些容易被忽视的细节。我在实际项目中习惯同时保留霍尔测速和反电动势估算两套通道互为备份。霍尔正常时以霍尔为准霍尔一旦出现异常还能临时切到无感估算保证系统不会瞬间失控。这个设计在售后维修场景里救过我很多次。最后说一个伴随我多年的习惯测速数据先不要急着加滤波、加闭环直接Raw数据打出来看一整天。波形平稳了再做速度环。很多所谓“转速跳变”的问题其实是信号源的问题不是算法的问题。希望这篇内容能帮你少走点弯路也欢迎在实际调试中有新的问题再来交流。