单片机 :STM32F407
开发板:DMF407电机开发板
平台:keil V5.31
HSE 为8MHZ
HSI为16MHZ
同时驱动2路BLDC电机:
主函数:
int main(void)
{
uint8_t key,t;
char buf[32];
int16_t pwm_duty_temp=0;
HAL_Init(); /* 初始化HAL库 */
sys_stm32_clock_init(336, 8, 2, 7); /* 设置时钟,168Mhz */
delay_init(168); /* 延时初始化 */
usart_init(115200); /* 串口初始化为115200 */
led_init(); /* 初始化LED */
key_init(); /* 初始化按键 */
lcd_init(); /* 初始化LCD */
bldc_init(10000-1,0);
bldc_ctrl(MOTOR_1,CCW,0); /* 初始无刷电机接口1速度 */
bldc_ctrl(MOTOR_2,CCW,0); /* 初始无刷电机接口2速度 */
g_point_color = WHITE;
g_back_color = BLACK;
lcd_show_string(10, 10, 200, 16, 16, "BLDC Motor Test",g_point_color);
lcd_show_string(10, 30, 200, 16, 16, "KEY0:Start forward", g_point_color);
lcd_show_string(10, 50, 200, 16, 16, "KEY1:Start backward", g_point_color);
lcd_show_string(10, 70, 200, 16, 16, "KEY2:Stop", g_point_color);
printf("按下KEY0 开始正转加速\r\n");
printf("按下KEY1 开始反转加速\r\n");
printf("按下KEY2 停止电机\r\n");
while (1)
{
t++;
if(t % 20 == 0)
{
sprintf(buf,"PWM_Duty:%.1f%%",(float)((g_bldc_motor1.pwm_duty/MAX_PWM_DUTY)*100));/* 显示控制PWM占空比 */
lcd_show_string(10,110,200,16,16,buf,g_point_color);
LED0_TOGGLE(); /* LED0(红灯) 翻转 */
}
key = key_scan(0);
if(key == KEY0_PRES) /* 按下KEY0占空比++ */
{
pwm_duty_temp += 500;
if(pwm_duty_temp >= MAX_PWM_DUTY/2)
pwm_duty_temp = MAX_PWM_DUTY/2;
if(pwm_duty_temp > 0)
{
g_bldc_motor1.pwm_duty = pwm_duty_temp;
g_bldc_motor1.dir = CW;
g_bldc_motor2.pwm_duty = pwm_duty_temp;
g_bldc_motor2.dir = CW;
}
else
{
g_bldc_motor1.pwm_duty = -pwm_duty_temp;
g_bldc_motor1.dir = CCW;
g_bldc_motor2.pwm_duty = -pwm_duty_temp;
g_bldc_motor2.dir = CCW;
}
g_bldc_motor1.run_flag = RUN;
start_motor1(); /* 开启运行 */
g_bldc_motor2.run_flag = RUN;
start_motor2();
}
else if(key == KEY1_PRES) /* 按下KEY1占空比-- */
{
pwm_duty_temp -= 500;
if(pwm_duty_temp <= -MAX_PWM_DUTY/2)
pwm_duty_temp = -MAX_PWM_DUTY/2;
if(pwm_duty_temp < 0)
{
g_bldc_motor1.pwm_duty = -pwm_duty_temp;
g_bldc_motor1.dir = CCW;
g_bldc_motor2.pwm_duty = -pwm_duty_temp;
g_bldc_motor2.dir = CCW;
}
else
{
g_bldc_motor1.pwm_duty = pwm_duty_temp;
g_bldc_motor1.dir = CW;
g_bldc_motor2.pwm_duty = pwm_duty_temp;
g_bldc_motor2.dir = CW;
}
g_bldc_motor1.run_flag = RUN; /* 开启运行 */
start_motor1(); /* 运行电机 */
g_bldc_motor2.run_flag = RUN; /* 开启运行 */
start_motor2(); /* 运行电机 */
}
else if(key == KEY2_PRES) /* 按下KEY2关闭电机 */
{
pwm_duty_temp = 0;
stop_motor1(); /* 停机 */
g_bldc_motor1.run_flag = STOP; /* 标记停机 */
g_bldc_motor1.pwm_duty = 0;
stop_motor2(); /* 停机 */
g_bldc_motor2.run_flag = STOP; /* 标记停机 */
g_bldc_motor2.pwm_duty = 0;
}
delay_ms(10);
}
}
电机:
/********************************************************************************************/
/*刹车引脚*/
#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)
#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) /* 电机停机标志 */
_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 uint8_t hall_table_cw[6] = {6,2,3,1,5,4}; /* 顺时针旋转表 */
const uint8_t hall_table_ccw[6] = {5,1,3,2,6,4}; /* 逆时针旋转表 */
const uint8_t hall_cw_table[12] = {0x62,0x23,0x31,0x15,0x54,0x46,0x63,0x21,0x35,0x14,0x56,0x42};
const uint8_t hall_ccw_table[12] = {0x45,0x51,0x13,0x32,0x26,0x64,0x41,0x53,0x12,0x36,0x24,0x65};
/**
* @brief 无刷电机初始化,包括定时器,编码器以及SD引脚初始化
* @param arr: 自动重装值
* @param psc: 时钟预分频数
* @retval 无
*/
void bldc_init(uint16_t arr, uint16_t psc)
{
GPIO_InitTypeDef gpio_init_struct;
SHUTDOWN_PIN_GPIO_CLK_ENABLE();
SHUTDOWN2_PIN_GPIO_CLK_ENABLE();
gpio_init_struct.Pin = SHUTDOWN_PIN;
gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP;
gpio_init_struct.Pull = GPIO_NOPULL;
gpio_init_struct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(SHUTDOWN_PIN_GPIO, &gpio_init_struct);
gpio_init_struct.Pin = SHUTDOWN2_PIN;
HAL_GPIO_Init(SHUTDOWN2_PIN_GPIO, &gpio_init_struct);
hall_gpio_init(); /* 霍尔接口初始化 */
atim_timx_oc_chy_init(arr, psc);
atim_timx2_oc_chy_init(arr, psc);
}
/**
* @brief BLDC控制函数
* @param dir :电机方向, Duty:PWM占空比
* @retval 无
*/
void bldc_ctrl(uint8_t 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 方向检测函数
* @param obj : 电机控制句柄
* @retval res : 旋转方向
*/
uint8_t check_hall_dir(_bldc_obj * obj)
{
uint8_t 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 无
* @retval 无
*/
void hall_gpio_init(void)
{
GPIO_InitTypeDef gpio_init_struct;
HALL1_U_GPIO_CLK_ENABLE();
HALL1_V_GPIO_CLK_ENABLE();
HALL1_W_GPIO_CLK_ENABLE();
HALL2_U_GPIO_CLK_ENABLE();
HALL2_V_GPIO_CLK_ENABLE();
HALL2_W_GPIO_CLK_ENABLE();
gpio_init_struct.Pin = HALL1_TIM_CH1_PIN;
gpio_init_struct.Mode = GPIO_MODE_INPUT;
gpio_init_struct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(HALL1_TIM_CH1_GPIO, &gpio_init_struct);
/* 定时器通道 2 引脚初始化 */
gpio_init_struct.Pin = HALL1_TIM_CH2_PIN;
HAL_GPIO_Init(HALL1_TIM_CH2_GPIO, &gpio_init_struct);
/* 定时器通道 3 引脚初始化 */
gpio_init_struct.Pin = HALL1_TIM_CH3_PIN;
HAL_GPIO_Init(HALL1_TIM_CH3_GPIO, &gpio_init_struct);
gpio_init_struct.Pin = HALL2_TIM_CH1_PIN;
gpio_init_struct.Mode = GPIO_MODE_INPUT;
gpio_init_struct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(HALL2_TIM_CH1_GPIO, &gpio_init_struct);
/* 定时器通道 2 引脚初始化 */
gpio_init_struct.Pin = HALL2_TIM_CH2_PIN;
HAL_GPIO_Init(HALL2_TIM_CH2_GPIO, &gpio_init_struct);
/* 定时器通道 3 引脚初始化 */
gpio_init_struct.Pin = HALL2_TIM_CH3_PIN;
HAL_GPIO_Init(HALL2_TIM_CH3_GPIO, &gpio_init_struct);
}
/**
* @brief 获取霍尔传感器引脚状态
* @param motor_id :无刷接口编号
* @retval 霍尔传感器引脚状态
*/
uint32_t hallsensor_get_state(uint8_t motor_id)
{
__IO static uint32_t 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;
}
}
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(&g_atimx_handle,TIM_CHANNEL_1);
HAL_TIM_PWM_Stop(&g_atimx_handle,TIM_CHANNEL_2);
HAL_TIM_PWM_Stop(&g_atimx_handle,TIM_CHANNEL_3);
/* 上下桥臂全部关断 */
g_atimx_handle.Instance->CCR2 = 0;
g_atimx_handle.Instance->CCR1 = 0;
g_atimx_handle.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(&g_atimx_handle,TIM_CHANNEL_1);
HAL_TIM_PWM_Start(&g_atimx_handle,TIM_CHANNEL_2);
HAL_TIM_PWM_Start(&g_atimx_handle,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)
{
g_atimx_handle.Instance->CCR2 = 0;
g_atimx_handle.Instance->CCR1 = g_bldc_motor1.pwm_duty; /* U相上桥臂PWM */
g_atimx_handle.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)
{
g_atimx_handle.Instance->CCR2 = 0;
g_atimx_handle.Instance->CCR1 = g_bldc_motor1.pwm_duty;
g_atimx_handle.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)
{
g_atimx_handle.Instance->CCR1=0;
g_atimx_handle.Instance->CCR2 = g_bldc_motor1.pwm_duty;
g_atimx_handle.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)
{
g_atimx_handle.Instance->CCR1 = 0;
g_atimx_handle.Instance->CCR2 = g_bldc_motor1.pwm_duty;
g_atimx_handle.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)
{
g_atimx_handle.Instance->CCR2 = 0;
g_atimx_handle.Instance->CCR3 = g_bldc_motor1.pwm_duty;
g_atimx_handle.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)
{
g_atimx_handle.Instance->CCR2 = 0;
g_atimx_handle.Instance->CCR3 = g_bldc_motor1.pwm_duty;
g_atimx_handle.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(&g_atimx2_handle,TIM_CHANNEL_1);
HAL_TIM_PWM_Stop(&g_atimx2_handle,TIM_CHANNEL_2);
HAL_TIM_PWM_Stop(&g_atimx2_handle,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(&g_atimx2_handle,TIM_CHANNEL_1);
HAL_TIM_PWM_Start(&g_atimx2_handle,TIM_CHANNEL_2);
HAL_TIM_PWM_Start(&g_atimx2_handle,TIM_CHANNEL_3);
}
void m2_uhvl(void)
{
g_atimx2_handle.Instance->CCR2 = 0;
g_atimx2_handle.Instance->CCR1 = g_bldc_motor2.pwm_duty;/*U相上桥臂PWM*/
g_atimx2_handle.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)
{
g_atimx2_handle.Instance->CCR2 = 0;
g_atimx2_handle.Instance->CCR1 = g_bldc_motor2.pwm_duty;
g_atimx2_handle.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)
{
g_atimx2_handle.Instance->CCR1=0;
g_atimx2_handle.Instance->CCR2 = g_bldc_motor2.pwm_duty;
g_atimx2_handle.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)
{
g_atimx2_handle.Instance->CCR1 = 0;
g_atimx2_handle.Instance->CCR2 = g_bldc_motor2.pwm_duty;
g_atimx2_handle.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)
{
g_atimx2_handle.Instance->CCR2 = 0;
g_atimx2_handle.Instance->CCR3 = g_bldc_motor2.pwm_duty;
g_atimx2_handle.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)
{
g_atimx2_handle.Instance->CCR2 = 0;
g_atimx2_handle.Instance->CCR3 = g_bldc_motor2.pwm_duty;
g_atimx2_handle.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);
}
定时器:
/* TIMX PWM 定义
* 默认使用的是TIM8_CH1.
* 注意: 通过修改这几个宏定义, 可以支持TIM1/TIM8定时器
*/
#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 时钟使能 */
void atim_timx_oc_chy_init(uint16_t arr, uint16_t psc)
{
ATIM_TIMX_PWM_CHY_CLK_ENABLE(); /* TIMX 时钟使能 */
g_atimx_handle.Instance = ATIM_TIMX_PWM; /* 定时器x */
g_atimx_handle.Init.Prescaler = psc; /* 定时器分频 */
g_atimx_handle.Init.CounterMode = TIM_COUNTERMODE_UP; /* 向上计数模式 */
g_atimx_handle.Init.Period = arr; /* 自动重装载值 */
g_atimx_handle.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1; /* 分频因子 */
g_atimx_handle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; /*使能TIMx_ARR进行缓冲*/
g_atimx_handle.Init.RepetitionCounter = 0; /* 开始时不计数*/
HAL_TIM_PWM_Init(&g_atimx_handle); /* 初始化PWM */
g_atimx_oc_chy_handle.OCMode = TIM_OCMODE_PWM1; /* 模式选择PWM1 */
g_atimx_oc_chy_handle.Pulse = 0;
g_atimx_oc_chy_handle.OCPolarity = TIM_OCPOLARITY_HIGH; /* 输出比较极性为高 */
g_atimx_oc_chy_handle.OCNPolarity = TIM_OCNPOLARITY_HIGH;
g_atimx_oc_chy_handle.OCFastMode = TIM_OCFAST_DISABLE;
g_atimx_oc_chy_handle.OCIdleState = TIM_OCIDLESTATE_RESET;
g_atimx_oc_chy_handle.OCNIdleState = TIM_OCNIDLESTATE_RESET;
HAL_TIM_PWM_ConfigChannel(&g_atimx_handle, &g_atimx_oc_chy_handle, ATIM_TIMX_PWM_CH1); /* 配置TIMx通道y */
HAL_TIM_PWM_ConfigChannel(&g_atimx_handle, &g_atimx_oc_chy_handle, ATIM_TIMX_PWM_CH2); /* 配置TIMx通道y */
HAL_TIM_PWM_ConfigChannel(&g_atimx_handle, &g_atimx_oc_chy_handle, ATIM_TIMX_PWM_CH3); /* 配置TIMx通道y */
/* 开启定时器通道1输出PWM */
HAL_TIM_PWM_Start(&g_atimx_handle,TIM_CHANNEL_1);
/* 开启定时器通道2输出PWM */
HAL_TIM_PWM_Start(&g_atimx_handle,TIM_CHANNEL_2);
/* 开启定时器通道3输出PWM */
HAL_TIM_PWM_Start(&g_atimx_handle,TIM_CHANNEL_3);
HAL_NVIC_SetPriority(TIM1_UP_TIM10_IRQn, 2, 2);
HAL_NVIC_EnableIRQ(TIM1_UP_TIM10_IRQn);
HAL_TIM_Base_Start_IT(&g_atimx_handle);/*启动高级定时器1*/
}
/**
* @brief 高级定时器TIM8 PWM输出 初始化函数
* @param arr: 自动重装值
* @param psc: 时钟预分频数
* @retval 无
*/
void atim_timx2_oc_chy_init(uint16_t arr, uint16_t psc)
{
ATIM_TIMX2_PWM_CHY_CLK_ENABLE(); /* TIMX 时钟使能 */
g_atimx2_handle.Instance = ATIM_TIMX2_PWM; /* 定时器x */
g_atimx2_handle.Init.Prescaler = psc; /* 定时器分频 */
g_atimx2_handle.Init.CounterMode = TIM_COUNTERMODE_UP; /* 向上计数模式 */
g_atimx2_handle.Init.Period = arr; /* 自动重装载值 */
g_atimx2_handle.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1; /* 分频因子 */
g_atimx2_handle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; /*使能TIMx_ARR进行缓冲*/
g_atimx2_handle.Init.RepetitionCounter = 0; /* 开始时不计数*/
HAL_TIM_PWM_Init(&g_atimx2_handle); /* 初始化PWM */
g_atimx2_oc_chy_handle.OCMode = TIM_OCMODE_PWM1; /* 模式选择PWM1 */
g_atimx2_oc_chy_handle.Pulse = 0;
g_atimx2_oc_chy_handle.OCPolarity = TIM_OCPOLARITY_HIGH; /* 输出比较极性为高 */
g_atimx2_oc_chy_handle.OCNPolarity = TIM_OCNPOLARITY_HIGH;
g_atimx2_oc_chy_handle.OCFastMode = TIM_OCFAST_DISABLE;
g_atimx2_oc_chy_handle.OCIdleState = TIM_OCIDLESTATE_RESET;
g_atimx2_oc_chy_handle.OCNIdleState = TIM_OCNIDLESTATE_RESET;
HAL_TIM_PWM_ConfigChannel(&g_atimx2_handle, &g_atimx2_oc_chy_handle, ATIM_TIMX2_PWM_CH1); /* 配置TIMx通道y */
HAL_TIM_PWM_ConfigChannel(&g_atimx2_handle, &g_atimx2_oc_chy_handle, ATIM_TIMX2_PWM_CH2); /* 配置TIMx通道y */
HAL_TIM_PWM_ConfigChannel(&g_atimx2_handle, &g_atimx2_oc_chy_handle, ATIM_TIMX2_PWM_CH3); /* 配置TIMx通道y */
/* 开启定时器通道1输出PWM */
HAL_TIM_PWM_Start(&g_atimx2_handle,TIM_CHANNEL_1);
/* 开启定时器通道2输出PWM */
HAL_TIM_PWM_Start(&g_atimx2_handle,TIM_CHANNEL_2);
/* 开启定时器通道3输出PWM */
HAL_TIM_PWM_Start(&g_atimx2_handle,TIM_CHANNEL_3);
HAL_NVIC_SetPriority(TIM8_UP_TIM13_IRQn, 2, 3);
HAL_NVIC_EnableIRQ(TIM8_UP_TIM13_IRQn);
HAL_TIM_Base_Start_IT(&g_atimx2_handle); /* 启动高级定时器8 */
}
/**
* @brief 定时器底层驱动,时钟使能,引脚配置
此函数会被HAL_TIM_PWM_Init()调用
* @param htim:定时器句柄
* @retval 无
*/
void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim)
{
if (htim->Instance == ATIM_TIMX_PWM)
{
GPIO_InitTypeDef gpio_init_struct;
ATIM_TIMX_PWM_CHY_CLK_ENABLE(); /* 开启通道y的GPIO时钟 */
ATIM_TIMX_PWM_CH1_GPIO_CLK_ENABLE(); /* IO时钟使能 */
ATIM_TIMX_PWM_CH2_GPIO_CLK_ENABLE(); /* IO时钟使能 */
ATIM_TIMX_PWM_CH3_GPIO_CLK_ENABLE(); /* IO时钟使能 */
M1_LOW_SIDE_U_GPIO_CLK_ENABLE(); /* IO时钟使能 */
M1_LOW_SIDE_V_GPIO_CLK_ENABLE(); /* IO时钟使能 */
M1_LOW_SIDE_W_GPIO_CLK_ENABLE(); /* IO时钟使能 */
/* UVW_LOW的IO初始化 */
gpio_init_struct.Pin = M1_LOW_SIDE_U_PIN;
gpio_init_struct.Pull = GPIO_NOPULL;
gpio_init_struct.Speed = GPIO_SPEED_HIGH;
gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP; /* 推挽输出模式 */
HAL_GPIO_Init(M1_LOW_SIDE_U_PORT, &gpio_init_struct);
gpio_init_struct.Pin = M1_LOW_SIDE_V_PIN;
HAL_GPIO_Init(M1_LOW_SIDE_V_PORT, &gpio_init_struct);
gpio_init_struct.Pin = M1_LOW_SIDE_W_PIN;
HAL_GPIO_Init(M1_LOW_SIDE_W_PORT, &gpio_init_struct);
/*定时器IO初始化*/
gpio_init_struct.Pin = ATIM_TIMX_PWM_CH1_GPIO_PIN; /* 通道y的CPIO口 */
gpio_init_struct.Mode = GPIO_MODE_AF_PP; /* 复用推挽输出 */
gpio_init_struct.Pull = GPIO_NOPULL; /* 上拉 */
gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH; /* 高速 */
gpio_init_struct.Alternate = ATIM_TIMX_PWM_CHY_GPIO_AF; /* 端口复用 */
HAL_GPIO_Init(ATIM_TIMX_PWM_CH1_GPIO_PORT, &gpio_init_struct);
gpio_init_struct.Pin = ATIM_TIMX_PWM_CH2_GPIO_PIN; /* 通道y的CPIO口 */
HAL_GPIO_Init(ATIM_TIMX_PWM_CH2_GPIO_PORT, &gpio_init_struct);
gpio_init_struct.Pin = ATIM_TIMX_PWM_CH3_GPIO_PIN; /* 通道y的CPIO口 */
HAL_GPIO_Init(ATIM_TIMX_PWM_CH3_GPIO_PORT, &gpio_init_struct);
}
else if (htim->Instance == ATIM_TIMX2_PWM)
{
GPIO_InitTypeDef gpio_init_struct;
ATIM_TIMX2_PWM_CHY_CLK_ENABLE(); /* 开启通道y的CPIO时钟 */
ATIM_TIMX2_PWM_CH1_GPIO_CLK_ENABLE(); /* IO时钟使能 */
ATIM_TIMX2_PWM_CH2_GPIO_CLK_ENABLE(); /* IO时钟使能 */
ATIM_TIMX2_PWM_CH3_GPIO_CLK_ENABLE(); /* IO时钟使能 */
M2_LOW_SIDE_U_GPIO_CLK_ENABLE(); /* IO时钟使能 */
M2_LOW_SIDE_V_GPIO_CLK_ENABLE(); /* IO时钟使能 */
M2_LOW_SIDE_W_GPIO_CLK_ENABLE(); /* IO时钟使能 */
/* UVW_LOW的IO初始化 */
gpio_init_struct.Pin = M2_LOW_SIDE_U_PIN;
gpio_init_struct.Pull = GPIO_NOPULL;
gpio_init_struct.Speed = GPIO_SPEED_HIGH;
gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP; /* 推挽输出模式 */
HAL_GPIO_Init(M2_LOW_SIDE_U_PORT, &gpio_init_struct);
gpio_init_struct.Pin = M2_LOW_SIDE_V_PIN;
HAL_GPIO_Init(M2_LOW_SIDE_V_PORT, &gpio_init_struct);
gpio_init_struct.Pin = M2_LOW_SIDE_W_PIN;
HAL_GPIO_Init(M2_LOW_SIDE_W_PORT, &gpio_init_struct);
/*定时器IO初始化*/
gpio_init_struct.Pin = ATIM_TIMX2_PWM_CH1_GPIO_PIN; /* 通道y的CPIO口 */
gpio_init_struct.Mode = GPIO_MODE_AF_PP; /* 复用推挽输出 */
gpio_init_struct.Pull = GPIO_NOPULL; /* 上拉 */
gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH; /* 高速 */
gpio_init_struct.Alternate = ATIM_TIMX2_PWM_CHY_GPIO_AF; /* 端口复用 */
HAL_GPIO_Init(ATIM_TIMX2_PWM_CH1_GPIO_PORT, &gpio_init_struct);
gpio_init_struct.Pin = ATIM_TIMX2_PWM_CH2_GPIO_PIN; /* 通道y的CPIO口 */
HAL_GPIO_Init(ATIM_TIMX2_PWM_CH2_GPIO_PORT, &gpio_init_struct);
gpio_init_struct.Pin = ATIM_TIMX2_PWM_CH3_GPIO_PIN; /* 通道y的CPIO口 */
HAL_GPIO_Init(ATIM_TIMX2_PWM_CH3_GPIO_PORT, &gpio_init_struct);
}
}
/**
* @brief 定时器中断服务函数
* @param 无
* @retval 无
*/
void ATIM_TIMX_PWM_IRQHandler(void)
{
HAL_TIM_IRQHandler(&g_atimx_handle);
}
/**
* @brief 定时器中断服务函数
* @param 无
* @retval 无
*/
void ATIM_TIMX2_PWM_IRQHandler(void)
{
HAL_TIM_IRQHandler(&g_atimx2_handle);
}
/**
* @brief 定时器中断回调
* @param htim:定时器句柄
* @retval 无
*/
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
uint8_t bldc_dir=0;
if(htim->Instance == ATIM_TIMX_PWM) /* 55us */
{
#ifdef H_PWM_L_ON
if(g_bldc_motor1.run_flag == RUN)
{
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;
}
if(g_bldc_motor1.step_last != g_bldc_motor1.step_sta) /* 霍尔状态发生改变,代表换向 */
{
g_bldc_motor1.hall_keep_t=0;
bldc_dir = check_hall_dir(&g_bldc_motor1); /* 检测旋转方向,根据方向,进行位置计数 */
if(bldc_dir == CCW)
{
g_bldc_motor1.pos -=1;
}
else if(bldc_dir == CW)
{
g_bldc_motor1.pos +=1;
}
g_bldc_motor1.step_last = g_bldc_motor1.step_sta;
}
else if(g_bldc_motor1.run_flag == RUN) /* 运行且霍尔保持时 */
{
g_bldc_motor1.hall_keep_t++; /* 换向一次所需计数值(时间) 单位1/18k */
}
}
#endif
}
if(htim->Instance == ATIM_TIMX2_PWM) /* 55us */
{
#ifdef H_PWM_L_ON
if(g_bldc_motor2.run_flag == RUN)
{
if(g_bldc_motor2.dir == CW)
{
g_bldc_motor2.step_sta = hallsensor_get_state(MOTOR_2);
}
else
{
g_bldc_motor2.step_sta = 7 - hallsensor_get_state(MOTOR_2);
}
if((g_bldc_motor2.step_sta <= 6)&&(g_bldc_motor2.step_sta >= 1))
{
pfunclist_m2[g_bldc_motor2.step_sta-1]();
}
else /* 编码器错误、接触不良、断开等情况 */
{
stop_motor2();
g_bldc_motor2.run_flag = STOP;
}
if(g_bldc_motor2.step_last != g_bldc_motor2.step_sta)
{
g_bldc_motor2.hall_keep_t=0;
bldc_dir = check_hall_dir(&g_bldc_motor2);
if(bldc_dir == CCW)
{
g_bldc_motor2.pos -=1;
}
else if(bldc_dir == CW)
{
g_bldc_motor2.pos +=1;
}
g_bldc_motor2.step_last = g_bldc_motor2.step_sta;
}
else if(g_bldc_motor2.run_flag == RUN) /* 运行且霍尔保持时 */
{
g_bldc_motor2.hall_keep_t++; /* 换向一次所需计数值(时间) 单位1/18k */
}
}
#endif
}
}
测试结果:

