AD7606具有八通道的采集信号,我们可以用它来采集各种模拟信号。我所用的模块如下:
如上图,右边10个接口,中间CH1~CH8为八路模拟信号输入,其两端为AGND。
左边为单片机或 fpga连接的线。本次用的是并行,所以DB0~DB15作为信号线输出给fpga。
OS0~OS2代码里均设置为0或也可自行接地,即无过采样。CO-A和CO-B连接到fpga的同一个引脚,FR-D可接也可不接,busy,RD/SC(代码对应是ad_rd)。SER接地(相当于并行输出,如果接高电平,相当于串行输出)如下图手册说明。
时序图,程序按看第一(即图2)和第三个(图4)来的。
用的板子芯片为7020的,上海微相板子,对应连接线如下。
ps:关于AD7606的供电可以用fpga的5V和gnd供电。
AD7606_UART代码如下:
`timescale 1ns / 1ps
module ad7606_uart(
sys_clk,
rst_n,
ad_data,
ad_busy,
first_data,
ad_os,
ad_cs,
ad_rd,
ad_reset,
ad_convstab,
uart_tx
);
input sys_clk; //50mhz
input rst_n;
input [15:0] ad_data; //ad7606 采样数据
input ad_busy; //ad7606 忙标志位
input first_data; //ad7606 第一个数据标志位
output [2:0] ad_os; //ad7606 过采样倍率选择
output ad_cs; //ad7606 AD cs
output ad_rd; //ad7606 AD data read
output ad_reset; //ad7606 AD reset
output ad_convstab; //ad7606 AD convert start
wire[15:0] ad_ch1 ; //AD第1通道的数据
wire[15:0] ad_ch2 ; //AD第2通道的数据
wire[15:0] ad_ch3 ; //AD第3通道的数据
wire[15:0] ad_ch4 ; //AD第4通道的数据
wire[15:0] ad_ch5 ; //AD第5通道的数据
wire[15:0] ad_ch6 ; //AD第6通道的数据
wire[15:0] ad_ch7 ; //AD第7通道的数据
wire[15:0] ad_ch8 ; //AD第8通道的数据 */
wire[15:0]data1 ;
wire[15:0]data2 ;
wire[15:0]data3 ;
wire[15:0]data4 ;
wire[15:0]data5 ;
wire[15:0]data6 ;
wire[15:0]data7 ;
wire[15:0]data8 ;
output uart_tx;
ad7606 ad7606(
. clk(sys_clk), //50mhz
. rst_n(rst_n),
. ad_data(ad_data), //ad7606 采样数据
. ad_busy(ad_busy), //ad7606 忙标志位
. first_data( first_data), //ad7606 第一个数据标志位
. ad_os(ad_os), //ad7606 过采样倍率选择
. ad_cs(ad_cs), //ad7606 AD cs
. ad_rd(ad_rd), //ad7606 AD data read
. ad_reset(ad_reset), //ad7606 AD reset
. ad_convstab(ad_convstab), //ad7606 AD convert start
.ad_ch1(ad_ch1), //AD第1通道的数据
.ad_ch2(ad_ch2), //AD第2通道的数据
.ad_ch3(ad_ch3), //AD第3通道的数据
.ad_ch4(ad_ch4), //AD第4通道的数据
.ad_ch5(ad_ch5), //AD第5通道的数据
.ad_ch6(ad_ch6), //AD第6通道的数据
.ad_ch7(ad_ch7), //AD第7通道的数据
.ad_ch8(ad_ch8) //AD第8通道的数据
//output reg [3:0] cnt
);
uart_test uart_test(
.sys_clk(sys_clk) , //system clock 50Mhz on board
.rst_n(rst_n) , //reset ,low active
.data1(ad_ch1) ,
.data2(ad_ch2) ,
.data3(ad_ch3) ,
.data4(ad_ch4) ,
.data5(ad_ch5) ,
.data6(ad_ch6) ,
.data7(ad_ch7) ,
.data8(ad_ch8) ,
.uart_tx(uart_tx)
);
endmodule
底层ad7606代码如下:
`timescale 1ns / 1ns
//
// Module Name: ad7606
//
module ad7606(
input clk, //50mhz
input rst_n,
input [15:0] ad_data, //ad7606 采样数据
input ad_busy, //ad7606 忙标志位
input first_data, //ad7606 第一个数据标志位
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 reg [15:0] ad_ch1, //AD第1通道的数据
output reg [15:0] ad_ch2, //AD第2通道的数据
output reg [15:0] ad_ch3, //AD第3通道的数据
output reg [15:0] ad_ch4, //AD第4通道的数据
output reg [15:0] ad_ch5, //AD第5通道的数据
output reg [15:0] ad_ch6, //AD第6通道的数据
output reg [15:0] ad_ch7, //AD第7通道的数据
output reg [15:0] ad_ch8 //AD第8通道的数据
//output reg [3:0] cnt
);
reg [3:0] state;
reg [7:0] cnt = 0 ;
reg [15:0] cnt50us = 0;
reg [5:0] i;
//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;
//parameter display=4'd13;
assign ad_os=3'b000; //无过采样
//ad复位
always@(posedge clk)
begin
if(cnt<8'hff) begin
cnt<=cnt+1;
ad_reset<=1'b1;
end
else
ad_reset<=1'b0; //计数器达到ff后停止,ad_reset恒为零
end
//使用定时器来设置采样频率
always @(posedge clk or negedge rst_n) //每50us读取一次数据,ad的采样率为20K
begin
if(rst_n == 0)
cnt50us <= 0;
else begin
if(cnt50us < 16'd2499)
begin
cnt50us <= cnt50us + 1;
end
else
cnt50us <= 0;
end
end
always @(posedge clk)
begin
if (ad_reset==1'b1) begin //初始化ad
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; //8通道同步采样
i<=0;
end
else begin
case(state) //need time:(20+2+5+1+3*8+1)*20ns=1060ns, fmax=1/1060ns=1MHZ
IDLE: begin
ad_cs<=1'b1;
ad_rd<=1'b1;
ad_convstab<=1'b1;
if(i==20) begin //延时20个时钟后开始转换
i<=0;
state<=AD_CONV;
end
else
i<=i+1'b1;
end
AD_CONV: begin
if(i==2) begin //等待2个lock,convstab的下降沿最少为25ns,故至少需要两个时钟
i<=0;
state<=Wait_1;
ad_convstab<=1'b1;
end
else begin
i<=i+1'b1;
ad_convstab<=1'b0; //启动AD转换
end
end
Wait_1: begin
if(i==5) begin //等待5个clock, 等待busy信号为高(tconv)
i<=0;
state<=Wait_busy;
end
else
i<=i+1'b1;
end
Wait_busy: begin
if(ad_busy==1'b0) begin //等待busy为低电平 即转换之后读取模式
i<=0;
state<=READ_CH1;
end
end
READ_CH1: begin
ad_cs<=1'b0; //cs信号有效 直到读取8通道结束
if(i==3) begin // 低电平持续3个时钟,完成通道1的读入
ad_rd<=1'b1;
i<=0;
ad_ch1<=ad_data; //读CH1
state<=READ_CH2;
end
else begin
ad_rd<=1'b0;
i<=i+1'b1;
end
end
READ_CH2: begin
if(i==3) begin
ad_rd<=1'b1;
i<=0;
ad_ch2<=ad_data; //读CH2
state<=READ_CH3;
end
else begin
ad_rd<=1'b0;
i<=i+1'b1;
end
end
READ_CH3: begin
if(i==3) begin
ad_rd<=1'b1;
i<=0;
ad_ch3<=ad_data; //读CH3
state<=READ_CH4;
end
else begin
ad_rd<=1'b0;
i<=i+1'b1;
end
end
READ_CH4: begin
if(i==3) begin
ad_rd<=1'b1;
i<=0;
ad_ch4<=ad_data; //读CH4
state<=READ_CH5;
end
else begin
ad_rd<=1'b0;
i<=i+1'b1;
end
end
READ_CH5: begin
if(i==3) begin
ad_rd<=1'b1;
i<=0;
ad_ch5<=ad_data; //读CH5
state<=READ_CH6;
end
else begin
ad_rd<=1'b0;
i<=i+1'b1;
end
end
READ_CH6: begin
if(i==3) begin
ad_rd<=1'b1;
i<=0;
ad_ch6<=ad_data; //读CH6
state<=READ_CH7;
end
else begin
ad_rd<=1'b0;
i<=i+1'b1;
end
end
READ_CH7: begin
if(i==3) begin
ad_rd<=1'b1;
i<=0;
ad_ch7<=ad_data; //读CH7
state<=READ_CH8;
end
else begin
ad_rd<=1'b0;
i<=i+1'b1;
end
end
READ_CH8: begin
if(i==3) begin
ad_rd<=1'b1;
i<=0;
ad_ch8<=ad_data; //读CH8
state<=READ_DONE;
end
else begin
ad_rd<=1'b0;
i<=i+1'b1;
end
end
READ_DONE:begin //完成读,回到idle状态
ad_rd<=1'b1;
ad_cs<=1'b1;
if(cnt50us == 16'd2499) //不加此条件,则ad完成一次读取需1280ns,采样频率781.25K,但需注意ad每通道的追高采样只能为200K
state<=IDLE;
else
state<=READ_DONE;
end
default: state<=IDLE;
endcase
end
end
endmodule
uart_test代码如下:
module uart_test(
input sys_clk, //system clock 50Mhz on board
input rst_n, //reset ,low active
input [15:0] data1,
input [15:0] data2,
input [15:0] data3,
input [15:0] data4,
input [15:0] data5,
input [15:0] data6,
input [15:0] data7,
input [15:0] data8,
output uart_tx
);
parameter CLK_FRE = 50;//Mhz
localparam IDLE = 0;
localparam SEND = 1; //send HELLO ALINX\r\n
localparam WAIT = 2; //wait 1 second and send uart received data
reg[7:0] tx_data;
reg[7:0] tx_str;
reg tx_data_valid;
wire tx_data_ready;
reg[7:0] tx_cnt;
reg[31:0] wait_cnt;
reg[3:0] state;
always@(posedge sys_clk or negedge rst_n)
begin
if(rst_n == 1'b0)
begin
wait_cnt <= 32'd0;
tx_data <= 8'd0;
state <= IDLE;
tx_cnt <= 8'd0;
tx_data_valid <= 1'b0;
end
else
case(state)
IDLE:
state <= SEND;
SEND:
begin
wait_cnt <= 32'd0;
tx_data <= tx_str;
if(tx_data_valid == 1'b1 && tx_data_ready == 1'b1 && tx_cnt < 8'd23)//Send 12 bytes data
begin
tx_cnt <= tx_cnt + 8'd1; //Send data counter
end
else if(tx_data_valid && tx_data_ready)//last byte sent is complete
begin
tx_cnt <= 8'd0;
tx_data_valid <= 1'b0;
state <= WAIT;
end
else if(~tx_data_valid)
begin
tx_data_valid <= 1'b1;
end
end
WAIT:
begin
wait_cnt <= wait_cnt + 32'd1;
if(tx_data_valid && tx_data_ready)
begin
tx_data_valid <= 1'b0;
end
else if(wait_cnt >= CLK_FRE * 1000000) // wait for 1 second
state <= SEND;
end
default:
state <= IDLE;
endcase
end
//combinational logic
//Send "HELLO ALINX\r\n"
always@(*)
begin
case(tx_cnt)
8'd0 : tx_str <= "C1";
8'd1 : tx_str <= data1[15:8];
8'd2 : tx_str <= data1[7:0];
8'd3: tx_str <= "C2";
8'd4 : tx_str <= data2[15:8];
8'd5 : tx_str <= data2[7:0];
8'd6: tx_str <= "C3";
8'd7 : tx_str <= data3[15:8];
8'd8 : tx_str <= data3[7:0];
8'd9: tx_str <= "C4";
8'd10 : tx_str <= data4[15:8];
8'd11 : tx_str <= data4[7:0];
8'd12: tx_str <= "C5";
8'd13 : tx_str <= data5[15:8];
8'd14 : tx_str <= data5[7:0];
8'd15: tx_str <= "C6";
8'd16 : tx_str <= data6[15:8];
8'd17 : tx_str <= data6[7:0];
8'd18: tx_str <= "C7";
8'd19 : tx_str <= data7[15:8];
8'd20 : tx_str <= data7[7:0];
8'd21: tx_str <= "C8";
8'd22 : tx_str <= data8[15:8];
8'd23 : tx_str <= data8[7:0];
default:tx_str <= 8'd0;
endcase
end
uart_tx#
(
.CLK_FRE(CLK_FRE),
.BAUD_RATE(115200)
) uart_tx_inst
(
.clk (sys_clk ),
.rst_n (rst_n ),
.tx_data (tx_data ),
.tx_data_valid (tx_data_valid ),
.tx_data_ready (tx_data_ready ),
.tx_pin (uart_tx )
);
endmodule
uart_test同样包含一个子模块,如下:
module uart_tx
#(
parameter CLK_FRE = 50, //clock frequency(Mhz)
parameter BAUD_RATE = 115200 //serial baud rate
)
(
input clk, //clock input
input rst_n, //asynchronous reset input, low active
input[7:0] tx_data, //data to send
input tx_data_valid, //data to be sent is valid
output reg tx_data_ready, //send ready
output tx_pin //serial data output
);
//calculates the clock cycle for baud rate
localparam CYCLE = CLK_FRE * 1000000 / BAUD_RATE;
//state machine code
localparam S_IDLE = 1;
localparam S_START = 2;//start bit
localparam S_SEND_BYTE = 3;//data bits
localparam S_STOP = 4;//stop bit
reg[2:0] state;
reg[2:0] next_state;
reg[15:0] cycle_cnt; //baud counter
reg[2:0] bit_cnt;//bit counter
reg[7:0] tx_data_latch; //latch data to send
reg tx_reg; //serial data output
assign tx_pin = tx_reg;
always@(posedge clk or negedge rst_n)
begin
if(rst_n == 1'b0)
state <= S_IDLE;
else
state <= next_state;
end
always@(*)
begin
case(state)
S_IDLE:
if(tx_data_valid == 1'b1)
next_state <= S_START;
else
next_state <= S_IDLE;
S_START:
if(cycle_cnt == CYCLE - 1)
next_state <= S_SEND_BYTE;
else
next_state <= S_START;
S_SEND_BYTE:
if(cycle_cnt == CYCLE - 1 && bit_cnt == 3'd7)
next_state <= S_STOP;
else
next_state <= S_SEND_BYTE;
S_STOP:
if(cycle_cnt == CYCLE - 1)
next_state <= S_IDLE;
else
next_state <= S_STOP;
default:
next_state <= S_IDLE;
endcase
end
always@(posedge clk or negedge rst_n)
begin
if(rst_n == 1'b0)
begin
tx_data_ready <= 1'b0;
end
else if(state == S_IDLE)
if(tx_data_valid == 1'b1)
tx_data_ready <= 1'b0;
else
tx_data_ready <= 1'b1;
else if(state == S_STOP && cycle_cnt == CYCLE - 1)
tx_data_ready <= 1'b1;
end
always@(posedge clk or negedge rst_n)
begin
if(rst_n == 1'b0)
begin
tx_data_latch <= 8'd0;
end
else if(state == S_IDLE && tx_data_valid == 1'b1)
tx_data_latch <= tx_data;
end
always@(posedge clk or negedge rst_n)
begin
if(rst_n == 1'b0)
begin
bit_cnt <= 3'd0;
end
else if(state == S_SEND_BYTE)
if(cycle_cnt == CYCLE - 1)
bit_cnt <= bit_cnt + 3'd1;
else
bit_cnt <= bit_cnt;
else
bit_cnt <= 3'd0;
end
always@(posedge clk or negedge rst_n)
begin
if(rst_n == 1'b0)
cycle_cnt <= 16'd0;
else if((state == S_SEND_BYTE && cycle_cnt == CYCLE - 1) || next_state != state)
cycle_cnt <= 16'd0;
else
cycle_cnt <= cycle_cnt + 16'd1;
end
always@(posedge clk or negedge rst_n)
begin
if(rst_n == 1'b0)
tx_reg <= 1'b1;
else
case(state)
S_IDLE,S_STOP:
tx_reg <= 1'b1;
S_START:
tx_reg <= 1'b0;
S_SEND_BYTE:
tx_reg <= tx_data_latch[bit_cnt];
default:
tx_reg <= 1'b1;
endcase
end
endmodule
引脚约束如下:由于实现过程中,Vivado 报错:[Place 30-574] Poor placement for routing between an IO pin and BUFG.,将其报错语句中给的修改推荐复制到约束文件里即可。使用.xdc文件中的CLOCK_DEDICATED_ROUTE约束将此消息降级为警告。
语句为:set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets clk_IBUF]
set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets clk_IBUF]
set_property IOSTANDARD LVCMOS33 [get_ports {ad_data[15]}]
set_property IOSTANDARD LVCMOS33 [get_ports {ad_data[14]}]
set_property IOSTANDARD LVCMOS33 [get_ports {ad_data[13]}]
set_property IOSTANDARD LVCMOS33 [get_ports {ad_data[12]}]
set_property IOSTANDARD LVCMOS33 [get_ports {ad_data[11]}]
set_property IOSTANDARD LVCMOS33 [get_ports {ad_data[10]}]
set_property IOSTANDARD LVCMOS33 [get_ports {ad_data[9]}]
set_property IOSTANDARD LVCMOS33 [get_ports {ad_data[8]}]
set_property IOSTANDARD LVCMOS33 [get_ports {ad_data[7]}]
set_property IOSTANDARD LVCMOS33 [get_ports {ad_data[6]}]
set_property IOSTANDARD LVCMOS33 [get_ports {ad_data[5]}]
set_property IOSTANDARD LVCMOS33 [get_ports {ad_data[4]}]
set_property IOSTANDARD LVCMOS33 [get_ports {ad_data[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {ad_data[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {ad_data[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {ad_data[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports {ad_os[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {ad_os[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {ad_os[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports ad_busy]
set_property IOSTANDARD LVCMOS33 [get_ports ad_cs]
set_property IOSTANDARD LVCMOS33 [get_ports ad_convstab]
set_property IOSTANDARD LVCMOS33 [get_ports ad_rd]
set_property IOSTANDARD LVCMOS33 [get_ports ad_reset]
set_property IOSTANDARD LVCMOS33 [get_ports clk]
set_property IOSTANDARD LVCMOS33 [get_ports first_data]
set_property IOSTANDARD LVCMOS33 [get_ports rst_n]
set_property IOSTANDARD LVCMOS33 [get_ports sys_clk]
set_property IOSTANDARD LVCMOS33 [get_ports uart_tx]
set_property PACKAGE_PIN N17 [get_ports {ad_data[15]}]
set_property PACKAGE_PIN P18 [get_ports {ad_data[14]}]
set_property PACKAGE_PIN R16 [get_ports {ad_data[13]}]
set_property PACKAGE_PIN R17 [get_ports {ad_data[12]}]
set_property PACKAGE_PIN T16 [get_ports {ad_data[11]}]
set_property PACKAGE_PIN U17 [get_ports {ad_data[10]}]
set_property PACKAGE_PIN W18 [get_ports {ad_data[9]}]
set_property PACKAGE_PIN W19 [get_ports {ad_data[8]}]
set_property PACKAGE_PIN Y18 [get_ports {ad_data[7]}]
set_property PACKAGE_PIN Y19 [get_ports {ad_data[6]}]
set_property PACKAGE_PIN Y16 [get_ports {ad_data[5]}]
set_property PACKAGE_PIN Y17 [get_ports {ad_data[4]}]
set_property PACKAGE_PIN V17 [get_ports {ad_data[3]}]
set_property PACKAGE_PIN V18 [get_ports {ad_data[2]}]
set_property PACKAGE_PIN W14 [get_ports {ad_data[1]}]
set_property PACKAGE_PIN Y14 [get_ports {ad_data[0]}]
set_property PACKAGE_PIN V16 [get_ports {ad_os[2]}]
set_property PACKAGE_PIN W16 [get_ports {ad_os[1]}]
set_property PACKAGE_PIN T17 [get_ports {ad_os[0]}]
set_property PACKAGE_PIN R18 [get_ports ad_busy]
set_property PACKAGE_PIN V12 [get_ports ad_convstab]
set_property PACKAGE_PIN W13 [get_ports ad_cs]
set_property PACKAGE_PIN T14 [get_ports ad_rd]
set_property PACKAGE_PIN T15 [get_ports ad_reset]
set_property PACKAGE_PIN T11 [get_ports clk]
set_property PACKAGE_PIN T10 [get_ports first_data]
set_property PACKAGE_PIN P16 [get_ports rst_n]
set_property PACKAGE_PIN N18 [get_ports sys_clk]
set_property PACKAGE_PIN P14 [get_ports uart_tx]
至此,所有代码完毕。开始生成比特流文件,接好线,烧录程序
打开串口,设置波特率115200.接收数据
采集到数据为31 XX XX 32 XX XX 33 XX XX 34 XX XX 35 XX XX 36 XX XX 37 XX XX 38 XX XX.
其中31,32…38均为通道号,通道号后面为采集到的电压数据。本次实验中,只有CH1通道接了3.3V,其他通道号均悬空,悬空时电压为2.0V左右。
取CH1通道的一组31 29 26 ,数据为29 36,用计算器转化成10进制10550.
我这个ad7606的J2盖帽连接在10V处,其原理图显示为Range=1.
故而计算公式选择如下红框处,VIN=CODE×10/32768
把10550代入,VIN=10550×10/32768=3.219V 与我实际给的电压差不多,和万用表实测电压一致。
看其他CH2~CH8,取其中一个CH2 的数据1A 7B。同样接着计算,
结果为2V,与通道号悬空时候实测电压一致。至此程序的编写没问题。
链接:https://pan.baidu.com/s/1mylaGHqWAYowPT-4RKgumg
提取码:8sv4
–来自百度网盘超级会员V5的分享