⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tec_control_pgfa.v

📁 使用fpga基于积分分离的pid算法进行温控的程序
💻 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 + -