关于bldc的学习笔记(二)驱动原理-六步换相

对于无刷电机(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;
			}

无刷直流电机 无刷直流电机(或简称BLDC电机)是一种采用直流电源并通过外部电机控制器控制实现电子换向的电机。不同于有刷电机,BLDC电机依靠外部控制器来实现换向。简言之,换向就是切换电机各相中的电流以产生运动的过程。有刷电机是指具有物理电刷的电机,其每转一次可实现两次换向过程,而BLDC电机无电刷配备,因此而得名。由于其设计特性,无刷电机能够实现任意数量的换向磁极对。   与传统有刷电机相比,BLDC电机具有极大的优势。这种电机的效率通常可提高15-20%;没有电刷物理磨损,因而能减少维护;无论在什么额定速度下都可以获得平坦的转矩曲线。虽然BLDC电机并不是新发明,但由于需要复杂控制和反馈电路,所以广泛采用的进展较为缓慢。然而,由于近期半导体技术的发展、永磁体品质提升,以及对更高效率不断增长的需求,促使BLDC电机在大量应用中取代了有刷电机。BLDC电机在许多行业找到了市场定位,包括白色家电、汽车、航空航天、消费、医疗、工业化自动设备和仪器仪表等。   随着行业朝着需要在更多应用中使用BLDC电机的方向发展,许多工程师不得不将目光投向该技术。虽然电机设计的基础要素仍然适用,但添加外部控制电路也增加了另一系列需考虑的设计事项。在诸多设计问题中,最重要的一点是如何获取电机换向的反馈。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值