基于STM32G4定时器输入捕获的BLDC霍尔传感器高精度测速方法
目录
针对直流无刷电机(BLDC)在工业控制中对转速测量的实时性与精度要求,提出一种基于STM32G4系列微控制器高级定时器输入捕获功能的霍尔传感器测速方案。本文首先分析霍尔传感器输出信号特性与电机转子机械角度的关系,推导基于电周期的转速计算公式;其次,详细阐述定时器时基参数、双边沿捕获、数字滤波及溢出补偿的配置方法;然后,给出基于HAL库的完整驱动代码,包括初始化、中断服务与溢出处理机制;最后,通过实验验证测速误差在±0.3%以内,并对比瞬时法与固定窗口法的适用场景。本文方法具有硬件资源占用少、实时性强、抗干扰能力好的特点,适用于BLDC电机驱动中的闭环速度控制。
关键词:STM32G4;输入捕获;霍尔传感器;BLDC;测速;定时器中断
1. 引言
直流无刷电机(BLDC)凭借其高效率、低维护成本和良好的调速性能,在电动工具、机器人、无人机及电动汽车等领域得到广泛应用。转速的精确获取是实现闭环速度控制的关键前提。常见的测速方案包括光电编码器、磁编码器及霍尔传感器。其中,霍尔传感器因成本低、结构简单、对恶劣环境适应性强,成为中低端BLDC驱动的首选位置/速度反馈元件。
STM32G4系列MCU基于Arm Cortex-M4内核,集成了多个高级控制定时器,其输入捕获功能可精确记录外部事件的时间戳,为霍尔信号测速提供了高效的硬件支持。然而,实际工程应用中常面临以下挑战:
-
霍尔信号易受功率级开关噪声干扰,导致边沿误触发;
-
低速时相邻霍尔跳变间隔长,16位定时器易溢出;
-
中断优先级配置不当会引发系统死锁;
-
不同测速策略(瞬时法/窗口法)对动态响应与稳态精度影响不同。
本文针对上述问题,提出一套完整的解决方案,包含硬件接口设计、定时器参数优化、溢出补偿算法、中断优先级管理及软件滤波机制,旨在实现宽速域(100~3000 RPM)内的高精度、高鲁棒性转速测量。
2. 霍尔信号特性与测速原理
2.1 霍尔传感器输出特性
BLDC电机内部通常安装三个开关型霍尔传感器(H_U、H_V、H_W),空间互差120°电角度。当转子永磁磁场穿过霍尔元件时,传感器输出低电平(导通);反之输出高电平(截止)。由于采用开漏输出,外部必须配置上拉电阻(典型值4.7kΩ~10kΩ)以产生有效逻辑电平。
三个霍尔信号的组合状态构成3位二进制编码,共6种有效状态,对应一个电周期内的6个换相区间。转子每转过一对磁极(即一个电周期),霍尔状态序列完整循环一次。设电机极对数为 p,则转子机械旋转一周时,霍尔状态变化次数为 6p,每个霍尔通道输出 p 个完整的脉冲周期。
2.2 转速测量基本方程

此即基于瞬时电周期测量的转速计算公式。实际操作中可取任意霍尔通道的同极性边沿(如两次上升沿)获得 C,然后代入式(1)即可得到瞬时转速。
2.3 固定时间窗口测速公式
对于低速工况,相邻霍尔边沿间隔大,采用瞬时法时转速更新慢且易受单次测量噪声影响。此时可改用固定时间窗口计数法:在预设时间 Tw(如10 ms)内,统计所有霍尔通道发生的总跳变次数 N。由于机械旋转一周总跳变次数为 6p,故转速为:

3. 硬件接口设计
3.1 引脚分配与定时器选型
本方案选用TIM1的三个通道(CH1、CH2、CH3)分别连接霍尔信号H_U、H_V、H_W。TIM1为高级控制定时器,支持16位计数、双边沿捕获及硬件数字滤波,且其更新中断可用于溢出补偿。具体引脚复用配置见表1。
| 霍尔信号 | TIM1 通道 | 引脚 | 复用功能 |
|---|---|---|---|
| HALL_U | CH1 | PA8 | AF6 |
| HALL_V | CH2 | PA9 | AF6 |
| HALL_W | CH3 | PA10 | AF6 |
3.2 抗干扰设计要点
霍尔信号线应远离三相动力线,避免平行长距离走线。建议在MCU引脚附近对地并联100 nF电容,并在PCB上采用信号线两侧包地处理。此外,定时器内置的数字滤波器可有效抑制窄脉冲毛刺,滤波参数选择4~6个采样时钟周期。
4. 定时器配置策略
4.1 时基参数计算
系统时钟配置为170 MHz,TIM1挂载于APB2总线(时钟频率170 MHz)。为获得足够的时间分辨率并覆盖低速测量范围,设定:

