lcytms 发表于 2017-2-8 17:13:37

FPGA初级课程第二十二讲 AD

本帖最后由 lcytms 于 2017-2-10 11:26 编辑

FPGA初级课程
第二十二讲 AD

Hi,大家好!我是至芯科技的李老师。
今天讲课的题目是:AD。
本节课我先简要地介绍一下AD转换芯片工作的基本原理,然后实际演示一下AD驱动逻辑电路的建模与仿真,我们还要结合第四讲的数码管一起编写一个完整的演示逻辑,并下板查看实际效果。

演示平台为至芯科技开发的ZX_2开发板。
开发板采用的AD转换芯片为TI公司的8位串行控制模数转换器TLC549。

lcytms 发表于 2017-2-8 17:15:21

打开《ZX_2.pdf》文件,我们看一下AD部分的电路图。

lcytms 发表于 2017-2-8 17:17:54

我们打开至芯科技编写的《基于FPGA的TLC549驱动设计(AD).pdf》文档。

lcytms 发表于 2017-2-8 17:20:17

本帖最后由 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-8 17:25:26

本帖最后由 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 17:27:08

本帖最后由 lcytms 于 2017-2-8 20:11 编辑

5. 硬件设计
用TLC549芯片搭建的AD转换电路如下图所示。

lcytms 发表于 2017-2-8 17:29:05

AD芯片的工作原理既然已经清楚,我们下面来进行系统设计。
命名AD驱动逻辑为adc。
架构图如下所示。

lcytms 发表于 2017-2-8 20:09:38

本帖最后由 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:12:53

本帖最后由 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:22:27

本帖最后由 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
页: [1] 2 3
查看完整版本: FPGA初级课程第二十二讲 AD