ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

AM32源码深度解析:从三相全桥到六步换相的无刷电机控制

AM32源码深度解析:从三相全桥到六步换相的无刷电机控制 上一篇文章把 AM32 的来龙去脉、固件选择和刷机流程讲完了后台收到最多的反馈是固件刷进去了电机也转起来了但一打开源码就失重——几十个文件、一堆中断回调到底哪里是入口哪里在控制换相哪里在处理油门其实这种断层非常正常因为 AM32 不像普通应用层固件它天生就是贴着硬件写的一套电机控制程序。不了解三相无刷电机的驱动原理看源码就像看天书反过来把原理和源码对照着读效果立竿见影。这一篇就是专门解决这个问题的从三相全桥电路、六步换相、反电动势过零检测这些底层原理讲起再对照 AM32 源码结构一条条拆解最后给出一套可以照做的阅读和调参路线图。1. 先建立整体认知AM32是一套什么样的固件1.1 为什么AM32在开源电调里地位这么高接触过无人机电调的人应该都知道 BLHeli_S 和 BLHeli_32前者是 8 位 MCU 时代的经典后者是闭源固件功能强大但不开放源码。AM32 的定位很直接以 STM32/GD32 等 ARM Cortex-M 系列芯片为平台从底层到应用层全部开源的固件方案。维度BLHeli_SBLHeli_32AM32源码闭源闭源GPL 开源常见 MCU8 位如 EFM832 位 ARMSTM32/GD32 等DShot部分支持支持支持双向 DShot不支持支持支持遥测协议有限有限KISS、Arduino、FrSky 等可定制性低低高正是因为开源AM32 成了很多创客和极客的首选。你可以按需裁剪功能也可以根据自己画的电调板调整引脚映射还可以把它的换相算法移植到自己的项目中。对想深入研究无人机电调的人来说AM32 是最好的教材没有之一。1.2 源码目录与模块边界AM32 源码的组织方式非常“嵌入式风格”没有复杂的抽象层每个外围设备一个文件职责边界清晰。我建议拿到源码后先扒一遍目录结构不要急着打开 main.c 从头看到尾。src/ ├── main.c # 入口系统初始化 主循环任务调度 ├── bldc.c # 电机控制核心换相、启动、过零处理 ├── comparator.c # 比较器配置与过零中断处理 ├── pwm_input.c # 传统PWM/Oneshot/DShot信号接收 ├── pwm_output.c # 三相PWM输出、死区配置 ├── dshot.c # DShot协议编解码 ├── adc.c # 电流/电压采样 ├── telemetry.c # eRPM等遥测输出 ├── settings.c # 参数读写 ├── flash.c # Flash存储 ├── pins.c # 引脚映射 ├── nfet.c # 低边MOSFET控制相关 └── timer.c # 定时器底层配置大家注意这些文件名已经暴露了关键信息AM32 的主循环不会做太多耗时操作真正的实时逻辑全部在中断里完成。bldc.c是灵魂comparator.c决定了无感换相能否稳定工作而pwm_input.c和pwm_output.c负责信号的进出。理解了这个边界后面读代码时就不会迷路。1.3 从复位到电机转起来固件内部发生了什么用一个宏观时间线来回答“固件到底做了哪些事”上电复位启动文件完成堆栈和向量表初始化。main.c里先做时钟配置、GPIO 复用设置、定时器初始化。从flash.c读取用户参数包括电机方向、启动功率、换相提前角等。初始化 PWM 输入捕获开始监听飞控发来的油门信号。主循环进入轮询模式如果检测到油门信号有效则触发bldc_start()。电机先进入开环启动阶段AM32 按预设的换相频率强拖电机转动。转速达到一定阈值后切入反电动势过零检测闭环进入稳定运行。这条链路就是整个电调的“剧情主线”。后面拆源代码本质就是沿着这条主线往下走。2. 三相全桥与六步换相看懂源代码前必须吃透的驱动底层2.1 三相全桥和MOSFET电调里的功率心脏无人机电调的输出级几乎无一例外是三相全桥电路也就是由 6 个 MOSFET 组成的桥式结构3 个高边管和 3 个低边管分别对应电机的 A、B、C 三相。每个 MOSFET 本质上是一个电压控制的开关管对 N 沟道 MOSFET 来说栅源电压 Vgs 大于阈值电压时导通小于阈值电压时截止。日常用的锂电池供电场景是低压大电流MOSFET 导通电阻小、开关速度快所以低压大电流的功率级几乎全是 N 沟道 MOSFET 的天下。相比之下双极性三极管是电流驱动器件在大电流下饱和压降带来的损耗不可接受IGBT 更适合高压大功率场合在低压下有明显的通态压降劣势。所以无人机电调里你看到的基本都是 MOSFET而不是三极管或 IGBT。这个选型逻辑想通了再看电路图就顺了。需要注意一个关键细节N 沟道 MOSFET 做高边开关时源极接电机相线导通瞬间相线电压会被拉到接近电源电压此时要让 Vgs 足够大栅极电压必须比电源电压更高。这就需要自举电容或者专门的栅极驱动芯片。AM32 的源码里大量时间花在配置互补 PWM 和死区时间上目的就是让高边和低边管子不会同时导通避免直通短路。2.2 六步换相谁导通、谁关断、谁悬空三相无刷电机的转子是永磁体定子是三相绕组。要让转子持续转起来必须让定子绕组产生的磁场方向不断变化相当于一直在“追”转子。最经典的驱动方式是六步换相也叫梯形波控制。一个电周期内分成 6 个扇区每个扇区都有一相在高边 PWM 调制、一相在低边常通、一相悬空。扇区高边PWM低边常通悬空0ABC1ACB2BCA3BAC4CAB5CBA为什么必须留一相悬空因为无感电调没有霍尔传感器必须利用悬空相来检测反电动势。这是整个无感 BLDC 控制的灵魂。如果三相全都导通就没有一个干净的通道去观察反电动势信号转子位置就丢了。所以你看bldc.c里的换相函数本质就是在切换这张表更新定时器的比较寄存器让对应通道输出 PWM让对应通道拉低让对应通道变成高阻输入。2.3 反电动势过零检测没有霍尔传感器怎么知道转子在哪我们先明确一个概念转子旋转时定子绕组会切割永磁体的磁场从而在绕组上感应出反电动势。反电动势的大小和转子速度相关而它的相位直接反映了转子位置。六步换相中最关键的时间点就是换相点而换相点通常在反电动势过零点之后延迟 30 度电角度。反电动势怎么检测最常用的办法是把悬空相电压和虚拟中点电压送给比较器。比较器可以理解成一个工作在开环状态的运算放大器两个输入端的电位差直接决定输出是高还是低。当悬空相的反电动势从小于中点电压变成大于中点电压时比较器输出翻转MCU 捕获这个翻转边沿记录此时的时间戳然后算出延迟换相的时间。如果你用 ADC 直接采样悬空相电压再软件判断过零也不是不行但 ADC 采样速率、触发时机和计算延迟都会限制电调的最高转速。AM32 走的是“硬件比较器 定时器捕获”的路线边沿一来直接进中断延迟极小这也解释了为什么 AM32 能跑到很高的电频率。2.4 PWM 调制方式和续流容易被忽略的细节六步换相里的 PWM 调制方式对电调效率和噪声影响很大。AM32 默认采用高边 PWM、低边常通的方式也就是 H_PWM-L_ON。在一个 PWM 周期内高边管按占空比开关低边管在整个扇区保持导通。关断期间电流通过低边 MOS 管的体二极管或者反向导通继续续流形成持续电流路径。这里有个实际调参中常见的坑如果死区时间设置太短高边和低边管子瞬间“打架”电流尖峰巨大轻则噪声大重则烧管。如果死区时间设置太长续流阶段出现拖尾换相效率下降电机发热明显。AM32 源码里对死区参数有默认值但不同 PCB 布局和 MOSFET 栅极电阻会导致实际开关时间不同高速大功率场景下必须自己微调。3. 从DShot信号到MOSFET导通AM32核心数据流拆解3.1 输入侧传统PWM协议和DShot怎么进MCU飞控给电调的油门信号传统上是 PWM 脉宽一般是 1ms 到 2ms频率 50Hz 到 500Hz。这种模拟信号对抖动比较敏感而且不同飞控的输出速率不同。后来出现 Oneshot125、Multishot本质是缩小脉宽范围来提高更新率。再后来就是 DShot数字信号协议直接把油门值编码成数字帧。协议更新速率特点传统PWM50~500Hz兼容性最好延迟高Oneshot125约 1kHz比 PWM 快仍需校准DShot150约 1.2kHz数字信号无需校准DShot300约 2.4kHz延迟更低DShot600约 4.8kHz常用高性能方案DShot 的帧结构是 16 位包含一个起始位、11 位油门数据、遥测请求位和 CRC 校验位。MCU 通过定时器输入捕获测量每一位的高电平时长来解码。AM32 的pwm_input.c和dshot.c会先判断当前输入是哪种协议再做对应解码。这也是为什么 AM32 使用时基本不需要做油门行程校准因为 DShot 本身就是数字油门不像模拟 PWM 那样需要记住最小和最大脉宽。3.2 数据流油门值怎么变成换相参数从飞控发出的油门 0~2047经过 DShot 解码后会映射到 AM32 内部的油门百分比。软件里再根据油门百分比决定 PWM 占空比。注意这部分不是简单的线性映射AM32 会根据启动阶段和正常运行阶段做不同处理启动时是开环强拖PWM 占空比和换相频率由启动参数决定进入闭环后PWM 占空比才真正和油门信号相关。源码里你会看到主循环里不断更新throttle相关变量但换相中断里读取的是一个volatile修饰的共享变量。因为中断和主循环之间存在“生产者-消费者”关系不加 volatile 的话编译器可能优化掉实时读取。这种底层细节稍不注意就会导致油门响应迟钝或者偶发抖动。3.3 输出侧PWM波形怎么送到MOSFET栅极决定好当前扇区后AM32 要做的第二件事就是配置通用定时器的各通道。以 STM32 系列为例高级定时器可以产生带死区插入的互补 PWM 输出一个通道输出高边 PWM互补通道输出低边控制信号硬件自动在边沿之间插入死区时间。pwm_output.c里需要完成根据当前扇区把对应通道设置为 PWM 输出模式。把悬空相设置为高阻输入模式避免干扰反电动势检测。更新 CCR 寄存器修改占空比。确保定时器工作在中心对齐或边沿对齐模式满足占空比精度。换相瞬间实际上是先关掉上一个扇区的 PWM 通道再打开下一个扇区的通道。一个粗心的实现可能在这里造成瞬间全桥直通所以源码里对操作顺序有严格要求先禁止输出再改通道映射最后重新使能输出。3.4 比较器中断里发生了什么过零检测中断是 AM32 最高优先级的实时路径。比较器输入翻转时如果 MCU 的比较器外设支持输出到定时器捕获通道硬件会自动记录当前定时器计数值整个过程不占用 CPU 时间。AM32 在中断回调里会读取捕获值计算距离上一次换相的时间。根据当前电频率估算转子速度。用这个速度推算从过零到换相点需要延迟的电角度时间。配置一个定时器在延迟时间到点后执行换相操作。这个延迟时间不是一个固定值它会随着转速动态变化。AM32 还提供了换相提前角参数Timing Advance用来补偿负载和绕组电感带来的相位滞后。理解这条数据流之后再看comparator.c里的中断回调基本就能对号入座了。4. 启动与闭环的临界窗口反电动势检测为什么最难调4.1 为什么启动必须开环强拖电机静止时反电动势为零比较器无从判断过零。所以 AM32 的启动过程必须依赖开环强行换相不管转子在什么位置直接按预设的换相频率和占空比逐扇区切换让定子磁场“推着”转子转起来。启动通常分两步对齐阶段先固定给某个扇区通电一小段时间让转子被动转到已知位置。强拖加速阶段按预设的启动频率不断切换扇区速度从零逐步增加。这个阶段如果启动功率太大转子会被突然拉过头导致失步如果启动功率太小转子转不起来电机只会嗡嗡响。AM32 启动参数里的 Start Power 和 Start RPM 就是干这个用的。实际调试时建议先把 Start Power 调到中等偏大确认电机能顺利启动后再逐步减小找到既能可靠启动又不过冲的临界值。4.2 过零检测的噪声与滤波为什么相线上总有个RC反电动势信号非常微弱尤其是在小油门、低转速时毫伏级的过零信号很容易被 PWM 开关噪声淹没。所以大多数电调硬件上会在比较器输入端加一级 RC 低通滤波。但这个滤波是一把双刃剑滤波越狠过零信号越干净但相位延迟越大高速时会让换相点明显滞后导致电机电流增大、效率下降。AM32 固件里也提供了一个软件滤波选项。和硬件 RC 滤波不同软件滤波通常是在过零检测后做多次确认比如连续检测到几次稳定翻转才认作有效过零。这个方法的好处是延迟可控坏处是如果算法写得保守会漏掉高速下的过零信号。调参的时候建议优先级是这样先保证硬件 RC 时间常数不要过大再通过软件滤波抵抗噪声而不是反过来。4.3 状态机视角正常运行只是其中一个阶段AM32 固件内部本质上跑了一个有限状态机常见的状态大概可以归纳成状态说明退出条件IDLE等待有效油门信号检测到启动命令ALIGN转子对齐对齐时间到OPEN_LOOP开环启动加速电频率达到闭环阈值RUN闭环运行油门归零或故障FAULT保护停机重启或重新上电我在调试中最常遇到的问题就是状态机卡在 OPEN_LOOP 和 RUN 之间来回跳。电机如果启动时好时坏大概率是开环加速到闭环切换的阈值参数不合适。AM32 判断能否进入闭环的指标是电频率转速太低时反电动势信号太小切早了必然失步切晚了又会在开环下长时间运行电流剧增电调发热严重。这里分享一个排查思路先用示波器抓悬空相电压波形。如果能清楚看到比较器翻转边沿说明信号质量没问题问题大概率在参数阈值如果波形一团糟说明硬件滤波和 PCB 布局的问题更大先别急着改软件参数。很多朋友上来就调 Start Power 和 Timing结果调了一晚上也没用最后发现是采样电路干扰太大。5. 工程实践编译刷写、阅读路线图与常见调参问题5.1 从克隆到编译烧录的完整命令AM32 的编译依赖 arm-none-eabi-gcc 工具链建议直接用 Linux 或者 WSL 环境Windows 下会遇到一些 path 和 make 兼容性问题。先安装工具链sudo apt install gcc-arm-none-eabi make git git clone https://github.com/AM32-firmware/AM32.git cd AM32/src make MCUSTM32G071 -j4具体 MCU 参数需要根据你的电调板芯片型号来指定常见的有 STM32F051、STM32G071、GD32E230 等。编译产物是一个 hex/bin 文件烧录方式取决于你板上是否预留了 AM32 Bootloader如果已经有 Bootloader可以进入 DFU 模式后用dfu-util刷写否则用 STM32CubeProgrammer 通过 SWD 接口直接烧录。第一次玩的话SWD 最稳。5.2 阅读源码的建议顺序别一上来就看中断嵌套和汇编。我建议按这个顺序读先读main.c的初始化流程和主循环搞清楚哪些变量在中断里更新。再读pins.c和timer.c把引脚和定时器通道映射背下来不然后面连哪路 PWM 是 A 相都分不清。读pwm_input.cdshot.c弄明白油门信号怎么进来。读bldc.c的换相函数和启动函数这是核心中的核心。最后读comparator.c结合示波器波形理解过零检测。读bldc.c时建议一边读一边对照导通表。AM32 里经常用数组或枚举来定义 6 个扇区的开关状态你把这几个数组对应到三相桥上代码瞬间就活了。5.3 几个实战调参场景症状常见原因参数调整方向启动困难电机前后抖动开环启动功率不足增大 Start Power启动瞬间电流过大、异响启动功率过冲减小 Start Power高速时电机发热严重换相提前角不足增大 Timing 提前角负载变化时失步闭环切入过早、滤波过强提高闭环切入电频率、减弱软件滤波小油门卡顿过零信号被噪声掩盖检查硬件滤波、调整比较器阈值这些参数之间互相耦合改一个往往会影响另一个。比如把 Start Power 调大了可能启动是顺了但换相冲击变大又引出 DEMAG去磁补偿的问题。AM32 提供了去磁补偿参数用于处理高速大电流时相电流还没归零就换相导致的反向力矩问题。这个参数在 3D 机、重载机上特别重要普通小穿越机不敏感。5.4 没有示波器也能排查问题的土办法很多朋友没有示波器总觉得调无感电调寸步难行。实际上有几个土办法很实用听声音电机启动时的“嗡嗡”声频率异常基本可以判断是开环强拖与闭环切换不匹配。摸温度换相逻辑错位会导致电流剧增电机和电调在几秒内迅速发热这时先降温再说别继续怼油门。用逻辑分析仪几十块钱的逻辑分析仪就能抓 DShot 波形和 PWM 输出虽然看不到模拟电压但能确认信号时序和占空比。看飞控日志如果电调支持遥测飞控里能看到 eRPM 和电流曲线换相稳定性的变化非常直观。我一直认为有没有示波器决定的是调试效率而不是能不能调试。关键是你要理解每个参数背后的物理意义把现象和数据对应起来。AM32 最大的优势就是源码开源遇到反直觉的现象可以直接加调试代码、开 GPIO 翻转引脚用逻辑分析仪把内部事件打点串出来。最后聊一点个人体会。我在读 AM32 源码前其实已经玩了好几年 BLHeli 系列但始终停留在“会刷不会用”的状态。真正开始啃 AM32是在一次大载重四轴的调试现场高速高负载下电机频繁失步BLHeli 又看不清内部状态被逼着逐行看代码。那段时间我把bldc.c的启动函数和比较器中断来回读了几十遍最后发现是硬件 RC 滤波常数太大导致高速过零边沿晚了差不多半个电角度。换了一颗小电容之后整机立刻稳定。这种感觉很难形容但有一点很确定吃透原理后再调电调就不再是玄学。希望大家也能通过这篇文章把 AM32 这块硬骨头啃下来遇到问题时多看一眼源码多测一组波形答案往往就在那里。
返回列表