资讯中心

单极性步进电机原理与驱动时序:从28BYJ-48到ULN2003的完整实践

📅 2026/9/26 5:09:16
单极性步进电机原理与驱动时序:从28BYJ-48到ULN2003的完整实践
做嵌入式这几年凡是上手做过小型云台、智能家居窗帘、或者玩具类机电装置的朋友基本都会遇到一个白色小方块——28BYJ-48。它是最有代表性的单极性步进电机五根引线接上5V电源就能转。说它入门是因为驱动电路真的简单一颗ULN2003就能搞定说它值得深挖是因为从线圈结构到驱动时序再到单片机里的状态机代码每一步都有可以展开讲的门道。这篇就把单极性步进电机的原理、三种驱动方式单相、双相、半步和代码实现一次讲透。不管你是刚接触步进电机的新手还是想彻底搞明白半步驱动为什么要这样写的老手这篇应该都能给你一点启发。1. 从线圈开始单极性步进电机到底长什么样1.1 中心抽头与“单极性”这个名称的由来单极性步进电机的命名根源在它的线圈结构上。拆开一个28BYJ-48里面能看到两组带中心抽头的绕组。每组绕组实际上被中心抽头分成了两段所以对外引出的线就变成了四相线加上一或两根公共线。五线制的电机把两个中心抽头在内部合并后只引出一根公共线六线制的则把两个中心抽头分别引出来多了一根线但也多了一种供电方式。这个“单极性”指的就是线圈电流的方向始终只有一个方向。公共线接电源正极四个端脚通过驱动管轮流接地。电流永远从公共线流入线圈再从端脚流出去中途不需要也不会反向。好处很明显驱动电路不需要H桥这种复杂的换向结构四个达林顿管阵列最典型的就是ULN2003就能应付。而且单极性线圈的端脚接地时线圈另一端始终是固定的高电位续流路径天然存在不容易烧管这对入门用户来说是极大的友好。1.2 转子为什么“一步一步”走磁阻最小与步距角步进电机的核心运动逻辑是“磁阻最小原理”说白了就是磁场会让转子转到磁阻力最小的位置。单极性步进电机的转子是永磁体定子线圈通电后产生N/S极转子上的永磁体就会自动转向与定子磁场对齐。每切换一次线圈的通电组合定子磁场的方向就转一个角度转子就跟着“咔哒”一下对齐到新的位置。这个“咔哒”的角度就是步距角。28BYJ-48的标称步距角是5.625°指的是内部转子每走一步转过的角度不是输出轴的角度。360°除以5.625°正好等于64也就是说内部转子需要64步才能转完一整圈。注意这里是“内部”因为这个电机带减速箱输出轴的实际转速还要再除以减速比。如果只看步数整步驱动下输出轴走完一圈需要64步乘64倍减速也就是4096步。很多人第一次拿到电机照着网上的例程写发现转了好久才转一圈就是因为把内部步距角和减速后的步数搞混了。1.3 单极性电机的“天生短板”扭矩、转速与发热单极性结构有一个绕不开的物理代价就是同一块定子窗口里线圈被中心抽头分成了两半铜线利用率比双极性电机低。同样的体积和电压下单极性电机能产生的安匝数偏小电感还偏大电感大意味着电流的建立速度慢。高速旋转时电流还没涨上去下一个脉冲就来了扭矩会急剧衰减。这也是为什么用ULN2003驱动28BYJ-48时转速一旦超过某个值就会明显乏力甚至丢步。再加上ULN2003本身的饱和压降通常是1V到1.2V左右5V供电情况下线圈两端实际分到的电压只有不到4V这进一步限制了高速能力。所以在选型时单极性电机适合低速、轻负载、或者对成本极度敏感的场合。想让它跑得又稳又快那就得考虑双极性电机加专用驱动芯片的方案了这个放到后面第5节细说。2. 三种驱动时序单相、双相、半步怎么选2.1 单相驱动Wave Drive四拍走一步省电但扭矩偏弱单相驱动也叫1相励磁方式或者Wave Drive。它的工作方式是每个时刻只给一个相位通电。以四线单极性电机的四个端脚编号1、2、3、4来看通电顺序就是1、2、3、4、1、2……循环。每一步切换磁场方向旋转90°电角度内部转子走一个步距角5.625°。这种方式的优点直观同时只有一个线圈通电整机的功耗最低电流也最小单片机IO口和驱动管的压力都比较小。但缺点同样明显——扭矩低。因为磁场只来自一个线圈力矩输出大约只有双相驱动的70%左右有些资料上甚至说接近一半。对轻负载、要求低功耗的场景比如小型仪表指示、玩具旋转机构Wave Drive完全够用还能省电。但如果负载稍有阻力wave模式最容易失步。我第一次做实验时用手轻轻捏一下输出轴电机就咔咔响着不动了就是这个原因。2.2 双相驱动Full Step两相同时激磁扭矩更稳双相驱动也叫2相励磁方式严格说应该叫“双相同时驱动”因为Full Step的字面意思是整步。它的通电规则是每一拍同时给两个相邻相位通电通电顺序是12、23、34、41、12……这样磁场的矢量合成效果比单相驱动强得多扭矩几乎接近双倍转子在平衡位置附近的保持力也更好定位更准。需要注意的是双相驱动的步距角和单相驱动是一样的仍然是5.625°一圈仍然是64拍。它没有提高分辨率而是在同样步距角的前提下提升了扭矩和动态响应。这也是为什么大多数现成的步进电机驱动库默认用的就是Full Step模式比如很多Arduino的Stepper库底层就是2相整步。只要不是特别在意功耗日常的位置控制优先选双相驱动最简单也最不容易出问题。2.3 半步驱动Half Step交替单相和双相分辨率翻倍半步驱动的官方叫法是1-2相励磁思路很简单把单相驱动的每一拍和双相驱动的每一拍交替排列。通电顺序变成1、12、2、23、3、34、4、41、1……一共8个状态。这样一来转子先被一个线圈拉到一个整步位置然后两个线圈同时拉到一个中间位置再换到另一个线圈的整步位置如此反复。每个状态之间的角度差从整步的5.625°减半到2.8125°电机分辨率直接翻倍。半步驱动的好处有三个第一输出轴的分辨率提高一倍28BYJ-48在整步下输出轴一圈是4096步半步模式就变成8192步做精密定位时优势明显第二针对某些低速场景半步驱动的细腻感比整步强很多不会有明显的“一顿一顿”的感觉第三由于等效脉冲频率翻倍可以有效避开低速区的机械共振点。但半步驱动不是没有代价。单相通电时扭矩小双相通电时扭矩大扭矩会出现周期性的波动。转速比较高时这种扭矩脉动反而会加剧振动和噪声。另外代码状态表比整步模式长一倍单片机查表逻辑也更复杂一点。好在现代单片机动辄几十MHz这点开销几乎可以忽略。2.4 三种驱动方式的直观对比我整理了一张表把三种方式的差异列一下方便对照着选型。特性单相Wave双相Full Step半步Half Step每圈内部步数646412828BYJ-48输出轴每圈步数409640968192相对扭矩较弱约0.5~0.7强基准1.0单双交替存在脉动定位稳定性一般过冲稍大最好好功耗最低最高介于两者之间代码复杂度低低中适用场景低功耗轻负载常规位置控制低速平滑转动、高分辨率定位日常项目里我的建议是对扭矩有要求的用双相驱动对平滑度有要求的用半步驱动。Wave驱动更多是用来讲原理或者在一些电池供电、负载极轻的小装置里做省电选择。3. 从时序到代码把驱动逻辑写进单片机3.1 驱动电路到底怎么搭ULN2003和单片机的关系先理清一个容易混淆的问题单片机GPIO直接驱动步进电机行不行大多数情况不行。28BYJ-48单个线圈的额定电流大约在200mA到260mA之间而普通单片机引脚的输出能力只有几毫安到二十毫安根本带不动强行接上去要么电机纹丝不动要么烧了引脚。所以中间必须加驱动级。最常见的方案就是用ULN2003模块。ULN2003内部是七个达林顿管对地开关输入侧是TTL电平输出侧是集电极开路结构。单片机引脚输出高电平时对应的输出端把电机线圈端脚拉到GND线圈两端形成压差电流就从公共线流入线圈再从端脚经ULN2003流到地。代码上把GPIO写1表示当前相线圈导通写0表示断开。这里注意ULN2003还有一个非常贴心的设计内部集成了续流二极管电机线圈是感性负载关断瞬间会产生反电动势如果没有续流回路很容易把驱动管击穿。接线方面公共线接电源正极。如果用5V单片机供电可以直接接5V。但为了电机扭矩更足也可以把公共线接到更高的电压上比如9V或12V不过要确认电机额定电压和ULN2003模块的耐压范围28BYJ-48有个常见规格是5V版本也有12V版本买的时候看清标签。我平时用5V版本接5V稳妥省事。3.2 三种模式的真值表与统一代码封装写代码之前先把真值表确定下来。以下四个引脚分别对应电机的四个端脚逻辑1表示该引脚输出高电平让线圈导通。注意顺序要和实际接线一致不然电机可能抖动不转。单相Wave模式4拍 1: 1 0 0 0 2: 0 1 0 0 3: 0 0 1 0 4: 0 0 0 1双相Full Step模式4拍 1: 1 1 0 0 2: 0 1 1 0 3: 0 0 1 1 4: 1 0 0 1半步Half Step模式8拍 1: 1 0 0 0 2: 1 1 0 0 3: 0 1 0 0 4: 0 1 1 0 5: 0 0 1 0 6: 0 0 1 1 7: 0 0 0 1 8: 1 0 0 1C语言里把这些状态存成二维数组就形成一个查表式的驱动核心。下面这个示例代码用的是HAL库风格的GPIO操作但核心逻辑完全通用// 引脚映射根据你自己的接线调整 #define M_PIN1 GPIO_PIN_0 #define M_PIN2 GPIO_PIN_1 #define M_PIN3 GPIO_PIN_2 #define M_PIN4 GPIO_PIN_3 #define M_PORT GPIOA // 单相Wave真值表 const uint8_t wave_steps[4][4] { {1, 0, 0, 0}, {0, 1, 0, 0}, {0, 0, 1, 0}, {0, 0, 0, 1} }; // 双相Full Step真值表 const uint8_t full_steps[4][4] { {1, 1, 0, 0}, {0, 1, 1, 0}, {0, 0, 1, 1}, {1, 0, 0, 1} }; // 半步Half Step真值表 const uint8_t half_steps[8][4] { {1, 0, 0, 0}, {1, 1, 0, 0}, {0, 1, 0, 0}, {0, 1, 1, 0}, {0, 0, 1, 0}, {0, 0, 1, 1}, {0, 0, 0, 1}, {1, 0, 0, 1} }; #define MODE_WAVE 0 #define MODE_FULL 1 #define MODE_HALF 2 // 写一次GPIO void motor_write(const uint8_t *step) { HAL_GPIO_WritePin(M_PORT, M_PIN1, step[0] ? GPIO_PIN_SET : GPIO_PIN_RESET); HAL_GPIO_WritePin(M_PORT, M_PIN2, step[1] ? GPIO_PIN_SET : GPIO_PIN_RESET); HAL_GPIO_WritePin(M_PORT, M_PIN3, step[2] ? GPIO_PIN_SET : GPIO_PIN_RESET); HAL_GPIO_WritePin(M_PORT, M_PIN4, step[3] ? GPIO_PIN_SET : GPIO_PIN_RESET); }3.3 步数、角度和方向控制的计算有了真值表和GPIO写入函数接下来要解决三个问题走多少步、正转还是反转、每步间隔多长。方向控制本质上是查表顺序的方向。正向走下标加1反向走下标减1。注意C语言的取模运算在负数和正数上行为不同如果直接用(index - 1) % 4当index为0时会得到-1直接越界。所以要么在计算后加模长再取模要么干脆用int16_t保存序号判断成负数就加回来。我习惯写一个辅助函数uint8_t index_add(uint8_t index, int8_t delta, uint8_t len) { int16_t v (int16_t)index delta; v v % len; if (v 0) v len; return (uint8_t)v; }角度和步数的换算跟模式强相关。28BYJ-48输出轴一整圈Full Step是4096步Half Step是8192步。如果目标是转45°那就用4096 / 360 * 45或8192 / 360 * 45取整即可。更多时候你会用速度来倒推延时假设Full Step下每秒要走500步那么每步之间的间隔就是1000000 / 500 2000微秒。插一句28BYJ-48在5V电压下不要妄图拿满速跑一般把输出轴转速控制在10到15转每分左右对应Full Step大约是每秒700到1000步超过这个区间丢步风险会明显增加。3.4 速度控制与加减速从延时到定时器代码里最简单的做法是阻塞延时走一步这在低转速低负载场景下完全可行void move_steps(int32_t target_steps, uint16_t step_delay_us, uint8_t mode) { uint8_t len (mode MODE_HALF) ? 8 : 4; const uint8_t (*table)[4] (mode MODE_WAVE) ? wave_steps : (mode MODE_FULL) ? full_steps : half_steps; uint8_t index 0; int8_t dir (target_steps 0) ? 1 : -1; int32_t steps (target_steps 0) ? target_steps : -target_steps; while (steps--) { index index_add(index, dir, len); motor_write(table[index]); delay_us(step_delay_us); } }但是这个写法在延时期间CPU被占死你要是边控制电机边扫描按键或者处理显示就卡住了。工程化的做法是用定时器。把目标步数和当前步数做成一个状态变量定时器每中断一次就发送一拍。比如配置定时器周期为2000微秒中断里调用一次查表写GPIO主循环只负责改目标速度或目标步数。这样电机转动的同时单片机还能干别的事。至于加减速很多项目直接固定步间延时启动时跑太快就丢步。标准解决办法是梯形加减速启动时用较大的延时低速然后逐步减小延时加速到达巡航速度后保持匀速接近目标步数时再逐步增大延时减速。这个逻辑不算复杂但需要维护一个“当前速度”变量每次中断里按照加速度调整。对28BYJ-48这种低速电机来说加速度别设太猛我一般让它在200到300毫秒内从零加速到目标速度就足够顺滑了。4. 实操中的坑失步、发热、噪音与排查4.1 失步和堵转为什么电机咔咔响却不转最常见的问题就是电机堵转或者失步。断电状态下用手转动输出轴感觉阻尼很大这正常因为有减速箱。但通电后如果电机发出嗡嗡声甚至咔咔声输出轴却纹丝不动大概率是扭矩不够或者相序不对。扭矩不够的原因无非几个供电电压太低、负载太重、启动速度太快。28BYJ-48的扭矩本来就不大满打满算也就1kgf·cm级别还是带减速后的拿它去直接推一个需要更大扭矩的结构那基本没戏。相序不对导致的“不转”则更典型。电机内部两组线圈如果四条控制线里有一组对调了通电后磁场方向就乱套电机只会在一个位置上反复振荡听起来嗡嗡响轴轻轻颤动但转不起来。排查方法是用万用表电阻档找出公共线然后分别测公共线和其余四根线之间的阻值一般是50Ω左右。两根一组阻值相同的两组就是同一相的两端。把1、3分到一组2、4分到另一组再按真值表顺序接驱动板基本就能转了。4.2 发热问题线圈一直通电会怎样步进电机和直流电机不同它通电锁定时的功耗不低。28BYJ-48的线圈电阻大概在50Ω上下5V供电时单相电流理论值有100mA双相驱动时两相同时通电就是200mA。线圈持续通过这么大的电流电机本体慢慢发热是很正常的尤其环境温度高或者连续通电几分钟摸上去烫手但不至于烧毁。问题是很多新手在位置上电锁定时电机只是停着不动程序里却还在不停执行最后一步的状态线圈一直保持激磁功耗一直存在。解决办法取决于你的应用。如果要求电机停住的位置不能松那就只能保持激磁毕竟步进电机断电后由减速箱自锁但齿轮箱摩擦力也有限受到外力依然可能被推走。如果只是短暂停留可以做一个“自动断电”逻辑电机走完目标步数后把所有GPIO全部拉低让线圈彻底断电降温省电。还有一种取巧的办法是定位完成后执行一个特殊的PWM半流锁定比如把保持时的有效占空比降到50%能明显减少发热但位置保持力矩也会相应降低。我个人的建议是能用断电就断电保持扭矩不够的场景就换个扭矩大一圈的电机别跟发热硬耗。4.3 噪音和共振低速抖动怎么处理步进电机低速时那种“哒、哒、哒”的声音本质上是步进脉冲激励下的机械振动。每个脉冲电气上驱动转子转动一个步距角但转子的惯性会使其在平衡位置附近过冲、回摆几次形成衰减振荡。当脉冲频率和机械系统的固有频率接近时振荡被放大表现为明显的噪声和抖动。解决低速共振最简单的办法有两个。一个是提高驱动分辨率从整步模式切换为半步模式这样每次转过的角度减半同样的输出转速下脉冲频率翻倍很容易就避开了低频共振区。另一个是把转过这个频率范围的加速过程拉快一点不要让电机长时间在共振区间慢悠悠地跑。如果是做那种很慢的匀速转动比如复古仪表指针、桌面罗盘时钟那么建议直接用半步驱动把每步之间的间隔调均匀同时兼顾平滑度。还有一个小技巧如果机械上允许可以在电机输出轴上加一个小飞轮利用惯量吸收转速波动噪声会小很多。4.4 常见问题速查表把前面提到的和没提到的典型问题都整理成一张表方便现场排查。现象可能原因排查方向电机不转有嗡嗡声相序接错通电相数不对负载卡死检查四根线的相序逐个核对真值表电机抖动后单方向断续转动某一路驱动管损坏或引脚虚焊用LED逐路检查GPIO输出替换驱动板高速跑着跑着停了供电电压跌落加速过快加稳压电容改用梯形加减速电机发热严重持续锁定电流过大供电电压偏高终点断电降低保持电流输出轴能转但是角位忽前忽后失步累积半流锁定与全流切换不一致降低负载校正目标步数低速时噪声特别大存在机械共振改用半步模式避开共振频率运行5. 选型与扩展单极性方案还能怎么玩5.1 单极性还是双极性什么时候该升级如果你的项目已经在用28BYJ-48但总抱怨扭矩不够、速度上不去、控制精度差那么问题往往不是代码而是电机本身的结构。单极性电机因为绕组利用率低和驱动管压降大高速性能确实拼不过双极性电机。双极性电机配A4988或者DRV8825这类专用驱动器能支持更高的供电电压、灵巧的细分数以及恒流斩波控制。同样的NEMA17电机在12V供电下能跑出的扭矩和转速单极性方案很难望其项背。所以我的选型建议是做教学实验、验证算法、或者只是想让一个东西转起来选28BYJ-48加ULN2003便宜又皮实做3D打印机、雕刻机、云台甚至只是想认真做一个桌面摆件建议直接上42步进电机加A4988驱动逻辑看着复杂一点但排错和调优的空间大得多。说到底技术选型不是越贵越好而是匹配需求。5.2 从ULN2003到专用驱动性能提升的方向单极性电机不一定只能用ULN2003。几十年前的针式打印机里就有大量单极性电机用的专用驱动芯片内部集成恒流斩波电路能显著提升电流建立速度从而改善高速扭矩。如果你手里刚好有这种老芯片又想做复古改造也可以试一下。但这种芯片现在不好买资料也难找实际意义不大。更常规的升级路径是放弃单极性换双极性电机加DRV8825。DRV8825支持最高32细分意味着每个整步可以分成32个微步机械振动能被压得极低。细分的本质是用PWM控制两相电流的比例让合成磁场矢量光滑旋转效果就是动静极小、运行如丝般顺滑。这一点是ULN2003这种只有“通断”两种状态的驱动方式做不到的。5.3 闭环与反馈失步了能不能自己修正最后聊一个进阶方向。开环控制是步进电机的默认工作方式好处是简单坏处就是一旦失步位置误差会一直累积下去。如果项目对位置准确度有硬性要求可以在输出轴上装一个编码器或者磁性霍尔角度传感器让MCU实时读取实际位置与目标位置比较后修正脉冲。这等于把步进电机变成了一个简易闭环系统。这种做法的成本并不高特别是现在便宜的AS5600角度传感器模块十几块钱就能买到和主控走I2C代码量也不算大。但说实话一个小型DIY项目绝大多数情况下没有必要上闭环。更务实的做法是在选型阶段留足力矩余量一般按负载扭矩的1.5到2倍选电机再把加减速参数调得稳妥一些失步问题自然就很少发生了。我见过不少项目最后发现所谓“失步”其实是供电电压不足引起的所以在怀疑算法之前先用万用表看看运行电压是不是一直稳定。我个人的一个体会是步进电机入门必须动手调一把。光看真值表很难理解为什么半步驱动更平滑但只要接好线把Wave、Full、Half三种方式都跑一遍亲眼看到齿轮箱输出轴在三种模式下的转动差异原理就刻在脑子里了。最后分享一个调试小技巧在ULN2003模块的信号输入侧并四个LED每个控制线接一个电机运转时能直观看到哪一路通电、时序对不对。遇到不转的情况那一排LED会第一时间告诉你信号到底有没有传到驱动板省下不少拿万用表瞎戳的功夫。

看完文章,想为自己的企业也做一次专业网站诊断?

尧图顾问免费为您评估现有网站,并给出建站/改版建议与报价方案。

免费获取方案