基于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、遇到问题时,不要气馁,沉住气。问题总会解决的。

原文地址:https://www.cnblogs.com/wen2376/p/3283167.html