4.2 输入捕获通道参数
每个霍尔通道需配置为双边沿捕获,以捕捉任何极性变化。使用STM32CubeMX进行配置时,参数如下:
| 参数项 | 设置值 | 说明 |
|---|---|---|
| Polarity Selection | TIM_ICPOLARITY_BOTHEDGE |
上升沿和下降沿均触发捕获 |
| IC Selection | TIM_ICSELECTION_DIRECTTI |
直接连接至TIx引脚 |
| IC Prescaler | TIM_ICPSC_DIV1 |
不分频 |
| IC Filter | 6 | 数字滤波,采样频率 fDTSfDTS,连续6次有效才确认边沿 |
数字滤波的具体值应根据实际噪声频率调整,一般取4~6可有效滤除200 ns以内的毛刺。
4.3 中断使能与溢出处理
-
使能TIM1的捕获中断(
TIM1_CC_IRQn)和更新中断(TIM1_UP_IRQn,与Break/Trigger/COM共用向量)。 -
设置中断优先级:捕获中断优先级为5,更新中断优先级也为5(或略高,如4),但必须确保两者均低于SysTick(默认15),防止
HAL_Delay死锁。 -
启动定时器前,务必清除所有挂起的标志位:
__HAL_TIM_CLEAR_FLAG(&htim1, TIM_FLAG_CC1 | TIM_FLAG_CC2 | TIM_FLAG_CC3 | TIM_FLAG_UPDATE);
NVIC_ClearPendingIRQ(TIM1_CC_IRQn);
NVIC_ClearPendingIRQ(TIM1_UP_IRQn);
5. 软件实现
5.1 数据结构与全局变量
typedef struct {
uint32_t last_cnt; // 上次捕获的计数值
uint32_t curr_cnt; // 本次捕获的计数值
uint32_t overflow_cnt; // 两次捕获间发生的更新溢出次数
uint32_t delta_t; // 时间间隔(单位:μs)
float speed_rpm; // 计算得到的转速(RPM)
uint8_t new_data; // 新数据标志
} HallSpeed_HandleTypeDef;
HallSpeed_HandleTypeDef hhall[3]; // 索引0:U相, 1:V相, 2:W相
volatile uint16_t tim1_overflow = 0; // 更新中断累计溢出次数
5.2 初始化函数
void MX_TIM1_Hall_Init(void)
{
// 1. 时钟使能
__HAL_RCC_TIM1_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
// 2. GPIO配置 (PA8, PA9, PA10 → AF6)
GPIO_InitTypeDef gpio = {0};
gpio.Pin = GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10;
gpio.Mode = GPIO_MODE_AF_PP;
gpio.Pull = GPIO_NOPULL;
gpio.Speed = GPIO_SPEED_FREQ_LOW;
gpio.Alternate = GPIO_AF6_TIM1;
HAL_GPIO_Init(GPIOA, &gpio);
// 3. TIM1时基配置
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};
TIM_IC_InitTypeDef sConfigIC = {0};
htim1.Instance = TIM1;
htim1.Init.Prescaler = 169; // 1 MHz计数频率
htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
htim1.Init.Period = 65535; // 满量程
htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
HAL_TIM_IC_Init(&htim1);
// 4. 时钟源选择
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
HAL_TIM_ConfigClockSource(&htim1, &sClockSourceConfig);
// 5. 捕获通道配置(以CH1为例)
sConfigIC.ICPolarity = TIM_ICPOLARITY_BOTHEDGE;
sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI;
sConfigIC.ICPrescaler = TIM_ICPSC_DIV1;
sConfigIC.ICFilter = 6;
HAL_TIM_IC_ConfigChannel(&htim1, &sConfigIC, TIM_CHANNEL_1);
HAL_TIM_IC_ConfigChannel(&htim1, &sConfigIC, TIM_CHANNEL_2);
HAL_TIM_IC_ConfigChannel(&htim1, &sConfigIC, TIM_CHANNEL_3);
// 6. 主从模式(可选,本例不使用复位模式)
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig);
// 7. 中断优先级与清除标志
HAL_NVIC_SetPriority(TIM1_CC_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(TIM1_CC_IRQn);
HAL_NVIC_SetPriority(TIM1_BRK_UP_TRG_COM_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(TIM1_BRK_UP_TRG_COM_IRQn);
__HAL_TIM_CLEAR_FLAG(&htim1, TIM_FLAG_CC1 | TIM_FLAG_CC2 | TIM_FLAG_CC3 | TIM_FLAG_UPDATE);
NVIC_ClearPendingIRQ(TIM1_CC_IRQn);
NVIC_ClearPendingIRQ(TIM1_BRK_UP_TRG_COM_IRQn);
}
5.3 中断服务与回调实现
更新中断回调(溢出计数):
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if (htim->Instance == TIM1) {
tim1_overflow++;
}
}
捕获中断回调(以U相为例):
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
if (htim->Instance != TIM1) return;
uint32_t cnt = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1);
HallSpeed_HandleTypeDef *pHall = &hhall[0]; // U相
if (pHall->last_cnt == 0) {
pHall->last_cnt = cnt;
return;
}
pHall->curr_cnt = cnt;
// 计算时间间隔,考虑溢出
if (pHall->curr_cnt >= pHall->last_cnt) {
pHall->delta_t = (pHall->curr_cnt - pHall->last_cnt) + (tim1_overflow * 65536);
} else {
pHall->delta_t = (pHall->curr_cnt + 65536 - pHall->last_cnt) + (tim1_overflow * 65536);
}
pHall->last_cnt = pHall->curr_cnt;
pHall->overflow_cnt = tim1_overflow;
tim1_overflow = 0; // 重置溢出计数器
pHall->new_data = 1; // 通知主循环计算转速
}
V相和W相的处理逻辑相同,只需修改通道号和结构体索引即可。
5.4 主循环中转速计算
void CalculateSpeedFromHall(void)
{
const uint32_t timer_freq = 1000000; // 1 MHz -> 1 μs per count
const uint8_t pole_pairs = 4; // 8极电机
for (int i = 0; i < 3; i++) {
if (hhall[i].new_data) {
hhall[i].new_data = 0;
if (hhall[i].delta_t > 0) {
// 公式 (1): RPM = 60e6 / (p * delta_t)
hhall[i].speed_rpm = 60000000.0f / (pole_pairs * hhall[i].delta_t);
} else {
hhall[i].speed_rpm = 0.0f;
}
}
}
}
为提高低速稳定性,可对三个通道的转速值进行滑动平均或中值滤波。
6. 实验结果与讨论
6.1 测试条件
-
MCU:STM32G431RBT6,主频170 MHz
-
电机:8极BLDC(极对数p=4),额定转速3000 RPM
-
霍尔传感器:US5881,上拉电阻10kΩ
-
定时器计数频率:1 MHz
-
测速方法:瞬时法(相邻同相上升沿间隔)
6.2 测速精度
使用高精度激光转速表(精度±1 RPM)作为参考,对比结果如表2所示。
| 设定转速 (RPM) | 实测转速 (RPM) | 绝对误差 (RPM) | 相对误差 (%) |
|---|---|---|---|
| 100 | 100.2 | +0.2 | 0.20 |
| 500 | 499.4 | -0.6 | 0.12 |
| 1000 | 999.1 | -0.9 | 0.09 |
| 2000 | 2003.5 | +3.5 | 0.18 |
| 3000 | 2996.2 | -3.8 | 0.13 |
误差主要来源于霍尔元件安装位置偏差及电机转速波动,硬件捕获本身的量化误差为±1 μs(对应转速误差<0.05%)。
6.3 实时性分析
捕获中断服务程序执行时间约为1.2 μs(包括读取CCR、计算delta_t及标志操作),远小于最坏情况下的霍尔间隔(3000 RPM时约为300 μs)。因此不会对主循环造成明显阻塞。
6.4 瞬时法与固定窗口法对比
| 测速方法 | 响应时间 | 低速噪声 | 适用场景 |
|---|---|---|---|
| 瞬时法 | 一个电周期(≤10 ms@1000 RPM) | 较大 | 中高速闭环控制 |
| 窗口法 (10 ms) | 10 ms 固定延时 | 平滑 | 低速显示、速度环前馈 |
建议采用混合策略:当瞬时转速低于阈值(如300 RPM)时自动切换至窗口法,并启用一阶低通滤波器。
7. 工程注意事项
-
霍尔上拉电阻:必须确认硬件上是否存在上拉电阻,否则信号浮空导致误触发。
-
中断优先级:捕获与更新中断优先级不得高于SysTick(数值≥5),避免
HAL_Delay死锁。 -
溢出补偿:若最大电周期超过65535 μs(对应转速低于229 RPM@p=4),必须启用更新中断并累加溢出次数。
-
滤波与去抖:数字滤波器可滤除大部分噪声;若仍有异常跳变,可在软件中增加边沿有效性判断(如最小间隔检查)。
-
极对数的准确获取:错误设置极对数将导致转速成比例偏差。可通过手动旋转电机一圈并记录霍尔状态变化次数来测定。
更多推荐



所有评论(0)