基于FPGA的PI环调节电压
硬件资源
FPGA开发板
AD7606-AD采样模块
AD9767-DA输出模块
实验过程
默认DA输出初始电压-AD获取DA输入电压-FPGA负责根据目标值进行调节-最终DA输出电压稳定在目标电压附近-改变目标值DA输出随之改变
公式分析
%计算target和meas的误差
error = meas(AD)- target(我都会设置为1.0V)
%通过pi环计算ref值,系数定为:Kp=0.5 Ki=0.05
%先计算积分
integral = integral_prev + δerror
%然后计算需要送出去的值要增加减少多少
δu = Kp * error + Ki * integral
%然后计算出要送出去的值
u(DA_OUT2) = u_prev + δu
%限幅送出去的电压
u(DA_OUT2) = [0.8, 1.2]
Verilog代码
AD7606控制代码
`timescale 1ns / 1ps
module ad7606_if(
input clk,
input rst_n,
input [15:0] ad_data, //ad7606 data
input ad_busy, //ad7606 busy
input first_data, //ad7606 first data
output [2:0] ad_os, //ad7606
output reg ad_cs, //ad7606 AD cs
output reg ad_rd, //ad7606 AD data read
output reg ad_reset, //ad7606 AD reset
output reg ad_convstab, //ad7606 AD convert start
output ad_data_valid,
output reg ad_data_valid_temp,
output reg [15:0] ad_ch1,
output reg [15:0] ad_ch2,
output reg [15:0] ad_ch3,
output reg [15:0] ad_ch4,
output reg [15:0] ad_ch5,
output reg [15:0] ad_ch6,
output reg [15:0] ad_ch7,
output reg [15:0] ad_ch8,
output reg [3:0] state
);
reg [15:0] rst_cnt;
reg [5:0] i;
reg [15:0] start_count;
//reg [3:0] state;
parameter IDLE=4'd0;
parameter AD_CONV=4'd1;
parameter Wait_1=4'd2;
parameter Wait_busy=4'd3;
parameter READ_CH1=4'd4;
parameter READ_CH2=4'd5;
parameter READ_CH3=4'd6;
parameter READ_CH4=4'd7;
parameter READ_CH5=4'd8;
parameter READ_CH6=4'd9;
parameter READ_CH7=4'd10;
parameter READ_CH8=4'd11;
parameter READ_DONE=4'd12;
assign ad_os=3'b000;// oversample
assign ad_data_valid = state == READ_DONE ? 1'b1 : 1'b0;
always@(posedge clk or negedge rst_n)
begin
if(rst_n == 1'b0)
begin
rst_cnt <= 16'd0;
ad_reset <= 1'b0;
end
else if(rst_cnt < 16'hffff)
begin
rst_cnt <= rst_cnt + 16'd1;
ad_reset <= 1'b1;
end
else
ad_reset <= 1'b0;
end
always@(posedge clk or negedge rst_n)
begin
if(rst_n == 1'b0)
begin
ad_data_valid_temp<=1'b0;
end
else if(ad_data_valid ==1'b1)
begin
ad_data_valid_temp<=1'b1;
end
else
ad_data_valid_temp<=1'b0;
end
always@(posedge clk)
begin
if(ad_reset==1'b1)
begin
state <= IDLE;
ad_ch1 <= 0;
ad_ch2 <= 0;
ad_ch3 <= 0;
ad_ch4 <= 0;
ad_ch5 <= 0;
ad_ch6 <= 0;
ad_ch7 <= 0;
ad_ch8 <= 0;
ad_cs <= 1'b1;
ad_rd <= 1'b1;
ad_convstab <= 1'b1;
i <= 6'd0;
start_count<=16'd0;
end
else
begin
case(state)
IDLE:
begin
ad_cs<=1'b1;
ad_rd<=1'b1;
ad_convstab<=1'b1;
if(start_count==50) begin
start_count <= 16'd0;
state<=AD_CONV;
end
else
start_count<=start_count+1;
end
AD_CONV:
begin
if(i==2)
begin //wait 2 clock
i <= 6'd0;
state<=Wait_1;
ad_convstab<=1'b1;
end
else
begin
i <= i + 6'd1;
ad_convstab<=1'b0;
end
end
Wait_1:
begin
if(i==5)
begin //wait 5 clock
i <= 6'd0;
state<=Wait_busy;
end
else
i <= i + 6'd1;
end
Wait_busy:
begin
if(ad_busy==1'b0)
begin //wait busy low
i <= 6'd0;
state<=READ_CH1;
end
end
READ_CH1:
begin
ad_cs<=1'b0; //cs valid
if(i==3)
begin
ad_rd<=1'b1;
i <= 6'd0;
ad_ch1<=ad_data; //read CH1
state<=READ_CH2;
end
else
begin
ad_rd<=1'b0;
i <= i + 6'd1;
end
end
READ_CH2:
begin
if(i==3)
begin
ad_rd<=1'b1;
i <= 6'd0;
ad_ch2<=ad_data; //read CH2
state<=READ_CH3;
end
else
begin
ad_rd<=1'b0;
i <= i + 6'd1;
end
end
READ_CH3:
begin
if(i==3)
begin
ad_rd<=1'b1;
i <= 6'd0;
ad_ch3<=ad_data; //read CH3
state<=READ_CH4;
end
else
begin
ad_rd<=1'b0;
i <= i + 6'd1;
end
end
READ_CH4:
begin
if(i==3)
begin
ad_rd<=1'b1;
i <= 6'd0;
ad_ch4<=ad_data; //read CH4
state<=READ_CH5;
end
else
begin
ad_rd<=1'b0;
i <= i + 6'd1;
end
end
READ_CH5:
begin
if(i==3)
begin
ad_rd<=1'b1;
i <= 6'd0;
ad_ch5<=ad_data; //read CH5
state<=READ_CH6;
end
else
begin
ad_rd<=1'b0;
i <= i + 6'd1;
end
end
READ_CH6:
begin
if(i==3)
begin
ad_rd<=1'b1;
i <= 6'd0;
ad_ch6<=ad_data; //read CH6
state<=READ_CH7;
end
else
begin
ad_rd<=1'b0;
i <= i + 6'd1;
end
end
READ_CH7:
begin
if(i==3)
begin
ad_rd<=1'b1;
i <= 6'd0;
ad_ch7<=ad_data; //read CH7
state<=READ_CH8;
end
else
begin
ad_rd<=1'b0;
i <= i + 6'd1;
end
end
READ_CH8:
begin
if(i==3)
begin
ad_rd<=1'b1;
i <= 6'd0;
ad_ch8<=ad_data; //read CH8
state<=READ_DONE;
end
else
begin
ad_rd<=1'b0;
i <= i + 6'd1;
end
end
READ_DONE:
begin
ad_rd<=1'b1;
ad_cs<=1'b1;
state<=IDLE;
end
default:
state<=IDLE;
endcase
end
end
endmodule
PI环公式模块
代码如下(示例):
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2024/11/26 12:06:29
// Design Name:
// Module Name: ad_calculate
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module ad_calculate(
input clk,
input rst_n,
input ad_data_valid,
input ad_data_valid_temp,
input signed [15:0] ad_ch1,
input signed [15:0] ad_ch2,
input signed [15:0] ad_ch3,
output reg cal_mode,
output wire flag_error,
output [15:0] data_out //7863 - 5242
);
parameter v_1 = 16'd6578;
parameter k_p = 16'd50;//*100
parameter k_i = 16'd5;//*100
reg ad_data_valid_temp3;
reg ad_data_valid_temp4;
reg ad_data_valid_temp2;
reg signed [15:0] error ;
reg signed [15:0] delta_error ;
reg signed [15:0] error_prev ;
reg signed [31:0] integral ;
reg signed [31:0] integral_prev ;
reg signed [31:0] delta_u_t ;
reg signed [31:0] u_t ;
reg signed [31:0] u_t_prev ;
assign data_out=u_t[15:0];
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cal_mode<=1'd0;
end
else if(ad_data_valid==1'b1 && ad_ch1 > $signed('d16383) )begin
cal_mode<=1'd0;
end
else if(ad_data_valid==1'b1 && ad_ch1< $signed('d16383))begin
cal_mode<=1'd1;
end
else begin
cal_mode<=cal_mode;
end
end
assign flag_error=((ad_ch2>>2)>(ad_ch3>>2))?1:0;
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
ad_data_valid_temp2<=1'd0;
ad_data_valid_temp3<=1'd0;
ad_data_valid_temp4<=1'd0;
end
else begin
ad_data_valid_temp2<=ad_data_valid_temp;
ad_data_valid_temp3<=ad_data_valid_temp2;
ad_data_valid_temp4<=ad_data_valid_temp3;
end
end
//计算error flag_error 1->ad_ch3>1.0v 0->ad_ch3<1.0v
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
error<=16'd0;
end
else if(ad_data_valid==1'b1 )begin
// error<=ad_ch3-ad_ch2;
error<=-(ad_ch2-ad_ch3);
end
else begin
error<=error;
end
end
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
error_prev<=16'd0;
end
else if (ad_data_valid_temp==1'b1 )begin
error_prev<=error;
end
end
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
delta_error<=16'd0;
end
else if (ad_data_valid_temp==1'b1 )begin
delta_error<=error-error_prev;
end
else begin
delta_error<=delta_error;
end
end
// always @(posedge clk or negedge rst_n)begin
// if(!rst_n)begin
// integral_prev<=32'd0;
// end
// else begin
// integral_prev<=integral;
// end
// end
// always @(posedge clk or negedge rst_n)begin
// if(!rst_n)begin
// integral<=32'd0;
// end
// else if(ad_data_valid_temp==1'b1 && integral < $signed('d150000))begin
// integral<=integral_prev+error;
// end
// else begin
// integral<=integral;
// end
// end
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
delta_u_t<=32'd0;
end
else if(ad_data_valid_temp2==1'b1 && (error >$signed('d100) || error<$signed(-'d100)))begin
delta_u_t<=(50*delta_error+5*error)/100;
end
else if (ad_data_valid_temp4==1'b1 && (error >$signed('d100) || error<$signed(-'d100)))begin
delta_u_t<=32'd0;
end
end
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
u_t<=32'd7863; //对应0.9V
end
else if(ad_data_valid_temp3==1'b1 )begin
u_t<=u_t_prev+delta_u_t;
end
else begin
u_t<=u_t;
end
end
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
u_t_prev<=32'd0;
end
else begin
u_t_prev<=u_t;
end
end
endmodule
TOP顶层模块
还例化了一个PLL IP核 -生成100m hz的ad_clk
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2024/11/30 11:10:40
// Design Name:
// Module Name: top
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module top(
//system clocks
input sys_clk,
input rst_n,
input[15:0] ad7606_data, //ad7606 data
input ad7606_busy, //ad7606 busy
input ad7606_first_data, //ad7606 first data
output[2:0] ad7606_os, //ad7606
output ad7606_cs, //ad7606 AD cs
output ad7606_rd, //ad7606 AD data read
output ad7606_reset, //ad7606 AD reset
output ad7606_convstab, //ad7606 AD convert start
output da1_clk, //AD9767 CH1 clock
output da1_wrt, //AD9767 CH1 enable
output [13:0] da1_data, //AD9767 CH1 data output
output led,
output adc_clk,
output [3:0] state,
output da2_clk, //AD9767 CH2 clock
output da2_wrt, //AD9767 CH2 enable
output [13:0] da2_data //AD9767 CH2 data output
);
wire [15:0] data_out; //AD9767 CH2 data output
wire [13:0] da2_data_temp; //
wire ad_data_valid;
wire ad_data_valid_temp;
//wire adc_clk;
//wire [3:0] state ;
wire cal_mode;
//wire adc_clk;
wire signed[15:0] ad_ch1;
wire signed[15:0] ad_ch2;
wire signed[15:0] ad_ch3;
wire signed[15:0] ad_ch4;
wire signed[15:0] ad_ch5;
wire signed[15:0] ad_ch6;
wire signed[15:0] ad_ch7;
wire signed[15:0] ad_ch8;
//wire [3:0] state;
wire [31:0] ad_v;
wire [31:0] da_add;
assign ad_v=da2_data_temp*152;
assign da_add=ad_v/610;
assign da2_data_temp=data_out[13:0];
assign da2_data=da_add+$unsigned('d8192);
assign da1_clk=adc_clk;
assign da1_wrt=adc_clk;
assign da1_data=(cal_mode==1'b0)?14'h2000:14'h2666;
assign da2_clk=adc_clk;
assign da2_wrt=adc_clk;
assign led=cal_mode;
adc_pll u_adc_pll_m0
(
.clk_in1 (sys_clk ),
.clk_out1 (adc_clk ),
.reset (1'b0 ),
.locked ( )
);
ad_calculate u_ad_calculate(
.clk(adc_clk),
.rst_n(rst_n),
.ad_data_valid(ad_data_valid),
.ad_data_valid_temp(ad_data_valid_temp),
.ad_ch1(ad_ch1),
.ad_ch2(ad_ch2),
.ad_ch3(ad_ch3),
.cal_mode(cal_mode),
.flag_error(),
.data_out(data_out)
);
ad7606_if ad7606_if_m0(
.clk (adc_clk ),
.rst_n (rst_n ),
.ad_data (ad7606_data ), //ad7606 data
.ad_busy (ad7606_busy ), //ad7606 busy
.first_data (ad7606_first_data ), //ad7606 first data
.ad_os (ad7606_os ), //ad7606
.ad_cs (ad7606_cs ), //ad7606 AD cs
.ad_rd (ad7606_rd ), //ad7606 AD data read
.ad_reset (ad7606_reset ), //ad7606 AD reset
.ad_convstab (ad7606_convstab ), //ad7606 AD convert start
.ad_data_valid (ad_data_valid ),
.ad_data_valid_temp (ad_data_valid_temp ),
.ad_ch1 (ad_ch1 ),
.ad_ch2 (ad_ch2 ),
.ad_ch3 (ad_ch3 ),
.ad_ch4 (ad_ch4 ),
.ad_ch5 (ad_ch5 ),
.ad_ch6 (ad_ch6 ),
.ad_ch7 (ad_ch7 ),
.ad_ch8 (ad_ch8 ),
.state (state )
);
endmodule
仿真分析
仿真注意:
AD7606数字量范围与AD9767不同,注意数字量之间要基于基础电压单位进行切换,避免仿真跑飞
原文地址:https://blog.csdn.net/g_125487/article/details/144354232
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!