要素察觉:
- 本文基于 AD7888 八输入通道 模数转换芯片,对转换后的数据在 FPGA 中进行接收,所使用的 HDL 为 Verilog;
- 所有实现步骤依据 AD7888 DataSheet 中给出的相关数据和时序图,对原理和相应 Verilog 实现进行系统、完整说明;
- TestBench 测试程序可直接调用;
- 先看一下TestBench仿真测试结果
一、为什么需要模数转换
在许多电路系统中会对一些变量进行收集,从而实现对相应电路模块的控制。这些变量无论是光照强度,还是温度和湿度,都通过一定的传感器电路变成电压这个模拟量。通过对电压模拟量的采集和AD转换,达到芯片进行读取和控制的目的。
二、AD转换原理
限于侧重点和不同需求,会另附链接进行说明。
三、Verilog 实现思想
1.端口操作
首先得知道:
(1)要对 AD7888 哪些端口进行操作
(2)这些端口对于 FPGA 来说是输入端口还是输出端口
下图是 AD7888 的管脚封装图以及各管脚的功能说明
实际上与 FPGA 相连的只有四个端口: SCLK、CS、DIN、DOUT。
这四个端口与 FPGA 之间的信号流向如下图所示:
由 FPGA 对 CS 端口进行片选操作;FPGA 生成串行时钟供给 SCLK 端口使用;DOUT 端口负责向 FPGA 发送模数转换后的结果。
DIN 端口负责接受来自 FPGA 的控制信号,下图是传输到 DIN 端口的 8 bit控制信号,图中 MSB 为第一个传输的 bit。
控制信号包括 :
[ADD2 ADD1 ADD0]:对 8 个输入端口(通道)的模数转换结果的通道选择;
[REF]:内部 REF 参考电压的使能与否;
[PM1 PM0]:AD7888 的工作模式。
注意:
在对某一通道数据采样结果进行传输的前一个传输周期就要在 DIN 中将这个通道的地址赋值好。
2.端口时序
下图是 AD7888 的数据传输时序图
只要按照这个时序图来写 Verilog 程序就好。
(1)生成 SCLK 串行时钟
AD7888 与 FPGA 的所有数据传输完全基于 SCLK,查阅 AD7888 的DataSheet
发现其最大 SCLK 传输频率为 2MHz,本文以 2MHz作为其传输频率,以 FPGA 的时钟 CLK 为 65MHz 为例,要找一个寄存器变量counter_sclk 让其对 CLK 进行计数,从而生成 SCLK。
CLK:对应程序中寄存器变量 clk
SCLK:对应程序中寄存器变量 sclk_7888
计算过程:
(65M / 2M)/ 2 = 16.25 ,这里为方便取 17,即 counter_sclk 对 clk 每计数 17次后,让变量 sclk_7888[0:0] 进行翻转。
(2) 生成 CS 片选信号和沿信号
只有当 CS 为低电平时,数据传输才能进行。
查阅 DataSheet 发现,当 CS 由高变低的下降沿开始,SCLK 的第一个下降沿后开始进行数据传输。
那么什么时候 对CS 拉低?这里操作为:当 SCLK 的第一个上升沿的时候,对 CS 进行拉低。
所以接下来要采集 SCLK 的上升沿和下降沿,采沿的操作,和对异步信号采沿的操作一样(例如RS232)。
数据传输过程同样牵涉到 SCLK 上升沿和下降沿。
(3)DIN、DOUT 数据传输
采用 AD7888 主要就是可以对 8个模拟量进行数模转换,而转换结果只能通过一个通道 DOUT 传输。这就要对每一个通道的转换结果进行轮回传输,同时为保证每个通道最后输出结果逼近偏差小,连续采每个通道的几个值,进行平均。
最复杂的就是本步骤,要使用状态机进行轮回采样。
四、TestBench 测试仿真程序
**2.TestBench 测试仿真程序**
```c
module tb_AD7888_sample( );
reg sys_clk;
reg sys_rst_n;
reg din_7888;
wire dout_7888;
wire cs_7888;
wire sclk_7888;
wire [7:0]sensor_1;
wire [7:0]sensor_2;
wire [7:0]sensor_3;
wire [7:0]sensor_4;
wire [7:0]sensor_5;
wire [7:0]sensor_6;
wire [7:0]sensor_7;
wire [7:0]sensor_8;
wire [2:0]channel_out;
AD7888_sample uut(
.sys_clk (sys_clk),
.sys_rst_n(sys_rst_n),
.din_7888(din_7888),
.dout_7888(dout_7888),
.cs_7888(cs_7888 ),
.sclk_7888(sclk_7888),
.sensor_1(sensor_1 ),
.sensor_2(sensor_2 ),
.sensor_3(sensor_3 ),
.sensor_4(sensor_4 ),
.sensor_5(sensor_5 ),
.sensor_6(sensor_6 ),
.sensor_7(sensor_7 ),
.sensor_8(sensor_8 ),
.channel_out(channel_out)
);
initial begin
sys_clk = 0 ;
sys_rst_n = 0 ;
din_7888 = 0;
#200
sys_rst_n = 1;
end
always #10 sys_clk <= ~sys_clk;
endmodule
3.时序仿真结果