第 7 篇:霍尔传感器——角度与速度反馈

前面 6 篇搭好了电流环,但 Park 变换需要的 θ_e(电角度)还没有着落。这篇讲 BLDC 电机最常用的位置反馈方案——霍尔传感器。


1. 为什么 BLDC 电机用霍尔

绝大多数 BLDC 电机出厂就自带三个霍尔传感器。三个霍尔在定子上空间互差 120°(电角度),转子每转过 60° 电角度,霍尔状态就变化一次——一个电周期提供 6 个离散位置

霍尔最大的优势:上电就能直接知道转子在哪个扇区,不需要任何对齐操作。


2. 霍尔信号与扇区

三个霍尔(H1、H2、H3)在定子上空间互差 120°:

电角度范围     H1 H2 H3    扇区
0°   ~ 60°     1  0  1     5
60°  ~ 120°    1  0  0     4
120° ~ 180°    1  1  0     6
180° ~ 240°    0  1  0     2
240° ~ 300°    0  1  1     3
300° ~ 360°    0  0  1     1

3. GD32 读取霍尔

#define HALL_PORT  GPIOB
#define HALL_H1    GPIO_PIN_6
#define HALL_H2    GPIO_PIN_7
#define HALL_H3    GPIO_PIN_8

void hall_gpio_init(void)
{
    rcu_periph_clock_enable(RCU_GPIOB);
    gpio_init(GPIOB, GPIO_MODE_IPU, GPIO_OSPEED_50MHZ,
              GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_8);
}

uint8_t hall_read(void)
{
    uint8_t h1 = (gpio_input_bit_get(HALL_PORT, HALL_H1) != 0);
    uint8_t h2 = (gpio_input_bit_get(HALL_PORT, HALL_H2) != 0);
    uint8_t h3 = (gpio_input_bit_get(HALL_PORT, HALL_H3) != 0);
    return (h1 << 2) | (h2 << 1) | h3;
}

4. 从 6 个离散位置推算连续角度(核心算法)

霍尔只给你 6 个离散位置(每个间隔 60° 电角度),FOC 需要连续角度。解法是:霍尔变化时用霍尔做绝对校准,霍尔没变化时用速度积分外推。

typedef struct {
    uint8_t  hall_state;       // 当前霍尔状态 (1~6)
    uint8_t  last_hall;        // 上一个霍尔状态
    uint32_t hall_timestamp;   // 上一次霍尔变化的时间戳 (μs)
    float    theta_elec;       // 当前电角度 (rad)
    float    omega_elec;       // 电角速度 (rad/s)
    uint16_t hall_change_count;
} hall_sensor_t;

#define HALL_SECTOR_ANGLE  (3.14159265f / 3.0f)  // 60° = π/3

// 查表:霍尔状态 → 对应扇区的中心电角度
const float hall_angle_table[8] = {
    0,                    // 0 = 无效
    5.235987f,            // 1 = 101 → 300°
    3.141592f,            // 2 = 100 → 180°
    4.188790f,            // 3 = 110 → 240°
    1.047197f,            // 4 = 010 → 60°
    6.283185f,            // 5 = 011 → 360°/0°
    2.094395f,            // 6 = 001 → 120°
    0                     // 7 = 111 = 无效
};

void hall_update(hall_sensor_t *hs, uint32_t sys_tick_us)
{
    uint8_t hall = hall_read();

    // 只处理有效状态
    if (hall < 1 || hall > 6) return;

    if (hall != hs->hall_state) {
        // ═══ 霍尔变化:用霍尔做绝对校准 ═══
        float hall_angle = hall_angle_table[hall];
        float last_angle = hall_angle_table[hs->hall_state];

        // 角度差(处理 0/2π 跨越)
        float angle_delta = hall_angle - last_angle;
        if (angle_delta > 3.14159f) angle_delta -= 6.283185f;
        if (angle_delta < -3.14159f) angle_delta += 6.283185f;

        // 计算速度
        uint32_t dt_ticks = sys_tick_us - hs->hall_timestamp;
        float dt = dt_ticks * 1e-6f;  // μs → s
        if (dt > 0.0001f && dt < 1.0f) {
            hs->omega_elec = angle_delta / dt;
        }

        // 校准角度——霍尔是绝对位置
        hs->theta_elec = hall_angle;
        hs->hall_state = hall;
        hs->hall_timestamp = sys_tick_us;
        hs->hall_change_count++;

    } else {
        // ═══ 霍尔没变化:速度积分外推 ═══
        uint32_t dt_ticks = sys_tick_us - hs->hall_timestamp;
        float dt = dt_ticks * 1e-6f;
        hs->theta_elec += hs->omega_elec * dt;

        // 归一化到 [0, 2π)
        while (hs->theta_elec >= 6.283185f) hs->theta_elec -= 6.283185f;
        while (hs->theta_elec < 0) hs->theta_elec += 6.283185f;
    }
}

