news 2026/10/21 1:31:10

esp_sensorless_bldc_control 比较器反电势过零检测与六步换相源码解读

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
esp_sensorless_bldc_control 比较器反电势过零检测与六步换相源码解读

esp_sensorless_bldc_control 比较器反电势过零检测与六步换相源码解读

【免费下载链接】esp-iot-solutionEspressif IoT Library. IoT Device Drivers, Documentations and Solutions.项目地址: https://gitcode.com/GitHub_Trending/es/esp-iot-solution

这篇文章以 esp-iot-solution 仓库中的esp_sensorless_bldc_control组件为对象,讲清基于硬件比较器检测反电动势(BEMF)过零点的无感方波电机控制方案:先给出过零信号的物理来源与虚拟中性点技巧,再走读三路比较器硬件电路,然后按"采样、滤波、测速、状态映射"四个机制逐段读源码,最后覆盖接线、bldc_user_cfg.h配置与闭环启动的完整流程,并附上典型故障现象的排查对照。跟着走读完成后,你可以基于仓库自带测试用例独立完成比较器三路接线、参数调整与无感闭环启动。

一、快速总览

条目内容
核心概念比较器输出过零电平判断转子位置
硬件门槛三路比较器、等阻网络、三个输入 GPIO
适用场景低成本无感方波驱动、无霍尔电机
关键文件comparer.c 与 six_step.c

该方案是组件内与ALIGNMENT_ADC(ADC 采样)并列的另一种无感模式,通过配置项ALIGNMENT_COMPARER启用。两者共用同一套六步换相框架,区别只在过零信号的产生与确认方式。

二、原理走读

过零信号从哪来:反电势幅值与转速成正比

方波驱动的 BLDC 电机任意时刻只有两相导通(一相接正、一相接负),第三相浮空。浮空相绕组没有电流,其端电压主要就是反电动势,因此浮空相是检测转子位置的最佳窗口。

反电势的物理来源是绕组切割转子磁场,按楞次定律其极性总是阻碍电流变化:

BEMF = NlrBω
符号含义
N绕组匝数
l转子导条有效长度
r转子内半径
B转子磁场强度
ω转子角速度

电机下线后 N、l、r、B 都是定值,所以反电势幅值只与角速度 ω 成正比。这直接决定了两个工程事实:转速越快过零检测越可靠;转速过低时反电势弱到淹没在噪声里,必须先靠对齐(ALIGNMENT)和强拖(DRAG)把转速拉起来,过零信号才稳定可用。

图中每个 60° 电角度发生一次换相,换相后新浮空相的反电势在半周期内穿越中点,这个穿越点就是比较器要捕捉的过零点。

关键技巧:等阻电阻重构虚拟中性点

判断过零需要比较"端电压与中性点电压谁大",但星形接法的电机通常不引出中性点,无法直接测量。比较器方案的做法是用相同阻值的电阻把三相拉到公共点,该公共点电压近似等于真实中性点,称为虚拟中性点。每相端电压与虚拟中性点各接一路比较器的输入,比较器输出高低电平即代表该相端电压在不在中性点上方,电平翻转时刻就是过零点。

过零间隔与转速的数学关系

浮空相反电势每半个电气周期(180° 电角度)穿越一次中点。设计时基准频率为 ft、电机极对数为 n、两次过零之间累计的计数值为 c,则:

speed_rpm = ft / (2 × n × c) × 60

ft 是周期中断频率,2×n 对应一个机械转内含有的半电气周期数。按组件默认配置MCPWM_CLK_SRC=20MHz、MCPWM_PERIOD=2000,计时周期ALARM_COUNT_US=100µs,POLE_PAIR=5,代入后系数为 60000,即speed_rpm = 60000 / speed_count。

三、硬件/接口走读

下左图是组件文档给出的功率侧参考:三相全桥(UH/VH/WH 上管、UL/VL/WL 下管)驱动星形绕组,母线 Udc 加在桥臂之间。下右图是信号侧:每相端电压经 1K 分压电阻(R25/R28、R29/R31、R32/R34)接入比较器反相端,等阻 20K 电阻(R25 上方标注 20K 的网络)合成虚拟中性点接比较器同相端,输出经 100R + 100nF 滤波后分别得到 BEMF_1/2/3 三路过零信号,另有一路比较器(U8:2)用于输出端分压参考。

