单片机 STM32F407开发板DMF407电机开发板平台keil V5.31HSE 为8MHZHSI为16MHZ第一步当只有一对级时转子旋转一圈霍尔输出一个完整脉冲其中高电平与低电平持续时间均为180°电角度第二步计算其中高电平的持续时间即t C / Ft其中t为180°电角度所代表的时间Ft是霍尔脉冲的频率C为计数次数第三步所以旋转一圈需要的总时间为T 2*C/Ft第四步所得出的结果单位为s/圈 倒数即为圈/s需将其单位转化为RPM即Ft/2*C*60。第五步当转子为2对级时霍尔输出的高低电平时间均为360°电角度所以速度公式为Ft/(4*C)*60。主函数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}; 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); bldc_ctrl(MOTOR_1,CCW,0); /* 初始无刷电机接口1速度 */ pid_init(); g_point_color WHITE; g_back_color BLACK; lcd_show_string(10,10,240,24,24,BLDC Motor Test,g_point_color); lcd_show_string(10,40,200,16,16,KEY0:Step,g_point_color); lcd_show_string(10,60,200,16,16,KEY1:Step--,g_point_color); lcd_show_string(10,80,200,16,16,KEY2:Stop,g_point_color); adc_nch_dma_init(); #if DEBUG_ENABLE /* 开启调试*/ debug_init(); /* PID调试初始化*/ debug_send_motorcode(BLDC_MOTOR ); /* 直流无刷电机 */ debug_send_motorstate(IDLE_STATE); /* 电机空闲 */ /* 初始化同步数据选择第x组PIDX,目标速度地址,P,I,D参数到上位机 */ debug_send_initdata(TYPE_PID1,(float*)(g_speed_pid.SetPoint),S_KP,S_KI,S_KD);/* 速度环PID参数PID1*/ #endif 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,100,200,16,16,buf,g_point_color); sprintf(buf,SetSpeed:%4d ,(int16_t)*user_setpoint); /* 显示设置速度 */ lcd_show_string(10,120,200,16,16,buf,g_point_color); sprintf(buf,M1 Speed:%4d ,(int16_t)g_bldc_motor1.speed); lcd_show_string(10,140,200,16,16,buf,g_point_color); /* 显示测量速度 */ sprintf(buf,M1 pos:%4d,g_bldc_motor1.pos); lcd_show_string(10,160,200,16,16,buf,g_point_color); /* 显示位置变化 */ sprintf(buf,Power:%.3fV ,g_adc_value[0]*ADC2VBUS); lcd_show_string(10,180,200,16,16,buf,g_point_color); /* 显示电源电压 */ sprintf(buf,Temp:%.1fC ,get_temp(g_adc_value[1])); lcd_show_string(10,200,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; } 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)adc_amp_bus); lcd_show_string(10,290,200,16,16,buf,g_point_color); } key key_scan(0); if(key KEY0_PRES) /* 按下KEY1速度目标值 */ { g_bldc_motor1.run_flag RUN; /* 开启运行 */ start_motor1(); /* 开启运行 */ if(*user_setpoint 0 g_bldc_motor1.dir CCW) { pid_init(); /* 换向时刻重新初始化PID防止速度突变 */ g_bldc_motor1.dir CW; } *user_setpoint 400; /* 顺时针旋转下递增 */ if(*user_setpoint 4000) *user_setpoint 4000; if(*user_setpoint 0) { g_bldc_motor1.run_flag STOP; stop_motor1(); /* 停机 */ g_bldc_motor1.speed 0; motor_pwm_s 0; g_bldc_motor1.pwm_duty 0; } } else if(key KEY1_PRES) /* 按下KEY1速度目标值-- */ { g_bldc_motor1.run_flag RUN; /* 开启运行 */ start_motor1(); /* 开启运行 */ if(*user_setpoint 0 g_bldc_motor1.dir CW) { pid_init(); g_bldc_motor1.dir CCW; } *user_setpoint - 400; /* 逆时针旋转下递增 */ if(*user_setpoint -4000) *user_setpoint -4000; if(*user_setpoint 0) { g_bldc_motor1.run_flag STOP; stop_motor1(); /* 停机 */ g_bldc_motor1.speed 0; motor_pwm_s 0; g_bldc_motor1.pwm_duty 0; } } else if(key KEY2_PRES) /* 按下KEY2关闭电机 */ { bldc_speed_stop(); /* 清除电机状态并关闭电机 */ } #if DEBUG_ENABLE /* Debug发送部分 */ /* 主要显示参数 */ debug_send_valtage(g_adc_value[0] * ADC2VBUS); /* 发送电压 */ debug_send_speed(g_bldc_motor1.speed); /* 发送速度 */ debug_send_temp(50,get_temp(g_adc_value[1])); /* 发送电机温度、驱动板温度 */ debug_send_current((float)(current_lpf[0]/1000),(float)(current_lpf[0]/1000),(float)(current_lpf[0]/1000)); /* 发送电流 */ /* 电流波形和速度波形 */ debug_send_wave_data(1,(int16_t)g_bldc_motor1.speed); /* 选择通道1 发送实际速度 */ debug_send_wave_data(2,(int16_t)*user_setpoint); /* 选择通道2 发送实际速度 */ debug_send_wave_data(3,current_lpf[0]); /* 选择通道3 发送实际电流U */ debug_send_wave_data(4,current_lpf[1]); /* 选择通道4 发送实际电流V */ debug_send_wave_data(5,current_lpf[2]); /* 选择通道5 发送实际电流W */ debug_send_wave_data(6,current_lpf[3]); /* 选择通道6 发送实际母线电流 */ /* Debug接收部分 */ debug_receive_pid(TYPE_PID1,(float*)g_speed_pid.Proportion,/* 查询接收PID助手的PID1参数 */ (float*)g_speed_pid.Integral,(float*)g_speed_pid.Derivative); debug_cmd debug_receive_ctrl_code(); /* 读取命令 */ if(debug_cmd HALT_CODE) /* 停机 */ { 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; } else if(debug_cmd RUN_CODE) /* 运行 */ { g_bldc_motor1.dir CW; g_bldc_motor1.run_flag RUN; /* 运行标记 */ *user_setpoint 400; /* 自动设置目标 */ start_motor1(); /* 启动电机 */ debug_send_motorstate(RUN_STATE); /* 电机运行 */ } else if (debug_cmd BREAKED) /* 刹车电机停止 点击电机运行才可解除 */ { *user_setpoint 0; /* 减速直至0 */ debug_send_motorstate(BREAKED_STATE); /* 电机刹车 */ } #endif delay_ms(10); } } /** * brief 清除电机状态并关闭电机 * param 无 * retval 无 */ void 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; }PIDvoid pid_init(void) { g_speed_pid.SetPoint 0; /* 设定目标值 */ g_speed_pid.ActualValue 0.0; /* 期望值输出 */ g_speed_pid.SumError 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 20; g_speed_pid.IngMin -20; g_speed_pid.OutMax 150; /* 输出限制 */ g_speed_pid.OutMin -150; } /** * brief 闭环PID控制算法设计 * note 通过宏 INCR_LOCT_SELECT 选择使用位置式算法/增量式算法 * param *PIDPID结构体句柄所对应的目标值 * param Feedback_value 实际值 * retval 目标控制量 */ int32_t increment_pid_ctrl(PID_TypeDef *PID,float Feedback_value) { PID-Error (float)(PID-SetPoint - Feedback_value); /* 速度档位偏差*/ #if INCR_LOCT_SELECT PID-ActualValue (PID-Proportion * (PID-Error - PID-LastError)) /* E[k]项*/ (PID-Integral * PID-Error) /* E[k-1]项*/ (PID-Derivative * (PID-Error - 2 * PID-LastError PID-PrevError)); /*E[k-2]项*/ PID-PrevError PID-LastError; /* 存储误差用于下次计算*/ PID-LastError PID-Error; #else PID-SumError PID-Error; PID-ActualValue (PID-Proportion * PID-Error) /* E[k]项*/ (PID-Integral * PID-SumError) /* E[k-1]项*/ (PID-Derivative * (PID-Error - PID-LastError)); /* E[k-2]项*/ PID-LastError PID-Error; #endif return ((int32_t)(PID-ActualValue)); /* 返回实际控制数值*/ }定时器void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { uint8_t i; uint8_t bldc_dir0; static uint8_t times_count0; /* 定时器时间记录 */ int16_t temp_speed0; /* 临时速度存储 */ if(htim-Instance ATIM_TIMX_PWM) /* 55us */ { /******************************* 六步换向 *******************************/ 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; } /******************************* 速度计算 *******************************/ 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.2379f); /* 一阶滤波 */ g_bldc_motor1.no_single 0; g_bldc_motor1.count_j 0; } if(g_bldc_motor1.hall_sta_edge 1) /* 当采集到下降沿时数据清0 */ { 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) { 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; } /******************************* 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) /* 判断正负值 */ { g_bldc_motor1.pwm_duty -motor_pwm_s; } else { g_bldc_motor1.pwm_duty motor_pwm_s; } /******************************* 三相电流计算 *******************************/ for(i0; i3; i) { adc_val_m1[i] g_adc_val[i2]; adc_amp[i] adc_val_m1[i] - adc_amp_offset[i][ADC_AMP_OFFSET_TIMES]; /* 运动状态ADC值 - 停机状态ADC值 实际作用ADC值 */ 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 */ } } } else 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); for(i0; iADC_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(i0; i3; i) { avg[i] / ADC_AMP_OFFSET_TIMES; /* 取平均 */ adc_amp_offset[i][ADC_AMP_OFFSET_TIMES] avg[i]; /* 赋值 */ } } } }测试结果速度环电流环控制主函数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; lcd_show_string(10,10,200,16,16,BLDC Motor Test,g_point_color); lcd_show_string(10,30,200,16,16,KEY0:Step,g_point_color); lcd_show_string(10,50,200,16,16,KEY1:Step--,g_point_color); lcd_show_string(10,70,200,16,16,KEY2:Stop,g_point_color); adc_nch_dma_init(); #if DEBUG_ENABLE /* 开启调试 */ debug_init(); /* PID调试初始化 */ debug_send_motorcode(BLDC_MOTOR); /* 直流电机 */ debug_send_motorstate(IDLE_STATE); /* 电机空闲 */ /* 初始化同步数据选择第x组PIDX,目标速度地址,P,I,D参数到上位机 */ debug_send_initdata(TYPE_PID1,(float*)(g_speed_pid.SetPoint),C_KP,C_KI,C_KD); /* 电流环PID参数PID1*/ debug_send_initdata(TYPE_PID2,(float*)(g_speed_pid.SetPoint),S_KP,S_KI,S_KD); /* 速度环PID参数PID2*/ #endif 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; } 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)adc_amp_bus); lcd_show_string(10,290,200,16,16,buf,g_point_color); } 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(); } #if DEBUG_ENABLE /* Debug发送部分 */ /* 主要显示参数 */ debug_send_valtage(g_adc_value[0] * ADC2VBUS); /* 发送电压*/ debug_send_speed(g_bldc_motor1.speed); /* 发送速度*/ debug_send_temp(50,get_temp(g_adc_value[1])); /* 发送电机温度、驱动板温度*/ debug_send_current((float)(current_lpf[0]/1000),(float)(current_lpf[0]/1000),(float)(current_lpf[0]/1000));/*发送电流*/ /* 电流波形和速度波形 */ debug_send_wave_data(1,(int16_t)g_bldc_motor1.speed); /* 选择通道1 发送实际速度 */ debug_send_wave_data(2,(int16_t)*user_setpoint); /* 选择通道2 发送目标速度 */ debug_send_wave_data(3,current_lpf[0]); /* 选择通道3 发送实际电流U */ debug_send_wave_data(4,current_lpf[1]); /* 选择通道4 发送实际电流V */ debug_send_wave_data(5,current_lpf[2]); /* 选择通道5 发送实际电流W */ debug_send_wave_data(7,current_lpf[3]); /* 选择通道7 发送实际电流 */ debug_send_wave_data(8,g_current_pid.SetPoint); /* 选择通道8 发送目标电流 */ /* Debug接收部分 */ debug_receive_pid(TYPE_PID1,(float*)g_current_pid.Proportion, /* 查询接收PID助手的PID1参数*/ (float*)g_current_pid.Integral,(float*)g_current_pid.Derivative); debug_receive_pid(TYPE_PID2,(float*)g_speed_pid.Proportion, /* 查询接收PID助手的PID2参数*/ (float*)g_speed_pid.Integral,(float*)g_speed_pid.Derivative); debug_cmd debug_receive_ctrl_code(); /* 读取命令 */ if(debug_cmd HALT_CODE) /* 停机 */ { 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; } else if(debug_cmd RUN_CODE) /* 运行 */ { g_bldc_motor1.run_flag RUN; /* 运行标记 */ *user_setpoint 400; /* 自动设置目标 */ debug_data_temp *user_setpoint; start_motor1(); /* 启动电机 */ debug_send_motorstate(RUN_STATE); /* 电机运行 */ } else if (debug_cmd BREAKED) /* 刹车电机停止 点击电机运行才可解除 */ { *user_setpoint 0; /* 减速直至0 */ debug_send_motorstate(BREAKED_STATE); /* 电机刹车 */ } #endif 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; }PIDvoid 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 *PIDPID结构体句柄所对应的目标值 * 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)); /* 返回实际控制数值 */ }void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { uint8_t i; uint8_t bldc_dir0; static uint8_t times_count0; /* 定时器时间记录 */ int16_t temp_speed0; /* 临时速度存储 */ if(htim-Instance ATIM_TIMX_PWM) /* 55us */ { if(g_bldc_motor1.run_flag RUN) { /******************************* 三相电流计算 *******************************/ for(i0; i3; i) { adc_val_m1[i] g_adc_val[i2]; /* 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执行之前对调节数值进行预先判断 */ #if DEBUG_ENABLE debug_set_point_range(3000,-3000,6000); /* 控制目标调节范围(3000~-3000)并且最大步进值不超过6000 RPM */ debug_data_temp *user_setpoint; if(*user_setpoint 0) /* 上位机指令欲切换旋转方向 */ { /* 为简化控制逻辑 只以电机状态作为判依据同步*/ if(g_bldc_motor1.speed 0) { g_bldc_motor1.dir CCW; } else if(g_bldc_motor1.dir CW g_bldc_motor1.speed ! 0)/* 当前状态不能立刻切换 */ { *user_setpoint 0; } } else if(*user_setpoint 0) { if(g_bldc_motor1.speed 0) { g_bldc_motor1.dir CW; } else if(g_bldc_motor1.dir CCW g_bldc_motor1.speed ! 0)/* 当前状态不能立刻切换 */ { *user_setpoint 0; } } #endif /******************************* PID计算 *******************************/ temp_pwm1 increment_pid_ctrl(g_speed_pid,g_bldc_motor1.speed); 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); 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; } } }测试结果