对于无刷电机(bldc)驱动方式,主要有正弦波驱动与方波驱动,也就是六步换相法与FOC,在这里我们先讲六步换相。(文末附上相关代码)
以下是内转子式bldc简图:
可以知道,控制电机旋转,我们只需要在意对bldc三个定子线圈交替通电,而六步换相法在这里,主要是两两导通,根据对应的导通顺序,即可控制电机正转与反转。
(实际上,还有三三导通与二三导通,FOC就是三三导通,这个链接有关于这方面的科普)
无刷电机换相-六步换向-两两导通与三三导通-CSDN博客
依图,似乎可以推断,我们只需要按照图示换相的方式,交替向其中输入电平,似乎就可以达成换相,理论上确实使这样,但实际上,直接通入电流,会导致电机转速会骤升,加大丢步等问题发生的可能性,不利于控制。所以我们一般使用PWM波驱动电机,能够有效提升操作性
我们通过逆变器,再根据方式选择控制bldc。主要有无感控制(利用反电动势过零检测)与有感检测。以下内容主要讲用H_PWM – L_ON(上桥臂pwm控制、下桥臂高低电平直接控制,电机转速主要取决于上桥臂PWM的占空比)的有感控制。
对于电机旋转时,我们必须要知道转子的位置,才能对电机进行对应的定子通断电,因此有感控制特意使用霍尔传感器作为位置检测。
上图主要针对极对数为1进行分析。
电角度 = 机械角度 * 极对数
这是一个重要的公式,后续测速也要根据它来理解。
通过不同的霍尔信号,我们也就得到了霍尔与绕组得电情况的真值表,这也就是六步换相顺序表,值得一提,它通用于不同极对数的bldc。
对于不同极对数的bldc,我们可以这么理解:
极对数多的电机霍尔传感器读值会更多,会在相同转速下更快地达到下一个换向状态,因为电机的极对数越多,电机的步进角(即转子每换向一次所需的电角度)就越小。这意味着对于极对数较多的电机,换向的频率会更高,电机的控制需要更加精细和快速响应。
值得注意,霍尔传感器的布置角度除了120度,还有60度。
到这里,我们也就知道了使用六步换相法控制bldc,只需要通过三相逆变电路切换极性,通过控制上桥臂PWM占空比来进行调速,并且通过位置传感器检测当前转子位置,控制线圈按照真值表顺序通电。
以下附上相关代码:
#include "bldc.h"
_bldc_obj g_bldc_motor1 = {STOP,0,0,CCW,0,0,0,0,0,0}; /* 电机结构体 */
_bldc_obj g_bldc_motor2 = {STOP,0,0,CCW,0,0,0,0,0,0}; /* 电机结构体 */
const u8 hall_table_cw[6] = {6,2,3,1,5,4}; /* 顺时针旋转表 */
const u8 hall_table_ccw[6] = {5,1,3,2,6,4}; /* 逆时针旋转表 */
const u8 hall_cw_table[12] = {0x62,0x23,0x31,0x15,0x54,0x46,0x63,0x21,0x35,0x14,0x56,0x42};
const u8 hall_ccw_table[12] = {0x45,0x51,0x13,0x32,0x26,0x64,0x41,0x53,0x12,0x36,0x24,0x65};
/**
* @brief BLDC控制函数
* @param dir :电机方向, Duty:PWM占空比
* @retval 无
*/
void bldc_ctrl(u8 motor_id,int32_t dir,float duty)
{
if(motor_id == MOTOR_1)
{
g_bldc_motor1.dir = dir; /* 方向 */
g_bldc_motor1.pwm_duty = duty; /* 占空比 */
}
if(motor_id == MOTOR_2)
{
g_bldc_motor2.dir = dir; /* 方向 */
g_bldc_motor2.pwm_duty = duty; /* 占空比 */
}
}
/**
* @brief BLDC初始化函数
* @param 无
* @retval 无
*/
void bldc_init(void)
{
/* 开启定时器通道1输出PWM */
HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_1);
HAL_TIM_PWM_Start(&htim8,TIM_CHANNEL_1);
/* 开启定时器通道2输出PWM */
HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_2);
HAL_TIM_PWM_Start(&htim8,TIM_CHANNEL_2);
/* 开启定时器通道3输出PWM */
HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_3);
HAL_TIM_PWM_Start(&htim8,TIM_CHANNEL_3);
// HAL_TIM_Base_Start_IT(&htim1);
// HAL_TIM_Base_Start_IT(&htim8);
bldc_ctrl(MOTOR_1,CCW,0); /* 初始无刷电机接口1速度 */
bldc_ctrl(MOTOR_2,CCW,0); /* 初始无刷电机接口2速度 */
}
/**
* @brief 方向检测函数
* @param obj : 电机控制句柄
* @retval res : 旋转方向
*/
u8 check_hall_dir(_bldc_obj * obj)
{
u8 temp,res = HALL_ERROR;
if((obj->step_last <= 6)&&(obj->step_sta <= 6))
{
temp = ((obj->step_last & 0x0F) << 4)|(obj->step_sta & 0x0F);
if((temp == hall_ccw_table[0])||(temp == hall_ccw_table[1])||\
(temp == hall_ccw_table[2])||(temp == hall_ccw_table[3])||\
(temp == hall_ccw_table[4])||(temp == hall_ccw_table[5]))
{
res = CCW;
}
else if((temp == hall_cw_table[0])||(temp == hall_cw_table[1])||\
(temp == hall_cw_table[2])||(temp == hall_cw_table[3])||\
(temp == hall_cw_table[4])||(temp == hall_cw_table[5]))
{
res = CW;
}
}
return res;
}
/**************************************** 霍尔接口初始化 *************************************************/
/**
* @brief 获取霍尔传感器引脚状态
* @param motor_id :无刷接口编号
* @retval 霍尔传感器引脚状态
*/
u32 hallsensor_get_state(u8 motor_id)
{
__IO static u32 state;
state = 0;
if(motor_id == MOTOR_1)
{
if(HAL_GPIO_ReadPin(HALL1_TIM_CH1_GPIO,HALL1_TIM_CH1_PIN) != GPIO_PIN_RESET) /* 霍尔传感器状态获取 */
{
state |= 0x01U;
}
if(HAL_GPIO_ReadPin(HALL1_TIM_CH2_GPIO,HALL1_TIM_CH2_PIN) != GPIO_PIN_RESET) /* 霍尔传感器状态获取 */
{
state |= 0x02U;
}
if(HAL_GPIO_ReadPin(HALL1_TIM_CH3_GPIO,HALL1_TIM_CH3_PIN) != GPIO_PIN_RESET) /* 霍尔传感器状态获取 */
{
state |= 0x04U;
g_bldc_motor1.hall_single_sta = 1; //检测单次霍尔电平信号,做速度计算
}
else g_bldc_motor1.hall_single_sta = 0;
}
else if(motor_id == MOTOR_2)
{
if(HAL_GPIO_ReadPin(HALL2_TIM_CH1_GPIO,HALL2_TIM_CH1_PIN) != GPIO_PIN_RESET) /* 霍尔传感器状态获取 */
{
state |= 0x01U;
}
if(HAL_GPIO_ReadPin(HALL2_TIM_CH2_GPIO,HALL2_TIM_CH2_PIN) != GPIO_PIN_RESET) /* 霍尔传感器状态获取 */
{
state |= 0x02U;
}
if(HAL_GPIO_ReadPin(HALL2_TIM_CH3_GPIO,HALL2_TIM_CH3_PIN) != GPIO_PIN_RESET) /* 霍尔传感器状态获取 */
{
state |= 0x04U;
}
}
return state;
}
/************************************* BLDC相关函数 *************************************/
/**
* @brief 关闭电机运转
* @param 无
* @retval 无
*/
void stop_motor1(void)
{
/* 关闭半桥芯片输出 */
SHUTDOWN_OFF;
/* 关闭PWM输出 */
HAL_TIM_PWM_Stop(&htim1,TIM_CHANNEL_1);
HAL_TIM_PWM_Stop(&htim1,TIM_CHANNEL_2);
HAL_TIM_PWM_Stop(&htim1,TIM_CHANNEL_3);
/* 上下桥臂全部关断 */
htim1.Instance->CCR2 = 0;
htim1.Instance->CCR1 = 0;
htim1.Instance->CCR3 = 0;
HAL_GPIO_WritePin(M1_LOW_SIDE_U_PORT,M1_LOW_SIDE_U_PIN,GPIO_PIN_RESET);
HAL_GPIO_WritePin(M1_LOW_SIDE_V_PORT,M1_LOW_SIDE_V_PIN,GPIO_PIN_RESET);
HAL_GPIO_WritePin(M1_LOW_SIDE_W_PORT,M1_LOW_SIDE_W_PIN,GPIO_PIN_RESET);
}
/* 开启电机运转 */
void start_motor1(void)
{
SHUTDOWN_EN;
/* 使能PWM输出 */
HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_1);
HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_2);
HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_3);
}
/*************************** 上下桥臂的导通情况,共6种,也称为6步换向(接口一) ****************************/
/* 六步换向函数指针 */
pctr pfunclist_m1[6] =
{
&m1_uhwl, &m1_vhul, &m1_vhwl,
&m1_whvl, &m1_uhvl, &m1_whul
};
/* 上下桥臂的导通情况,共6种,也称为6步换向 */
void m1_uhvl(void)
{
htim1.Instance->CCR2 = 0;
htim1.Instance->CCR1 = g_bldc_motor1.pwm_duty; /* U相上桥臂PWM */
htim1.Instance->CCR3 = 0;
HAL_GPIO_WritePin(M1_LOW_SIDE_V_PORT,M1_LOW_SIDE_V_PIN,GPIO_PIN_SET); /* V相下桥臂导通 */
HAL_GPIO_WritePin(M1_LOW_SIDE_U_PORT,M1_LOW_SIDE_U_PIN,GPIO_PIN_RESET); /* U相下桥臂关闭 */
HAL_GPIO_WritePin(M1_LOW_SIDE_W_PORT,M1_LOW_SIDE_W_PIN,GPIO_PIN_RESET); /* W相下桥臂关闭 */
}
void m1_uhwl(void)
{
htim1.Instance->CCR2 = 0;
htim1.Instance->CCR1 = g_bldc_motor1.pwm_duty;
htim1.Instance->CCR3 = 0;
HAL_GPIO_WritePin(M1_LOW_SIDE_W_PORT,M1_LOW_SIDE_W_PIN,GPIO_PIN_SET);
HAL_GPIO_WritePin(M1_LOW_SIDE_U_PORT,M1_LOW_SIDE_U_PIN,GPIO_PIN_RESET);
HAL_GPIO_WritePin(M1_LOW_SIDE_V_PORT,M1_LOW_SIDE_V_PIN,GPIO_PIN_RESET);
}
void m1_vhwl(void)
{
htim1.Instance->CCR1=0;
htim1.Instance->CCR2 = g_bldc_motor1.pwm_duty;
htim1.Instance->CCR3=0;
HAL_GPIO_WritePin(M1_LOW_SIDE_W_PORT,M1_LOW_SIDE_W_PIN,GPIO_PIN_SET);
HAL_GPIO_WritePin(M1_LOW_SIDE_U_PORT,M1_LOW_SIDE_U_PIN,GPIO_PIN_RESET);
HAL_GPIO_WritePin(M1_LOW_SIDE_V_PORT,M1_LOW_SIDE_V_PIN,GPIO_PIN_RESET);
}
void m1_vhul(void)
{
htim1.Instance->CCR1 = 0;
htim1.Instance->CCR2 = g_bldc_motor1.pwm_duty;
htim1.Instance->CCR3 = 0;
HAL_GPIO_WritePin(M1_LOW_SIDE_U_PORT,M1_LOW_SIDE_U_PIN,GPIO_PIN_SET);
HAL_GPIO_WritePin(M1_LOW_SIDE_V_PORT,M1_LOW_SIDE_V_PIN,GPIO_PIN_RESET);
HAL_GPIO_WritePin(M1_LOW_SIDE_W_PORT,M1_LOW_SIDE_W_PIN,GPIO_PIN_RESET);
}
void m1_whul(void)
{
htim1.Instance->CCR2 = 0;
htim1.Instance->CCR3 = g_bldc_motor1.pwm_duty;
htim1.Instance->CCR1 = 0;
HAL_GPIO_WritePin(M1_LOW_SIDE_U_PORT,M1_LOW_SIDE_U_PIN,GPIO_PIN_SET);
HAL_GPIO_WritePin(M1_LOW_SIDE_V_PORT,M1_LOW_SIDE_V_PIN,GPIO_PIN_RESET);
HAL_GPIO_WritePin(M1_LOW_SIDE_W_PORT,M1_LOW_SIDE_W_PIN,GPIO_PIN_RESET);
}
void m1_whvl(void)
{
htim1.Instance->CCR2 = 0;
htim1.Instance->CCR3 = g_bldc_motor1.pwm_duty;
htim1.Instance->CCR1 = 0;
HAL_GPIO_WritePin(M1_LOW_SIDE_V_PORT,M1_LOW_SIDE_V_PIN,GPIO_PIN_SET);
HAL_GPIO_WritePin(M1_LOW_SIDE_U_PORT,M1_LOW_SIDE_U_PIN,GPIO_PIN_RESET);
HAL_GPIO_WritePin(M1_LOW_SIDE_W_PORT,M1_LOW_SIDE_W_PIN,GPIO_PIN_RESET);
}
/*************************** 上下桥臂的导通情况,共6种,也称为6步换向(接口二) ****************************/
pctr pfunclist_m2[6] =
{
&m2_uhwl, &m2_vhul, &m2_vhwl,
&m2_whvl, &m2_uhvl, &m2_whul
};
void stop_motor2(void)
{
SHUTDOWN2_OFF;
HAL_TIM_PWM_Stop(&htim8,TIM_CHANNEL_1);
HAL_TIM_PWM_Stop(&htim8,TIM_CHANNEL_2);
HAL_TIM_PWM_Stop(&htim8,TIM_CHANNEL_3);
HAL_GPIO_WritePin(M2_LOW_SIDE_U_PORT,M2_LOW_SIDE_U_PIN,GPIO_PIN_RESET);
HAL_GPIO_WritePin(M2_LOW_SIDE_V_PORT,M2_LOW_SIDE_V_PIN,GPIO_PIN_RESET);
HAL_GPIO_WritePin(M2_LOW_SIDE_W_PORT,M2_LOW_SIDE_W_PIN,GPIO_PIN_RESET);
}
void start_motor2(void)
{
SHUTDOWN2_EN;
HAL_TIM_PWM_Start(&htim8,TIM_CHANNEL_1);
HAL_TIM_PWM_Start(&htim8,TIM_CHANNEL_2);
HAL_TIM_PWM_Start(&htim8,TIM_CHANNEL_3);
}
void m2_uhvl(void)
{
htim8.Instance->CCR2 = 0;
htim8.Instance->CCR1 = g_bldc_motor2.pwm_duty;/*U相上桥臂PWM*/
htim8.Instance->CCR3 = 0;
HAL_GPIO_WritePin(M2_LOW_SIDE_V_PORT,M2_LOW_SIDE_V_PIN,GPIO_PIN_SET);/*V相下桥臂导通*/
HAL_GPIO_WritePin(M2_LOW_SIDE_U_PORT,M2_LOW_SIDE_U_PIN,GPIO_PIN_RESET);/*U相下桥臂关闭*/
HAL_GPIO_WritePin(M2_LOW_SIDE_W_PORT,M2_LOW_SIDE_W_PIN,GPIO_PIN_RESET);/*W相下桥臂关闭*/
}
void m2_uhwl(void)
{
htim8.Instance->CCR2 = 0;
htim8.Instance->CCR1 = g_bldc_motor2.pwm_duty;
htim8.Instance->CCR3 = 0;
HAL_GPIO_WritePin(M2_LOW_SIDE_W_PORT,M2_LOW_SIDE_W_PIN,GPIO_PIN_SET);
HAL_GPIO_WritePin(M2_LOW_SIDE_U_PORT,M2_LOW_SIDE_U_PIN,GPIO_PIN_RESET);
HAL_GPIO_WritePin(M2_LOW_SIDE_V_PORT,M2_LOW_SIDE_V_PIN,GPIO_PIN_RESET);
}
void m2_vhwl(void)
{
htim8.Instance->CCR1=0;
htim8.Instance->CCR2 = g_bldc_motor2.pwm_duty;
htim8.Instance->CCR3=0;
HAL_GPIO_WritePin(M2_LOW_SIDE_W_PORT,M2_LOW_SIDE_W_PIN,GPIO_PIN_SET);
HAL_GPIO_WritePin(M2_LOW_SIDE_U_PORT,M2_LOW_SIDE_U_PIN,GPIO_PIN_RESET);
HAL_GPIO_WritePin(M2_LOW_SIDE_V_PORT,M2_LOW_SIDE_V_PIN,GPIO_PIN_RESET);
}
void m2_vhul(void)
{
htim8.Instance->CCR1 = 0;
htim8.Instance->CCR2 = g_bldc_motor2.pwm_duty;
htim8.Instance->CCR3 = 0;
HAL_GPIO_WritePin(M2_LOW_SIDE_U_PORT,M2_LOW_SIDE_U_PIN,GPIO_PIN_SET);
HAL_GPIO_WritePin(M2_LOW_SIDE_V_PORT,M2_LOW_SIDE_V_PIN,GPIO_PIN_RESET);
HAL_GPIO_WritePin(M2_LOW_SIDE_W_PORT,M2_LOW_SIDE_W_PIN,GPIO_PIN_RESET);
}
void m2_whul(void)
{
htim8.Instance->CCR2 = 0;
htim8.Instance->CCR3 = g_bldc_motor2.pwm_duty;
htim8.Instance->CCR1 = 0;
HAL_GPIO_WritePin(M2_LOW_SIDE_U_PORT,M2_LOW_SIDE_U_PIN,GPIO_PIN_SET);
HAL_GPIO_WritePin(M2_LOW_SIDE_V_PORT,M2_LOW_SIDE_V_PIN,GPIO_PIN_RESET);
HAL_GPIO_WritePin(M2_LOW_SIDE_W_PORT,M2_LOW_SIDE_W_PIN,GPIO_PIN_RESET);
}
void m2_whvl(void)
{
htim8.Instance->CCR2 = 0;
htim8.Instance->CCR3 = g_bldc_motor2.pwm_duty;
htim8.Instance->CCR1 = 0;
HAL_GPIO_WritePin(M2_LOW_SIDE_V_PORT,M2_LOW_SIDE_V_PIN,GPIO_PIN_SET);
HAL_GPIO_WritePin(M2_LOW_SIDE_U_PORT,M2_LOW_SIDE_U_PIN,GPIO_PIN_RESET);
HAL_GPIO_WritePin(M2_LOW_SIDE_W_PORT,M2_LOW_SIDE_W_PIN,GPIO_PIN_RESET);
}
/******************************************************************************************/
/**
* @brief 检测输入信号是否发生变化
* @param val :输入信号
* @note 测量速度使用,获取输入信号状态翻转情况,计算速度
* @retval 0:计算高电平时间,1:计算低电平时间,2:信号未改变
*/
u8 uemf_edge(u8 val)
{
static u8 old_val;
if(old_val != val)
{
old_val = val;
if(val == 1) return 0; //上升沿
else return 1; //下降沿
}
return 2;
}
/**
* @brief 清除电机状态并关闭电机
* @param 无
* @retval 无
*/
void m1_bldc_speed_stop(void)
{
// pid_init(); /* 重新初始化PID,防止积分过大失控 */
g_bldc_motor1.run_flag = STOP; /* 标记停机 */
stop_motor1(); /* 停机 */
g_bldc_motor1.speed = 0;
// motor_pwm_s = 0;
g_bldc_motor1.pwm_duty = 0;
}
/**
* @brief 清除电机状态并关闭电机
* @param 无
* @retval 无
*/
void m2_bldc_speed_stop(void)
{
// pid_init(); /* 重新初始化PID,防止积分过大失控 */
g_bldc_motor2.run_flag = STOP; /* 标记停机 */
stop_motor2(); /* 停机 */
g_bldc_motor2.speed = 0;
// motor_pwm_s = 0;
g_bldc_motor2.pwm_duty = 0;
}
#ifndef _bldc_h
#define _bldc_h
#include "headerfile.h"
#include "main.h"
/******************************************************************************************/
typedef struct {
__IO u8 run_flag; /* 运行标志 */
__IO u8 locked_rotor; /* 堵转标记 */
__IO u8 step_sta; /* 本次霍尔状态 */
__IO u8 hall_single_sta;/* 单个霍尔状态 */
__IO u8 hall_sta_edge; /* 单个霍尔状态跳变 */
__IO u8 step_last; /* 上次霍尔状态 */
__IO u8 dir; /* 电机旋转方向 */
__IO int32_t pos; /* 电机位置 */
__IO int32_t speed; /* 电机速度 */
__IO int16_t current; /* 电机速度 */
__IO u16 pwm_duty; /* 电机占空比 */
__IO u32 hall_keep_t; /* 霍尔保持时间 */
__IO u32 hall_pul_num; /* 霍尔传感器脉冲数 */
__IO u32 lock_time; /* 电机堵转时间 */
__IO u32 hall_no_single_time; /* 电机没有换相的时间,(霍尔信号没有发生改变)即电机停止的时间 */
__IO u32 count_tim; /* 计算速度专用计数值,用于计算霍尔信号高电平或者低电平的时间 */
} _bldc_obj;
/******************************************************************************************/
#define MOTOR_1 1
#define MOTOR_2 2
extern _bldc_obj g_bldc_motor1;
extern _bldc_obj g_bldc_motor2;
/********************************************************************************************/
/*刹车引脚*/
#define SHUTDOWN_PIN GPIO_PIN_10
#define SHUTDOWN_PIN_GPIO GPIOF
#define SHUTDOWN_PIN_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOF_CLK_ENABLE(); }while(0) /* PF口时钟使能 */
#define SHUTDOWN2_PIN GPIO_PIN_2
#define SHUTDOWN2_PIN_GPIO GPIOF
#define SHUTDOWN2_PIN_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOF_CLK_ENABLE(); }while(0) /* PF口时钟使能 */
#define SHUTDOWN_EN HAL_GPIO_WritePin(SHUTDOWN_PIN_GPIO,SHUTDOWN_PIN,GPIO_PIN_SET);
#define SHUTDOWN_OFF HAL_GPIO_WritePin(SHUTDOWN_PIN_GPIO,SHUTDOWN_PIN,GPIO_PIN_RESET);
#define SHUTDOWN2_EN HAL_GPIO_WritePin(SHUTDOWN2_PIN_GPIO,SHUTDOWN2_PIN,GPIO_PIN_SET);
#define SHUTDOWN2_OFF HAL_GPIO_WritePin(SHUTDOWN2_PIN_GPIO,SHUTDOWN2_PIN,GPIO_PIN_RESET);
/******************************************************************************************/
/*霍尔传感器接口*/
#define HALL1_TIM_CH1_PIN GPIO_PIN_10 /* U */
#define HALL1_TIM_CH1_GPIO GPIOH
#define HALL1_U_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOH_CLK_ENABLE(); }while(0) /* PH口时钟使能 */
#define HALL1_TIM_CH2_PIN GPIO_PIN_11 /* V */
#define HALL1_TIM_CH2_GPIO GPIOH
#define HALL1_V_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOH_CLK_ENABLE(); }while(0) /* PH口时钟使能 */
#define HALL1_TIM_CH3_PIN GPIO_PIN_12 /* W */
#define HALL1_TIM_CH3_GPIO GPIOH
#define HALL1_W_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOH_CLK_ENABLE(); }while(0) /* PH口时钟使能 */
#define HALL2_TIM_CH1_PIN GPIO_PIN_12 /* U */
#define HALL2_TIM_CH1_GPIO GPIOD
#define HALL2_U_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOD_CLK_ENABLE(); }while(0) /* PD口时钟使能 */
#define HALL2_TIM_CH2_PIN GPIO_PIN_13 /* V */
#define HALL2_TIM_CH2_GPIO GPIOD
#define HALL2_V_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOD_CLK_ENABLE(); }while(0) /* PD口时钟使能 */
#define HALL2_TIM_CH3_PIN GPIO_PIN_8 /* W */
#define HALL2_TIM_CH3_GPIO GPIOB
#define HALL2_W_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOB_CLK_ENABLE(); }while(0) /* PB口时钟使能 */
/********************************************************************************************/
#define MAX_PWM_DUTY (((10000) - 1)*0.96) //定时器arr = 10000
#define H_PWM_L_ON
#ifndef H_PWM_L_ON
#define H_PWM_L_PWM
#endif
#define CCW (1) /* 逆时针 */
#define CW (2) /* 顺时针 */
#define HALL_ERROR (0xF0) /* 霍尔错误标志 */
#define RUN (1) /* 电机运动标志 */
#define STOP (0) /* 电机停机标志 */
#define Ft 84000000/84/1000 //使用tim7定时中断1ms
#define pole_pairs 10 //极对数
#define SPEED_COEFF (u32)((Ft/pole_pairs)*60) /* 旋转一圈变化4个信号,2对级永磁体特性,NSNS共4级数*/
typedef void(*pctr) (void);
void stop_motor1(void); /* 停机 */
void start_motor1(void); /* 启动电机 */
void stop_motor2(void);
void start_motor2(void);
void m1_bldc_speed_stop(void);
void m2_bldc_speed_stop(void);
/******************************************************************************************/
/* 外部接口函数*/
void bldc_init(void); /* BLDC初始化 */
u8 check_hall_dir(_bldc_obj * obj); /* 检测电机旋转方向 */
u32 hallsensor_get_state(u8 motor_id); /* 获取霍尔状态 */
extern pctr pfunclist_m1[6]; /* 六步换相函数指针数组 */
void bldc_ctrl(u8 motor_id,int32_t dir,float duty);/* bldc控制函数 */
extern pctr pfunclist_m2[6]; /* 六步换相函数指针数组 */
u8 uemf_edge(u8 val); //计算速度使用,判断霍尔信号是上升沿还是下降沿
/* 六步换相 */
void m1_uhvl(void);
void m1_uhwl(void);
void m1_vhwl(void);
void m1_vhul(void);
void m1_whul(void);
void m1_whvl(void);
void m2_uhvl(void);
void m2_uhwl(void);
void m2_vhwl(void);
void m2_vhul(void);
void m2_whul(void);
void m2_whvl(void);
/*******************************************TIM1初始化宏**************************************************************/
#define ATIM_TIMX_PWM_CH1_GPIO_PORT GPIOA
#define ATIM_TIMX_PWM_CH1_GPIO_PIN GPIO_PIN_8
#define ATIM_TIMX_PWM_CH1_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOA_CLK_ENABLE(); }while(0) /* PA口时钟使能 */
#define ATIM_TIMX_PWM_CH2_GPIO_PORT GPIOA
#define ATIM_TIMX_PWM_CH2_GPIO_PIN GPIO_PIN_9
#define ATIM_TIMX_PWM_CH2_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOA_CLK_ENABLE(); }while(0) /* PA口时钟使能 */
#define ATIM_TIMX_PWM_CH3_GPIO_PORT GPIOA
#define ATIM_TIMX_PWM_CH3_GPIO_PIN GPIO_PIN_10
#define ATIM_TIMX_PWM_CH3_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOA_CLK_ENABLE(); }while(0) /* PA口时钟使能 */
/* 互补通道IO */
#define M1_LOW_SIDE_U_PORT GPIOB
#define M1_LOW_SIDE_U_PIN GPIO_PIN_13
#define M1_LOW_SIDE_U_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOB_CLK_ENABLE(); }while(0) /* PB口时钟使能 */
#define M1_LOW_SIDE_V_PORT GPIOB
#define M1_LOW_SIDE_V_PIN GPIO_PIN_14
#define M1_LOW_SIDE_V_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOB_CLK_ENABLE(); }while(0) /* PB口时钟使能 */
#define M1_LOW_SIDE_W_PORT GPIOB
#define M1_LOW_SIDE_W_PIN GPIO_PIN_15
#define M1_LOW_SIDE_W_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOB_CLK_ENABLE(); }while(0) /* PB口时钟使能 */
/*******************************************TIM8初始化宏**************************************************************/
#define ATIM_TIMX2_PWM_CH1_GPIO_PORT GPIOI
#define ATIM_TIMX2_PWM_CH1_GPIO_PIN GPIO_PIN_5
#define ATIM_TIMX2_PWM_CH1_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOI_CLK_ENABLE(); }while(0) /* PI口时钟使能 */
#define ATIM_TIMX2_PWM_CH2_GPIO_PORT GPIOI
#define ATIM_TIMX2_PWM_CH2_GPIO_PIN GPIO_PIN_6
#define ATIM_TIMX2_PWM_CH2_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOI_CLK_ENABLE(); }while(0) /* PI口时钟使能 */
#define ATIM_TIMX2_PWM_CH3_GPIO_PORT GPIOI
#define ATIM_TIMX2_PWM_CH3_GPIO_PIN GPIO_PIN_7
#define ATIM_TIMX2_PWM_CH3_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOI_CLK_ENABLE(); }while(0) /* PI口时钟使能 */
/* 互补通道IO */
#define M2_LOW_SIDE_U_PORT GPIOH
#define M2_LOW_SIDE_U_PIN GPIO_PIN_13
#define M2_LOW_SIDE_U_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOH_CLK_ENABLE(); }while(0) /* PH口时钟使能 */
#define M2_LOW_SIDE_V_PORT GPIOH
#define M2_LOW_SIDE_V_PIN GPIO_PIN_14
#define M2_LOW_SIDE_V_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOH_CLK_ENABLE(); }while(0) /* PH口时钟使能 */
#define M2_LOW_SIDE_W_PORT GPIOH
#define M2_LOW_SIDE_W_PIN GPIO_PIN_15
#define M2_LOW_SIDE_W_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOH_CLK_ENABLE(); }while(0) /* PH口时钟使能 */
#define ATIM_TIMX_PWM_CHY_GPIO_AF GPIO_AF1_TIM1
#define ATIM_TIMX_PWM TIM1
#define ATIM_TIMX_PWM_IRQn TIM1_UP_TIM10_IRQn
#define ATIM_TIMX_PWM_IRQHandler TIM1_UP_TIM10_IRQHandler
#define ATIM_TIMX_PWM_CH1 TIM_CHANNEL_1 /* 通道1 */
#define ATIM_TIMX_PWM_CH2 TIM_CHANNEL_2 /* 通道2 */
#define ATIM_TIMX_PWM_CH3 TIM_CHANNEL_3 /* 通道3 */
#define ATIM_TIMX_PWM_CHY_CLK_ENABLE() do{ __HAL_RCC_TIM1_CLK_ENABLE(); }while(0) /* TIM1 时钟使能 */
#define ATIM_TIMX2_PWM_CHY_GPIO_AF GPIO_AF3_TIM8
#define ATIM_TIMX2_PWM TIM8
#define ATIM_TIMX2_PWM_IRQn TIM8_UP_TIM13_IRQn
#define ATIM_TIMX2_PWM_IRQHandler TIM8_UP_TIM13_IRQHandler
#define ATIM_TIMX2_PWM_CH1 TIM_CHANNEL_1 /* 通道1 */
#define ATIM_TIMX2_PWM_CH2 TIM_CHANNEL_2 /* 通道2 */
#define ATIM_TIMX2_PWM_CH3 TIM_CHANNEL_3 /* 通道3 */
#define ATIM_TIMX2_PWM_CHY_CLK_ENABLE() do{ __HAL_RCC_TIM8_CLK_ENABLE(); }while(0) /* TIM8 时钟使能 */
/******************************************************************************************/
#endif
/******************************* 六步换向 *******************************/
if(g_bldc_motor1.dir == CW)
{
g_bldc_motor1.step_sta = hallsensor_get_state(MOTOR_1);
}
else
{
g_bldc_motor1.step_sta = 7 - hallsensor_get_state(MOTOR_1);
}
if((g_bldc_motor1.step_sta <= 6)&&(g_bldc_motor1.step_sta >= 1))/* 判断霍尔组合值是否正常 */
{
pfunclist_m1[g_bldc_motor1.step_sta-1]();
}
else /* 编码器错误、接触不良、断开等情况 */
{
stop_motor1();
g_bldc_motor1.run_flag = STOP;
}
/******************************* 速度计算 *******************************/
g_bldc_motor1.count_tim++; /* 计算速度专用计数值,也就是"C",计算定时器计数次数 */
g_bldc_motor1.hall_sta_edge = uemf_edge(g_bldc_motor1.hall_single_sta); //输入第三个霍尔信号的电平状态
if(g_bldc_motor1.hall_sta_edge == 0) //上升沿
{
/*计算速度*/
if(g_bldc_motor1.dir == CW)//顺时针旋转
{
temp_speed = (SPEED_COEFF / g_bldc_motor1.count_tim);
}
else
{
temp_speed = -(SPEED_COEFF / g_bldc_motor1.count_tim);
}
FirstOrderRC_LPF(g_bldc_motor1.speed,temp_speed,0.2379f); /* 一阶滤波 */
g_bldc_motor1.hall_no_single_time = 0;
g_bldc_motor1.count_tim = 0;
}
if(g_bldc_motor1.hall_sta_edge == 1) //下降沿
{
g_bldc_motor1.hall_no_single_time = 0;
g_bldc_motor1.count_tim = 0;
}
if(g_bldc_motor1.hall_sta_edge == 2) //电平无变化,即电机停止工作
{
g_bldc_motor1.hall_no_single_time++; /* 不换相时间累计 超时则判定速度为0 */
if(g_bldc_motor1.hall_no_single_time > 800) //800ms
{
g_bldc_motor1.hall_no_single_time = 0;
g_bldc_motor1.speed = 0; /* 超时换向 判定为停止 速度为0 */
}
}
/******************************* 位置记录 *******************************/
if(g_bldc_motor1.step_last != g_bldc_motor1.step_sta) /* 霍尔状态发生改变,代表换向 */
{
g_bldc_motor1.hall_keep_t=0;
bldc_dir.dir1 = check_hall_dir(&g_bldc_motor1); /* 检测旋转方向,根据方向,进行位置计数 */
if(bldc_dir.dir1 == CCW)
{
g_bldc_motor1.pos -=1;
}
else if(bldc_dir.dir1 == CW)
{
g_bldc_motor1.pos +=1;
}
g_bldc_motor1.step_last = g_bldc_motor1.step_sta;
}