硬件要点:

  • 三路比较器支路:每相一路,负责把该相端电压与虚拟中性点的比较结果变成数字电平,是过零信号的直接来源;排查时先用示波器确认三路输出在电机转动时确有规律翻转。
  • 等阻虚拟中性点网络:R28/R29/R32 等电阻必须同阻值,任一路偏差都会把中性点基准拉偏,导致某一相过零点系统性偏移。
  • 输出 RC 滤波:100R 串联加 100nF 对地,抑制 PWM 开关噪声;电容过大则电平翻转滞后,与软件滤波叠加会加大换相延迟。
  • GPIO 接口:三路信号接普通 GPIO,组件按输入模式初始化,active_level字段用于适配比较器输出极性。

硬件排查顺序建议:先测三路比较器输出是否随转速稳定翻转,再核对等阻电阻的实测偏差(建议 1% 以内),最后检查输出端滤波电容取值与比较器供电、地线是否干净。

四、源码机制走读

同步采样:MCPWM on_full 时刻的 64 位移入队列

做什么:MCPWM 定时器每次计数到峰值(on_full 事件)时,把三路比较器 GPIO 电平各取一次,逐位移入每相 64 位环形队列。

为什么:换相刚发生的窗口内,端电压受续流二极管和开关噪声影响严重,连续读 GPIO 会采到大量脏数据。绑定 PWM 峰值时刻采样,保证每个 PWM 周期只取一个干净的样本点,同时把采样节拍与 PWM 严格同步。

在哪做:bldc_control.c 中注册回调,bldc_zero_cross_comparer.c 中实现采样:

// bldc_control.c: ALIGNMENT_COMPARER 分支 control->zero_cross = &bldc_zero_cross_comparer_operation; control->cbs->on_full = &read_comparer_on_full; /* 关键:PWM 峰值时刻触发采样 */ config->six_step_config.upper_switch_config.bldc_mcpwm.timer_cb_user_data = (void *)control->zero_cross_handle;
// bldc_zero_cross_comparer.c: 每相 64 位队列左移 1 位并入当前电平 static void IRAM_ATTR alignment_comparer_get_value(bldc_zero_cross_comparer_t *zero_cross) { for (int i = 0; i < PHASE_MAX; i++) { zero_cross->alignment_queue_value[i] = zero_cross->alignment_queue_value[i] << 1; zero_cross->alignment_queue_value[i] |= gpio_ll_get_level(&GPIO, zero_cross->alignment_pin[i]); } }

怎么调:采样时刻固定在 on_full,无独立参数可调;采样密度由MCPWM_CLK_SRC与MCPWM_PERIOD决定(默认 10kHz PWM),改 PWM 频率时注意队列窗口覆盖的时间随之变化。

连续滤波与过零确认:0xFFFF 相同样本判有效

做什么:把队列低 16 位与ZERO_CROSS_DETECTION_ACCURACY做按位与,全 1 判该相为高、全 0 判为低、否则判滤波失败并跳过本周期处理。

为什么:硬件滤波后仍可能有窄脉冲噪声,"连续多次同电平"的判决能拒绝孤立毛刺,避免把噪声当过零事件触发误换相。滤波失败时filter_failed_count累加,超过 15000 次会被主状态机判为堵转(BLOCKED),这一计数同时是信号质量的在线监测指标。

在哪做:bldc_zero_cross_comparer.c:

for (int i = 0; i < PHASE_MAX; i++) { if ((zero_cross->alignment_queue_value[i] & ZERO_CROSS_DETECTION_ACCURACY) == ZERO_CROSS_DETECTION_ACCURACY) { zero_cross->queue_filter_state[i] = 1; /* 连续 16 次高电平 */ } else if ((zero_cross->alignment_queue_value[i] & ZERO_CROSS_DETECTION_ACCURACY) == 0) { zero_cross->queue_filter_state[i] = 0; /* 连续 16 次低电平 */ } else { zero_cross->control_param->filter_failed_count++; return 0; /* 滤波失败:本周期不处理 */ } }

怎么调:ZERO_CROSS_DETECTION_ACCURACY默认0xFFFF(连续 16 次相同),最大0xFFFFFFFF(32 次)。改大会提高抗噪能力,但电平确认延迟增大、换相整体后移,需与ZERO_CROSS_ADVANCE联动补偿。

测速与提前角补偿:speed_count 折算 RPM

