本帖最后由 瓜弟 于 2020-2-13 17:50 编辑
在某些场合下,使用的核心处理器不含电机控制相关外设,同时又对系统的实时性有较高要求,我们可以使用FPGA来实现这部分外设功能,如PWM生成、ADC输出采集与简单处理、电场角度判断等。本贴介绍利用Simulink与ModelSim联合仿真,实现BLDC六步方波闭环控制系统的仿真。
本仿真使用的软件如下:
MatLab 2018a;
ModelSim SE-64 10.04 (不同版本的Matlab对于ModelSim版本有具体要求)
Matlab与ModelSim的联合仿真配置过程可参考https://blog.csdn.net/u012151773/article/details/43833287 本文不再重述。
图1 电源、逆变桥、电机
图2 闭环控制环路
图3 转子转速、转子转角、电磁转矩
在图2中,左侧的speed_loop模块利用PI实现对电机转速的闭环控制,由图可见,目标转速为2000RPM。图2中间的BLDC_Controller实现六步换向的方波生成(非PWM),由于BLDC电机正反转逻辑不同,故在模块speed_loop与模块BLDC_Controller之间进行了目标转矩的方向判断。图2右边的ModelSim模块实现了PWM生成,该PWM生成后直接送入图1中的三项逆变桥中。
电流的闭环控制的计算比较简单,代码如下:
float speed_loop(float CurrentSpeed, float TargetSpeed)
{
par_SpeedLoopPID.Goal = TargetSpeed;
pid_calculate(&par_SpeedLoopPID, TargetSpeed - CurrentSpeed);
return (par_SpeedLoopPID.Output)/100;
}
其中,函数pid_calculate()与PID参数结构体如下
typedef struct PID_data_Struct
{
float Kp;
float Ki;
float Kd;
float Integral;
float Difference;
float IntegralHighLimit;
float Goal;
float Err;
float LastErr;
float Output;
} pid_data;
//////////////////////////////////////////////////////////////////////////////
void pid_calculate(pid_data * PidDat, float ErrDat)
{
PidDat->LastErr = PidDat->Err;
PidDat->Err = ErrDat;
PidDat->Difference = PidDat->Err - PidDat->LastErr;
PidDat->Integral = PidDat->Integral + PidDat->Err;
PidDat->Integral = (PidDat->Integral > PidDat->IntegralHighLimit)?
PidDat->IntegralHighLimit : PidDat->Integral;
PidDat->Integral = (PidDat->Integral < (-(PidDat->IntegralHighLimit)))?
(-(PidDat->IntegralHighLimit)) : PidDat->Integral;
PidDat->Output = PidDat->Kp * PidDat->Err
+ PidDat->Ki * PidDat->Integral
+ PidDat->Kd * PidDat->Difference;
}
模块BLDC_Controller中的六步换向序列生成的代码如下
void PWM_generator(int Angle, float Duty, unsigned char Direction,
char *A_duty, char *B_duty, char *C_duty)
{
Angle = Angle % 360;
if(Angle < 0)
Angle = Angle + 360;
if((Angle >= 330)||(Angle < 30))
{
if(Direction == ROTATION_DIRECTION_FORWARD)
{
*A_duty = 0;
*B_duty = 100 * Duty;
*C_duty = -1;
}
else
{
*A_duty = 0;
*B_duty = -1;
*C_duty = 100 * Duty;
}
}
else if((Angle >= 30) && (Angle <90))
{
if(Direction == ROTATION_DIRECTION_FORWARD)
{
*A_duty = -1;
*B_duty = 100 * Duty;
*C_duty = 0;
}
else
{
*A_duty = 100 * Duty;
*B_duty = -1;
*C_duty = 0;
}
}
else if((Angle >= 90) && (Angle <150))
{
if(Direction == ROTATION_DIRECTION_FORWARD)
{
*A_duty = -1;
*B_duty = 0;
*C_duty = 100 * Duty;
}
else
{
*A_duty = 100 * Duty;
*B_duty = 0;
*C_duty = -1;
}
}
else if((Angle >= 150) && (Angle <210))
{
if(Direction == ROTATION_DIRECTION_FORWARD)
{
*A_duty = 0;
*B_duty = -1;
*C_duty = 100 * Duty;
}
else
{
*A_duty = 0;
*B_duty = 100 * Duty;
*C_duty = -1;
}
}
else if((Angle >= 210) && (Angle <270))
{
if(Direction == ROTATION_DIRECTION_FORWARD)
{
*A_duty = 100 * Duty;
*B_duty = -1;
*C_duty = 0;
}
else
{
*A_duty = -1;
*B_duty = 100 * Duty;
*C_duty = 0;
}
}
else if((Angle >= 270) && (Angle <330))
{
if(Direction == ROTATION_DIRECTION_FORWARD)
{
*A_duty = 100 * Duty;
*B_duty = 0;
*C_duty = -1;
}
else
{
*A_duty = -1;
*B_duty = 0;
*C_duty = 100 * Duty;
}
}
}
使用Verilog实现PWM生成的代码如下(懒得写死区控制)
`timescale 100ns/100ns
//PWM基波 20KHz
module six_step_PWM_generator
(
input wire[7:0] A_duty,
input wire[7:0] B_duty,
input wire[7:0] C_duty,
input wire RSTn,
input wire CLK_4MHz,
output wire At,
output wire Ab,
output wire Bt,
output wire Bb,
output wire Ct,
output wire Cb
);
parameter DeadZoneTime = 4; //4*250ns = 1us;
parameter PWM_CounterMax = 99;
reg[7:0] A_reg;
reg[7:0] B_reg;
reg[7:0] C_reg;
reg At_reg;
reg Ab_reg;
reg Bt_reg;
reg Bb_reg;
reg Ct_reg;
reg Cb_reg;
reg[7:0] PWM_Counter;
reg PWM_Counter_UpDown; //1: up; 0: down
always @(posedge CLK_4MHz)
begin
if(PWM_Counter_UpDown)
begin
PWM_Counter = PWM_Counter + 8'h01;
if(PWM_Counter >= 8'd99)
begin
PWM_Counter_UpDown = 1'b0;
end
end
else
begin
PWM_Counter = PWM_Counter - 8'h01;
if(PWM_Counter == 8'h00)
begin
PWM_Counter_UpDown = 1'b1;
end
end
end
initial
begin
A_reg = 8'h00;
B_reg = 8'h00;
C_reg = 8'h00;
At_reg = 1'b0;
Ab_reg = 1'b0;
Bt_reg = 1'b0;
Bb_reg = 1'b0;
Ct_reg = 1'b0;
Cb_reg = 1'b0;
PWM_Counter = 7'h00;
PWM_Counter_UpDown = 1'b1;
end
always @ (negedge RSTn)
begin
A_reg = 8'h00;
B_reg = 8'h00;
C_reg = 8'h00;
At_reg = 1'b0;
Ab_reg = 1'b0;
Bt_reg = 1'b0;
Bb_reg = 1'b0;
Ct_reg = 1'b0;
Cb_reg = 1'b0;
PWM_Counter = 7'h00;
PWM_Counter_UpDown = 1'b1;
end
assign At = At_reg;
assign Ab = Ab_reg;
assign Bt = Bt_reg;
assign Bb = Bb_reg;
assign Ct = Ct_reg;
assign Cb = Cb_reg;
always #1
begin
if(A_duty == 0)
begin
At_reg = 1'b0;
Ab_reg = 1'b0;
end
else if(A_duty == 8'hFF)
begin
At_reg = 1'b0;
Ab_reg = 1'b1;
end
else
begin
Ab_reg = 1'b0;
if(PWM_Counter < A_duty)
At_reg = 1'b1;
else
At_reg = 1'b0;
end
if(B_duty == 0)
begin
Bt_reg = 1'b0;
Bb_reg = 1'b0;
end
else if(B_duty == 8'hFF)
begin
Bt_reg = 1'b0;
Bb_reg = 1'b1;
end
else
begin
Bb_reg = 1'b0;
if(PWM_Counter < B_duty)
Bt_reg = 1'b1;
else
Bt_reg = 1'b0;
end
if(C_duty == 0)
begin
Ct_reg = 1'b0;
Cb_reg = 1'b0;
end
else if(C_duty == 8'hFF)
begin
Ct_reg = 1'b0;
Cb_reg = 1'b1;
end
else
begin
Cb_reg = 1'b0;
if(PWM_Counter < C_duty)
Ct_reg = 1'b1;
else
Ct_reg = 1'b0;
end
end
endmodule
通过上述代码,实现了BLDC电机的闭环控制。其中隐藏的问题,望各位指正!
此内容由EEWORLD论坛网友瓜弟原创,如需转载或用于商业用途需征得作者同意并注明出处