BLDC有感控制—Hall代码易错点
迪丽瓦拉
2025-05-29 06:13:50
0

霍尔值的获取时间间隔

霍尔值的获取,建议在中断里面完成

中断由定时器负责配置,也就是说隔多久获取一次霍尔值,取决于定时器配置的周期

/*** @brief  霍尔传感器定时器初始化* @param  无* @retval 无*/
static void hall_tim_init(void)
{TIM_HallSensor_InitTypeDef  hall_sensor_cfg;  /* 基本定时器外设时钟使能 */HALL_TIM_CLK_ENABLE();/* 定时器基本功能配置 */htimx_hall.Instance = HALL_TIM;htimx_hall.Init.Prescaler = 128 - 1;       // 预分频htimx_hall.Init.CounterMode = TIM_COUNTERMODE_UP;           // 向上计数htimx_hall.Init.Period = 0xFFFF - 1;             // 计数周期htimx_hall.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;     // 时钟分频hall_sensor_cfg.IC1Prescaler = TIM_ICPSC_DIV1;            // 输入捕获分频hall_sensor_cfg.IC1Polarity = TIM_ICPOLARITY_BOTHEDGE;    // 输入捕获极性hall_sensor_cfg.IC1Filter = 10;                           // 输入滤波hall_sensor_cfg.Commutation_Delay = 0U;                   // 不使用延迟触发HAL_TIMEx_HallSensor_Init(&htimx_hall, &hall_sensor_cfg);HAL_NVIC_SetPriority(HALL_TIM_IRQn, 0, 0);    // 设置中断优先级HAL_NVIC_EnableIRQ(HALL_TIM_IRQn);            // 使能中断
}

时钟树传递过来的时钟是84M Hz

计算公式如下:84000000 / 128 / 65535 = 10.1 Hz

也就是100ms左右,每隔100ms获取一次霍尔值。

获取三相霍尔的状态

同时读取三个输入引脚的高低电平,一个3bits位的二进制数,需要注意一下有的U相在高位,有的在低位,都可以。

uint8_t get_hall_state(void)
{uint8_t state = 0;#if 1/* 读取霍尔传感器 U 的状态 */if(HAL_GPIO_ReadPin(HALL_INPUTU_GPIO_PORT, HALL_INPUTU_PIN) != GPIO_PIN_RESET){state |= 0x01U;}/* 读取霍尔传感器 V 的状态 */if(HAL_GPIO_ReadPin(HALL_INPUTV_GPIO_PORT, HALL_INPUTV_PIN) != GPIO_PIN_RESET){state |= 0x02U;}/* 读取霍尔传感器 W 的状态 */if(HAL_GPIO_ReadPin(HALL_INPUTW_GPIO_PORT, HALL_INPUTW_PIN) != GPIO_PIN_RESET){state |= 0x04U;}
#elsestate = (GPIOH->IDR >> 10) & 7;    // 读 3 个霍尔传感器的状态
#endifreturn state;    // 返回传感器状态
}

如何判断电机正转还是反转?

按照咱们最直接的反应,记录当前霍尔值,与之前的霍尔值进行比较,就知道了。

可霍尔值,可是一段没啥规律的数:

正传 546231

反转 132645

似乎也没法比较,但我们可以先规定一个数组(反转的)step[6] = {1, 3, 2, 6, 4, 5}

在这个数组里面呢,霍尔值为1=step[0],霍尔值为3=step[1]……

然后咱们比较0和1的大小就可以了,

/*** @brief  更新电机实际速度方向* @param  dir_in:霍尔值* @retval 无*/
static void update_speed_dir(uint8_t dir_in)
{uint8_t step[6] = {1, 3, 2, 6, 4, 5};static uint8_t num_old = 0;uint8_t step_loc = 0;    // 记录当前霍尔位置数组对应的位数int8_t dir = 1;for (step_loc=0; step_loc<6; step_loc++){if (step[step_loc] == dir_in)    // 找到当前霍尔的位置{break;}}/* 端点处理 */if (step_loc == 0){if (num_old == 1){dir = 1;}else if (num_old == 5){dir = -1;}}/* 端点处理 */else if (step_loc == 5){if (num_old == 0){dir = 1;}else if (num_old == 4){dir = -1;}}else if (step_loc > num_old)//直接判断,当前>之前,符合数组顺序,那就是反转{dir = -1;}else if (step_loc < num_old){dir = 1;}num_old = step_loc;
//  motor_drive.speed *= dir;;motor_drive.speed_group[count-1]*= dir;
}

在中断回调函数里进行换相!

这算是最核心部分的代码了。

首先一上来肯定要获取霍尔值:

  /* 获取霍尔传感器引脚状态,作为换相的依据 */uint8_t step = 0;step = get_hall_state();

然后先获取电机转动方向,你想让电机正转还是反转。因为正转的反转对应打开的上下桥臂是不一样的!按照这个表来写。

比如,正传,霍尔值=5 101 此时U+ V-

使用高级定时器互补输出的功能,采用PWM调节方法里的H_PWM – L_ON模式:

case 5:     /* U+  V -*/
__HAL_TIM_SET_COMPARE(&htimx_bldcm, TIM_CHANNEL_3, 0);                            // 通道 3 配置为 0
HAL_GPIO_WritePin(MOTOR_OCNPWM3_GPIO_PORT, MOTOR_OCNPWM3_PIN, GPIO_PIN_RESET);    // 关闭下桥臂__HAL_TIM_SET_COMPARE(&htimx_bldcm, TIM_CHANNEL_2, 0);                            // 通道 1 配置为 0
HAL_GPIO_WritePin(MOTOR_OCNPWM1_GPIO_PORT, MOTOR_OCNPWM1_PIN, GPIO_PIN_RESET);    // 关闭下桥臂__HAL_TIM_SET_COMPARE(&htimx_bldcm, TIM_CHANNEL_1, bldcm_pulse);                  // 通道 1 配置的占空比
HAL_GPIO_WritePin(MOTOR_OCNPWM2_GPIO_PORT, MOTOR_OCNPWM2_PIN, GPIO_PIN_SET);      // 开启下桥臂
break;

V和W的上桥臂,其实这时候也开着,只不过占空比为零;

U和W的下桥臂是关闭状态。

相关内容