做什么:以 U 相滤波状态为基准做边沿检测,检测到 1→0 下降沿时,把本半周期累计的speed_count折算成转速,经一阶低通后写回speed_rpm,同时算出提前换向延迟filter_delay。

为什么:无传感器方案需要转速反馈给 PID;而比较器检测到的过零点理论上是换向前 30° 电角度到来,加上软件滤波滞后,若立即换相角度会偏晚,需要按当前转速折算出延迟量做补偿。

在哪做:bldc_zero_cross_comparer.c,系数定义在 bldc_config.h:

#define COMPARER_RPM_CALCULATION_COEFFICIENT (((1000000 / ALARM_COUNT_US) / (2.0 * POLE_PAIR)) * 60) // bldc_zero_cross_comparer.c: U 相状态 1->0 下降沿处 if (filterEdge == 0) { if (zero_cross->zero_stable_flag >= ZERO_STABLE_FLAG_CNT) { speed_rpm = (uint32_t)(COMPARER_RPM_CALCULATION_COEFFICIENT / zero_cross->control_param->speed_count); BLDC_LPF(zero_cross->control_param->speed_rpm, speed_rpm, 0.2); /* 系数 0.2 低通平滑 */ } zero_cross->control_param->filter_delay = zero_cross->control_param->speed_count / ZERO_CROSS_ADVANCE; }

怎么调:POLE_PAIR默认 5,必须按电机实际极对数设置,否则转速读数整体成倍偏差。ZERO_CROSS_ADVANCE默认 8,提前角 = 180°/该值(默认 22.5°,略小于理论 30° 以抵消滤波滞后),注释要求不小于 6;改小则换相更提前,过快会过冲,建议用示波器对比实际与理论换相角。

六种过零状态到换相动作的映射

做什么:滤波后的三相状态(各 0/1)共六种有效组合,zero_cross_comparer_get_phase()输入三相状态与方向dir,返回 1~6 的相位号;相位号变化时bldc_six_step_turn()按方向选择对应的六步数组执行换相。

为什么:三相比较器电平的组合恰好唯一编码了当前转子所在的 60° 扇区,查表即可把"电平组合"翻译成"下一步该导通哪两相",无需任何位置积分。

在哪做:相位判定在 bldc_zero_cross_comparer.c,换相序列与执行在 bldc_six_step.c:

// bldc_zero_cross_comparer.c: 连续稳定后取相位 uint8_t phase = zero_cross_comparer_get_phase(zero_cross->queue_filter_state, zero_cross->control_param->dir); if (phase <= 0 || phase > 6) { zero_cross->control_param->error_hall_count++; /* 非法组合:信号质量异常 */ return 0; }
// bldc_six_step.c: 正转六步序列(函数指针数组) static void (*six_step_comparer_cw_array[6])(...) = { &bldc_six_step_UphaseH_VphaseL, /* U 上管 PWM,V 下管导通 */ &bldc_six_step_WphaseH_VphaseL, &bldc_six_step_WphaseH_UphaseL, &bldc_six_step_VphaseH_UphaseL, &bldc_six_step_VphaseH_WphaseL, &bldc_six_step_UphaseH_WphaseL, };

方向数组的选择在 bldc_six_step.c:alignment_mode == ALIGNMENT_COMPARER时绑定比较器专用数组,否则绑定 ADC 数组。

官方文档中的映射表("1/0" 表示该相比较器输出高于/低于虚拟中性点;"上开下关 / 上关下开 / 上关下关" 表示该相桥臂状态):

正转(CW):

序号ZERO UZERO VZERO WU 相状态V 相状态W 相状态
1001上开下关上关下开上关下关
2011上开下关上关下关上关下开
3010上关下关上开下关上关下开
4110上关下开上开下关上关下关
5100上关下开上关下关上开下关
6101上关下关上关下开上开下关

反转(CCW):

序号ZERO UZERO VZERO WU 相状态V 相状态W 相状态
1010上关下开上开下关上关下关
2110上关下开上关下关上开下关
3100上关下关上关下开上开下关
4101上开下关上关下开上关下关
5001上开下关上关下关上关下开
6011上关下关上开下关上关下开

说明:仓库文档 bldc_snls_comparer.rst 中两张映射表的表头三列均写作 "ZERO U",结合源码queue_filter_state[PHASE_MAX]为 U/V/W 三相状态数组的事实判断,三列实际依次为 ZERO U、ZERO V、ZERO W,上表按此呈现。

怎么调:方向由bldc_control_set_dir(handle, CW/CCW)设置,方向设置必须与电机实际绕线一致,否则会反向或无法启动;调试时观察error_hall_count,持续递增说明三相状态长期落在六种合法组合之外,优先查硬件。

五、实践三步

第 1 步:添加组件依赖与用户配置文件

在项目根目录执行:

idf.py add-dependency "espressif/esp_sensorless_bldc_control=*"

把 user_cfg/bldc_user_cfg.h 复制到项目的main/目录(保持文件名bldc_user_cfg.h),并在main/CMakeLists.txt中追加(与 test_apps/bldc_comparer/main/CMakeLists.txt 相同):

idf_component_get_property(bldc_lib espressif__esp_sensorless_bldc_control COMPONENT_LIB) cmake_policy(SET CMP0079 NEW) target_link_libraries(${bldc_lib} PUBLIC ${COMPONENT_LIB})

验证点:idf.py build通过,且不再报bldc_user_cfg.h not found, must provide by user(该报错由 bldc_config.h 的__has_include检查触发)。

第 2 步:填写硬件配置结构体

参考 test_comparer.c,LEDC 驱动上管、GPIO 驱动下管的最小配置:

bldc_zero_cross_comparer_config_t zero_cross_comparer_config = { .comparer_gpio[0] = { .gpio_num = 3, .gpio_mode = GPIO_MODE_INPUT, .active_level = 0 }, /* U 相过零 */ .comparer_gpio[1] = { .gpio_num = 46, .gpio_mode = GPIO_MODE_INPUT, .active_level = 0 }, /* V 相过零 */ .comparer_gpio[2] = { .gpio_num = 9, .gpio_mode = GPIO_MODE_INPUT, .active_level = 0 }, /* W 相过零 */ }; bldc_control_config_t config = { .speed_mode = SPEED_CLOSED_LOOP, .control_mode = BLDC_SIX_STEP, .alignment_mode = ALIGNMENT_COMPARER, /* 关键:选择比较器过零检测 */ .six_step_config = { .lower_switch_active_level = 0, /* 关键:下管有效电平,须与驱动板一致 */ .upper_switch_config = upper_switch_config, .lower_switch_config = lower_switch_config, .mos_en_config.has_enable = false, }, .zero_cross_comparer_config = zero_cross_comparer_config, };

验证点:comparer_gpio[i].gpio_num与硬件上 BEMF_1/2/3 的接线一一对应;active_level与比较器输出极性匹配(反接时软件滤波会一直判失败)。

第 3 步:初始化、设方向并启动

bldc_control_handle_t bldc_control_handle = NULL; bldc_control_init(&bldc_control_handle, &config); /* 初始化硬件驱动 */ bldc_control_set_dir(bldc_control_handle, CCW); /* 设置旋转方向 */ bldc_control_start(bldc_control_handle, 300); /* 以 300 RPM 启动 */

验证点:串口日志依次出现BLDC_CONTROL_ALIGNMENT、BLDC_CONTROL_DRAG,稳定运行后打印CLOSED_LOOP事件(事件名表见 bldc_control.c);只停在 DRAG 不进入闭环即说明过零信号未达标。

六、排障速查

现象可能原因对策
比较器 GPIO 长期无规律翻转,进不了 DRAG 后的闭环采样支路断线、等阻电阻偏差大、比较器未供电示波器逐一确认 BEMF_1/2/3 输出;核对 20K 等阻网络阻值一致性(建议 1% 精度)
强拖正常但始终进不了 CLOSED_LOOP滤波判决长期失败,filter_failed_count高先把ZERO_CROSS_DETECTION_ACCURACY调大验证;仍无效则查硬件滤波电容与active_level配置
闭环后运行抖动、偶尔丢步滤波深度不足,窄脉冲噪声触发误换相ZERO_CROSS_DETECTION_ACCURACY从0xFFFF提到0xFFFFFFFF,并同步减小ZERO_CROSS_ADVANCE补偿延迟
电机反转或启动时抖一下再反着转dir与绕线方向不符,或某两相线序接反对调 U/V 两相接线,或bldc_control_set_dir改方向,二者改其一
闭环后进入 BLOCKED(日志打印 BLOCKED)filter_failed_count超 15000 被判堵转,信号持续无效观察error_hall_count是否同步递增;递增则为信号质量差,按前两项排查硬件
转速读数明显偏离实际值POLE_PAIR设置错误,测速系数成倍偏差按电机铭牌极对数重设POLE_PAIR,读数偏差与设置比应成反比

