为适应芯片以及集成编译环境,软件部分选用了最常用的硬件描述语言Verilog HDL语言。其灵活的语法结构与C语言极其相似,对于熟练嵌入式系统开发的人员而言,能够极其迅速地掌握并熟练使用,这就为嵌入式系统开发人员提供了极大的便利。
-
-
- ADC转换系统设计
-
ADC采集对于电压采集和电流采集的流程代码和算法结构都极其相似,因此,本文只对电压采集过程的代码进行列举,控制系统设计过程中产生的全套文件以及具体工程文件详情见附件连接。
(1)定义ADC采集文件接口。该部分定义了调用该.V文件所要用到的基本输入变量和输出变量。
|
module adc |
|
( |
|
input wire sys_clk , //时钟 |
|
input wire sys_rst_n , //复位信号,低电平有效 |
|
input wire [7:0] ad_data_voltage , //AD输入电压数据 |
|
input wire [7:0] ad_data_current , //AD输入电流数据 |
|
output wire ad_clk , //AD驱动时钟,最大支持20Mhz时钟 |
|
output reg median_en_voltage, //中值使能,为1使能 |
|
output wire sign_voltage , //正负符号位 |
|
output wire [15:0] data_voltage , //数据转换后的电压值 |
|
output reg median_en_current, //中值使能,为1使能 |
|
output wire sign_current , //正负符号位 |
|
output wire [15:0] data_current //数据转换后的电压值 |
|
); |
(2)实现对系统时钟四分频,得到采样时钟。因为系统的ADC采样时间无法与系统主频同步,必须放慢ADC采集速度,在放慢速度的同时又要提供准确的时钟信号,因此,最好解决方案就是对系统频率进行分频处理。对于选用的ADC采集芯片来说,支持25MHZ以内的采样频率,考虑到采集数据的可靠性,应保证选定的采样频率小于芯片采样的最高频率,最终决定对系统时钟进行四分频得到12.5MHZ采样时钟。
|
//时钟分频(4分频,时钟频率为12.5Mhz),产生采样AD数据时钟 |
|
always@(posedge sys_clk or negedge sys_rst_n) |
|
if(sys_rst_n == 1'b0) |
|
begin |
|
cnt_sys_clk <= 2'd0; |
|
clk_sample <= 1'b0; |
|
end |
|
else |
|
begin |
|
cnt_sys_clk <= cnt_sys_clk + 2'd1; |
|
if(cnt_sys_clk == 2'd1) |
|
begin |
|
cnt_sys_clk <= 2'd0; |
|
clk_sample <= ~clk_sample; |
|
end |
|
end |
(3)前期采样并计数,求取0电位基准ADC转换值。该ADC采集芯片支持最大-5V到+5V的电压采集,中心零电位采集值会因为开机情况变动而变动,因此本系统选用前期未接入电压(可近似认为为零电位)的时候进行零电位采集,得到基准零电位ADC值。为了解决温度漂移等不可控因素的影响,采用均值滤波对零电位采集值进行处理,先对数据采集1024次后再求均值,将均值作为零电位ADC值。
|
//cnt_median_voltage:中值数据累加计数器median_en 为低电平时进行计数,median_en 为高电平时,保持计数最大值 |
|
//每次计数加一 |
|
always@(posedge clk_sample or negedge sys_rst_n) |
|
if(sys_rst_n == 1'b0) |
|
cnt_median_voltage <= 11'd0; |
|
else if(median_en_voltage == 1'b0) |
|
cnt_median_voltage <= cnt_median_voltage + 1'b1; |
|
//data_sum_m_voltage:1024次中值数据累加总和 |
|
always@(posedge clk_sample or negedge sys_rst_n) |
|
if(sys_rst_n == 1'b0) |
|
data_sum_m_voltage <= 19'd0; |
|
else if(cnt_median_voltage == CNT_DATA_MAX) |
|
data_sum_m_voltage <= 19'd0; |
|
else |
|
data_sum_m_voltage <= data_sum_m_voltage + ad_data_voltage; |
|
//data_median_voltage:中值数据,保存中值数据 |
|
always@(posedge clk_sample or negedge sys_rst_n) |
|
if(sys_rst_n == 1'b0) |
|
data_median_voltage <= 8'd0; |
|
else if(cnt_median_voltage == CNT_DATA_MAX) |
|
data_median_voltage <= data_sum_m_voltage / CNT_DATA_MAX; |
|
else |
|
data_median_voltage <= data_median_voltage; |
(4)根据基准电压值,即0电位值计算正负向电压分辨率。因为每次开机零电位不同,对于正负方向上的分辨率就不同,所以每次开机都需要计算正负向的分辨率,才能有效的计算具体的电压采集值。
|
//data_p_voltage:根据中值计算出的正向电压AD分辨率(放大2^13*1000倍) |
|
//data_n_voltage:根据中值计算出的负向电压AD分辨率(放大2^13*1000倍) |
|
assign data_p_voltage = (median_en_voltage == 1'b1) ? 8192_0000 / ((255 - data_median_voltage) * 2) : 0; |
|
assign data_n_voltage = (median_en_voltage == 1'b1) ? 8192_0000 / ((data_median_voltage + 1) * 2) : 0; |
(5)根据分辨率进行电压稳定值的采集,并计算折算后的电压值。
1 |
|
2 |
//volt_reg_voltage:处理后的稳定数据 |
3 |
always@(posedge clk_sample or negedge sys_rst_n) |
4 |
if(sys_rst_n == 1'b0) |
|
volt_reg_voltage <= 1'd0; |
|
else if(median_en_voltage == 1'b1) |
|
if((ad_data_voltage > (data_median_voltage - 3))&&(ad_data_voltage < (data_median_voltage + 3)))//滤波 |
|
volt_reg_voltage <= 1'd0; |
|
else if(ad_data_voltage < data_median_voltage) |
|
volt_reg_voltage <= (data_n_voltage *(data_median_voltage - ad_data_voltage)) >> 13; |
|
else if(ad_data_voltage > data_median_voltage) |
|
volt_reg_voltage <= (data_p_voltage *(ad_data_voltage - data_median_voltage)) >> 13; |
|
else |
|
volt_reg_voltage <= 1'd0; |
|
//data_voltage:数据转换后的电压值 |
|
assign data_voltage = volt_reg_voltage; |
(6)符号位的计算。正负向计算(即符号位)需要根据采集到的ADC值是否比零基准电压值大或小来判断正负向的。
|
//sign_voltage¤t:正负符号位 |
|
assign sign_voltage = (ad_data_voltage < data_median_voltage) ? 1'b1 : 1'b0; |
|
assign sign_current = (ad_data_current < data_median_current) ? 1'b1 : 1'b0; |
脉冲频率计数主要针对测量系统转速而设计,通常涵盖以下几个部分。
(1)读取正反转信号。因为转速符号位是单个输入信号,所以在VerilogHDL语言里可以直接读取信号,无需做与电压符号位计算的类似转换。
(2)端口定义。该部分定义了调用该.V文件所要用到的基本输入变量和输出变量。
|
module freq_meter_calc |
|
( |
|
input wire sys_clk , //系统内置50MHz频率时钟信号 |
|
input wire sys_rst_n , //低电平有效的复位信号 |
|
input wire clk_test , //待检测时钟 |
|
output reg [33:0] freq //待检测时钟频率 |
|
); |
(3)限制最大脉冲计数。如果长时间没有脉冲输入,持续对标准脉冲进行计数会导致超过定义变量的最大范围。因此,采用最大值保护,防止数据超过量程。限制最大脉冲计数,即限制最长的计数时间和最小采集转速。该系统中为方便调试修改,选择常量类型对最大脉冲计数值进行定义。
|
parameter CNT_GATE_S_MAX = 28'd74_999_999 ;//软件闸门计数器最大值 |
|
wire clk_stand ; //标准时钟,频率100MHz |
|
reg [33:0] cnt_clk_stand ; //标准时钟周期计数器 |
|
reg gate_open_flag ; |
(4)计数标准脉冲。在采集脉冲周期内对标准脉冲进行计数,计算每个采集脉冲周期对应的标准脉冲数,间接计算采集周期的时间,算出采集脉冲周期。
|
//cnt_clk_stand:标准时钟周期计数器,计数实际闸门下标准时钟周期数 |
|
always@(posedge clk_stand or negedge sys_rst_n) |
|
if(sys_rst_n == 1'b0) |
|
cnt_clk_stand <= 33'd0; |
|
else if(cnt_clk_stand==CNT_GATE_S_MAX) |
|
cnt_clk_stand <= 33'd0; |
|
else if (gate_open_flag==1'b1) |
|
cnt_clk_stand <= cnt_clk_stand + 1'b1; |
|
else |
|
cnt_clk_stand<=1'b0; |
|
always@(posedge clk_test or negedge sys_rst_n) |
|
if(sys_rst_n == 1'b0) |
|
gate_open_flag <= 1'b1; |
|
else if(gate_open_flag==1) |
|
begin |
|
freq <= cnt_clk_stand/500 ; |
|
gate_open_flag<=1'b0; |
|
end |
|
else |
|
gate_open_flag<=1'b1; |
-
-
- 输出PWM调制脉宽控制系统设计
-
对于直接驱动全桥驱动器的脉冲,系统中分五路进行输出,只在此列举一路输出流程,其他四路与之相似不再赘述。
(1)产生标准时序。PWM输出具有周期性,只有在一个周期完成后再更改输出的脉宽,本系统采用对标准脉冲进行统计产生标准时序。
|
reg [14:0] count ; //辅助pwm输出寄存器 |
|
//提供周期性计数 |
|
always@(posedge sys_clk or negedge sys_rst_n) |
|
if(sys_rst_n == 1'b0) |
|
count <= 25'd0; |
|
else if(count == TIME_10000 ) |
|
count <= 25'd0; |
|
else |
|
count <= count + 1'b1; |
(2)脉冲输出控制。通过判断标准脉冲数判断是否输出高/底电平。
|
//电机控制端口1输出 |
|
always@(posedge sys_clk or negedge sys_rst_n) |
|
if(sys_rst_n == 1'b0) |
|
pwm_con_out_1 <= 1'd0; |
|
else if(count <= pwm_count_out_1 ) |
|
pwm_con_out_1 <= 1'd1; |
|
else |
|
pwm_con_out_1 <= 1'd0; |
对于调速系统控制算法,目前主要采用鲁棒性好的PID控制方案,具体有传统PID、前馈PID、增量式PID以及模糊PID。在具体实现时又根据控制方案中用到的部分,分为P、PI控制,以及传统PID针对动态结构改进的增量式PID和前馈式PID。考虑到传统PID控制结构、运算过程较为简单,算法结构清晰,同时大部分开发人员都比较熟悉,在本系统中被用于对电流环即转矩进行控制。模糊PID因算法结构较为复杂、动态特性和抗干扰特性兼顾较好、几乎无前馈式PID和增量式PID的参数跃变现象,在动态抗干扰特性以及鲁棒性要求较高的控制系统中被广泛采用。本系统中转速环对转速稳定度和系统动态特性要求较高,因此,该系统采用模糊PID对转速环进行控制。
-
-
- PID控制算法软件设计
-
(1)偏差积分计算。此部分计算预期期望值与实际值的偏差P以及偏差的累加值I。
|
//定义pid寄存器 |
|
reg signed [15:0] error ; //偏差 |
|
reg signed [15:0] error_last ; //上一次偏差 |
|
reg signed [31:0] I_error ; //偏差的积分 |
|
//pid中比例部分计算 |
|
always@(posedge sys_clk or negedge sys_rst_n) |
|
if(sys_rst_n == 1'b0) |
|
begin |
|
error <= 16'd0; |
|
I_error <= 0 ; |
|
error_last<=16'd0 ; |
|
end |
|
else if (median_en_current==1'b0) |
|
begin |
|
error <= 16'd0; |
|
I_error <= 0 ; |
|
error_last<=16'd0 ; |
|
end |
|
else if(sign_current==0) |
|
begin |
|
error <= expect_data-data_current; //延时一个时钟周期 |
|
I_error <=I_error + error; |
|
error_last<=error; |
|
//积分部分限制幅值 |
|
if(I_error> 2147000000) |
|
I_error<= 2147000000; |
|
else if(I_error<-2147000000) |
|
I_error<= 2147000000; |
|
end |
|
else if(sign_current==1) |
|
begin |
|
error <= expect_data+data_current; //延时一个时钟周期 |
|
I_error <= I_error + error; |
|
error_last<=error; |
|
//积分部分限制幅值 |
|
if(I_error> 2147000000) |
|
I_error<= 2147000000; |
|
else if(I_error<-2147000000) |
|
I_error <=-2147000000; |
|
end |
(2)PID输出计算。此部分根据上节比例系数及积分系数计算KP*P+KI*I最终输出值。
|
//pid集中计算输出 |
|
always@(posedge sys_clk or negedge sys_rst_n) |
|
if(sys_rst_n == 1'b0) |
|
pwm_con_out <= 32'd0; |
|
else if ((median_en_current==1'b0)|(flag_current_max==1'b1)) |
|
pwm_con_out <= 32'd0; |
|
else |
|
pwm_con_out<= error * kp_current + I_error * ki_current; |
(3)PID输出值转化为脉冲输出。最终计算后的pwm_con_out需要经过决策树的判断后,再依次给PWM输出端口赋脉冲宽度值。
|
reg signed [31:0] pwm_con_out1;//用于交换pid输出值 |
|
always@(posedge sys_clk or negedge sys_rst_n) |
|
if(sys_rst_n == 1'b0) |
|
pwm_con_out1 <= 32'd0; |
|
else if (median_en_current==1'b0) |
|
pwm_con_out1 <= 32'd0; |
|
else if(pwm_con_out>0) |
|
begin |
|
pwm_con_out1=pwm_con_out>>11 ;//比例缩小 |
|
pwm_count_out_1<=pwm_con_out1; |
|
pwm_count_out_2<=0 ; |
|
pwm_count_out_3<=pwm_con_out1; |
|
pwm_count_out_4<=0 ; |
|
end |
|
else if(pwm_con_out<0) |
|
begin |
|
pwm_con_out1=pwm_con_out* -1 ; |
|
pwm_con_out1=pwm_con_out>>11 ;//比例缩小 |
|
pwm_count_out_1<=0 ; |
|
pwm_count_out_2<=pwm_con_out1; |
|
pwm_count_out_3<=0 ; |
|
pwm_count_out_4<=pwm_con_out1; |
|
end |
-
-
- FUZZY PID控制算法设计
-
模糊PID主要是明确模糊规则,并在计算隶属度后,按照模糊规则计算输出值,以下列出几个关键部分。
(1)模糊规则表的建立
模糊规则所在数组在Verilog HDL中无法在定义的同时直接初始化,因此,程序分两步实现模糊规则表的定义及初始化。再根据表 4.1给程序中规则变量依次赋值。
|
//定义模糊规则表 |
|
reg signed [31:0] kp_fuzzy ; |
|
reg signed [31:0] ki_fuzzy ; |
|
reg signed [31:0] kd_fuzzy ; |
|
//初始化模糊规则表 |
|
initial |
|
begin |
|
kp[0][0]<= NB;kp[0][1]<= NB;kp[0][2]<= NM;kp[0][3]<= NM;kp[0][4]<= NS;kp[0][5]<= Z0;kp[0][6]<= Z0; |
|
kp[1][0]<= NM;kp[1][1]<= NB;kp[1][2]<= NM;kp[1][3]<= NS;kp[1][4]<= NS;kp[1][5]<= NS;kp[1][6]<= PS; |
|
kp[2][0]<= NM;kp[2][1]<= NM;kp[2][2]<= NM;kp[2][3]<= NS;kp[2][4]<= Z0;kp[2][5]<= PS;kp[2][6]<= PS; |
|
kp[3][0]<= NM;kp[3][1]<= NM;kp[3][2]<= NS;kp[3][3]<= Z0;kp[3][4]<= PS;kp[3][5]<= PM;kp[3][6]<= PM; |
|
kp[4][0]<= NS;kp[4][1]<= NS;kp[4][2]<= Z0;kp[4][3]<= PS;kp[4][4]<= PM;kp[4][5]<= PM;kp[4][6]<= PM; |
|
kp[5][0]<= NS;kp[5][1]<= Z0;kp[5][2]<= PS;kp[5][3]<= PM;kp[5][4]<= PM;kp[5][5]<= PM;kp[5][6]<= PB; |
|
kp[6][0]<= Z0;kp[6][1]<= Z0;kp[6][2]<= NS;kp[6][3]<= PM;kp[6][4]<= PM;kp[6][5]<= PM;kp[6][6]<= PB; |
|
|
|
ki[0][0]<= NB;ki[0][1]<= NS;ki[0][2]<= NM;ki[0][3]<= NM;ki[0][4]<= NS;ki[0][5]<= Z0;ki[0][6]<= Z0; |
|
ki[1][0]<= NB;ki[1][1]<= NB;ki[1][2]<= NM;ki[1][3]<= NB;ki[1][4]<= NB;ki[1][5]<= Z0;ki[1][6]<= Z0; |
|
ki[2][0]<= NM;ki[2][1]<= NM;ki[2][2]<= NM;ki[2][3]<= NB;ki[2][4]<= Z0;ki[2][5]<= PS;ki[2][6]<= PS; |
|
ki[3][0]<= NM;ki[3][1]<= NM;ki[3][2]<= NS;ki[3][3]<= Z0;ki[3][4]<= PS;ki[3][5]<= PM;ki[3][6]<= PM; |
|
ki[4][0]<= NM;ki[4][1]<= NS;ki[4][2]<= Z0;ki[4][3]<= PS;ki[4][4]<= PM;ki[4][5]<= PM;ki[4][6]<= PB; |
|
ki[5][0]<= Z0;ki[5][1]<= Z0;ki[5][2]<= PS;ki[5][3]<= PS;ki[5][4]<= PM;ki[5][5]<= PB;ki[5][6]<= PB; |
|
ki[6][0]<= Z0;ki[6][1]<= Z0;ki[6][2]<= PM;ki[6][3]<= PM;ki[6][4]<= PM;ki[6][5]<= PB;ki[6][6]<= PB; |
|
|
|
kd[0][0]<= NB;kd[0][1]<= NS;kd[0][2]<= NB;kd[0][3]<= NB;kd[0][4]<= NS;kd[0][5]<= NM;kd[0][6]<= PS; |
|
kd[1][0]<= NB;kd[1][1]<= NS;kd[1][2]<= NB;kd[1][3]<= NM;kd[1][4]<= NM;kd[1][5]<= NS;kd[1][6]<= Z0; |
|
kd[2][0]<= Z0;kd[2][1]<= NS;kd[2][2]<= NM;kd[2][3]<= NM;kd[2][4]<= NM;kd[2][5]<= NS;kd[2][6]<= Z0; |
|
kd[3][0]<= Z0;kd[3][1]<= NS;kd[3][2]<= NS;kd[3][3]<= NS;kd[3][4]<= NS;kd[3][5]<= NS;kd[3][6]<= Z0; |
|
kd[4][0]<= Z0;kd[4][1]<= Z0;kd[4][2]<= Z0;kd[4][3]<= Z0;kd[4][4]<= Z0;kd[4][5]<= Z0;kd[4][6]<= Z0; |
|
kd[5][0]<= PB;kd[5][1]<= PS;kd[5][2]<= PS;kd[5][3]<= PS;kd[5][4]<= PS;kd[5][5]<= PS;kd[5][6]<= PB; |
|
kd[6][0]<= PB;kd[6][1]<= PM;kd[6][2]<= PM;kd[6][3]<= PM;kd[6][4]<= PS;kd[6][5]<= PS;kd[6][6]<= PB; |
|
|
|
E_about_left<=0;E_about_right<=0;EC_about_left<=0;EC_about_right<=0; |
|
end |
(2)计算偏差和积分微分值。根据转速的期望值(expect_data)与转速的实际值(freq)计算转速偏差(error_this),以及转速偏差量的变化量(EC_error)。
|
always @(posedge flag_change) |
|
if(direction==0) |
|
begin |
|
error_last<=error_this; |
|
error_this<=expect_data*100-freq;//此处freq必须经过限弧转换 |
|
error_this<=error_this/100; |
|
EC_error <=error_this-error_last; |
|
i_error=i_error+error_this; |
|
//限幅 |
|
if(i_error>3000000) |
|
i_error<=3000000; |
|
else if(i_error< -3000000) |
|
i_error<=-3000000; |
|
if(error_this>256) |
|
error_this<=256; |
|
else if(error_this< -256) |
|
error_this<=-256; |
|
if(EC_error>256) |
|
EC_error<=256; |
|
else if(EC_error< -256) |
|
EC_error<=-256; |
|
end |
|
else |
|
begin |
|
error_last<=error_this; |
|
error_this<=expect_data*100+freq;//此处freq必须经过限弧转换 |
|
error_this<=error_this/100; |
|
EC_error<=error_this-error_last; |
|
i_error=i_error+error_this; |
|
//限幅 |
|
if(i_error>3000000) |
|
i_error<=3000000; |
|
else if(i_error< -3000000) |
|
i_error<=-3000000; |
|
if(error_this>256) |
|
error_this<=256; |
|
else if(error_this< -256) |
|
error_this<=-256; |
|
if(EC_error>25600) |
|
EC_error<=25600; |
|
else if(EC_error< -256) |
|
EC_error<=-256; |
|
end |
(3)计算隶属度,即模糊化。根据E和EC所属区间计算实际的KP,KI,KD系数,其中对应系数参照重心法求得,即计算E和EC所属区间的隶属度之和。
|
//判断E和EC所属区间,并计算差额,计算隶属度 |
|
always@(posedge sys_clk or negedge sys_rst_n) |
|
if(sys_rst_n == 1'b0) |
|
begin |
|
E=4'd0; |
|
E_about_left<=0; |
|
E_about_right<=0; |
|
end |
|
else if(error_this>=171) |
|
begin |
|
E=4'd5; |
|
E_about_right<=(((error_this-171)*100)/85); |
|
E_about_left <=(((256-error_this)*100)/85); |
|
end |
|
else if(error_this>=86&&error_this<171) |
|
begin |
|
E=4'd4; |
|
E_about_right<=(((error_this-86)*100)/85); |
|
E_about_left <=(((171-error_this)*100)/85); |
|
end |
|
else if(error_this>=0&&error_this<86) |
|
begin |
|
E=4'd3; |
|
E_about_right<=(((error_this)*100)/86); |
|
E_about_left <=(((86-error_this)*100)/86); |
|
end |
|
else if(error_this< -171) |
|
begin |
|
E=4'd0; |
|
E_about_left <=(((-error_this-171)*100)/85); |
|
E_about_right<=(((256+ error_this)*100)/85); |
|
end |
|
else if(error_this>=-171&&error_this<-86) |
|
begin |
|
E=4'd1; |
|
E_about_left <=(((-error_this-86)*100)/85); |
|
E_about_right<=(((171+error_this)*100)/85); |
|
end |
|
else if(error_this>=-86&&error_this<0) |
|
begin |
|
E=4'd2; |
|
E_about_left <=(((-error_this )*100)/86); |
|
E_about_right<=(((86+error_this)*100)/86); |
|
end |
|
always@(posedge sys_clk or negedge sys_rst_n) |
|
if(sys_rst_n == 1'b0) |
|
begin |
|
EC=4'd0; |
|
EC_about_left<=0; |
|
EC_about_right<=0; |
|
end |
|
else if(EC_error>=171) |
|
begin |
|
EC=4'd5; |
|
EC_about_right<=(((EC_error-171)*100)/85); |
|
EC_about_left <=(((256-EC_error)*100)/85); |
|
end |
|
else if(EC_error>=86&&EC_error<171) |
|
begin |
|
EC=4'd4; |
|
EC_about_right<=(((EC_error-86)*100)/85); |
|
EC_about_left <=(((171-EC_error)*100)/85); |
|
end |
|
else if(EC_error>=0&&EC_error<86) |
|
begin |
|
EC=4'd3; |
|
EC_about_right<=(((EC_error)*100)/86); |
|
EC_about_left <=(((86-EC_error)*100)/86); |
|
end |
|
else if(EC_error< -171) |
|
begin |
|
EC=4'd0; |
|
EC_about_left <=(((-EC_error-171)*100)/85); |
|
EC_about_right<=(((256+ EC_error)*100)/85); |
|
end |
|
else if(EC_error>=-171&&EC_error<-86) |
|
begin |
|
EC=4'd1; |
|
EC_about_left <=(((-EC_error-86)*100)/85); |
|
EC_about_right<=(((171+EC_error)*100)/85); |
|
end |
|
else if(EC_error>=-86&&EC_error<0) |
|
begin |
|
EC=4'd2; |
|
EC_about_left <=(((-EC_error )*100)/86); |
|
EC_about_right<=(((86+EC_error)*100)/86); |
|
end |
(4)根据隶属度计算PID的值,即数字化。根据数字化后的值清晰化输出值。
|
//根据隶属度求kp,ki,kd,计算输出pwm的值 |
|
always@(posedge sys_clk or negedge sys_rst_n) |
|
if(sys_rst_n == 1'b0) |
|
begin |
|
kp_fuzzy <=0; |
|
ki_fuzzy <=0; |
|
kd_fuzzy <=0; |
|
pid_out_fuzzy<=0; |
|
end |
|
else |
|
begin |
|
kp_fuzzy<=(kp[E][EC ]*E_about_left*EC_about_left )+(kp[E+1][EC ]*E_about_right*EC_about_left )+ |
|
(kp[E][EC+1]*E_about_left*EC_about_right)+(kp[E+1][EC+1]*E_about_right*EC_about_right); |
|
ki_fuzzy<=(ki[E][EC ]*E_about_left*EC_about_left )+(ki[E+1][EC ]*E_about_right*EC_about_left )+ |
|
(ki[E][EC+1]*E_about_left*EC_about_right)+(ki[E+1][EC+1]*E_about_right*EC_about_right); |
|
kd_fuzzy<=(kd[E][EC ]*E_about_left*EC_about_left )+(kd[E+1][EC ]*E_about_right*EC_about_left )+ |
|
(kd[E][EC+1]*E_about_left*EC_about_right)+(kd[E+1][EC+1]*E_about_right*EC_about_right); |
|
kp_fuzzy<=(kp_fuzzy*1)/10000; |
|
ki_fuzzy<=(ki_fuzzy*1)/10000; |
|
ki_fuzzy<=(kd_fuzzy*1)/10000; |
|
pid_out_fuzzy=(kp_fuzzy*error_this)+(ki_fuzzy*i_error)/2000+(kd_fuzzy*EC_error); |
|
if(pid_out_fuzzy>=10000) |
|
pid_out_fuzzy<=10000; |
|
else if(pid_out_fuzzy<-10000) |
|
pid_out_fuzzy<=-10000; |
|
else if(flag_current_max==1)//长时间过电流保护 |
|
pid_out_fuzzy<=0; |
|
end |
(5)赋值给PWM控制器输出,与上一节雷同,这里不再赘述。
采用过流、过功率保护来对设备进行保护。通过监测过电流时间和过功率时间触发保护位寄存器动作,对输出PWM进行闭锁实现保护。
|
//长时间过电流、过功率统计 |
|
reg [31:0] time_current ; |
|
reg flag_current_max; |
|
reg [31:0] time_power ; |
|
reg flag_power_max; |
|
parameter current_max_times = 150000000;//过载最大三秒 |
|
parameter power_max_times = 150000000;//过载最大三秒 |
|
always@(posedge sys_clk or negedge sys_rst_n) |
|
if(sys_rst_n == 1'b0) |
|
begin |
|
time_current<=0; |
|
time_power <=0; |
|
flag_current_max<=1'b0; |
|
time_power <=1'b0; |
|
end |
|
else if((median_en_current==0)|(data_current<110)) |
|
time_current<=0; |
|
else if((median_en_current==0)|(data_current*data_voltage<12100)) |
|
time_power <=0; |
|
else if((median_en_current==1)|(data_current>110)) |
|
begin |
|
time_current<=time_current+1; |
|
if(time_current>=current_max_times) |
|
begin |
|
flag_current_max=1'b1; |
|
time_current<=current_max_times; |
|
end |
|
end |
|
else if((median_en_current==1)|(data_current*data_voltage>12100)) |
|
begin |
|
time_power<=time_power+1; |
|
if(time_power>=power_max_times) |
|
begin |
|
flag_power_max=1'b1; |
|
time_power<=power_max_times; |
|
end |
|
end |