目录

一、AD7606数据手册

     1.ADC采样原理

     2.AD7606使用手册

二、实例

     1.状态转移图

     2.Verilog代码

     3.仿真结果

总结

一、AD7606数据手册

     1.ADC采样原理

        在实际的工程中,经前端传感器出来的信号基本都是模拟信号,而后端mcu主控芯片是基于数字信号进行处理的,因此需要用到ADC进行模数转换。ADC包括三个基本功能:抽样、量化和编码。抽样过程是将模拟信号在时间上离散化,使之成为抽样信号;量化是将抽样信号的幅度离散化使之成为数字信号;而编码则是将数字信号转换成数字系统所能接受的形式。如何实现这三个功能就决定了ADC的形式和性能。同时,ADC的分辨率(即采样精度)越高,需要的转换时间就越长,转换速度就越低,故ADC的分辨率和转换速率两者总是相互制约的。

       对于一个16位的ADC来说,如果输入的模拟信号幅值在0到3.3V,那么采样后输出的数字信号对应的应该在0到65535,采样精度是1/65536。因此,我们发现,采样位数越高的AD,其采样精度越高,信噪比越大,其越接近原始信号。

      采样率即是两个采样点之间的间隔时间,两个采样点之间的间隔时间越短,其采样率越高。根据奈奎斯特采样定律,信号的采样率应该大于其最大频率的2倍。而实际应用中,通常选择信号最大频率的几十倍的采样率,为了更加准确有效的恢复出原始信号。

     2.AD7606使用手册

         AD7606是16位,8通道同步采集模数数据采集系统。各器件均内置模拟输入钳位保护、二阶抗混叠滤波器、跟踪保持放大器、16位电荷再分配逐次逼近型模数转换器、灵活的数字滤波器、2.5V基准电压源、基准电压缓冲以及高速串行和并行接口。

       AD7606采用5V单电源供电,可以处理正负10V和正负5V真双极性输入信号,同时所有通道均能以高达200kSPS的吞吐速率采样。输入钳位保护电路可以耐受最高达正负16.5V的电压。无论以何种采样频率工作,  AD7606的模拟输入阻抗均为1MΩ。它采用单电源工作方式,具有片内滤波和高输入阻抗,因此无需驱动运算放大器和外部双极性电源。AD7606抗混叠滤波器的3dB截止频率22kHz;当采样率为200kSPS时,它具有40dB抗混叠抑制特性。灵活的数字滤波器采用引脚驱动,可以改善信噪比(SNR),并降低3dB带宽。

       下面给出AD7606引脚配置和功能描述,下图是AD7606的引脚图:

       下图给出AD7606的引脚功能描述:

       其中,AD7606可以选择三种工作模式,通过配置引脚PAR/SER/BYTE SEL和DB15,如下图所示:

       上述三种工作模式都需要首先给AD7606一个转换信号,如果是各通道同步采样,则需要同时给出CONVST_A和CONVST_B信号,然后等待BUSY信号,如果选择等待AD转换后读取,则需要等待BUSY信号拉低后再进行数据读取;如果选择在AD转换期间读取,则不需要等待BUSY信号拉低。下面给出两种不同时刻读取数据的时序图:

        在读取数据时,需要首先给AD7606一个读取数据的使能信号CS,接着给出读取数据的时钟信号RD/SCLK,然后AD7606给出相应的数据。

        如果工作在并行接口模式,在CS信号拉低后,RD给出8个时钟,分别读取8个通道采集到的数据DATA[15:0],在读取通道1时FRSTDATA信号拉高,时序图如下所示:

         如果工作在串行接口模式,在CS信号拉低后,SCLK给出16*4=64个时钟,分别读取DOUTA输出的采集到的通道1~4上的数据和DOUTB上输出的采集到的通道5~8上的数据,在读取通道1时,FRSTDATA信号拉高时序图如下所示:

        

         如果工作在并行字节接口模式,在CS信号拉低后,RD给出2*8=16个时钟,两个时钟为一组,分别读取某一通道采集到的数据的高八位和低八位,数据从DATA[7:0]输出,时序图如下所示:

   下表给出上述三种模式对应的时序规格:

 

 

 

 

二、实例

       要求:通过AD7606同步采集八个通道的数据,FPGA按照串行读取的操作,分别读取各通道采集到的数据。

     1.状态转移图

           共定义九个状态进行转换,通过输入caiji_flag标志信号开始每次的数据采集,当数据采集结束后,输出caiji_over结束信号。

           2.Verilog代码

module ad7606_1(

input clk,

input res,

input dout_a, //ad7606通道a输入串行读取数据

input dout_b, //ad7606通道b输入串行读取数据

input ad_busy, //ad7606输入busy信号

input caiji_flag, //外界输入开始数据采集的标志

output reg ad_cs, //读ad7606的使能信号

output reg ad_rd, //读ad7606的时钟信号

output reg ad_convstab //ad7606开始转换信号,低电平有效

);

parameter IDLE = 9'b0_0000_0001;

parameter AD_CONV = 9'b0_0000_0010;

parameter WAIT_1 = 9'b0_0000_0100;

parameter WAIT_BUSY = 9'b0_0000_1000;

parameter READ_CH15 = 9'b0_0001_0000;

parameter READ_CH26 = 9'b0_0010_0000;

parameter READ_CH37 = 9'b0_0100_0000;

parameter READ_CH48 = 9'b0_1000_0000;

parameter READ_STOP = 9'b1_0000_0000;

parameter CONV_TIME = 5; //AD_CONV状态持续时间等价转换信号低电平持续时间

parameter WAIT_TIME = 5; //WAIT_1状态持续时间

parameter FIV_CLK = 4;

parameter CNT_CLK = 16; //每个通道一次发送的时钟个数

reg [8:0]stata;

reg [5:0]cnt ; //在数据读取状态表示分频系数

reg [4:0]cnt_bite;

reg [15:0]databuffa; //a通道串并转换后存储

reg [15:0]databuffb; //b通道串并转换后存储

//存储八个通道采集到的数据

reg [15:0] data_ch1;

reg [15:0] data_ch2;

reg [15:0] data_ch3;

reg [15:0] data_ch4;

reg [15:0] data_ch5;

reg [15:0] data_ch6;

reg [15:0] data_ch7;

reg [15:0] data_ch8;

reg [2 :0] over;

wire caiji_over;

always@(posedge clk or negedge res)

if(!res)

cnt <= 'd0;

else if(stata == AD_CONV)

if(cnt == CONV_TIME)

cnt <= 'd0;

else

cnt <= cnt + 1;

else if(stata == WAIT_1)

if(cnt == WAIT_TIME)

cnt <= 'd0;

else

cnt <= cnt + 1;

else if(stata == WAIT_BUSY) //为了在下一个状态,cnt从6开始计数,为了让CS和RD信号前后有延时