BLDC电源电压、电流及温度的采集




主函数:
int main(void)
{
uint8_t key,t;
char buf[32];
int16_t pwm_duty_temp=0;
float current[3]= {0.0f};
float current_lpf[4]= {0.0f};
HAL_Init(); /* 初始化HAL库 */
sys_stm32_clock_init(336, 8, 2, 7); /* 设置时钟,168Mhz */
delay_init(168); /* 延时初始化 */
usart_init(115200); /* 串口初始化为115200 */
led_init(); /* 初始化LED */
key_init(); /* 初始化按键 */
lcd_init(); /* 初始化LCD */
bldc_init(10000-1,0);
bldc_ctrl(MOTOR_1,CCW,0); /* 初始无刷电机接口1速度 */
g_point_color = WHITE;
g_back_color = BLACK;
lcd_show_string(10, 10, 200, 16, 16, "BLDC Motor Test",g_point_color);
lcd_show_string(10, 30, 200, 16, 16, "KEY0:Start forward", g_point_color);
lcd_show_string(10, 50, 200, 16, 16, "KEY1:Start backward", g_point_color);
lcd_show_string(10, 70, 200, 16, 16, "KEY2:Stop", g_point_color);
adc_nch_dma_init();
printf("按下KEY0 增加比较值即正转加速\r\n");
printf("按下KEY1 减少比较值即反转加速\r\n");
printf("按下KEY2 停止电机\r\n");
while (1)
{
t++;
if(t % 20 == 0)
{
sprintf(buf,"PWM_Duty:%.1f%%",(float)((g_bldc_motor1.pwm_duty/MAX_PWM_DUTY)*100));/* 显示控制PWM占空比 */
lcd_show_string(10,110,200,16,16,buf,g_point_color);
sprintf(buf,"Power:%.3fV ",g_adc_val[0]*ADC2VBUS);
lcd_show_string(10,190,200,16,16,buf,g_point_color);
sprintf(buf,"Temp:%.1fC ",get_temp(g_adc_val[1]));
lcd_show_string(10,210,200,16,16,buf,g_point_color);
LED0_TOGGLE(); /* LED0(红灯) 翻转 */
current[0] = adc_amp_un[0]* ADC2CURT; /* 计算出三相电流值,U */
current[1] = adc_amp_un[1]* ADC2CURT; /* 计算出三相电流值,V */
current[2] = adc_amp_un[2]* ADC2CURT; /* 计算出三相电流值,W */
/*一阶数字滤波 滤波系数0.1 用于显示*/
FirstOrderRC_LPF(current_lpf[0],current[0],0.1f); /* U相电流 */
FirstOrderRC_LPF(current_lpf[1],current[1],0.1f); /* V相电流 */
FirstOrderRC_LPF(current_lpf[2],current[2],0.1f); /* W相电流 */
FirstOrderRC_LPF(current_lpf[3],adc_amp_bus,0.1f); /* 母线电流 */
if(g_bldc_motor1.run_flag == STOP) /* 停机的电流显示 */
{
current_lpf[0] = 0;
current_lpf[1] = 0;
current_lpf[2] = 0;
current_lpf[3] = 0;
}
/* LCD显示提示信息 */
sprintf(buf,"Amp U:%.3fmA ",(float)current_lpf[0]);
lcd_show_string(10,230,200,16,16,buf,g_point_color);
sprintf(buf,"Amp V:%.3fmA ",(float)current_lpf[1]);
lcd_show_string(10,250,200,16,16,buf,g_point_color);
sprintf(buf,"Amp W:%.3fmA ",(float)current_lpf[2]);
lcd_show_string(10,270,200,16,16,buf,g_point_color);
sprintf(buf,"Amp Bus:%.3fmA ",(float)current_lpf[3]);
lcd_show_string(10,290,200,16,16,buf,g_point_color);
/* 串口打印信息 */
printf("Valtage:%.1fV \r\n", g_adc_val[0]*ADC2VBUS);
printf("Temp:%.1fC \r\n", get_temp(g_adc_val[1]));
printf("U相电流为:%.3fmA\r\n", (current_lpf[0]));
printf("V相电流为:%.3fmA\r\n", (current_lpf[1]));
printf("W相电流为:%.3fmA\r\n", (current_lpf[2]));
printf("母线电流为:%.3fmA\r\n", (current_lpf[3]));
printf("\r\n");
}
key = key_scan(0);
if(key == KEY0_PRES) /* 按下KEY0占空比++ */
{
pwm_duty_temp += 500;
if(pwm_duty_temp >= MAX_PWM_DUTY)
pwm_duty_temp = MAX_PWM_DUTY;
if(pwm_duty_temp > 0)
{
g_bldc_motor1.pwm_duty = pwm_duty_temp;/* 设置占空比 */
g_bldc_motor1.dir = CW; /* 设置方向 */
}
else
{
g_bldc_motor1.pwm_duty = -pwm_duty_temp;
g_bldc_motor1.dir = CCW;
}
g_bldc_motor1.run_flag = RUN; /* 运行标志 */
start_motor1(); /* 开启运行*/
}
else if(key == KEY1_PRES) /* 按下KEY1占空比-- */
{
pwm_duty_temp -= 500;
if(pwm_duty_temp <= -MAX_PWM_DUTY)
pwm_duty_temp = -MAX_PWM_DUTY;
if(pwm_duty_temp < 0)
{
g_bldc_motor1.pwm_duty = -pwm_duty_temp;
g_bldc_motor1.dir = CCW;
}
else
{
g_bldc_motor1.pwm_duty = pwm_duty_temp;
g_bldc_motor1.dir = CW;
}
g_bldc_motor1.run_flag = RUN; /* 开启运行*/
start_motor1(); /* 运行电机*/
}
else if(key == KEY2_PRES) /* 按下KEY2关闭电机 */
{
stop_motor1(); /* 停机*/
g_bldc_motor1.run_flag = STOP; /* 标记停机*/
pwm_duty_temp = 0;
g_bldc_motor1.pwm_duty = 0;
}
delay_ms(10);
}
}
ADC:
/* ADC及引脚 定义 */
#define ADC_ADCX_CH0_GPIO_PORT GPIOB /* 电源电压采集引脚 */
#define ADC_ADCX_CH0_GPIO_PIN GPIO_PIN_1
#define ADC_ADCX_CH0_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOB_CLK_ENABLE(); }while(0)
#define ADC_ADCX_CH1_GPIO_PORT GPIOA /* 温度采集引脚 */
#define ADC_ADCX_CH1_GPIO_PIN GPIO_PIN_0
#define ADC_ADCX_CH1_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOA_CLK_ENABLE(); }while(0)
#define ADC_ADCX_CH2_GPIO_PORT GPIOB /* U相采集引脚 */
#define ADC_ADCX_CH2_GPIO_PIN GPIO_PIN_0
#define ADC_ADCX_CH2_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOB_CLK_ENABLE(); }while(0)
#define ADC_ADCX_CH3_GPIO_PORT GPIOA /* V相采集引脚 */
#define ADC_ADCX_CH3_GPIO_PIN GPIO_PIN_6
#define ADC_ADCX_CH3_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOA_CLK_ENABLE(); }while(0)
#define ADC_ADCX_CH4_GPIO_PORT GPIOA /* W相采集引脚 */
#define ADC_ADCX_CH4_GPIO_PIN GPIO_PIN_3
#define ADC_ADCX_CH4_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOA_CLK_ENABLE(); }while(0)
#define ADC_ADCX ADC1
#define ADC_ADCX_CH0 ADC_CHANNEL_9 /* 通道Y, 0 <= Y <= 17 */
#define ADC_ADCX_CH1 ADC_CHANNEL_0
#define ADC_ADCX_CH2 ADC_CHANNEL_8
#define ADC_ADCX_CH3 ADC_CHANNEL_6
#define ADC_ADCX_CH4 ADC_CHANNEL_3
#define ADC_ADCX_CHY_CLK_ENABLE() do{ __HAL_RCC_ADC1_CLK_ENABLE(); }while(0) /* ADC1 时钟使能 */
#define ADC_CH_NUM 5 /* 需要转换的通道数目 */
#define ADC_COLL 50 /* 单采集次数 */
#define ADC_SUM ADC_CH_NUM * ADC_COLL /* 总采集次数 */
/* ADC单通道/多通道 DMA采集 DMA数据流相关 定义
* 注意: 这里我们的通道还是使用上面的定义.
*/
#define ADC_ADCX_DMASx DMA2_Stream4
#define ADC_ADCX_DMASx_Chanel DMA_CHANNEL_0 /* ADC1_DMA请求源 */
#define ADC_ADCX_DMASx_IRQn DMA2_Stream4_IRQn
#define ADC_ADCX_DMASx_IRQHandler DMA2_Stream4_IRQHandler
void adc_init(void)
{
ADC_ChannelConfTypeDef sConfig = {0};
g_adc_nch_dma_handle.Instance = ADC_ADCX;
g_adc_nch_dma_handle.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4; /* 4分频,ADCCLK = PCLK2/4 = 84/4 = 21Mhz */
g_adc_nch_dma_handle.Init.Resolution = ADC_RESOLUTION_12B; /* 12位模式 */
g_adc_nch_dma_handle.Init.ScanConvMode = ENABLE; /* 扫描模式 多通道使用 */
g_adc_nch_dma_handle.Init.ContinuousConvMode = ENABLE; /* 连续转换模式,转换完成之后接着继续转换 */
g_adc_nch_dma_handle.Init.DiscontinuousConvMode = DISABLE; /* 禁止不连续采样模式 */
g_adc_nch_dma_handle.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; /* 使用软件触发 */
g_adc_nch_dma_handle.Init.ExternalTrigConv = ADC_SOFTWARE_START; /* 软件触发 */
g_adc_nch_dma_handle.Init.DataAlign = ADC_DATAALIGN_RIGHT; /* 右对齐 */
g_adc_nch_dma_handle.Init.NbrOfConversion = ADC_CH_NUM; /* 使用转换通道数,需根据实际转换通道去设置 */
g_adc_nch_dma_handle.Init.DMAContinuousRequests = ENABLE; /* 开启DMA连续转换 */
g_adc_nch_dma_handle.Init.EOCSelection = ADC_EOC_SEQ_CONV;
HAL_ADC_Init(&g_adc_nch_dma_handle);
/* 配置使用的ADC通道,采样序列里的第几个转换,增加或者减少通道需要修改这部分 */
sConfig.Channel = ADC_ADCX_CH0; /* 电源电压采集 */
sConfig.Rank = 1;
sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES;
HAL_ADC_ConfigChannel(&g_adc_nch_dma_handle, &sConfig);
sConfig.Channel = ADC_ADCX_CH1; /* 温度采集 */
sConfig.Rank = 2;
HAL_ADC_ConfigChannel(&g_adc_nch_dma_handle, &sConfig);
sConfig.Channel = ADC_ADCX_CH2; /* U相电压采集 */
sConfig.Rank = 3;
HAL_ADC_ConfigChannel(&g_adc_nch_dma_handle, &sConfig);
sConfig.Channel = ADC_ADCX_CH3; /* V相电压采集 */
sConfig.Rank = 4;
HAL_ADC_ConfigChannel(&g_adc_nch_dma_handle, &sConfig);
sConfig.Channel = ADC_ADCX_CH4; /* W相电压采集 */
sConfig.Rank = 5;
HAL_ADC_ConfigChannel(&g_adc_nch_dma_handle, &sConfig);
}
/**
* @brief ADC DMA读取 初始化函数
* @note 本函数还是使用adc_init对ADC进行大部分配置,有差异的地方再单独配置
* @param par : 外设地址
* @param mar : 存储器地址
* @retval 无
*/
void adc_nch_dma_init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
ADC_ADCX_CHY_CLK_ENABLE(); /* 使能ADCx时钟 */
ADC_ADCX_CH0_GPIO_CLK_ENABLE(); /* 开启GPIO时钟 */
ADC_ADCX_CH1_GPIO_CLK_ENABLE();
ADC_ADCX_CH2_GPIO_CLK_ENABLE();
ADC_ADCX_CH3_GPIO_CLK_ENABLE();
ADC_ADCX_CH4_GPIO_CLK_ENABLE();
/* AD采集引脚模式设置,模拟输入 */
GPIO_InitStruct.Pin = ADC_ADCX_CH0_GPIO_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(ADC_ADCX_CH0_GPIO_PORT, &GPIO_InitStruct);
GPIO_InitStruct.Pin = ADC_ADCX_CH1_GPIO_PIN;
HAL_GPIO_Init(ADC_ADCX_CH1_GPIO_PORT, &GPIO_InitStruct);
GPIO_InitStruct.Pin = ADC_ADCX_CH2_GPIO_PIN;
HAL_GPIO_Init(ADC_ADCX_CH2_GPIO_PORT, &GPIO_InitStruct);
GPIO_InitStruct.Pin = ADC_ADCX_CH3_GPIO_PIN;
HAL_GPIO_Init(ADC_ADCX_CH3_GPIO_PORT, &GPIO_InitStruct);
GPIO_InitStruct.Pin = ADC_ADCX_CH4_GPIO_PIN;
HAL_GPIO_Init(ADC_ADCX_CH4_GPIO_PORT, &GPIO_InitStruct);
adc_init();
if ((uint32_t)ADC_ADCX_DMASx > (uint32_t)DMA2) /* 大于DMA1_Channel7, 则为DMA2的通道了 */
{
__HAL_RCC_DMA2_CLK_ENABLE(); /* DMA2时钟使能 */
}
else
{
__HAL_RCC_DMA1_CLK_ENABLE(); /* DMA1时钟使能 */
}
/* DMA配置 */
g_dma_nch_adc_handle.Instance = ADC_ADCX_DMASx; /* 设置DMA通道 */
g_dma_nch_adc_handle.Init.Channel = DMA_CHANNEL_0;
g_dma_nch_adc_handle.Init.Direction = DMA_PERIPH_TO_MEMORY; /* DIR = 1 , 外设到存储器模式 */
g_dma_nch_adc_handle.Init.PeriphInc = DMA_PINC_DISABLE; /* 外设非增量模式 */
g_dma_nch_adc_handle.Init.MemInc = DMA_MINC_ENABLE; /* 存储器增量模式 */
g_dma_nch_adc_handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; /* 外设数据长度:16位 */
g_dma_nch_adc_handle.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; /* 存储器数据长度:16位 */
g_dma_nch_adc_handle.Init.Mode = DMA_CIRCULAR; /* 外设流控模式 */
g_dma_nch_adc_handle.Init.Priority = DMA_PRIORITY_MEDIUM; /* 中等优先级 */
HAL_DMA_Init(&g_dma_nch_adc_handle);
__HAL_LINKDMA(&g_adc_nch_dma_handle,DMA_Handle,g_dma_nch_adc_handle);
HAL_NVIC_SetPriority(ADC_ADCX_DMASx_IRQn, 2, 1);
HAL_NVIC_EnableIRQ(ADC_ADCX_DMASx_IRQn);
HAL_ADC_Start_DMA(&g_adc_nch_dma_handle,(uint32_t *)g_adc_value,ADC_CH_NUM * ADC_COLL);
}
/**
* @brief ADC DMA采集中断服务函数
* @param 无
* @retval 无
*/
void ADC_ADCX_DMASx_IRQHandler(void)
{
HAL_DMA_IRQHandler(&g_dma_nch_adc_handle);
}
uint16_t g_adc_val[ADC_CH_NUM]; /* ADC平均值存放数组 */
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
if (hadc->Instance == ADC1) /* 大约2.6ms采集完成进入中断 */
{
HAL_ADC_Stop_DMA(&g_adc_nch_dma_handle); /* 关闭DMA转换 */
calc_adc_val(g_adc_val); /* ADC数值转换 */
HAL_ADC_Start_DMA(&g_adc_nch_dma_handle, (uint32_t *)&g_adc_value, (uint32_t)(ADC_SUM)); /* 再启动DMA转换*/
}
}
/**
* @brief 获取通道ch的转换值,取times次, 然后平均
* @param ch: 通道号, 0~17
* @retval 通道ch的times次转换结果平均值
*/
uint32_t adc_get_result_average(uint8_t ch)
{
uint32_t temp_val = 0;
uint16_t t;
for (t = ch; t < ADC_SUM; t += ADC_CH_NUM ) /* 获取times次数据 */
{
temp_val += g_adc_value[t];
}
return temp_val / ADC_COLL; /* 返回平均值 */
}
测试结果:
