• 基于Verilog HDL的ADC0809CCN数据采样


      本实验是用ADC0809CCN进行数据采样,并用7段数码管进行显示。

      ADC0809由一个8路模拟开关、一个地址锁存与译码器、一个A/D转换器和一个三态输出锁存器组成。多路开关可选通8个模拟通道,允许8路模拟量分时输入,共用A/D转换器进行转换。三态输出锁器用于锁存A/D转换完的数字量,当OE端为高电平时,才可以从三态输出锁存器取走转换完的数据。如下图所示。

    时序图(本实验用上升沿去采数据):

    原理图:

    工作方式:

    ALE为地址锁存允许输入线,高电平有效。当ALE线为高电平时,地址锁存与译码器将A,B,C三条地址线的地址信号进行锁存,经译码后被选中的通道的模拟量进入转换器进行转换。A,B和C为地址输入线,用于选通IN0-IN7上的一路模拟量输入,这里选通IN0。START为转换启动信号。当START上跳沿时,所有内部寄存器清零;下跳沿时,开始进行A/D转换;在转换期间,START应保持低电平。EOC为转换结束信号,在转换期间EOC为低。当EOC在为高电平时,表明转换结束;否则,表明正在进行A/D转换。OE为输出允许信号,用于控制三条输出锁存器向FPGA输出转换得到的数据。OE=1,输出转换得到的数据;OE=0,输出数据线呈高阻状态。D7-D0为数字量输出线,可以得到状态图。

    状态图:

     代码实现:

    adc0809_control.v

      1 module adc0809_control(
      2                 //input
      3                 sys_clk,
      4                 rst_n,
      5                 eoc,//adc转换结束信号标志
      6                 data,//adc转换出的数据,
      7                 
      8                 //ouput
      9                 clk_adc,//给adc的时钟500HZ
     10                 ale,//adc地址锁存
     11                 start,//启动adc
     12                 address,//adc地址选通
     13                 oe,//控制adc数据传出
     14                 seg_data//传给数码显示
     15                 );
     16 input sys_clk;//27MHZ
     17 input rst_n;
     18 input eoc;
     19 input [7:0] data;
     20 
     21 output clk_adc;
     22 output ale;
     23 output start;
     24 output [2:0] address;
     25 output oe;
     26 output [7:0] seg_data;
     27 /*********************************************/
     28 parameter     IDLE         = 3'd0,
     29             ALE             = 3'd1,
     30             START_P     = 3'd2,
     31             START_N     = 3'd3,
     32             CHECK_EOC_P = 3'd4,
     33             CHECK_EOC_N = 3'd5,
     34             OE             = 3'd6,
     35             SEND_DATA   = 3'd7;
     36 /*********************************************/
     37 //产生500kHZ的频率
     38 reg clk_adc;
     39 reg [4:0] cnt;
     40 always @(posedge sys_clk or negedge rst_n)
     41 if(!rst_n) begin
     42     cnt  <= 5'd0;
     43     clk_adc <= 1'b0;
     44 end
     45 else if(cnt == 5'd26)
     46 begin
     47     cnt <= 5'd0;
     48     clk_adc <= ~clk_adc;
     49 end
     50 else
     51     cnt <= cnt + 1'b1;
     52 /*********************************************/
     53 reg start;
     54 reg ale;
     55 reg oe;
     56 reg [7:0] data_temp;
     57 reg [2:0] state;
     58 //always @(clk_adc or rst_n or eoc)//用组合逻辑方式不行,采集不到数据
     59 always @(posedge clk_adc or negedge rst_n)
     60 if(!rst_n) begin
     61     start <= 1'b0;
     62     ale <= 1'b0;
     63     oe <= 1'b0;
     64     data_temp <= 8'd0;
     65     state <= IDLE;
     66 end
     67 else 
     68     case(state)
     69     IDLE: begin
     70         ale <= 1'b0;
     71         start <= 1'b0;
     72         oe <= 1'b0;
     73         state <= ALE;
     74     end
     75     
     76     ALE: begin
     77         ale <= 1'b1;
     78         start <= 1'b0;
     79         state <= START_P;
     80     end
     81     
     82     START_P: begin
     83         ale <= 1'b0;//1
     84         start <= 1'b1;
     85         state <= START_N;
     86     end
     87     
     88     START_N: begin
     89         ale <= 1'b0;
     90         start <= 1'b0;
     91         state <= CHECK_EOC_P;
     92     end
     93     
     94     CHECK_EOC_P: begin
     95         if(eoc == 1'b1)
     96             state = CHECK_EOC_P;
     97         else
     98             state = CHECK_EOC_N;//检测到了低电平,说明开始转换
     99     end
    100 
    101     CHECK_EOC_N: begin
    102         if(eoc == 1'b0)
    103             state <= CHECK_EOC_N;//等待转换的结束
    104         else
    105             state <= OE;
    106     end
    107     
    108     OE: begin
    109         oe <= 1'b1;
    110         state <= SEND_DATA;
    111     end
    112     
    113     SEND_DATA: begin
    114         data_temp <= data;
    115         state <= IDLE;
    116     end
    117     
    118     default: begin
    119         ale <= 1'b0;
    120         start <= 1'b0;
    121         oe <= 1'b0;
    122         state <= IDLE;
    123     end
    124     endcase
    125 /*********************************************/
    126 assign address = 3'b000;//选通IN0    
    127 assign seg_data = data_temp;
    128 /*********************************************/
    129 endmodule
    View Code

    display_control.v

     1 module  display_control(
     2                         //input
     3                         sys_clk,
     4                         rst_n,
     5                         seg_data,
     6                         
     7                         //output
     8                         slec_wei,
     9                         slec_duan
    10                     );
    11 input rst_n;
    12 input [7:0] seg_data;
    13 input sys_clk;
    14 
    15 output [3:0] slec_wei;
    16 output [6:0] slec_duan;
    17 /*****************************************/
    18 parameter     SEG_NUM0     = 7'h3f,//c0,
    19             SEG_NUM1     = 7'h06,//f9,
    20             SEG_NUM2     = 7'h5b,//a4,
    21             SEG_NUM3     = 7'h4f,//b0,
    22             SEG_NUM4     = 7'h66,//99,
    23             SEG_NUM5     = 7'h6d,//92,
    24             SEG_NUM6     = 7'h7d,//82,
    25             SEG_NUM7     = 7'h07,//F8,
    26             SEG_NUM8     = 7'h7f,//80,
    27             SEG_NUM9     = 7'h6f,//90,
    28             SEG_NUMa    = 7'h77,
    29             SEG_NUMb    = 7'h7c,
    30             SEG_NUMc    = 7'h39,
    31             SEG_NUMd    = 7'h5e,
    32             SEG_NUMe    = 7'h79,
    33             SEG_NUMf    = 7'h71;
    34 /*****************************************/
    35 reg[7:0] cnt;
    36 always @ (posedge sys_clk or negedge rst_n)
    37     if(!rst_n) cnt <= 8'd0;
    38     else cnt <= cnt+1'b1;
    39 /*****************************************/
    40 wire[3:0] num;    //用两位数码管显示
    41 assign num = cnt[7] ? seg_data[7:4] : seg_data[3:0];
    42 assign slec_wei[0] = cnt[7];
    43 assign slec_wei[1] = ~cnt[7];
    44 
    45 //由于板上数码管是四位,另两位不点亮
    46 assign slec_wei[2] = 1'b1;
    47 assign slec_wei[3] = 1'b1;
    48 
    49 reg [6:0] slec_duan;
    50 always @ (posedge sys_clk)
    51 case(num)    //进行编码
    52     4'h0: slec_duan <= SEG_NUM0;
    53     4'h1: slec_duan <= SEG_NUM1;
    54     4'h2: slec_duan <= SEG_NUM2;
    55     4'h3: slec_duan <= SEG_NUM3;
    56     4'h4: slec_duan <= SEG_NUM4;
    57     4'h5: slec_duan <= SEG_NUM5;
    58     4'h6: slec_duan <= SEG_NUM6;
    59     4'h7: slec_duan <= SEG_NUM7;
    60     4'h8: slec_duan <= SEG_NUM8;
    61     4'h9: slec_duan <= SEG_NUM9;
    62     4'ha: slec_duan <= SEG_NUMa;
    63     4'hb: slec_duan <= SEG_NUMb;
    64     4'hc: slec_duan <= SEG_NUMc;
    65     4'hd: slec_duan <= SEG_NUMd;
    66     4'he: slec_duan <= SEG_NUMe;
    67     4'hf: slec_duan <= SEG_NUMf;
    68     default:slec_duan <= SEG_NUM0;
    69 endcase
    70 /*****************************************/    
    71 endmodule 
    View Code

    adc0809_top.v

     1 module adc0809_top(//input
     2                     sys_clk,
     3                     rst_n,
     4                     eoc,
     5                     data,
     6                     
     7                     //output
     8                     clk_adc,
     9                     ale,
    10                     start,
    11                     address,
    12                     oe,
    13                     slec_wei,
    14                     slec_duan
    15                     );
    16 input sys_clk;//27MHZ
    17 input rst_n;
    18 input [7:0] data;
    19 input eoc;
    20 
    21 output clk_adc;
    22 output ale;
    23 output start;
    24 output [2:0] address;
    25 output oe;
    26 output [3:0] slec_wei;
    27 output [6:0] slec_duan;
    28 
    29 wire [7:0] seg_data;
    30 
    31 adc0809_control u1(
    32                     //input
    33                     .sys_clk(sys_clk),
    34                     .rst_n(rst_n),
    35                     .eoc(eoc),//adc转换结束信号标志
    36                     .data(data),//adc转换出的数据,
    37                 
    38                     //ouput
    39                     .clk_adc(clk_adc),//给adc的时钟500HZ
    40                     .ale(ale),//adc地址锁存
    41                     .start(start),//启动adc
    42                     .address(address),//adc地址选通
    43                     .oe(oe),//控制adc数据传出
    44                     .seg_data(seg_data)//传给数码显示
    45                 );
    46                 
    47 display_control        u2(
    48                 //input 
    49                 .sys_clk(sys_clk),
    50                 .rst_n(rst_n),
    51                 .seg_data(seg_data),
    52                 
    53                 //output
    54                 .slec_wei(slec_wei),
    55                 .slec_duan(slec_duan)
    56              );
    57 endmodule
    View Code

    仿真代码:

     1 `timescale 1 ns/ 1 ps
     2 module adc0809_top_vlg_tst();
     3 // constants                                           
     4 // general purpose registers
     5 reg eachvec;
     6 // test vector input registers
     7 reg [7:0] data;
     8 reg eoc;
     9 reg rst_n;
    10 reg sys_clk;
    11 // wires                                               
    12 wire [2:0] address;
    13 wire ale;
    14 wire clk_adc;
    15 wire oe;
    16 wire [6:0] slec_duan;
    17 wire [3:0] slec_wei;
    18 wire start;
    19 
    20 // assign statements (if any)                          
    21 adc0809_top i1 (
    22 // port map - connection between master ports and signals/registers   
    23     .address(address),
    24     .ale(ale),
    25     .clk_adc(clk_adc),
    26     .data(data),
    27     .eoc(eoc),
    28     .oe(oe),
    29     .rst_n(rst_n),
    30     .slec_duan(slec_duan),
    31     .slec_wei(slec_wei),
    32     .start(start),
    33     .sys_clk(sys_clk)
    34 );
    35 initial                                                
    36 begin                                                  
    37 sys_clk =0;
    38 rst_n = 0;
    39 #100;
    40 rst_n = 1;                     
    41 end                                                    
    42 always  #19 sys_clk = ~sys_clk;                                            
    43  
    44 initial   begin
    45     data = 8'h0;
    46     eoc = 1;
    47 end
    48 
    49 always @(negedge start)
    50 begin
    51     #2000;
    52     eoc = 0;
    53     data <= data + 1'b1;
    54     #10000;
    55     eoc = 1;
    56 end
    57 endmodule
    View Code

    仿真波形:

    调试过程的心情:

      看完人家的例子,时序图也看明白了,然后开始写自己的代码,在编译时也遇到很奇怪的问题,如下图,代码中找了许久都没找到,这让很头疼,后来我就把关于case这段语句剪切掉,只留接口定义部分,进行编译,编译OK,我在把刚才剪切掉的代码复制原位置(完全是一摸一样),编译既然通过了,很郁闷,这个问题一直没有弄明白,实在想不通,就跳过这个问题,既然编译通过了,那赶紧下载到板子上去验证吧,下完之后,显示两个0,变阻器无论怎么调都没用,哎,无语了,只能回过头在检查代码,看是否哪里有错误。实在检查不出来,只有仿真看时序对不对哦,仿真后还真没看出来有啥问题(很可能当时仿真代码没有写好,其实也没仔细的看波形),然后反复的看别人的代码,对照自己的代码是否哪里写的不对。最终把这个语句always @(clk_adc or rst_n or eoc)改为时序逻辑always @(posedge clk_adc or negedge rst_n)就可以了 ,终于看到了数码显示数据了,调电位器,数据也在变动,很高兴啊。。。。

    总结:

    1、例子最好找一个比较规范的例子,可以到网上收集相同的例子,进行参考对比。

    2、遇到问题时,不要气馁,沉住气。问题总会解决的。

  • 相关阅读:
    更改Delphi系统的默认字体
    Delphi TThread中文注释
    Delphi中的线程类 TThread详解
    TreeView使用笔记
    用未公开函数实现Shell操作监视
    Delphi面向对象编程的20条规则
    Delphi操作Excel命令
    delphi 创建一个纯文本文件
    判断滚动条到底部、
    数据库性能优化之SQL语句优化1
  • 原文地址:https://www.cnblogs.com/wen2376/p/3283167.html
Copyright © 2020-2023  润新知