if(ad_busy == 1'b0)

cnt <= 'd6;

else

cnt <= cnt;

else if(stata == READ_CH15 || stata == READ_CH26 || stata == READ_CH37 || stata == READ_CH48)

if(cnt == (2*FIV_CLK-1))

cnt <= 'd0;

else

cnt <= cnt + 1;

always@(posedge clk or negedge res)

if(!res)

cnt_bite <= 'd0;

else if(stata == READ_CH15 )

if(cnt_bite == (CNT_CLK) && cnt == (2*FIV_CLK-1))

cnt_bite <= 'd0;

else if(cnt == (2*FIV_CLK-1))

cnt_bite <= cnt_bite + 1;

else

cnt_bite <= cnt_bite;

else if( stata == READ_CH26 || stata == READ_CH37 || stata == READ_CH48)

if(cnt_bite == (CNT_CLK -1) && cnt == (2*FIV_CLK-1))

cnt_bite <= 'd0;

else if(cnt == (2*FIV_CLK-1))

cnt_bite <= cnt_bite + 1;

else

cnt_bite <= cnt_bite;

else

cnt_bite <= 'd0;

always@(posedge clk or negedge res)

if(!res)

stata <= 4'd0;

else begin

case(stata)

IDLE : if(caiji_flag == 1'b1)

stata <= AD_CONV;

else

stata <= IDLE;

AD_CONV : if(cnt == CONV_TIME)

stata <= WAIT_1;

else

stata <= AD_CONV;

WAIT_1 : if(cnt == WAIT_1)

stata <= WAIT_BUSY;

else

stata <= WAIT_1;

WAIT_BUSY : if(ad_busy == 1'b0)

stata <= READ_CH15;

else

stata <= WAIT_BUSY;

READ_CH15 : if(cnt_bite == (CNT_CLK ) && cnt == (2*FIV_CLK-1))

stata <= READ_CH26;

else

stata <= READ_CH15;

READ_CH26 : if(cnt_bite == (CNT_CLK -1) && cnt == (2*FIV_CLK-1))

stata <= READ_CH37;

else

stata <= READ_CH26;

READ_CH37 : if(cnt_bite == (CNT_CLK -1) && cnt == (2*FIV_CLK-1))

stata <= READ_CH48;

else

stata <= READ_CH37;

READ_CH48 : if(cnt_bite == (CNT_CLK -1) && cnt == (2*FIV_CLK-1))

stata <= READ_STOP;

else

stata <= READ_CH48;

READ_STOP : stata <= IDLE;

default:stata <= IDLE;

endcase

end

//输出信号

always@(posedge clk or negedge res)

if(!res)

ad_convstab <= 1'b1;

else if(stata == AD_CONV)

ad_convstab <= 1'b0;

else

ad_convstab <= 1'b1;

always@(posedge clk or negedge res)

if(!res)

ad_cs <= 1'b1;

else if(stata == WAIT_BUSY && ad_busy == 1'b0)

ad_cs <= 1'b0;

else if(stata == READ_STOP)

ad_cs <= 1'b1;

else

ad_cs <= ad_cs;

always@(posedge clk or negedge res)

if(!res)

ad_rd <= 1'b1;

else if(stata == READ_CH15 || stata == READ_CH26 || stata == READ_CH37 || stata == READ_CH48)

if(cnt == (FIV_CLK-1))

ad_rd <= 1'b0;

else if(cnt == 2*FIV_CLK-1)

ad_rd <= 1'b1;

else

ad_rd <= ad_rd;

else

ad_rd <= 1'b1;

//处理输入的串行数据

always@(posedge clk or negedge res)

if(!res)begin

databuffa <= 16'd0;

databuffb <= 16'd0;

end

else if(stata == READ_CH15 || stata == READ_CH26 || stata == READ_CH37 || stata == READ_CH48)begin

if(cnt == FIV_CLK && ad_rd == 1'b0)begin

databuffa <= {databuffa[14:0],dout_a};

databuffb <= {databuffb[14:0],dout_b};

end

else begin

databuffa <= databuffa;

databuffb <= databuffb;

end

end

else begin

databuffa <= 16'd0;

databuffb <= 16'd0;

end

//将采集到的数据存储到data_ch1-data_ch8中

always@(posedge clk or negedge res)

if(!res)begin

data_ch1 <= 16'd0;

data_ch2 <= 16'd0;

data_ch3 <= 16'd0;

data_ch4 <= 16'd0;

data_ch5 <= 16'd0;

data_ch6 <= 16'd0;

data_ch7 <= 16'd0;

data_ch8 <= 16'd0;

end

else if(stata == READ_CH15 && cnt_bite == (CNT_CLK) && cnt == (2*FIV_CLK-1))begin

data_ch1 <= databuffa;

data_ch5 <= databuffb;

end

else if(stata == READ_CH26 && cnt_bite == (CNT_CLK -1) && cnt == (2*FIV_CLK-1))begin

data_ch2 <= databuffa;

data_ch6 <= databuffb;

end

else if(stata == READ_CH37 && cnt_bite == (CNT_CLK -1) && cnt == (2*FIV_CLK-1))begin

data_ch3 <= databuffa;

data_ch7 <= databuffb;

end

else if(stata == READ_CH48 && cnt_bite == (CNT_CLK -1) && cnt == (2*FIV_CLK-1))begin

data_ch4 <= databuffa;

data_ch8 <= databuffb;

end

else begin

data_ch1 <= data_ch1 ;

data_ch2 <= data_ch2 ;

data_ch3 <= data_ch3 ;

data_ch4 <= data_ch4 ;

data_ch5 <= data_ch5 ;

data_ch6 <= data_ch6 ;

data_ch7 <= data_ch7 ;

data_ch8 <= data_ch8 ;

end

//八个通道采集结束后,对over信号打拍处理,输出over_flag

assign caiji_over = over[2];

always@(posedge clk or negedge res)

if(!res)

over <= 3'd0;

else if(stata == READ_STOP)begin

over[0] <= 1'b1;

over[1] <= over[0];

over[2] <= over[1];

end

else begin

over[0] <= 1'b0;

over[1] <= over[0];

over[2] <= over[1];

end

endmodule

下面给出tb测试文件:

`timescale 1ns/1ns

module tb1();

reg clk;

reg res;

reg data_b;

reg data_a;

reg busy;

reg caiji_flag;

wire ad_cs;

wire ad_rd;

wire ad_convstab;

reg ad_convstab_buffer;

wire convstab_flag;

reg [9:0]cnt;

initial begin

clk <= 1'b0;

res <= 1'b0;

busy <= 1'b0;

data_a <= 1'b0;

data_b <= 1'b0;

caiji_flag <= 1'b0;

#100 res <= 1'b1;

end

always #10 clk <= ~clk;

//检测ad_convstb的下降沿

always@(posedge clk)

ad_convstab_buffer <= ad_convstab;

assign convstab_flag = (~ad_convstab)&ad_convstab_buffer;

always@(posedge clk or negedge res)

if(!res)

cnt <= 0;

else if(convstab_flag)

cnt <= cnt + 1;

else if(cnt == 7)

cnt <= cnt;

else

cnt <= cnt + 1;

always@(posedge clk)begin

if(cnt >5 && cnt <8)begin

caiji_flag <= 1'b1;

busy <= 1'b0;

end

else if(cnt == 8)begin

caiji_flag <= 1'b0;

busy <= 1'b0;

end

else if(cnt>8 && cnt<20)begin

busy <= 1'b1;

caiji_flag <= 1'b0;

end

else if(cnt == 20)begin

busy <= 1'b0;

caiji_flag <= 1'b0;

end

else

busy <= busy;

end

always@(posedge ad_rd or posedge ad_cs)

if(ad_cs)begin

data_a <= 1'b0;

data_b <= 1'b0;

end

else begin

data_a <= {$random}%2;

data_b <= {$random}%2;

end

ad7606_1 u_ad7606_1(

. clk (clk) ,

. res (res) ,

. dout_a (data_a) , //ad7606 数据

. dout_b (data_b) ,

. ad_busy (busy) , //ad7606 busy

. caiji_flag (caiji_flag) ,

. ad_cs (ad_cs) , //ad7606 AD 片选

. ad_rd (ad_rd) , //ad7606 AD 串行读数据时钟

. ad_convstab (ad_convstab) //ad7606 AD convert start

);

endmodule

        3.仿真结果

           仿真结果如下图所示:图1给出了前五个状态的时序图,图2给出了后四个状态(数据采集)的时序图,图3给出了整体的时序仿真图。

                                                                图1 

                                                               图2

                                                              图3

总结

        总体而言,该芯片是一款性能不错的AD芯片,操作时序图相对比较简单,基本能够满足一般系统的性能要求。当然如果系统对数据采集的要求过高,即要求高信噪比,那么在AD选型的过程中可以考虑18位的AD(AD7690、CBM79AD60)或者是24位AD(AD1258)芯片;这里给大家推荐一下AD7690,18位的AD芯片,单通道数据采集,差分输入,串行读取AD数据,其操作时序十分简单,封装为MSOP-10,占用PCB空间较小。

       初次创作,难免文章中存在错误,希望读者能够及时纠正并给予私信,望大家共同进步!

精彩内容

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: