霍尔传感器

1、 霍尔传感器模式

  霍尔传感器是根据霍尔效应制作的一种磁场传感器。霍尔效应:当电流垂直于外磁场通过半导体时,载流子发生偏转,垂直于电流和磁场的方向会产生一附加电场,从而在半导体的两端产生电势差,这一现象就是霍尔效应,这个电势差也被称为霍尔电势差。

  霍尔效应原理: 磁场会对位于其中的带电导体内运动的电荷载流子施加一个垂直于其运动方向的力,该力会使得正负电荷分别积聚到导体的两侧。这在薄而平的导体中尤为明显。电荷在导体两侧的积累会平衡磁场的影响, 在导体两侧建立稳定的电势差。产生这一电势差的过程就叫做霍尔效应,有 E.H.Hall 在 1879 年发现。
  霍尔传感器是根据霍尔效应制作的一种磁场传感器,它可以有效的反映通过霍尔原件的磁密度, 见下图:

                 霍尔传感器
  有霍尔传感器的BLDC 电机其霍尔传感器安装示意图见下图:

                  BLDC 电机横截面

                   霍尔的安装示例

  注:
    机械角度是指电机转子的旋转角度,由Θ m 表示;
    电角度是指磁场的旋转角度,由Θ e 表示。
    当转子为一对极时, Θm = Θe;
    当转子为 n 对极时, n*Θm=Θe。比如4对极时,转一圈的电角度为360*4=1440
  当霍尔在和电机的转子做相对运动时,会随着转子下磁密度的变化,产生变化的信号, 见下图:

                   霍尔信号

  在 BLDC 中一般采用 3 个开关型霍尔传感器测量转子的位置,由其输出的 3 位二进制编码去控制三相六臂全桥中的 6 个 MOS 管的导通实现换相。如果将一只霍尔传感器安装在靠近转子的位置,当 N 极逐渐靠近霍尔传感器即磁感器达到一定值时,其输出是导通状态;当 N 极逐渐离开霍尔传感器、磁感应逐渐小时,其输出仍然保持导通状态;只有磁场转变为 S 极便达到一定值时,其输出才翻转为截止状态。在 S 和 N 交替变化下传感器输出波形占高、低电平各占 50%。如果转子是一对极,则电机旋转一周霍尔传感器输出一个周期的电压波形,如果转子是两对极,则输出两个周期的波形。
  在直流无刷电机中一般把 3 个霍尔传感器按间隔 120 度或 60 度的圆周分布来安装,如果按间隔120 度来安装,则 3 个霍尔传感器输出波形相差 120 度电度角,输出信号中高、低电平各占 180度电度角。

  如果规定输出信号高电平用“1”表示,低电平用“0”表示,则输出的三个信号可以用三位二进制码表示,如下图所示。

  同无刷电机均匀分布的定子一样,用于输出 3 路磁场信号的 3 个霍尔传感器也是均匀分布在无刷电机的一周的,每相邻两个传感器电角度相差 120°。电机按一定方向转动时, 3 个霍尔的输出会按照 6 步的规律变化,如下所示。

         霍尔传感器安装位置 120°电角度

  电机按一定方向转动时, 3 个霍尔的输出会按照 6 步的规律变化(不会出现3个霍尔都是一样的值,只会两个霍尔一样), 见下图:

                   霍尔传感器旋转信号

  补充, 机械角度是指电机转子的旋转角度, 电角度是指磁场的旋转角度,它们的关系式满足: 电角度 = 机械角度 * 极对数。
  上图为电机旋转时三个霍尔传感器输出的波形,所对应的扇区组合。通过三个霍尔传感器输出的波形就可以判断当前转子的具体位置,同样满足 6 步一周期。
  6 步换向需要依赖霍尔传感器反馈的转子位置, 其相对应的就是三相逆变电路的上下桥臂导通情况, 如下表所示。

  结合BLDC的六步控制, 在每个霍尔信号都对应一个 BLDC 控制步,使得 BLDC 旋转一个角度, 这样可以制作下表: 表格 10-1 和表格 10-2:

  特别注意,一般 BLDC 厂家都会给出一个霍尔传感器和绕组得电情况对应关系表, 不一定跟上面两个表都完全对应一致, 但是原理分析都是一致的。

  上面两个表的对应意思就是:当检测到霍尔传感器信号为某个值时, 控制六个桥臂对应的开关状态。 例如, 我们想让电机正转,就用表格 10-1 中的对应信息,假设 STM32 检测到当前的霍尔信号为: 霍尔#1、 霍尔#2、 霍尔#3 分别对应为 1、 0、 1, 那么此时我们应该让 STM32 控制 A-和 C+桥臂导通,而其他桥臂都关断, 在 A-和 C+桥臂导通情况下, 电机的转子会向着一个位置旋转; 在旋转到达目标位置之前, 霍尔传感器信号就会发生改变, 此时变为: 霍尔#1、 霍尔#2、霍尔#3 分别对应为 0、 0、 1, 好了, 此时我们马上把 C+桥臂关断,而把 B+桥臂,即此时 A-和 B+桥臂导通,其他桥臂关断, 电机就又向旋转一个角度。 这样, 如此循环下去,电机就可以不停的旋转了。
  此时, 有些人肯定想问: 如果我不管霍尔信号变化,就按其中任一种给电,电机会怎样的呢? 电机会固定在一个位置,实际上, 这种情况是很危险的,我们知道,绕组都是漆包线铜丝,电阻非常小, 当总是给电时候,电路中电流就非常大,严重情况,烧毁电机或者电源。
  特别的,如果直接导通 A+和 A-这两桥臂,或者 B+和 B-这两桥臂, 或者 C+和C-这两桥臂会出现什么情况呢?结果就是电源必烧无疑,这些情况相当于电源正负极直接短路,所以这要求我们在接线或者电路设计是非常小心!!!

  最后我们可以得到有感驱动无刷电机整体框图如下:

 2、STM32霍尔传感器配置代码示例

  在STM32的定时器霍尔传感器模式下,Prescaler(预分频器)和Period(自动重装载值,ARR)的配置需根据电机转速、定时器时钟及控制需求综合确定。以下是具体配置原则和典型值分析:
  (1)Prescaler(预分频器)配置
  1) 推荐值
    通常设为 0(不分频),直接使用定时器时钟源频率
  2) 原因
    高分辨率需求:霍尔信号跳变间隔时间测量需要高精度计数器,不分频可最大化计数频率(例如84MHz),提高转速计算分辨率。
    实时性保障:高速电机(>10,000 RPM)换相要求快速响应,减少分频可降低信号处理延迟。
  3) 例外情况
    信号噪声较大时:可适当增大分频(如Prescaler=2-1),但会降低转速精度:
  (2)Period(自动重装载值,ARR)配置
  1) 推荐值
    16位定时器:设为最大值 0xFFFF(65535),避免频繁溢出
    32位定时器(如TIM2/TIM5):可设为 0xFFFFFFFF
  2) 原因
    覆盖最大时间间隔:
      确保两次霍尔跳变间隔内计数器不溢出。例如:
      定时器时钟=84MHz,ARR=65535时,最大可测时间=65535/84MHz≈780μs
    对应最低转速:转速(RPM) = 60 / (极对数 × 6 × 780μs) ≈ 214 RPM(4极电机)
    简化软件逻辑:避免频繁处理计数器溢出中断,减少CPU负载。
  3) 动态调整场景
    超低速电机(如<100 RPM):
      若0xFFFF无法满足测量需求,需启用溢出中断扩展计数:

volatile uint32_t overflow_count = 0;
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) 
{
    if (htim == &htim1) 
        overflow_count++;
}    

    实际时间计算:总时间 = (overflow_count * ARR) + CNT
  (3)配置实例分析
  1) 高速电机(50,000 RPM,4极)
    参数:
      定时器时钟=84MHz(APB2不分频)
      霍尔跳变频率 ≈ (50,000 RPM × 4极 × 6状态) / 60 = 20kHz
      每次跳变间隔 ≈ 84MHz / 20kHz = 4200计数
    配置:

htim1.Init.Prescaler = 0; // 84MHz计数
htim1.Init.Period = 0xFFFF; // 覆盖间隔(4200 << 65535)

  2) 低速电机(200 RPM,4极)
    参数:
      跳变间隔 ≈ 60 / (200 RPM × 4 × 6) = 12.5ms
      所需计数 = 84MHz × 12.5ms = 1,050,000 > 65535
    配置:

htim1.Init.Prescaler = 1; // 42MHz计数
htim1.Init.Period = 0xFFFF; // 启用溢出中断扩展  (4)霍尔模式下的特殊考量

  (4) 霍尔模式下的特殊考量

  1) 与普通定时器模式的区别
    CNT清零机制:霍尔跳变时硬件自动清零CNT(用于转速计算),Period主要限制溢出中断频率,而非直接控制换相。
    死区时间独立:由TIMx_BDTR寄存器配置,不影响Prescaler和Period。
  2) 滤波参数配合
    输入滤波(ICFilter):
      需与Prescaler协调,避免过度滤波导致信号延迟:
      sHallConfig.IC1Filter = 0x07; // 适中滤波(8个时钟周期)
  (5)总结:配置黄金法则

  公式验证:
    确保 (定时器时钟 / (Prescaler+1)) / Period > 6 × 极对数 × 最高转速 / 60

 

/********************************************************************************
                                   参数宏定义
*******************************************************************************/
//定义周期
#define GENERAL_TIME4_PERIOD                    65536    //霍尔传感器模式时通常将周期配置为最大65535,避免定时器频繁溢出,简化转速计算(直接读取捕获值)。

//预分频
#define GENERAL_TIME4_PRESCALER                    84        //霍尔传感器模式时通常将预分频配置为0,霍尔信号的频率通常较低(一般 <1 kHz),而定时器时钟(如STM32的72 MHz)远高于信号频率,无需分频即可精确捕获。


/********************************************************************************
                                   宏定义
*******************************************************************************/
//通用定时器4
#define GENERAL_TIME4                           TIM5                       
#define GENERAL_TIME4_CLK_ENABLE                __TIM5_CLK_ENABLE
#define GENERAL_TIME4_CLK_DISABLE                __TIM5_CLK_DISABLE

#define GENERAL_TIME4_IRQ                       TIM5_IRQn                  
#define GENERAL_TIME4_IRQHandler                TIM5_IRQHandler            





/********************************************************************************
                                   引脚宏定义
*******************************************************************************/
#define GENERAL_TIME4_CH1_GPIO_PORT                GPIOH
#define GENERAL_TIME4_CH1_GPIO_PIN                 GPIO_PIN_10
#define GENERAL_TIME4_CH1_GPIO_AF                GPIO_AF2_TIM5
#define GENERAL_TIME4_CH1_GPIO_CLK_ENABLE        __GPIOH_CLK_ENABLE

#define GENERAL_TIME4_CH2_GPIO_PORT                GPIOH
#define GENERAL_TIME4_CH2_GPIO_PIN                 GPIO_PIN_11
#define GENERAL_TIME4_CH2_GPIO_AF                GPIO_AF2_TIM5
#define GENERAL_TIME4_CH2_GPIO_CLK_ENABLE        __GPIOH_CLK_ENABLE

#define GENERAL_TIME4_CH3_GPIO_PORT                GPIOH
#define GENERAL_TIME4_CH3_GPIO_PIN                 GPIO_PIN_12
#define GENERAL_TIME4_CH3_GPIO_AF                GPIO_AF2_TIM5
#define GENERAL_TIME4_CH3_GPIO_CLK_ENABLE        __GPIOH_CLK_ENABLE




/********************************************************************************
                                   输入/捕获通道定义
*******************************************************************************/
//通道号
#define GENERAL_TIME4_CH1                        TIM_CHANNEL_1
#define GENERAL_TIME4_CH2                        TIM_CHANNEL_2
#define GENERAL_TIME4_CH3                        TIM_CHANNEL_3
#define GENERAL_TIME4_CH4                        TIM_CHANNEL_4





/********************************************************************************
                                   结构体声明
*******************************************************************************/
typedef struct GENERAL_TIME4_ParamTypeDef
{
    uint32_t hall_phase[2];            //霍尔信号
    uint32_t hall_intr_count;        //霍尔中断计数,用于计算电机转速
    uint32_t locked_rotor_count;    //堵转计数
}GENERAL_TIME4_ParamTypeDef;


/********************************************************************************
                                   函数声明
*******************************************************************************/
void GENERAL_TIME_ConfigInit(void);
void GENERAL_TIME_Open(uint8_t General_Timex);
void GENERAL_TIME_Close(uint8_t General_Timex);
uint32_t GENERAL_TIME4_GetHallSensorPhase(void);



/********************************************************************************
                                   变量声明
*******************************************************************************/
extern TIM_HandleTypeDef GENERAL_TIME4_HandleStruct;

extern GENERAL_TIME4_ParamTypeDef GENERAL_TIME4_Paramstruct;






TIM_HandleTypeDef GENERAL_TIME4_HandleStruct;


GENERAL_TIME4_ParamTypeDef GENERAL_TIME4_Paramstruct;

/**
  * @brief  通用定时器中断优先级配置
  * @param  无
  * @retval 无
  */
static void GENERAL_TIME_NvicConfig(void)
{ 
    HAL_NVIC_SetPriority(GENERAL_TIME4_IRQ, 2, 0);
    HAL_NVIC_EnableIRQ(GENERAL_TIME4_IRQ);    
}




 /**
  * @brief  通用定时器4模式配置
  * @param  无
  * @retval 无
  */
static void GENERAL_TIME4_HandleConfig(void)
{    
    GENERAL_TIME4_CLK_ENABLE();

    GENERAL_TIME4_HandleStruct.Instance = GENERAL_TIME4;
    GENERAL_TIME4_HandleStruct.Init.Period = GENERAL_TIME4_PERIOD-1;                //若通过CNT值计算两次换相的时间间隔,ARR需足够大以覆盖最大间隔
    GENERAL_TIME4_HandleStruct.Init.Prescaler = GENERAL_TIME4_PRESCALER-1;            //霍尔传感器模式下通常设为 0(不分频),以保持最高计时精度。若通过捕获两次霍尔跳变的时间间隔计算转速,更高的计数频率(更小的Prescaler)可提高转速分辨率。
    GENERAL_TIME4_HandleStruct.Init.CounterMode=TIM_COUNTERMODE_CENTERALIGNED1;        //计数器计数模式为中心对齐模式,减少中断延迟,适合高频信号处理。需对称PWM生成或高精度双向计数(如FOC控制)。
    GENERAL_TIME4_HandleStruct.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1;            //时钟分频因子

//    HAL_TIM_Base_Init(&GENERAL_TIME4_HandleStruct);////基础初始化(可选,霍尔传感器模式会自动处理)
}




/**
  * @brief  通用定时器霍尔传感器模式配置
  * @param  无
  * @retval 无
  */
static void GENERAL_TIME4_HallSensorModeConfig(void) 
{
    GPIO_InitTypeDef GPIO_InitStruct;
    TIM_HallSensor_InitTypeDef TIM_HallSensor_InitStruct;
    TIM_OC_InitTypeDef TIM_OC_InitStruct;  

    
    GENERAL_TIME4_CLK_ENABLE();
    GENERAL_TIME4_CH1_GPIO_CLK_ENABLE();
    GENERAL_TIME4_CH2_GPIO_CLK_ENABLE();
    GENERAL_TIME4_CH3_GPIO_CLK_ENABLE();


    GPIO_InitStruct.Mode      = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Speed     = GPIO_SPEED_FREQ_HIGH;
    GPIO_InitStruct.Pull      = GPIO_PULLUP;

    GPIO_InitStruct.Alternate = GENERAL_TIME4_CH1_GPIO_AF;
    GPIO_InitStruct.Pin       = GENERAL_TIME4_CH1_GPIO_PIN;
    HAL_GPIO_Init(GENERAL_TIME4_CH1_GPIO_PORT, &GPIO_InitStruct);

    GPIO_InitStruct.Alternate = GENERAL_TIME4_CH2_GPIO_AF;
    GPIO_InitStruct.Pin       = GENERAL_TIME4_CH2_GPIO_PIN;
    HAL_GPIO_Init(GENERAL_TIME4_CH2_GPIO_PORT, &GPIO_InitStruct);

    GPIO_InitStruct.Alternate = GENERAL_TIME4_CH3_GPIO_AF;
    GPIO_InitStruct.Pin       = GENERAL_TIME4_CH3_GPIO_PIN;
    HAL_GPIO_Init(GENERAL_TIME4_CH3_GPIO_PORT, &GPIO_InitStruct);

  

    TIM_HallSensor_InitStruct.Commutation_Delay = 0x06; // 延迟触发,7us,实际测试需要7us,配置计数器CNT中CCR2的值
    TIM_HallSensor_InitStruct.IC1Filter         = 0x0F; // 输入滤波;
    TIM_HallSensor_InitStruct.IC1Polarity       = TIM_ICPOLARITY_RISING;// 输入捕获极性,霍尔传感器时这里配置不起作用,它会自动检测上升沿和下降沿变化
    TIM_HallSensor_InitStruct.IC1Prescaler      = TIM_ICPSC_DIV1;       // 输入捕获预分频,霍尔传感器不需要分频
    HAL_TIMEx_HallSensor_Init(&GENERAL_TIME4_HandleStruct, &TIM_HallSensor_InitStruct);
    HAL_TIMEx_HallSensor_Start_IT(&GENERAL_TIME4_HandleStruct);//启动霍尔传感器中断
    
    
    
    //通道4配置为超时检测功能,当电机发生堵转时CH1、CH2、CH3就不会发生变化,通道4计时就会超时,此配置可以让电机停止
    TIM_OC_InitStruct.OCMode = TIM_OCMODE_TIMING;                //配置为计数模式
    TIM_OC_InitStruct.OCFastMode = TIM_OCFAST_DISABLE;            //快速输出模式,禁止  
    TIM_OC_InitStruct.OCPolarity = TIM_OCPOLARITY_HIGH;            //当定时器计数值小于CCR1_Val时为高电平
    TIM_OC_InitStruct.OCIdleState = TIM_OCIDLESTATE_SET;
    TIM_OC_InitStruct.Pulse = 0Xffff;                            //配置脉宽占空比,即设置CCR,无需减1
    HAL_TIM_OC_ConfigChannel(&GENERAL_TIME4_HandleStruct, &TIM_OC_InitStruct, GENERAL_TIME4_CH4);//配置PWM通道
    TIM_CCxChannelCmd(&GENERAL_TIME4_HandleStruct, GENERAL_TIME4_CH4, TIM_CCx_ENABLE);
}







/**
  * @brief  通用定时器初始化
  * @param  无
  * @retval 无
  */
void GENERAL_TIME_ConfigInit(void)
{
    GENERAL_TIME_NvicConfig();  
    GENERAL_TIME4_HandleConfig();
    GENERAL_TIME4_HallSensorModeConfig();
}





/**
  * @brief  GENERAL_TIME4获取霍尔传感器相位
  * @param  无
  * @retval 直接读取引脚的状态,数据字节的低三位分别对应UVW(HALL)的电平状态
  */
uint32_t GENERAL_TIME4_GetHallSensorPhase(void)
{
    uint32_t temp = 0;
    temp |= HAL_GPIO_ReadPin(GENERAL_TIME4_CH1_GPIO_PORT, GENERAL_TIME4_CH1_GPIO_PIN);//U(A)
    temp <<= 1;
    temp |= HAL_GPIO_ReadPin(GENERAL_TIME4_CH2_GPIO_PORT, GENERAL_TIME4_CH2_GPIO_PIN);//V(B)
    temp <<= 1;
    temp |= HAL_GPIO_ReadPin(GENERAL_TIME4_CH3_GPIO_PORT, GENERAL_TIME4_CH3_GPIO_PIN);//W(C)
    return (temp&0x0007); // 取低三位
}





