FPGA初级课程第二十二讲 AD
本帖最后由 lcytms 于 2017-2-10 11:26 编辑FPGA初级课程
第二十二讲 AD
Hi,大家好!我是至芯科技的李老师。
今天讲课的题目是:AD。
本节课我先简要地介绍一下AD转换芯片工作的基本原理,然后实际演示一下AD驱动逻辑电路的建模与仿真,我们还要结合第四讲的数码管一起编写一个完整的演示逻辑,并下板查看实际效果。
演示平台为至芯科技开发的ZX_2开发板。
开发板采用的AD转换芯片为TI公司的8位串行控制模数转换器TLC549。
打开《ZX_2.pdf》文件,我们看一下AD部分的电路图。
我们打开至芯科技编写的《基于FPGA的TLC549驱动设计(AD).pdf》文档。
本帖最后由 lcytms 于 2017-2-8 17:25 编辑
1. 实验引言
ADC和DAC是模拟量和数字量之间不可或缺的桥梁。
而AD、DA转换器在数字控制系统中也有着重要地位。
D/A转换器把收到的数字控制信号转换成模拟信号,实现对被控对象的控制。
而A/D转换器将各种模拟信号转换为抗干扰性更强的数字信号,直接进入数字计算机进行处理,存储并产生数字控制信号。
2.实验目的
熟悉串行模/数转换芯片TLC549的使用方法,掌握利用有限状态机实现一般时序逻辑分析方法,了解一般状态机的设计与应用。
3.实验内容
本实验的内容是利用状态机实现对TLC549的采样控制,制作一个简易的电压表。
实验时通过调节电位器RW1改变ADC的模拟输入值,数据采样读取后由数码管显示,最后用万用表测量输入电压,并与读取到的数据(经换算后的数据,单位为MV)作比较。
本帖最后由 lcytms 于 2017-2-10 11:51 编辑
4.实验原理
TLC549是一个8位的串行模数转换器,A/D转换时间最大17us,I/O时钟频率可达1.1MHz。
如图1所示为TLC549的访问时序,从图中可以看出当CS拉低时,ADC前一次的转换数据(A)的最高位A7立即出现在数据线DATA OUT上。
之后的数据在时钟I/O CLOCK的下降沿改变,可在I/O CLOCK的上升沿读取数据。
读完8位数据后,ADC开始转换这一次采样的信号(B),以便下一次读取。
转换时片选信号CS要置为高电平。
设计操作时序时要注意Tsu(CS)、Tconv及I/O CLOCK的频率等几个参数。
Tsu(CS)为CS拉低到I/O CLOCK 第一个时钟到来时间,至少要1.4us;
Tconv为ADC的转换时钟,不超过17us;
I/O CLOCK不能超过1.1MHz。
其他参数请参考数据手册。
由于ADC是8位的,所以采样的电压值为
V = (Vref * D) / 256
其中V为采样的电压值;
D为ADC转换后读取的8位二进制数;
Vref为参考电压值,这里是2.5V。
TLC549访问时序图示如下。
本帖最后由 lcytms 于 2017-2-8 20:11 编辑
5. 硬件设计
用TLC549芯片搭建的AD转换电路如下图所示。 AD芯片的工作原理既然已经清楚,我们下面来进行系统设计。
命名AD驱动逻辑为adc。
架构图如下所示。
本帖最后由 lcytms 于 2017-2-10 13:38 编辑
在后级加上数码管数据预处理模块pre_seg7、数码管模块seg7、数码管显示后处理模块post_seg7后,总体架构图如下。
其中,数码管数据预处理模块pre_seg7将AD数据(0~255)转换为电压值的1000倍(0~2500),数据刷新间隔设为0.1s,随后转换为4位BCD码(二进制为16位),输出至数码管模块seg7;
数码管显示后处理模块post_seg7则负责优化显示效果,将高位零禁止显示,并添加小数点。
比如AD数据128对应1.250V,1000倍则为1250,直接用数码管模块seg7显示的话,显示为001250,加上post_seg7优化显示效果后,数码管左边2位不显示,右边4位显示1.250。
本帖最后由 lcytms 于 2017-2-8 20:20 编辑
先从AD驱动逻辑模块adc.v做起吧!
新建工程文件夹adc。
新建adc.v文件。
`define TS 1300 //t(su)=2us,t(wh)=17us t(su)mix=1.4us
`define T0 0
`define T1 100 //t(su)
`define T2 `T1+50
`define T3 `T2+50
`define T4 `T3+50
`define T5 `T4+50
`define T6 `T5+50
`define T7 `T6+50
`define T8 `T7+50
module adc (clk, rst_n, sid, adc_clk, cs_n, data);
input clk, rst_n;
input sid;
output reg adc_clk;
output reg cs_n;
output reg data;
reg count;
reg temp;
always @(posedge clk or negedge rst_n)
begin : lsm_1
if(!rst_n)
count <= 0;
else
begin
if(count < `TS)
count <= count + 1;
else
count <= 0;
end
end
always @(posedge clk or negedge rst_n)
begin : lsm_2
if(!rst_n)
begin
cs_n <= 1;
temp <= 0;
data <= 0;
adc_clk <= 0;
end
else
begin
case(count)
`T0 : begin
adc_clk <= 0;
cs_n <= 0;
end
`T1 : begin
adc_clk <= 1;
temp <= sid;
end
`T1+25: adc_clk <= 0;
`T2 : begin
adc_clk <= 1;
temp <= sid;
end
`T2+25: adc_clk <= 0;
`T3 : begin
adc_clk <= 1;
temp <= sid;
end
`T3+25: adc_clk <= 0;
`T4: begin
adc_clk <= 1;
temp <= sid;
end
`T4+25: adc_clk <= 0;
`T5 : begin
adc_clk <= 1;
temp <= sid;
end
`T5+25: adc_clk <= 0;
`T6 : begin
adc_clk <= 1;
temp <= sid;
end
`T6+25: adc_clk <= 0;
`T7 : begin
adc_clk <= 1;
temp <= sid;
end
`T7+25: adc_clk <= 0;
`T8 : begin
adc_clk <= 1;
temp <= sid;
end
`T8+25: begin
adc_clk <= 0;
cs_n <= 1;
data <= temp;
end
`TS : cs_n <= 0;
default : ;
endcase
end
end
endmodule
本帖最后由 lcytms 于 2017-2-8 20:26 编辑
进行分析综合检查。
编写Testbench。
新建adc_tb.v文件。
`timescale 1ns/1ps
module adc_tb;
reg clk;
reg rst_n;
reg sid;
wire adc_clk;
wire cs_n;
wire data;
adc dut(
.clk(clk),
.rst_n(rst_n),
.sid(sid), //输入串行数据
.adc_clk(adc_clk),
.cs_n(cs_n), //片选信号 低有效
.data(data)
);
reg data_in;
initial
begin
clk = 1;
rst_n = 0;
sid = 0;
#200.1
rst_n = 1;
data_in = 8'h66;
#1500 sid = data_in;
#1000 sid = data_in;
#1000 sid = data_in;
#1000 sid = data_in;
#1000 sid = data_in;
#1000 sid = data_in;
#1000 sid = data_in;
#1000 sid = data_in;
#17000
data_in = 8'haa;
#2000 sid = data_in;
#1000 sid = data_in;
#1000 sid = data_in;
#1000 sid = data_in;
#1000 sid = data_in;
#1000 sid = data_in;
#1000 sid = data_in;
#1000 sid = data_in;
#17000 $stop;
end
always #10 clk=~clk;
endmodule