📄 tec_control_pgfa.v
字号:
// TEC温控系统程序
//
//
//
module tec_control( clk, // 系统输入主时钟 80MHz
//pwm_clk, // 80MHz
sync, // 温度数据同步信号
rst,
data_clk, // 温度数据串行读出时钟
convert_clk, // 启动转换信号
data, // 温度串行数据
data_tec,
data_sync,
clk_temp,
data_10K,
deta_k,
tset_syn, // 温度数据同步信号
tset, // 设定温度值
pwm // 温控PWM输出
);
input clk;
//input pwm_clk;
input sync;
input data;
input rst;
input [15:0] tset;
input tset_syn;
output [15:0] data_tec;
output data_sync;
output data_10K;
output data_clk;
output [3:0] pwm;
output convert_clk;
reg convert_clk;
reg data_clk;
reg [3:0] pwm;
reg [9:0] cnt;
output clk_temp;
reg clk_temp; // 1MHz
always@(posedge clk or negedge rst) // 80分频得到1MHz;
begin
if(~rst)
begin
cnt <= 0;
clk_temp <= 0;
end
else
begin
cnt <= cnt + 1;
if(cnt==399)
clk_temp <= 1;
if(cnt==799)
begin
clk_temp <= 0;
cnt <= 0;
end
end
end
/*
reg [7:0] cnt_4M;
reg clk_4M;
always@(posedge clk or negedge rst)
begin
if(~rst)
begin
cnt_4M <= 0;
clk_4M <= 0;
end
else
begin
cnt_4M <= cnt_4M + 1;
if(cnt_4M == 9)
clk_4M <= 1;
if(cnt_4M == 19)
begin
clk_4M <= 0;
cnt_4M <= 0;
end
end
end
*/
//////////////////////////////////////////////////////////
reg [7:0] cnt_convert;
always@(posedge clk_temp or negedge rst) // 1MHz 100分频得到10KHz采样时钟
begin
if(~rst)
begin
cnt_convert <= 0;
data_clk <= 0;
cnt_convert <= 0;
end
else
begin
cnt_convert <= cnt_convert + 1;
if(cnt_convert== 5)
data_clk <= 1; // clk0
if(cnt_convert== 6)
data_clk <= 0;
if(cnt_convert==19) // 占空比 20%
convert_clk <= 1;
if(cnt_convert>=30 && cnt_convert<= 65) // clk1~clk18
data_clk <= ~data_clk;
if(cnt_convert==66)
data_clk <= 0;
if(cnt_convert==99)
begin
convert_clk <= 0; // 10KHz 并行数据速率
data_clk <= 0; // 1MHz 串行数据速率
cnt_convert <=0;
end
end
end
////////////////////////////////////////////
// 温控data 数据串并转换
reg [15:0] data_tec;
reg [4:0] data_cnt;
reg data_sync; // 并行数据同步信号
reg [15:0] data_10K;
always@(negedge data_clk or posedge sync)
begin
if(sync)
begin
data_tec <= 0;
data_cnt <= 0;
data_sync <= 0;
//data_10K <= 0;
end
else begin
data_cnt <= data_cnt + 1;
if(data_cnt == 0)
data_tec[15] <= data;
if(data_cnt == 1)
data_tec[14] <= data;
if(data_cnt == 2)
data_tec[13] <= data;
if(data_cnt == 3)
data_tec[12] <= data;
if(data_cnt == 4)
data_tec[11] <= data;
if(data_cnt == 5)
data_tec[10] <= data;
if(data_cnt == 6)
data_tec[9] <= data;
if(data_cnt == 7)
data_tec[8] <= data;
if(data_cnt == 8)
data_tec[7] <= data;
if(data_cnt == 9)
data_tec[6] <= data;
if(data_cnt == 10)
data_tec[5] <= data;
if(data_cnt == 11)
data_tec[4] <= data;
if(data_cnt == 12)
data_tec[3] <= data;
if(data_cnt == 13)
data_tec[2] <= data;
if(data_cnt == 14)
data_tec[1] <= data;
if(data_cnt == 15)
data_tec[0] <= data;
if(data_cnt == 16)
begin
data_cnt <= data_cnt;
data_tec <= data_tec;
data_10K <= data_tec;
data_sync <= 1;
//data_cnt <= 0;
end
end
end
///////////////////////////////////////////////////////////////
reg [5:0] data_count;
reg [19:0] data_tec_sum; // 16个温度数据求和
reg [15:0] data_tec_avg;
always@(negedge data_sync or negedge rst)
begin
if(~rst)
begin
data_count <= 0;
data_tec_sum <= 0;
data_tec_avg <= 0;
end
else
begin
data_count <= data_count + 1;
if(data_count < 16)
data_tec_sum <= data_tec_sum + data_10K;
if(data_count == 16)
data_tec_avg <= data_tec_sum[19:4];
if(data_count == 19)
begin
data_tec_sum <= 0;
data_count <= 0;
end
end
end
/////////////////////////////////////////////////////
// PID参数定义
parameter KP = 16'b0010010011101010; // 8位整数,8位小数39
parameter KI = 16'b0000000000000001;
wire signed [16:0] tset_in; // 设定温度转换为有符号数
assign tset_in = {1'b0,tset[15:0]};
wire signed [16:0] data_tec_in; // 反馈温度转换为有符号数
//assign data_tec_in = {1'b0,data_10K[15:3],3'b000};
assign data_tec_in = {1'b0,data_tec_avg[15:0]};
//wire signed [16:0] total; // 使e(k)逐渐减小
//assign total = 17'h0FFFF;
wire signed [16:0] pid_in;
//wire signed [20:0] pid_in;
assign pid_in = tset_in - data_tec_in ;//+ ( 15'b0000001000010111 );
//assign pid_in = {pid_in_1[32],pid_in_1[19:0]};
///////////////////////////+,add the DC piaoyi
reg int_off; // 积分开关控制信号
always @(sys_rst or pid_in)
begin
if(sys_rst==1)
int_off = 1;
else begin
if(pid_in[16:0] > 512) // 积分分离PID
int_off = 1;
else
int_off = 0;
end
end
///////////////////////////
//2, parameter definition :
wire sys_rst;
assign sys_rst = tset_syn; // 温度同步信号作为复位信号
reg [12:0] counter_20K;
reg clk_20K; // PWM开关频率20KHz
always@(posedge clk or posedge sys_rst)
begin
if(sys_rst)
begin
clk_20K <= 0;
counter_20K <= 0;
end
else
begin
counter_20K <= counter_20K + 1;
if(counter_20K== 1999)
clk_20K <= 1;
if(counter_20K== 3999)
begin
clk_20K <= 0;
counter_20K <= 0;
end
end
end
reg [18:0] counter_1K;
reg clk_1K; // PID控制量更新频率1KHz
always@(posedge clk or posedge sys_rst)
begin
if(sys_rst)
begin
clk_1K <= 0;
counter_1K <= 0;
end
else
begin
counter_1K <= counter_1K + 1;
if(counter_1K== 39999)
clk_1K <= 1;
if(counter_1K== 79999)
begin
clk_1K <= 0;
counter_1K <= 0;
end
end
end
/////////////////////////////////////////////////////////
// 温控增量式PID算法
wire signed [15:0] B_con ;
//assign A_con = (~sys_rst)? KI + KP : 16'b0;
//assign A_con = (int_off)? KP : (KP + KI); // 积分分离PID控制
assign B_con = (~sys_rst)? KP : 16'b0;
reg signed [15:0] A_con;
always@(sys_rst or int_off)
begin
if(sys_rst==1)
A_con = 16'b0;
else
begin
if(int_off==1)
A_con = KP;
else
A_con = KP + KI;
end
end
reg signed [16:0] e_k, e_k_1;
always @(posedge clk_1K)
begin
if ( sys_rst == 1 ) // Tset数据同步信号
begin
e_k <= 0;
e_k_1 <= 0;
end
else // 16bit AD转换数据有效期间
begin
e_k <= pid_in; // pid_in 变化周期为AD采样周期,即10KHz
e_k_1 <= e_k;
end
end
wire signed [32:0] A_k , B_k_1 ; //16bit*17bit
assign B_k_1 = (~sys_rst) ? B_con * e_k_1 : 33'b0; // 其中A_con与B_con为8位小数精度
assign A_k = (~sys_rst) ? A_con * e_k : 33'b0;
wire signed [39:0] deta_u_k ;
wire signed [39:0] u_k;
reg signed [39:0] u_k_1 ; // 由于误差的累积作用,此控制量位数应足够高
//wire signed [32:0] data_temp;
//assign data_temp = A_k - B_k_1;
//assign deta_u_k = {data_temp[32],data_temp[32:15]} ; // 只取增量的整数部分即可
//assign u_k = deta_u_k + u_k_1; // 若控制量大于8000,则处于饱和状态
assign deta_u_k = A_k - B_k_1;
assign u_k = deta_u_k + u_k_1;
//reg signed [32:0] temp;
//reg signed [32:0] temp1;
//reg signed [32:0] u_k;
//always@(deta_u_k or u_k_1)
//begin
/*
if(e_k < 0 && e_k > -256)
temp = u_k_1 + 13'h1000;
else if (e_k > 0 && e_k < 256)
temp = u_k_1 - 13'h1000;
else if(e_k == 0)
temp = u_k_1;
else
temp = u_k_1 + deta_u_k;
if(deta_u_k < 64 && deta_u_k > 0)
temp = u_k_1 + 13'h1000; // 即u_k_1的第12位加1
else if(deta_u_k > -64 && deta_u_k < 0)
temp = u_k_1 - 13'h1000; // 即u_k_1的第12位减1
else
temp = u_k_1 + deta_u_k;
*/
//temp1 = {temp[32],5'b00000,temp[31:12]}; // 26位
/* temp = u_k_1 + deta_u_k;
if(temp[32]==0 && temp[31:0] > 4000) // 正向大于8000
//u_k = {21'h1F40,12'h000};
//u_k = 33'h1F40000;
begin
u_k[32:0] = 4000;
//u_k[11:0] = 0;
end
else if(temp[32]==1 && (~temp[31:0]+1)> 4000) // 反向大于8000
begin
u_k[32:0] = -4000; // -8000
//u_k[11:0] = 0;
end
else
u_k = temp;
end
*/
///////////////////////////////
reg signed [39:0] deta_k;
output [39:0] deta_k;
always@(posedge clk_1K)
begin
deta_k <= deta_u_k;
end
///////////////////////////////
always@(posedge clk_1K or posedge sys_rst)
begin
if (sys_rst)
u_k_1 <= 0;
else
u_k_1 <= u_k ;
end
//////////////////////////////////////////////////////////////////////////////////
wire signed [39:0] data_in;
assign data_in = u_k; // 控制量输入
wire [39:0] pwm_con;
wire [39:0] pwm_con_d;
assign pwm_con_d = (~data_in[39]) ? data_in[38:0] : ((~data_in[38:0])+1);
//assign pwm_con_d = pwm_con[37:19] + pwm_con[37:20] + pwm_con[37:21]+ 4000;//x/2+8K; 12: K=4; 11: K=8; 10: k=16
//assign pwm_con_d = pwm_con[32:3];// + 4000 ; // pwm_con[31:3];// + 2400;
assign pwm_con = pwm_con_d[35:18]+ 2000;
//assign pwm_con_d = pwm_con[31:12] +
//wire [16:0] pwm_cont;
reg [39:0] pwm_con_l;
parameter b=4'b0101; //UL-on UR-off LL-off LR-on
parameter a=4'b1010; //UL-off UR-on LL-on LR-off
parameter c=4'b1100; //UL-off UR-off LL-off LR-off
assign pwm_UL=pwm[0];
assign pwm_UR=pwm[2];
assign pwm_LL=pwm[1];
assign pwm_LR=pwm[3];
reg pwm_begin;
reg [12:0] count_20K;
always@(posedge clk) // 80MHz
begin
if(sys_rst)
begin
count_20K <= 0;
pwm_begin <= 0;
pwm_con_l <= 2000;
end
else begin
count_20K <= count_20K + 1'b1;
if ( count_20K == 3979 )
begin
pwm_con_l <= pwm_con; // 控制量时钟同步
pwm_begin <= 1;
end
if ( count_20K == 3999 )
begin
pwm_begin <= 0;
count_20K <= 0;
end
end
end
reg [15:0] count_pwm;
always@(posedge clk)
begin
if ((pwm_begin == 1) || (sys_rst==1)) // 复位及开关频率10KHz处H桥先断开
begin
pwm <= c;
count_pwm <= 0;
end
else begin
if ( data_in[39] == 0)
begin
pwm[2] <= 0;
pwm[0] <= 0; // TEC+ 始终为高电平
count_pwm <= count_pwm + 1'b1;
if (count_pwm < pwm_con_l - 20) // 死区时间为20clk,250ns
pwm[1] <= 1;
if (count_pwm == pwm_con_l - 20)
pwm[1] <= 0;
if(count_pwm >= pwm_con_l)
pwm[3] <= 0;
/*
count_pwm <= count_pwm + 1'b1;
if ( count_pwm < pwm_con_l)
pwm <= a;
else if (count_pwm <= (pwm_con_l + 9)) // 应考虑ADN8830的制冷方案,单向制冷,另一端始终为高电平
pwm <= c;
else
pwm <= b;
*/
end
else
begin
pwm[1] <= 0;
pwm[3] <= 0;
count_pwm <= count_pwm + 1'b1;
if (count_pwm < pwm_con_l - 20) // 死区时间为20clk,250ns
pwm[0] <= 1;
if (count_pwm == pwm_con_l - 20)
pwm[0] <= 0;
if(count_pwm >= pwm_con_l)
pwm[2] <= 0;
/*
count_pwm <= count_pwm + 1'b1;
if ( count_pwm < pwm_con_l )
pwm <= b;
else if (count_pwm <= (pwm_con_l + 9))
pwm <= c;
else
pwm <= a; // 不做反向的制热,由探测器的工作升温来完成
*/
end
end
end
//////////////////////////////////////////////////////////////
endmodule
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -