社区导航

 

搜索
查看: 526|回复: 10

[原创] Simulink与ModelSim联合仿真实现BLDC六步方波闭环控制系统

[复制链接]

18

TA的帖子

1

TA的资源

一粒金砂(中级)

Rank: 2

发表于 2020-2-13 17:30 | 显示全部楼层 |阅读模式
本帖最后由 瓜弟 于 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 本文不再重述。

电源、逆变、电机.JPG


图1 电源、逆变桥、电机

控制回路.JPG 图2 闭环控制环路

转子转速、转子转角、电磁转矩.JPG 图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论坛网友瓜弟原创,如需转载或用于商业用途需征得作者同意并注明出处

BLDC.zip

1.84 MB, 下载次数: 22

Simulink、ModelSim、BLDC

评分

1

查看全部评分



回复

使用道具 举报

1877

TA的帖子

1

TA的资源

五彩晶圆(初级)

Rank: 7Rank: 7Rank: 7

发表于 2020-2-13 21:10 | 显示全部楼层

问题是转起来了吗?来个动图。

点评

仿真呀,咋转呢?你是指实物?  详情 回复 发表于 2020-2-14 00:36
人已离开,无事别找,找也找不到。


回复

使用道具 举报

1877

TA的帖子

1

TA的资源

五彩晶圆(初级)

Rank: 7Rank: 7Rank: 7

发表于 2020-2-13 21:11 | 显示全部楼层

麻痹,仿真,,,应该也能仿真转圈吧

点评

第三张图的第二行,就是转子的转动角度随时间变化的呀,0~360°  详情 回复 发表于 2020-2-14 16:42
人已离开,无事别找,找也找不到。


回复

使用道具 举报

18

TA的帖子

1

TA的资源

一粒金砂(中级)

Rank: 2

 楼主| 发表于 2020-2-14 00:36 | 显示全部楼层
freebsder 发表于 2020-2-13 21:10 问题是转起来了吗?来个动图。

仿真呀,咋转呢?你是指实物?



回复

使用道具 举报

18

TA的帖子

1

TA的资源

一粒金砂(中级)

Rank: 2

 楼主| 发表于 2020-2-14 16:42 | 显示全部楼层
freebsder 发表于 2020-2-13 21:11 麻痹,仿真,,,应该也能仿真转圈吧

第三张图的第二行,就是转子的转动角度随时间变化的呀,0~360°



回复

使用道具 举报

6495

TA的帖子

4

TA的资源

版主

Rank: 6Rank: 6

发表于 2020-2-14 21:28 | 显示全部楼层

棒棒的!我来学习一下 

生活就是油盐酱醋再加一点糖,快活就是一天到晚乐呵呵的忙
===================================
做一个简单的人,踏实而务实,不沉溺幻想,不庸人自扰


回复

使用道具 举报

18

TA的帖子

1

TA的资源

一粒金砂(中级)

Rank: 2

 楼主| 发表于 2020-2-15 02:29 | 显示全部楼层
chenzhufly 发表于 2020-2-14 21:28 棒棒的!我来学习一下 

柱哥帮我看下,Verilog代码里,At_reg这个寄存器同时在两个always里赋值,为啥编译没报错?

点评

组合逻辑,算是正常使用  详情 回复 发表于 4 天前


回复

使用道具 举报

1877

TA的帖子

1

TA的资源

五彩晶圆(初级)

Rank: 7Rank: 7Rank: 7

发表于 2020-2-15 10:46 | 显示全部楼层

应该为瓜弟本篇受精。

人已离开,无事别找,找也找不到。


回复

使用道具 举报

18

TA的帖子

1

TA的资源

一粒金砂(中级)

Rank: 2

 楼主| 发表于 2020-2-15 14:39 | 显示全部楼层
freebsder 发表于 2020-2-15 10:46 应该为瓜弟本篇受精。



回复

使用道具 举报

65

TA的帖子

1

TA的资源

一粒金砂(中级)

Rank: 2

发表于 2020-2-16 10:00 | 显示全部楼层

不错,真的很干。。。。。



回复

使用道具 举报

1196

TA的帖子

1

TA的资源

一粒金砂(高级)

Rank: 3Rank: 3

发表于 2020-2-18 15:27 | 显示全部楼层
瓜弟 发表于 2020-2-15 02:29 柱哥帮我看下,Verilog代码里,At_reg这个寄存器同时在两个always里赋值,为啥编译没报错?

组合逻辑,算是正常使用



回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

关闭

站长推荐上一条 /5 下一条

  • 论坛活动 E手掌握

    扫码关注
    EEWORLD 官方微信

  • EE福利  唾手可得

    扫码关注
    EE福利 唾手可得

Archiver|手机版|小黑屋|电子工程世界 ( 京ICP证 060456 )

GMT+8, 2020-2-22 14:20 , Processed in 0.307436 second(s), 18 queries , Gzip On, MemCache On.

快速回复 返回顶部 返回列表