Arduino手搓BLDC驱动:六步换向法从原理到实战

📅 发布时间:2026/9/28 17:36:10
Arduino手搓BLDC驱动:六步换向法从原理到实战
1. 为什么我要用Arduino手搓一套BLDC驱动无刷电机这几年价格被打下来了航模用的2212、2208拆机的一大把几十块钱就能买到带霍尔的三相BLDC。但很多人拿到手之后卡在同一个地方驱动板太贵成品电调又不让你改控制逻辑想学六步换向法结果只能对着示波器干瞪眼。我自己最开始也是这个状态买了个成品电调转是能转但里面到底怎么换向的、霍尔信号怎么对应MOS管、死区时间设多少全是黑盒。后来我干脆用Arduino Uno加六颗MOS管搭了一套最原始的三相全桥把六步换向法从头到尾跑了一遍。这套方案的好处是每个环节都暴露在你面前霍尔信号直接进IO口MOS管栅极由你控制换向顺序写在代码里哪里不对立刻能看出来。它不追求效率也不追求静音追求的是让你彻底搞懂BLDC为什么能转起来。这篇文章适合三类人一是刚接触无刷电机、分不清BLDC和PMSM区别的入门玩家二是想从成品电调转向自研驱动、需要理解换向逻辑的嵌入式爱好者三是做智能小车、泵类负载这类项目想用Arduino直接控制BLDC但不想上FOC的开发者。整套方案的核心关键词就是Arduino、BLDC、MOS管、六步换向法我会把原理图思路、MOS管选型、霍尔换向表、代码实现、以及我踩过的坑全部摊开讲。需要提前说明的是六步换向法也叫梯形波驱动它和FOC是两条路线。六步换向每60度电角度换一次相任意时刻只有两相通电第三相悬空FOC则是三相同时通电用SVPWM合成旋转磁场。前者简单、对MCU要求低Arduino Uno就能跑后者平滑、噪音小但需要更强的算力和电流采样。你要是做云台、精密位置控制那得上FOC你要是做风扇、小车、泵类负载六步换向完全够用而且调试周期短得多。2. 六步换向法的核心原理拆解2.1 三相全桥和六个MOS管到底怎么摆三相BLDC的定子绕组是星形连接三个端点分别叫A、B、C中心点悬空不引出。要让电机转起来就得让电流按顺序流过不同的两相组合。三相全桥就是干这个的A相上面一个MOS管叫AH下面一个叫ALB相是BH、BLC相是CH、CL。一共六颗MOS管所以叫三相全桥。任意时刻我们只打开一颗上管和另一相的下管比如AH和BL导通电流从A相流入、从B相流出C相悬空。这时候A相和B相产生的磁场合成一个方向把转子往那个方向拽。每过60度电角度换一组管子导通磁场方向就跳60度转子跟着追这就是六步换向的名字来源。这里有个关键点上下管绝对不能同时导通。如果AH和AL同时打开电源正负极直接短路MOS管瞬间冒烟。所以代码里必须保证换向时先关断再开通中间留死区时间。我一开始图省事换向时直接改寄存器结果烧了两颗IRF3205后来老老实实加了死区。2.2 霍尔传感器给出的六个状态带霍尔的BLDC定子上嵌了三个霍尔元件间隔120度电角度摆放。转子磁钢转过去霍尔输出高低电平三个霍尔组合起来一共有六种有效状态对应转子的六个扇区。每种状态告诉你转子现在在哪个60度区间里你根据这个区间决定下一组该开哪两颗管子。霍尔状态和换向的对应关系不是固定的它取决于霍尔安装位置和绕组相序。我见过有人直接抄网上的换向表结果电机抖着不转就是因为相序对不上。正确的做法是先手动给一组管子通电看转子停在哪再记录此时霍尔读数然后按顺序换向把六个状态和六组管子一一对应起来。这个表我后面会给一个实测可用的版本但你最好自己验证一遍。2.3 反向电动势过零点检测为什么这里不用搜BLDC控制原理一定会看到反向电动势过零点检测。那是无霍尔方案用的悬空相的反向电动势会过零过零后延迟30度电角度就是换向点。但这套方法在低速时反向电动势幅值太小根本检测不到所以无霍尔方案启动困难通常要先开环强拖到一定转速再切闭环。我们这套用霍尔低速也能准确知道转子位置启动扭矩大代码简单。代价是多三根霍尔线电机成本略高。做小车、泵类负载霍尔方案更省心。你要是做高速风机霍尔安装精度可能成为瓶颈那时候再考虑无霍尔或者FOC。3. 硬件选型与电路搭建实操3.1 MOS管怎么选别只看电流参数MOS管选型是这套方案里最容易翻车的地方。很多人看IRF3205便宜、电流大直接拿来用结果发现Arduino的5V IO口根本推不动。IRF3205是标准MOS管Vgs(th)在2到4V但要让它的Rds(on)降到毫欧级别Vgs得给到10V。5V驱动时它工作在放大区内阻大、发热严重电机一转就烫手。正确的选择是逻辑电平MOS管比如IRLZ44N、IRF3708、AO3400这类它们在Vgs4.5V或5V时就能完全导通。我实测IRLZ44N在5V驱动下带2212电机电流2A左右管子只是温热。如果你要带更大的电机比如5065电流上到10A以上那就得用栅极驱动芯片比如IR2104半桥驱动它自带死区控制和自举电路能把栅极电压抬到12V让标准MOS管也完全导通。还有一个参数容易被忽略MOS管的寄生电容。栅极电容Ciss越大开关越慢开关损耗越大。IRLZ44N的Ciss大概1500pFArduino IO口直接推上升沿大概几百纳秒六步换向频率不高的话够用。但如果你PWM频率上到20kHz以上就得加栅极电阻和驱动芯片否则管子会发热。3.2 自举电路和死区时间用半桥驱动芯片时上管的栅极电压需要比电源电压还高才能让上管完全导通。自举电容就是干这个的下管导通时自举电容通过二极管充电到12V下管关断、上管要导通时自举电容把上管栅极抬到电源电压加12V保证Vgs足够。死区时间是上下管都关断的那段时间防止直通。IR2104内部有死区大概500ns一般够用。如果你自己用分立元件搭驱动就得在代码里控制死区。我的做法是换向时先把所有管子关断延时2微秒再打开下一组。2微秒对Arduino来说就是几十个时钟周期用delayMicroseconds(2)就行虽然粗糙但有效。3.3 电源和滤波别让电机把Arduino搞复位电机是感性负载换向瞬间电流突变电源线上会产生尖峰。我一开始用同一个5V给Arduino和电机供电电机一启动Arduino就复位。后来改成电机用12V电池直接供Arduino用单独的5V稳压模块共地但不共电源问题就解决了。电机的电源线上要并一个大电解电容比如470uF到1000uF吸收换向尖峰。再并一个0.1uF陶瓷电容滤高频。霍尔传感器的电源也要加0.1uF去耦否则霍尔信号会有毛刺导致换向误判。4. 霍尔换向表与代码实现4.1 实测可用的霍尔换向表下面这张表是我用2212电机、霍尔间隔120度、相序A-B-C实测出来的。霍尔读数用三位二进制表示H1H2H3。换向动作里PWM表示这一相给PWMON表示这一相下管常通OFF表示这一相悬空。霍尔状态导通上管导通下管A相B相C相001AHBLPWMONOFF011AHCLPWMOFFON010BHCLOFFPWMON110BHALONPWMOFF100CHALONOFFPWM101CHBLOFFONPWM这张表的意思是当霍尔读数为001时打开A相上管和B相下管A相给PWM调速B相下管常通C相悬空。每换一个状态就按表切换管子。注意PWM相是不断切换的这样可以让电机受力更均匀。4.2 Arduino代码框架代码分三部分霍尔读取与状态解码、换向表查表、PWM输出。我用的是Arduino Uno定时器1输出PWM到引脚9和10但六步换向需要三路PWMUno的定时器不够用。所以我的做法是只用一路PWM接在使能端另外两相用IO口控制开关。这样调速范围有限但入门够用。const int AH 2, AL 3, BH 4, BL 5, CH 6, CL 7; const int H1 8, H2 9, H3 10; const int PWM_PIN 11; int hallState 0; int lastHallState 0; void setup() { pinMode(AH, OUTPUT); pinMode(AL, OUTPUT); pinMode(BH, OUTPUT); pinMode(BL, OUTPUT); pinMode(CH, OUTPUT); pinMode(CL, OUTPUT); pinMode(H1, INPUT_PULLUP); pinMode(H2, INPUT_PULLUP); pinMode(H3, INPUT_PULLUP); pinMode(PWM_PIN, OUTPUT); Serial.begin(115200); } void allOff() { digitalWrite(AH, LOW); digitalWrite(AL, LOW); digitalWrite(BH, LOW); digitalWrite(BL, LOW); digitalWrite(CH, LOW); digitalWrite(CL, LOW); } void commutate(int state) { allOff(); delayMicroseconds(2); // 死区 switch(state) { case 1: // 001 digitalWrite(AH, HIGH); digitalWrite(BL, HIGH); analogWrite(PWM_PIN, 128); break; case 3: // 011 digitalWrite(AH, HIGH); digitalWrite(CL, HIGH); analogWrite(PWM_PIN, 128); break; case 2: // 010 digitalWrite(BH, HIGH); digitalWrite(CL, HIGH); analogWrite(PWM_PIN, 128); break; case 6: // 110 digitalWrite(BH, HIGH); digitalWrite(AL, HIGH); analogWrite(PWM_PIN, 128); break; case 4: // 100 digitalWrite(CH, HIGH); digitalWrite(AL, HIGH); analogWrite(PWM_PIN, 128); break; case 5: // 101 digitalWrite(CH, HIGH); digitalWrite(BL, HIGH); analogWrite(PWM_PIN, 128); break; } } void loop() { hallState digitalRead(H1) | (digitalRead(H2) 1) | (digitalRead(H3) 2); if (hallState ! lastHallState) { commutate(hallState); lastHallState hallState; } }这段代码是最简版本没有闭环调速PWM固定128。你把它烧进去电机应该能转起来。如果抖动不转先检查霍尔读数是否在1到6之间变化如果出现0或7说明霍尔接线或供电有问题。4.3 加入调速和启动逻辑上面代码上电直接换向如果转子正好停在换向点上可能会抖一下。更稳妥的做法是启动时先读霍尔按当前状态给一次换向让转子动起来再进主循环。调速可以用电位器接A0读值映射到PWM。int potValue analogRead(A0); int pwmValue map(potValue, 0, 1023, 0, 255); analogWrite(PWM_PIN, pwmValue);注意PWM频率。Arduino默认PWM频率约490Hz对电机来说偏低会有啸叫。你可以改定时器预分频把频率提到8kHz以上但会影响millis()和delay()。入门阶段先忍一忍等跑通了再优化。5. 调试过程中踩过的坑和排查技巧5.1 电机抖但不转先查相序和霍尔表这是最常见的问题。电机嗡嗡响、抖一下就不动八成是换向表对不上。排查步骤先断开电机手动给AH和BL通电看转子是否往一个方向轻微转动然后保持通电读霍尔值记下来再换BH和CL通电读霍尔值。按这个顺序把六组都试一遍你就能得到自己电机的真实换向表。网上的表只能参考不能照抄。5.2 MOS管发热严重检查栅极电压和死区如果电机能转但MOS管烫得摸不得先量栅极电压。逻辑电平MOS管在导通时Vgs应该接近5V如果只有2V多说明IO口驱动能力不够或者管子选错了。再检查死区用示波器看上下管栅极波形如果有重叠那就是直通必须加死区。没有示波器的话把死区时间从2微秒加到5微秒试试如果发热减轻就是死区问题。5.3 霍尔信号跳变加滤波电容和上拉电阻霍尔输出是开漏的必须接上拉电阻一般10k。如果信号线长还会引入干扰导致换向误判。我在霍尔电源和地之间并了0.1uF电容信号线上串了100欧姆电阻问题基本消失。软件上也可以做滤波连续读三次霍尔如果两次一致才认为状态有效。5.4 常见问题速查表现象可能原因排查方法上电不转霍尔无供电量霍尔VCC是否为5V抖动不转换向表错误手动通电验证相序转一下就停死区不足直通加大死区时间MOS管发热栅极电压不足换逻辑电平管或加驱动转速不稳PWM频率低提高PWM频率Arduino复位电源干扰电机和MCU分开供电6. 从六步换向到更实用的扩展方向这套六步换向跑通之后你可以往几个方向扩展。一是加闭环调速用霍尔频率算转速做PID让电机在负载变化时保持转速稳定。二是加电流采样用采样电阻加运放做限流保护防止堵转烧管。三是换用STM32或者ESP32用硬件定时器生成三路互补PWM自带死区代码更简洁还能上FOC。我个人的体会是六步换向是理解BLDC最好的入口。它把换向逻辑、霍尔解码、MOS管驱动这些基础问题全部暴露出来你调通一套之后再看FOC的代码会发现很多概念是相通的。别一上来就啃FOC先把六步换向跑稳后面升级会顺很多。最后分享一个小技巧调试时用串口把霍尔状态和换向动作打出来配合电机转动观察能快速定位是霍尔解码错了还是换向表错了。我一开始就是靠串口打印发现霍尔读数在0和7之间跳查了半天是霍尔地线没接。这种低级错误打印出来一眼就能看到。