1.三相采样电流的采集以u相为举例。
采集下桥臂I-V的电压。在除以采样电阻。就可以得到采样电流。但由于I-V的电压比较小。
需要一个放大电路把电压放大ADC才采集的到。
放大后的电压是AMP_IU.用ADC去采集这个电压。从而算出I_V的电压。
在电机停止的时候也会有微小的电压。并且包括1.25V的抬升电压。所以实际的电压如下计算:
先求电机停止时的偏置电压,在求运行时的电压。
I = (运行时的电压 - 偏置电压)/0.12
2.电源电压
运放是一个射极跟随器所以VBUS等于A点的电压 。当用ADC采集VBUS的电压就知道A点的电压。从而可以计算出POWER的电压(分压公式)。因为POWER是电机的供电电压。当比较相差很大时就可以判断有故障发生。
3.板子温度的采集
板子上有一个热敏电阻随温度的变化而变化。
跟电源电压一样运放是射极跟随器。VTEMP点的电压等于A点的电压。VCC等于3. 3v。可以求出R106的阻值。
上面实际温度的公式是根据热敏电阻的手册可以查出的。
上面的有些参数需要查手册如下:Rt就是通过上面分压计算得到。
4.速度环
当只有一对极时。旋转一圈有180度的高电平与180度的低电平(如图:霍尔1,2,3)。
当我们求出高电平的时间(t)=高电平的计数值*PWM的频率(不是定时器的频率)。
总的时间:2t(因为高电平与低电平相等) T=2(Cnt/fpwm) 单位s/圈。
倒数就是:圈每秒 T=fpwm/2*Cnt 如果转为RPM乘上60即可。
如果是两对极 T=fpwm/4*Cnt 霍尔1,2,3会经历两次的N-S。多对极依次推。
速度环的框图:
dome:速度-电流PID
高级定时器T1(开启更新中断55us进入一次),定时器6(计时作用防止堵转)。ADC采集温度,电源电源电压,三相采样电流(力矩)。开启DMA。各采集50次求平均值。减小误差。
高级定时器.h 与定时器6.h 一起
#ifndef __BLDC_TIM_H
#define __BLDC_TIM_H
#include "./SYSTEM/sys/sys.h"
/******************************************************************************************/
/* 高级定时器 定义 */
extern TIM_HandleTypeDef g_atimx_handle; /* 定时器x句柄 */
/* TIMX PWM 定义
* 注意: 通过修改这几个宏定义, 可以支持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口时钟使能 */
#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 时钟使能 */
/******************************************************************************************/
/* 基本定时器 定义 */
/* TIMX 中断定义
* 默认是针对TIM6
*/
#define BTIM_TIMX_INT TIM6
#define BTIM_TIMX_INT_IRQn TIM6_DAC_IRQn
#define BTIM_TIMX_INT_IRQHandler TIM6_DAC_IRQHandler
#define BTIM_TIMX_INT_CLK_ENABLE() do{ __HAL_RCC_TIM6_CLK_ENABLE(); }while(0) /* TIM6 时钟使能 */
extern TIM_HandleTypeDef g_atimx_handle; /* 定时器x句柄 */
/******************************************************************************************/
void atim_timx_oc_chy_init(uint16_t arr, uint16_t psc); /* 高级定时器 PWM初始化函数 */
void btim_timx_int_init(uint16_t arr, uint16_t psc); /* 基本定时器中断初始化 */
#endif
高级定时器.c与定时器6.c 一起
#include "./BSP/TIMER/bldc_tim.h"
#include "./BSP/LED/led.h"
#include "./BSP/BLDC/bldc.h"
#include "./BSP/PID/pid.h"
#include "./SYSTEM/delay/delay.h"
#include "./BSP/ADC/adc.h"
#include "./DEBUG/debug.h"
/******************************** 定时器配置句柄 定义 ***********************************/
TIM_HandleTypeDef g_atimx_handle; /* 定时器x句柄 */
TIM_OC_InitTypeDef g_atimx_oc_chy_handle; /* 定时器输出句柄 */
/******************************** 定义全局变量 ************************************/
extern _bldc_obj g_bldc_motor1;
extern PID_TypeDef g_speed_pid; /* 位置PID参数结构体 */
/******************************************************************************************/
/**
* @brief 高级定时器TIMX PWM 初始化函数
* @note
* 高级定时器的时钟来自APB2, 而PCLK2 = 168Mhz, 我们设置PPRE2不分频, 因此
* 高级定时器时钟 = 168Mhz
* 定时器溢出时间计算方法: Tout = ((arr + 1) * (psc + 1)) / Ft us.
* Ft=定时器工作频率,单位:Mhz
*
* @param arr: 自动重装值
* @param psc: 时钟预分频数
* @retval 无
*/
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 定时器底层驱动,时钟使能,引脚配置
此函数会被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的IO时钟 */
/* 三个上桥臂对应IO时钟使能 */
ATIM_TIMX_PWM_CH1_GPIO_CLK_ENABLE(); /* IO时钟使能 */
ATIM_TIMX_PWM_CH2_GPIO_CLK_ENABLE(); /* IO时钟使能 */
ATIM_TIMX_PWM_CH3_GPIO_CLK_ENABLE(); /* IO时钟使能 */
/* 三个下桥臂对应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的IO口 */
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;
HAL_GPIO_Init(ATIM_TIMX_PWM_CH2_GPIO_PORT, &gpio_init_struct);
gpio_init_struct.Pin = ATIM_TIMX_PWM_CH3_GPIO_PIN;
HAL_GPIO_Init(ATIM_TIMX_PWM_CH3_GPIO_PORT, &gpio_init_struct);
}
}
/**
* @brief 高级定时器TIMX中断服务函数
* @param 无
* @retval 无
*/
void ATIM_TIMX_PWM_IRQHandler(void)
{
HAL_TIM_IRQHandler(&g_atimx_handle);
}
/******************************************基本定时器初始化**********************************************************/
TIM_HandleTypeDef timx_handler; /* 定时器参数句柄 */
/**
* @brief 基本定时器TIMX定时中断初始化函数
* @note
* 基本定时器的时钟来自APB1,当PPRE1 ≥ 2分频的时候
* 基本定时器的时钟为APB1时钟的2倍, 而APB1为42 所以定时器时钟 = 84MHZ
* 定时器溢出时间计算方法: Tout = ((arr + 1) * (psc + 1)) / Ft us.
* Ft=定时器工作频率,单位:Mhz
*
* @param arr: 自动重装值。
* @param psc: 时钟预分频数
* @retval 无
*/
void btim_timx_int_init(uint16_t arr, uint16_t psc)
{
timx_handler.Instance = BTIM_TIMX_INT; /* 基本定时器X */
timx_handler.Init.Prescaler = psc; /* 设置预分频器 */
timx_handler.Init.CounterMode = TIM_COUNTERMODE_UP; /* 向上计数器 */
timx_handler.Init.Period = arr; /* 自动装载值 */
timx_handler.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; /* 时钟分频因子 */
HAL_TIM_Base_Init(&timx_handler);
HAL_TIM_Base_Start_IT(&timx_handler); /* 使能通用定时器x和及其更新中断:TIM_IT_UPDATE */
__HAL_TIM_CLEAR_IT(&timx_handler,TIM_IT_UPDATE); /* 清除更新中断标志位 */
}
/**
* @brief 定时器底册驱动,开启时钟,设置中断优先级
此函数会被HAL_TIM_Base_Init()函数调用
* @param 无
* @retval 无
*/
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{
if (htim->Instance == BTIM_TIMX_INT)
{
BTIM_TIMX_INT_CLK_ENABLE(); /* 使能TIM时钟*/
HAL_NVIC_SetPriority(BTIM_TIMX_INT_IRQn, 1, 3); /* 抢占1,子优先级3,组2 */
HAL_NVIC_EnableIRQ(BTIM_TIMX_INT_IRQn); /* 开启ITM3中断 */
}
}
/**
* @brief 基本定时器TIMX中断服务函数
* @param 无
* @retval 无
*/
void BTIM_TIMX_INT_IRQHandler(void)
{
HAL_TIM_IRQHandler(&timx_handler); /*定时器回调函数*/
}
/***********************************************定时器中断回调函数***********************************************/
static uint8_t pid_s_count = 0; /* 速度环运行标志 */
static uint8_t pid_c_count = 0; /* 电流环运行标志 */
static uint8_t cf_count = 0; /* 定时器时间记录 */
int32_t temp_pwm1 = 0; /* 存放速度环的PID计算结果 */
int32_t temp_pwm2 = 0; /* 存放电流环的PID计算结果 */
/* 将PID期望值进行一阶滤波后存放至以下变量 */
int32_t motor_pwm_s = 0;
int32_t motor_pwm_c = 0;
int32_t motor_pwm_sl= 0;
/* 停机状态下电流采集使用 */
#define ADC_AMP_OFFSET_TIMES 50
uint16_t adc_amp_offset[3][ADC_AMP_OFFSET_TIMES+1];
uint8_t adc_amp_offset_p = 0;
int16_t adc_amp[3];
volatile uint16_t adc_val_m1[ADC_CH_NUM];
int16_t adc_amp_un[3];
float adc_amp_bus = 0.0f;
float debug_data_temp = 0.0f;
float *user_setpoint = (float*)(&g_speed_pid.SetPoint); /* 目标值赋值 */
uint8_t clc = 0; /* 等待时间进入堵塞控制时间 */
/**
* @brief 定时器中断回调
* @param 无
* @retval 无
*/
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
uint8_t i;
uint8_t bldc_dir=0;
static uint8_t times_count=0; /* 定时器时间记录 */
int16_t temp_speed=0; /* 临时速度存储 */
if(htim->Instance == ATIM_TIMX_PWM) /* 55us */
{
if(g_bldc_motor1.run_flag == RUN)
{
/******************************* 三相电流计算 *******************************/
for(i=0; i<3; i++)
{
adc_val_m1[i] = g_adc_val[i+2]; /* UVW三相ADC通道 */
adc_amp[i] = adc_val_m1[i] - adc_amp_offset[i][ADC_AMP_OFFSET_TIMES];
if(adc_amp[i] >= 0) /* 去除反电动势引起的负电流数据 */
adc_amp_un[i] = adc_amp[i];
}
/* 运算母线电流(母线电流为任意两个有开关动作的相电流之和)*/
if(g_bldc_motor1.step_sta == 0x05)
{
adc_amp_bus = (adc_amp_un[0] + adc_amp_un[1])*ADC2CURT; /* UV */
}
else if(g_bldc_motor1.step_sta == 0x01)
{
adc_amp_bus = (adc_amp_un[0] + adc_amp_un[2])*ADC2CURT; /* UW */
}
else if(g_bldc_motor1.step_sta == 0x03)
{
adc_amp_bus = (adc_amp_un[1]+ adc_amp_un[2])*ADC2CURT; /* VW */
}
else if(g_bldc_motor1.step_sta == 0x02)
{
adc_amp_bus = (adc_amp_un[0]+ adc_amp_un[1])*ADC2CURT; /* UV */
}
else if(g_bldc_motor1.step_sta == 0x06)
{
adc_amp_bus= (adc_amp_un[0]+ adc_amp_un[2])*ADC2CURT; /* WU */
}
else if(g_bldc_motor1.step_sta == 0x04)
{
adc_amp_bus= (adc_amp_un[2]+ adc_amp_un[1])*ADC2CURT; /* WV */
}
/******************************* 六步换向 *******************************/
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_j++; /* 计算速度专用计数值 */
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_j);
else
temp_speed = -(SPEED_COEFF/g_bldc_motor1.count_j);
FirstOrderRC_LPF(g_bldc_motor1.speed,temp_speed,0.2379);
g_bldc_motor1.no_single = 0;
g_bldc_motor1.count_j = 0;
}
if(g_bldc_motor1.hall_sta_edge == 1)
{
g_bldc_motor1.no_single = 0;
g_bldc_motor1.count_j = 0;
}
if(g_bldc_motor1.hall_sta_edge == 2) /* 霍尔值一直不变代表未换向 */
{
g_bldc_motor1.no_single++; /* 不换相时间累计 超时则判定速度为0 */
if(g_bldc_motor1.no_single > 15000)
{
g_bldc_motor1.no_single = 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 = 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 */
if(g_bldc_motor1.hall_keep_t > 15000) /* 堵转 */
{
g_bldc_motor1.hall_keep_t = 0;
#if LOCK_TAC
stop_motor1();
g_bldc_motor1.run_flag = STOP;; /* 标记停机 */
g_bldc_motor1.pwm_duty = 0;
#endif
g_bldc_motor1.locked_rotor = 1; /* 标记堵转 */
}
}
/******************************* PID控制 *******************************/
if(g_bldc_motor1.run_flag == RUN) /* 进入PID闭环控制 */
{
pid_c_count++;
pid_s_count++;
if(pid_s_count > 2)
{
/******************************* PID计算 *******************************/
temp_pwm1 = increment_pid_ctrl(&g_speed_pid,g_bldc_motor1.speed); /* 速度环PID的控制 */
FirstOrderRC_LPF(motor_pwm_s,temp_pwm1,0.085); /* 一阶 */
if(motor_pwm_s < 0)
{
motor_pwm_sl = -motor_pwm_s;
}
else
{
motor_pwm_sl = motor_pwm_s;
}
*user_setpoint = debug_data_temp; /* 重新保持上位机指令要求 */
pid_s_count = 0;
}
if(pid_c_count > 1) /* 电流环 */
{
/* 换向尖峰电流大于设定的电流值将导致PID调节转至电流环调节 速度环无法起作用,转速无法调节 */
if(adc_amp_bus > (g_current_pid.SetPoint - 20))
{
cf_count++; /* 滤除换向尖峰电流的影响 */
if(cf_count > 4)
{
cf_count = 0;
temp_pwm2 = increment_pid_ctrl(&g_current_pid,adc_amp_bus); /* 电流环PID计算 */
FirstOrderRC_LPF(motor_pwm_c,temp_pwm2,0.085);/* 一阶数字滤波 滤波系数0.08 */
}
}
else
{
cf_count = 0;
temp_pwm2 = increment_pid_ctrl(&g_current_pid,adc_amp_bus);
FirstOrderRC_LPF(motor_pwm_c,temp_pwm2,0.085);
}
pid_c_count = 0;
}
/* 电流环输出值大于速度环输出则使用速度环调节 */
if(motor_pwm_c > motor_pwm_sl)
{
g_bldc_motor1.pwm_duty = motor_pwm_sl;
if(motor_pwm_s < 0) /* 正反转积分控制 */
g_current_pid.Ui = -g_speed_pid.Ui; /* 速度环积分给电流环 */
else
g_current_pid.Ui = g_speed_pid.Ui;
}
else /* 速度环输出值大于电流环输出则使用电流环调节 */
{
g_bldc_motor1.pwm_duty = motor_pwm_c;
if(motor_pwm_s < 0)
g_speed_pid.Ui = -g_current_pid.Ui;/* 电流环积分给速度环 */
else
g_speed_pid.Ui = g_current_pid.Ui;
}
}
}
}
if(htim->Instance == TIM6)
{
/******************************* 采集电机停机状态下的偏置电压 *******************************/
times_count++;
if(g_bldc_motor1.run_flag == STOP)
{
uint8_t i;
uint32_t avg[3] = {0,0,0};
adc_amp_offset[0][adc_amp_offset_p] = g_adc_val[2]; /* 得到还未开始运动时三相的基准电压 */
adc_amp_offset[1][adc_amp_offset_p] = g_adc_val[3];
adc_amp_offset[2][adc_amp_offset_p] = g_adc_val[4];
adc_amp_offset_p++;
NUM_CLEAR(adc_amp_offset_p,ADC_AMP_OFFSET_TIMES); /* 最大采集ADC_AMP_OFFSET_TIMES次,超过即从0开始继续采集 */
for(i = 0; i < ADC_AMP_OFFSET_TIMES; i++) /* 将采集的每个通道值累加 */
{
avg[0] += adc_amp_offset[0][i];
avg[1] += adc_amp_offset[1][i];
avg[2] += adc_amp_offset[2][i];
}
for(i = 0; i < 3; i++) /* 取平均即软件滤波 */
{
avg[i] /= ADC_AMP_OFFSET_TIMES;
adc_amp_offset[i][ADC_AMP_OFFSET_TIMES] = avg[i]; /* 得到还未开始运动时的基准电压 */
}
}
/******************************* 定时判断电机是否发生堵塞 *******************************/
if(times_count == SMAPLSE_PID_SPEED)
{
#if (LOCK_TAC == 2)
if(g_bldc_motor1.locked_rotor == 1) /* 堵转处理,当到达一定速度后可进入闭环控制 */
{
clc++;
if(clc > 50) /* 延迟2s后重新启动 */
{
#if DEBUG_ENABLE /*开启调试*/
debug_send_motorstate(RUN_STATE); /* 电机运行*/
#endif
clc = 0;
pid_init();
stop_motor1();
g_speed_pid.SetPoint = 400.0; /* 400PRM */
g_bldc_motor1.pwm_duty = 500; /* 加速启动速度 */
g_bldc_motor1.run_flag = RUN; /* 开启运行 */
start_motor1(); /* 运行电机 */
g_bldc_motor1.locked_rotor = 0;
}
}
#endif
times_count = 0;
}
}
}
霍尔传感器.h
#ifndef __BLDC_H
#define __BLDC_H
#include "./SYSTEM/sys/sys.h"
/******************************************************************************************/
typedef struct
{
__IO uint8_t run_flag; /* 运行标志 */
__IO uint8_t locked_rotor; /* 堵转标记 */
__IO uint8_t step_sta; /* 本次霍尔状态 */
__IO uint8_t hall_single_sta;/* 单个霍尔状态 */
__IO uint8_t hall_sta_edge; /* 单个霍尔状态跳变 */
__IO uint8_t step_last; /* 上次霍尔状态 */
__IO uint8_t dir; /* 电机旋转方向 */
__IO int32_t pos; /* 电机位置 */
__IO int32_t speed; /* 电机速度 */
__IO int16_t current; /* 电机速度 */
__IO uint16_t pwm_duty; /* 电机占空比 */
__IO uint32_t hall_keep_t; /* 霍尔保持时间 */
__IO uint32_t hall_pul_num; /* 霍尔传感器脉冲数 */
__IO uint32_t lock_time; /* 电机堵转时间 */
__IO uint32_t no_single;
__IO uint32_t count_j;
__IO uint64_t sum_pos;
} _bldc_obj;
/******************************************************************************************/
#define MOTOR_1 1
#define MOTOR_2 2
extern _bldc_obj g_bldc_motor1;
/********************************************************************************************/
/*刹车引脚*/
#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 (((168000/18) - 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) /* 电机停机标志 */
#define LOCK_TAC 2 /* 堵转处理:2为开启,其他关闭 */
#define SPEED_COEFF (uint32_t)((18000/4)*60) /* 旋转一圈变化4个信号,2对级永磁体特性,NSNS共4级数*/
#define ADC2CURT (float)(3.3f/4.096f/0.12f)
#define ADC2VBUS (float)(3.3f*25/4096)
#define NUM_CLEAR(para,val) {if(para >= val){para=0;}}
#define NUM_MAX_LIMIT(para,val) {if(para > val){para=val;}}
#define NUM_MIN_LIMIT(para,val) {if(para < val){para=val;}}
typedef void(*pctr) (void);
void stop_motor1(void);
void start_motor1(void);
#define FirstOrderRC_LPF(Yn_1,Xn,a) Yn_1 = (1-a)*Yn_1 + a*Xn; /* Yn:out;Xn:in;a:系数 */
/******************************************************************************************/
/* 外部接口函数*/
void bldc_init(uint16_t arr, uint16_t psc); /* BLDC初始化 */
uint8_t check_hall_dir(_bldc_obj * obj); /* 检测电机旋转方向 */
extern pctr pfunclist_m1[6]; /* 六步换相函数指针数组 */
void bldc_ctrl(uint8_t motor_id,int32_t dir,float duty); /* bldc控制函数 */
uint8_t uemf_edge(uint8_t val); /* 波形状态检测 */
float get_temp(uint16_t para); /* 获取温度值 */
void calc_adc_val(uint16_t * p); /* adc数据软件滤波函数 */
void hall_gpio_init(void); /* 霍尔接口初始化 */
uint32_t hallsensor_get_state(uint8_t motor_id); /* 获取霍尔状态 */
/* 六步换相 */
void m1_uhvl(void);
void m1_uhwl(void);
void m1_vhwl(void);
void m1_vhul(void);
void m1_whul(void);
void m1_whvl(void);
#endif
霍尔传感器.C
#include "./BSP/BLDC/bldc.h"
#include "./BSP/TIMER/bldc_tim.h"
#include "./BSP/ADC/adc.h"
#include "math.h"
_bldc_obj g_bldc_motor1 = {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);
btim_timx_int_init(1000 - 1 , 84 - 1);
}
/**
* @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; /* 占空比 */
}
}
/**
* @brief 旋转方向检测函数
* @param obj:电机控制句柄
* @retval 旋转方向定义如下:
* 正转,CW
* 反转,CCW
*/
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();
/* 霍尔通道 1 引脚初始化 */
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);
}
/**
* @brief 获取霍尔传感器引脚状态
* @param 无
* @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;
g_bldc_motor1.hall_single_sta=1;
}
else
g_bldc_motor1.hall_single_sta=0;
}
return State;
}
/************************************* BLDC相关函数 *************************************/
/* 关闭电机运转 */
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);
}
/*****************************************************************************************/
/* 六步换向函数指针 */
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);
}
/**
* @brief 检测输入信号是否发生变化
* @param val :输入信号
* @note 测量速度使用,获取输入信号状态翻转情况,计算速度
* @retval 0:计算高电平时间,1:计算低电平时间,2:信号未改变
*/
uint8_t uemf_edge(uint8_t val)
{
/* 主要是检测val信号从0 - 1 在从 1 - 0的过程,即高电平所持续的过程 */
static uint8_t oldval=0;
if(oldval != val)
{
oldval = val;
if(val == 0) return 0;
else return 1;
}
return 2;
}
/************************************* 第二部分 电压电流温度采集 **********************************************/
/*
Rt = Rp *exp(B*(1/T1-1/T2))
Rt 是热敏电阻在T1温度下的阻值;
Rp是热敏电阻在T2常温下的标称阻值;
exp是e的n次方,e是自然常数,就是自然对数的底数,近似等于 2.7182818;
B值是热敏电阻的重要参数,教程中用到的热敏电阻B值为3380;
这里T1和T2指的是开尔文温度,T2是常温25℃,即(273.15+25)K
T1就是所求的温度
*/
const float Rp = 10000.0f; /* 10K */
const float T2 = (273.15f + 25.0f); /* T2 */
const float Bx = 3380.0f; /* B */
const float Ka = 273.15f;
/**
* @brief 计算温度值
* @param para: 温度采集对应ADC通道的值(已滤波)
* @note 计算温度分为两步:
1.根据ADC采集到的值计算当前对应的Rt
2.根据Rt计算对应的温度值
* @retval 温度值
*/
float get_temp(uint16_t para)
{
float Rt;
float temp;
Rt = 3.3f / (para * 3.3f / 4096.0f / 4700.0f) - 4700.0f;
/* like this R=5000, T2=273.15+25,B=3470, RT=5000*EXP(3470*(1/T1-1/(273.15+25)) */
temp = Rt / Rp;
temp = log(temp); /* ln(Rt/Rp) */
temp /= Bx; /* ln(Rt/Rp)/B */
temp += (1.0f / T2);
temp = 1.0f / (temp);
temp -= Ka;
return temp;
}
extern uint16_t g_adc_value[ADC_CH_NUM * ADC_COLL];
/**
* @brief 计算ADC的平均值(滤波)
* @param * p :存放ADC值的指针地址
* @note 此函数对电压、温度、电流对应的ADC值进行滤波
* @retval 无
*/
void calc_adc_val(uint16_t * p)
{
uint32_t temp[ADC_CH_NUM] = {0,0,0}; /* 定义一个缓存数组 */
int i,j; /* 循环采集ADC_COLL次数 */
for(i=0;i<ADC_COLL;i++) /* 根据ADC通道数循环获取,并累加 */
{
for(j=0;j<ADC_CH_NUM;j++) /* 将采集到的ADC值,各通道进行累加 */
{
temp[j] += g_adc_value[j+i*ADC_CH_NUM];
}
}
for(j=0;j<ADC_CH_NUM;j++)
{
temp[j] /= ADC_COLL; /* 获取平均值 */
p[j] = temp[j]; /* 存到*p */
}
}
ADC.h
#ifndef __ADC_H
#define __ADC_H
#include "./SYSTEM/sys/sys.h"
/******************************************************************************************/
/* 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
extern uint16_t g_adc_val[ADC_CH_NUM];
/******************************************************************************************/
void adc_init(void); /* ADC初始化 */
uint32_t adc_get_result_average(uint8_t ch); /* 获得某个通道值 */
void adc_nch_dma_init(void);
#endif
ADC.c
#include "./BSP/ADC/adc.h"
#include "./SYSTEM/delay/delay.h"
#include "./BSP/DMA/dma.h"
#include "./BSP/BLDC/bldc.h"
#include "./BSP/TIMER/bldc_tim.h"
/* 多通道ADC采集 DMA读取 */
ADC_HandleTypeDef g_adc_nch_dma_handle; /* 与DMA关联的ADC句柄 */
DMA_HandleTypeDef g_dma_nch_adc_handle; /* 与ADC关联的DMA句柄 */
uint8_t g_adc_dma_sta = 0; /* DMA传输状态标志, 0,未完成; 1, 已完成 */
uint16_t g_adc_value[ADC_CH_NUM * ADC_COLL] = {0}; /* 存储ADC原始值 */
float g_adc_u_value[ADC_CH_NUM] = {0}; /* 存储ADC转换后的电压值 */
/***************************************多通道ADC采集(DMA读取)程序*****************************************/
/**
* @brief ADC初始化
* @param 无
* @retval 无
*/
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_28CYCLES;
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; /* 返回平均值 */
}
pid.h
#ifndef __PID_H
#define __PID_H
#include "./SYSTEM/sys/sys.h"
/************************************ PID相关参数 ****************************************/
#define C_KP 2.00f /* P参数 */
#define C_KI 0.20f /* I参数 */
#define C_KD 0.01f /* D参数 */
#define S_KP 0.00800f /* P参数 */
#define S_KI 0.00025f /* I参数 */
#define S_KD 0.00020f /* D参数 */
#define SMAPLSE_PID_SPEED 40 /* 采样率 单位ms */
/*PID结构体*/
typedef struct
{
__IO float SetPoint; /* 设定目标 */
__IO float ActualValue; /* 实际值 */
__IO float SumError; /* 误差累计 */
__IO float Up; /* 比例项 */
__IO float Ui; /* 积分项 */
__IO float Ud; /* 微分项 */
__IO float Proportion; /* 比例常数 P */
__IO float Integral; /* 积分常数 I */
__IO float Derivative; /* 微分常数 D */
__IO float Error; /* Error[-1] */
__IO float LastError; /* Error[-1] */
__IO float PrevError; /* Error[-2] */
__IO float IngMin;
__IO float IngMax;
__IO float OutMin;
__IO float OutMax;
} PID_TypeDef;
#define LIMIT_OUT(var,max,min) {(var)=(var)>(max)?(max):(var);(var)=(var)<(min)?(min):(var);}
extern PID_TypeDef g_current_pid; /* 电流PID参数结构体 */
extern PID_TypeDef g_speed_pid; /* 速度PID参数结构体 */
/*********************************** 函数声明 **************************************/
void pid_init(void); /* PID初始化函数 */
int32_t increment_pid_ctrl(PID_TypeDef *PID,float Feedback_value); /* PID控制算法 */
#endif
pid.c
#include "./BSP/PID/pid.h"
#include "./BSP/BLDC/bldc.h"
PID_TypeDef g_current_pid; /* 电流PID参数结构体 */
PID_TypeDef g_speed_pid; /* 速度PID参数结构体 */
/**
* @brief 初始化PID
* @param 无
* @retval 无
*/
void pid_init(void)
{
/* 设定电流目标1500mA(空载最小电流400mA左右)较高的转速对应的电流较大,力矩较大,可适应较高的转速调节*/
/* 【注意】如设置的转速对应的电流超过了电流设定值,将导致PID转至电流环调节,转速将无法继续提升 */
g_current_pid.SetPoint = 1500.0;
g_current_pid.ActualValue = 0.0; /* 设定目标Desired Value */
g_current_pid.LastError = 0.0; /* Error[1] */
g_current_pid.LastError = 0.0; /* Error[-1] */
g_current_pid.PrevError = 0.0; /* Error[-2] */
g_current_pid.Proportion = C_KP; /* 比例常数 Proportional Const */
g_current_pid.Integral = C_KI; /* 积分常数 Integral Const */
g_current_pid.Derivative = C_KD; /* 微分常数 Derivative Const */
g_current_pid.IngMax = 9000; /* 积分限制 */
g_current_pid.IngMin = 600;
g_current_pid.OutMin = 600;
g_current_pid.OutMax = 9000; /* 期望限制 */
g_speed_pid.SetPoint = 0; /* 设定目标Desired Value */
g_speed_pid.ActualValue = 0.0; /* 设定目标Desired Value */
g_speed_pid.Ui = 0.0;
g_speed_pid.Up = 0.0;
g_speed_pid.Ud = 0.0;
g_speed_pid.Error = 0.0; /* Error[1] */
g_speed_pid.LastError = 0.0; /* Error[-1] */
g_speed_pid.PrevError = 0.0; /* Error[-2] */
g_speed_pid.Proportion = S_KP; /* 比例常数 Proportional Const */
g_speed_pid.Integral = S_KI; /* 积分常数 Integral Const */
g_speed_pid.Derivative = S_KD; /* 微分常数 Derivative Const */
g_speed_pid.IngMax = 9000;
g_speed_pid.IngMin = -9000;
g_speed_pid.OutMax = 9000; /* 输出限制 */
g_speed_pid.OutMin = -9000;
}
/**
* @brief 位置式PID算法
* @param *PID:PID结构体句柄所对应的目标值
* @param Feedback_value : 实际值
* @retval 目标控制量
*/
int32_t increment_pid_ctrl(PID_TypeDef *PID,float Feedback_value)
{
PID->Error = (float)(PID->SetPoint - Feedback_value); /* 目标值与实际值的偏差值 */
PID->Up = PID->Proportion * PID->Error;
PID->Ui += (PID->Error * PID->Integral);
LIMIT_OUT(PID->Ui,PID->IngMax,PID->IngMin); /* 积分限制 */
PID->Ud = PID->Derivative * (PID->Error - PID->LastError);
PID->ActualValue = PID->Up + PID->Ui + PID->Ud;
LIMIT_OUT(PID->ActualValue,PID->OutMax,PID->OutMin); /* 输出限制 */
PID->LastError = PID->Error; /* 存储上次误差,以便下次计算使用 */
return ((int32_t)(PID->ActualValue)); /* 返回实际控制数值 */
}
main.c
#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"
#include "./BSP/LED/led.h"
#include "./BSP/TIMER/bldc_tim.h"
#include "./BSP/KEY/key.h"
#include "./BSP/LCD/lcd.h"
#include "./BSP/BLDC/bldc.h"
#include "./BSP/PID/pid.h"
#include "./DEBUG/debug.h"
#include "./BSP/ADC/adc.h"
extern float*user_setpoint;
extern float debug_data_temp;
extern int32_t motor_pwm_s;
extern int32_t temp_pwm1;
extern int16_t adc_amp_un[3];
extern float adc_amp_bus;
extern uint16_t g_adc_value[ADC_CH_NUM * ADC_COLL];
extern uint8_t clc;
void bldc_speed_stop(void); /* 清除电机状态并关闭电机 */
int main(void)
{
uint8_t debug_cmd = 0; /* 存放上位机指令 */
float current_lpf[4] = {0.0f}; /* 存放三相电流以及母线电流 */
uint8_t key,t;
char buf[32];
float current[3] = {0.0f};
int16_t speed_diplay = 0;
float user_setpoint_temp = 0.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(168000/18-1,0); /* 18KHz */
bldc_ctrl(MOTOR_1,CCW,0); /* 初始无刷电机接口1速度 */
pid_init();
g_point_color = WHITE;
g_back_color = BLACK;
adc_nch_dma_init();
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);
user_setpoint_temp = (*user_setpoint);
speed_diplay = g_bldc_motor1.speed;
sprintf(buf,"SetSpeed:%4d ",(int16_t)user_setpoint_temp); /* 显示设置速度 */
lcd_show_string(10,110,200,16,16,buf,g_point_color);
sprintf(buf,"M1 speed:%4d ",speed_diplay); /* 显示转速 */
lcd_show_string(10,130,200,16,16,buf,g_point_color);
sprintf(buf,"M1 pos:%4d",g_bldc_motor1.pos); /* 显示位置变化 */
lcd_show_string(10,150,200,16,16,buf,g_point_color);
sprintf(buf,"PWM_Duty:%.1f%% ",(float)((g_bldc_motor1.pwm_duty/(float)MAX_PWM_DUTY)*100)); /* 显示控制PWM占空比 */
lcd_show_string(10,170,200,16,16,buf,g_point_color);
sprintf(buf,"Power:%.3fV ",g_adc_value[0]*ADC2VBUS);
lcd_show_string(10,190,200,16,16,buf,g_point_color);
sprintf(buf,"Temp:%.1fC ",get_temp(g_adc_value[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);
FirstOrderRC_LPF(current_lpf[1],current[1],0.1f);
FirstOrderRC_LPF(current_lpf[2],current[2],0.1f);
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;
}
}
key = key_scan(0);
if(key == KEY0_PRES) /* 按下KEY0目标速度值++ */
{
g_bldc_motor1.run_flag = RUN; /* 开启运行 */
start_motor1(); /* 开启运行 */
if(g_bldc_motor1.dir == CCW && *user_setpoint == 0) /* 切换方向条件*/
{
g_bldc_motor1.dir = CW;
}
*user_setpoint += 400; /* 逆时针旋转下递增 */
if(*user_setpoint >= 3000) /* 最高不超过3000PRM */
*user_setpoint = 3000;
if(*user_setpoint == 0)
{
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;
}
debug_data_temp = *user_setpoint;
}
else if(key == KEY1_PRES) /* 按下KEY1目标速度值-- */
{
g_bldc_motor1.run_flag = RUN; /* 开启运行 */
start_motor1(); /* 运行电机 */
/* 切换方向条件 */
if(g_bldc_motor1.dir == CW && *user_setpoint == 0)
{
g_bldc_motor1.dir = CCW;
}
*user_setpoint -= 400; /* 逆时针旋转下递增 */
if(*user_setpoint <= -3000) /* 最高不超过300PRM */
*user_setpoint = -3000;
if(*user_setpoint == 0)
{
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;
}
debug_data_temp = *user_setpoint;
}
else if(key == KEY2_PRES) /* 按下KEY2关闭电机 */
{
bldc_speed_stop();
}
delay_ms(10);
}
}
/**
* @brief 关闭电机并清除状态
* @param 无
* @retval 无
*/
void bldc_speed_stop(void)
{
pid_init();
g_bldc_motor1.run_flag = STOP; /* 标记停机 */
stop_motor1(); /* 停机 */
g_bldc_motor1.speed = 0;
motor_pwm_s = 0;
g_bldc_motor1.pwm_duty = 0;
}
g_bldc_motor1.count_j就是高电平的计数值。在高电平时先清零累加。从1到0为低电平时。后去 g_bldc_motor1.count_j的值就是高电平的计数值。
#define SPEED_COEFF (uint32_t)((18000/4)*60) /* 旋转一圈变化4个信号,2对级永磁体特性,NSNS共4级数 */
速度计算:temp_speed = (SPEED_COEFF/g_bldc_motor1.count_j)
速度的计算在代码的体现:电机是两对极。完全与公式是相同的。