/**
  * 函数功能: 霍尔传感器回调函数
  * 输入参数: @htim,霍尔传感器接口定时器
  * 返 回 值: 无
  * 说    明: 
  */
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
    if (htim == (&GENERAL_TIME1_HandleStruct))
    {
        
    }
    else if (htim == (&GENERAL_TIME2_HandleStruct))
    {
        
    }
    else if (htim == (&GENERAL_TIME3_HandleStruct))
    {
        
    }
    else if (htim == (&GENERAL_TIME4_HandleStruct))
    {
        GENERAL_TIME4_Paramstruct.hall_phase[0] = GENERAL_TIME4_GetHallSensorPhase();     // 获取霍尔引脚的相位
        
        if (MOTOR_TYPE_1 == 0) //BLDC电机
        {
             //顺时针的霍尔顺序与逆时针的顺序是关于7互补,所以可以使用7减逆时针的顺序得到顺时针的霍尔顺序,这里使用异或代替减法
            if (MOTOR_RunStruct[0].direction == MOTOR_FORWARD_ROTATION)//电机正转
            {
                GENERAL_TIME4_Paramstruct.hall_phase[0] = GENERAL_TIME4_Paramstruct.hall_phase[0]^0x07;// 将低三位异或 111b ^ 010b -> 101b
            }
            else
            {
                GENERAL_TIME4_Paramstruct.hall_phase[0] = GENERAL_TIME4_Paramstruct.hall_phase[0];
            }
        }
        else//PMSM电机
        {
            //PMSM的旋转顺序跟BLDC刚好是相反的,设定为MOTOR_DIR_CCW的时候BLDC是逆时针旋转
            //PMSM是顺时针旋转,如果需要设定为MOTOR_DIR_CCW的时候PMSM为逆时针旋转,则使用
            //下面语句代替上面的语句
            if (MOTOR_RunStruct[0].direction == MOTOR_FORWARD_ROTATION)//电机正转
            {
                GENERAL_TIME4_Paramstruct.hall_phase[0] = GENERAL_TIME4_Paramstruct.hall_phase[0];
            }
            else
            {
                GENERAL_TIME4_Paramstruct.hall_phase[0] = GENERAL_TIME4_Paramstruct.hall_phase[0]^0x07;// 将低三位异或 111b ^ 010b -> 101b
            }        
        }
        ADVANCED_TIME2_MotorPhaseControl(GENERAL_TIME4_Paramstruct.hall_phase[0]);        //换相控制
        
        if (GENERAL_TIME4_Paramstruct.hall_phase[0] != GENERAL_TIME4_Paramstruct.hall_phase[1])//测试发现有时会连续出现两次相同的数据,这里滤掉重复的
        {
            GENERAL_TIME4_Paramstruct.hall_intr_count++;
            GENERAL_TIME4_Paramstruct.hall_phase[1] = GENERAL_TIME4_Paramstruct.hall_phase[0];
        }
    }
}





/**
  * 函数功能: 比较非阻塞模式下的回调
  * 输入参数: @htim,霍尔传感器接口定时器
  * 返 回 值: 无
  * 说    明: 
  */
void HAL_TIM_OC_DelayElapsedCallback(TIM_HandleTypeDef *htim)
{
    if (htim == (&GENERAL_TIME1_HandleStruct))
    {
        
    }
    else if (htim == (&GENERAL_TIME2_HandleStruct))
    {
        
    }
    else if (htim == (&GENERAL_TIME3_HandleStruct))
    {
        
    }
    else if (htim == (&GENERAL_TIME4_HandleStruct))
    {
        GENERAL_TIME4_Paramstruct.locked_rotor_count++;
        if (GENERAL_TIME4_Paramstruct.locked_rotor_count > 6)
        {
            MOTOR_Stop(MOTOR_NUMBER_1);
        }
    }
}

 

 

 

 

 

  

 

posted @ 2025-04-10 09:31  孤情剑客  阅读(547)  评论(0)    收藏  举报