七、关键参数速查

以下宏定义在 user_cfg/bldc_user_cfg.h:

宏默认值作用调整方向
ZERO_STABLE_FLAG_CNT4连续稳定检测到多少个过零后进入无感闭环偏大→进闭环更晚但更可靠;偏小→启动段误判风险高
ZERO_CROSS_DETECTION_ACCURACY0xFFFF连续多少次相同采样判为有效电平(16 次)偏大→抗噪强但换相延迟大,需配合减小ZERO_CROSS_ADVANCE;偏小→噪点易通过,filter_failed_count上升
ZERO_CROSS_ADVANCE8提前换向分母,提前角 = 180°/该值,要求 ≥ 6偏大→提前角变小、换相偏晚;偏小→换相过提前,角度过冲
POLE_PAIR5电机极对数,决定测速系数偏大→转速读数偏低;偏小→读数偏高,须按实际极对设置
RAMP_DUTY_STA/RAMP_DUTY_END20% / 40%强拖起始/结束占空比(DUTY_MAX为 1000)偏大→启动扭矩强但易过流;偏小→带载时拉不起来
RAMP_TIM_STA/RAMP_TIM_END600 / 90强拖换相间隔的起/止值(单位:gptimer 节拍)偏大→启动平滑但时间长;偏小→快但带载易丢步
MCPWM_CLK_SRC/MCPWM_PERIOD20MHz / 2000PWM 时钟与周期(10kHz),决定ALARM_COUNT_US=100µs改变会同步改变测速系数与滤波窗口,需整体复核
SPEED_KP/SPEED_KI0.004 / 0.00015速度闭环 PID 增益偏大→跟踪快但易振荡;偏小→响应迟钝、带载掉速

八、延伸阅读

  • bldc_overview.rst:BLDC 结构、逆变桥与有感/无感控制方式的总览对比。
  • bldc_snls_comparer.rst:官方对比较器方案的完整说明,含本文两张映射表的原始出处。
  • esp_sensorless_bldc_control.rst:INJECT/ALIGNMENT/DRAG/CLOSED_LOOP 各启动阶段的参数详解与调参提示。
  • bldc_control.c:状态机主体、事件分发与回调注册位置。
  • bldc_zero_cross_comparer.c 与 bldc_six_step.c:过零确认与六步换相的两段核心实现。
  • test_comparer.c:LEDC + GPIO 与 MCPWM 两种配置的完整运行示例,可直接烧录验证。

比较器方案的核心链条很短:等阻网络重构虚拟中性点,比较器把端电压比较结果变成三路电平,64 位队列滤波确认过零,再查表映射成六步换相。实际调参时最关键的一条经验是:加深ZERO_CROSS_DETECTION_ACCURACY滤波后务必同步减小ZERO_CROSS_ADVANCE,并用示波器核对实际换相角与理论换相角,换相角度并不是越提前越好。

【免费下载链接】esp-iot-solutionEspressif IoT Library. IoT Device Drivers, Documentations and Solutions.项目地址: https://gitcode.com/GitHub_Trending/es/esp-iot-solution

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/21 1:30:46

[deprecated]第四章:TTM分析: 4.2.1 存储分配ttm_bo_validate功能实现分析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/21 1:30:26

容器化迁移实战:从能跑到跑得漂亮的标准化与分层策略

1. 从“能跑就行”到“跑得漂亮”&#xff1a;应用容器化迁移的真实门槛很多团队第一次做容器化迁移&#xff0c;脑子里想的都是“把应用塞进镜像里&#xff0c;能跑起来就完事了”。我见过太多这样的案例&#xff1a;一个跑了三年的Java单体应用&#xff0c;运维同学花了一下午…

作者头像 李华
网站建设 2026/10/21 1:29:03

ESP32-S31 一键烧录包制作:Windows 双击即用,无需 Python 环境

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/21 1:28:57

Jessibuca:3 步在浏览器跑通 H5 直播流播放器

Jessibuca&#xff1a;3 步在浏览器跑通 H5 直播流播放器 【免费下载链接】jessibuca Jessibuca是一款开源的纯H5直播流播放器 项目地址: https://gitcode.com/GitHub_Trending/je/jessibuca Jessibuca H5 直播流播放器把 FFmpeg 的解码库用 Emscripten 编译成 WASM&…

作者头像 李华