为什么这个算法可靠? 霍尔每隔 60° 电角度校准一次,积分累积误差被限制在一个扇区内。转速越高,校准越频繁——误差越小。


5. 上电初始化

上电时读出霍尔状态,直接取对应扇区的中心角度作为初始角度。

void hall_init(hall_sensor_t *hs)
{
    uint8_t hall = hall_read();
    if (hall >= 1 && hall <= 6) {
        hs->theta_elec = hall_angle_table[hall];  // 直接取扇区中心角度
        hs->hall_state = hall;
        hs->omega_elec = 0;
        hs->hall_timestamp = get_sys_tick_us();
    }
}

不需要额外硬件的对齐流程——上电就能跑。这也是为什么方波驱动切换到 FOC 时,霍尔方案几乎没有额外的硬件改动。


6. 速度计算

从霍尔变化频率推算速度:

float hall_get_speed_rpm(hall_sensor_t *hs)
{
    // ω_elec 单位是 rad/s(电角速度)
    // 转换为机械 RPM
    float mech_rad_per_s = hs->omega_elec / MOTOR_POLE_PAIRS;
    return mech_rad_per_s * 60.0f / (2.0f * 3.14159265f);
}

低速时霍尔变化慢、速度更新滞后——这是霍尔方案的固有局限。如果应用需要极低转速的精确速度反馈,可以考虑无感观测器辅助。


7. 接入 FOC 主循环

hall_sensor_t hall;

void foc_current_loop_callback(void)
{
    // 1. 更新霍尔状态
    hall_update(&hall, get_sys_tick_us());

    // 2. 读电流
    phase_current_t curr = read_phase_currents();
    float i_alpha, i_beta;
    clarke_transform(curr.ia, curr.ib, curr.ic, &i_alpha, &i_beta);

    // 3. Park 变换(使用霍尔推算的角度)
    float id, iq;
    park_transform(i_alpha, i_beta, hall.theta_elec, &id, &iq);

    // 4. 电流 PI
    float vd = pi_update(&pi_d, id_ref, id, CURRENT_DT);
    float vq = pi_update(&pi_q, iq_ref, iq, CURRENT_DT);

    // 5. 反 Park → SVPWM
    float v_alpha, v_beta;
    inv_park_transform(vd, vq, hall.theta_elec, &v_alpha, &v_beta);

    uint8_t sector = get_sector(v_alpha, v_beta);
    float ta, tb, tc;
    calc_svpwm_duty(v_alpha, v_beta, VDC, sector, &ta, &tb, &tc);
    set_pwm_duty(ta, tb, tc);
}

8. 霍尔方案的局限与应对

局限表现应对
低速角度误差大< 100 RPM 时霍尔变化慢,积分段长速度环带宽降低;或切换无感观测器辅助
速度更新滞后速度阶跃后需等待下一次霍尔变化用电流模型推算速度作为补充
霍尔安装偏差三个霍尔不是精确 120°做一次霍尔角度标定

9. 小结

  • 霍尔是 BLDC 电机出厂标配,零额外成本
  • 核心算法:霍尔变化时校准,没变化时速度积分外推
  • 上电直接知道角度,无需对齐——这是霍尔最大的工程优势
  • 每 60° 电角度校准一次,累积误差可控
  • 大多数应用(风扇、水泵、电动车、电动工具)霍尔完全够用

下一篇:速度环——让电机转起来


下一篇:速度环——让电机转起来

更多推荐