设计背景:
模数转换器,又称A/D转换器,简称ADC,通常是指一个将模拟信号转换为抗干扰性更强的数字信号的电子器件。一般的ADC是将一个输入电压信号转换为一个输出的数字信号。由于数字信号本身不具有实际意义,仅仅表示一个相对大小,故任何一个ADC都需要一个参考模拟量作为转换标准。比较常见的参考标准为最大的可转换信号大小,而输出的数字量则表示输入信号相对于参考信号的大小。本设计则通过对模数转换芯片(TLC549)的采样控制,实现一个简易的数字电压表。
设计原理:
TLC549典型的配置电路如下图所示:
TLC549的端口描述如下:
TLC549是一个8位的串行模数转换器,A/D转换时间最大为17us,最大转换速率为4MHz。下图为TLC549的访问时序,从图中可以看出,TLC549的使用只需对外接输入输出时钟(I/O CLK)和芯片选择(/CS)、输入的模拟信号(ANALOG IN)的控制。
分析时序图可知:当片选信号(/CS)拉低时,ADC前一次的转换数据(A)的最高位A7立即出现在数据线DATA OUT上,之后的数据在时钟I/O CLOCK的下降沿改变,可在I/O CLOCK的上升沿读取数据。转换时,/CS要置为高电平。在设计操作时,要注意Tsu(CS)、Tconv、Twh(CS)和I/O CLOCK的频率这几个参数。Tsu(CS)为CS拉低到I/O CLOCK第一个时钟到来的时间,至少要1.4us;Twh(CS)为ADC的转换时钟,不超过17us,Tconv的值也不超过17us;I/O CLOCK为 1.1MHz。其他参数可参考数据手册。
由于ADC是8位的,所以采样的电压值为:
V =(D*Vref)/256
其中V为采样的电压值;D为ADC转换后读取的8位二进制数;Vref为参考电压值,此处为2.5V。
设计架构图:
本设计通过调节电位器RW1改变ADC的模拟输入值,数据采样读取后由数码管显示,最后用万用表测量输入电压,并与读取在数码管上的数据(单位为mV)作比较。设计的架构图如下:
设计架构图对应端口的功能描述表:
tlc549_Driver模块采用序列机实现接口访问时序,并且产生1MHz的ADC_Clk和采集到ADC_data;Control模块,将采集到的ADC数据(ADC_data)换算成对应的电压值,并经过二进制到BCD转换以后传送到数码管;DIG_LED_DRIVE模块负责数码管的驱动,将传递过来的数据显示出来。
设计代码:
tlc549_Driver模块代码:
0moduletlc549_Driver(Clk,Rst_n,En,ADC_Din,ADC_Clk,ADC_Cs_n,Data,Get_Flag);
1
2inputClk;//系统50MHz时钟输入
3inputRst_n;//全局复位
4inputEn;//ADC转换使能,高电平有效
5
6inputADC_Din;//ADC串行数据输入
7
8outputregADC_Clk;//ADC时钟信号输出
9outputregADC_Cs_n;//ADC片选信号输出
10outputregGet_Flag;//数据转换完成标志
11outputreg[7:0]Data;//ADC转换以后的电压值
12
13reg[10:0]Cnt1;//系统时钟计数器
14reg[7:0]data_tmp;//数据寄存器
15
16//系统时钟上升沿计数
17always@(posedgeClkornegedgeRst_n)
18begin
19if(!Rst_n)
20Cnt1<=11'd0;
21elseif(!En)
22Cnt1<=11'd0;
23elseif(Cnt1==11'd1310)
24Cnt1<=11'd0;
25else
26Cnt1<=Cnt1+1'b1;
27end
28
29always@(posedgeClkornegedgeRst_n)
30begin
31if(!Rst_n)
32begin
33ADC_Clk<=1'b0;
34ADC_Cs_n<=1'b1;
35data_tmp<=8'd0;
36Data<=8'd0;
37end
38elseif(En)
39begin
40case(Cnt1)
411:ADC_Cs_n<=1'b0;//1~71(Tsu)
4271:beginADC_Clk<=1;data_tmp[7]<=ADC_Din;end
4396:ADC_Clk<=0;
44121:beginADC_Clk<=1;data_tmp[6]<=ADC_Din;end
45146:ADC_Clk<=0;
46171:beginADC_Clk<=1;data_tmp[5]<=ADC_Din;end
47196:ADC_Clk<=0;
48221:beginADC_Clk<=1;data_tmp[4]<=ADC_Din;end
49246:ADC_Clk<=0;
50271:beginADC_Clk<=1;data_tmp[3]<=ADC_Din;end
51296:ADC_Clk<=0;
52321:beginADC_Clk<=1;data_tmp[2]<=ADC_Din;end
53346:ADC_Clk<=0;
54371:beginADC_Clk<=1;data_tmp[1]<=ADC_Din;end
55396:ADC_Clk<=0;
56421:beginADC_Clk<=1;data_tmp[0]<=ADC_Din;end
57446:beginADC_Clk<=0;ADC_Cs_n<=1'b1;Get_Flag<=1;end
58447:beginData<=data_tmp;Get_Flag<=0;end//447~1310(Twh)
591310:;
60default:;
61endcase
62end
63else
64begin
65ADC_Cs_n<=1'b1;
66ADC_Clk<=1'b0;
67end
68end
69
70endmodule
Control模块代码:
0moduleControl(Clk,Rst_n,Get_Flag,ADC_data,seg_data);
1
2inputClk;//系统时钟输入
3inputRst_n;//系统复位
4inputGet_Flag;//ADC采集数据完成标志
5input[7:0]ADC_data;//ADC采集数据输入
6
7outputreg[23:0]seg_data;//数码管待显示数据
8
9reg[3:0]qianwei;//千位
10reg[3:0]baiwei;//百位
11reg[3:0]shiwei;//十位
12reg[3:0]gewei;//个位
13reg[15:0]tenvalue;//采样的电压值
14
15//采集电压值计算
16always@(posedgeClkornegedgeRst_n)
17begin
18if(!Rst_n)
19tenvalue<=0;
20elseif(Get_Flag)//新的数据采集完成,可以进行计算
21tenvalue<=(ADC_data*100*25)/256;
22end
23
24//二进制转BCD值
25always@(posedgeClkornegedgeRst_n)
26begin
27if(!Rst_n)
28begin
29qianwei<=0;
30baiwei<=0;
31shiwei<=0;
32gewei<=0;
33end
34else
35begin
36qianwei<=tenvalue/1000;//2
37baiwei<=(tenvalue/100)%10;//5
38shiwei<=(tenvalue/10)%10;//0
39gewei<=tenvalue%10;//0
40end
41end
42
43//数码管显示数值
44always@(posedgeClkornegedgeRst_n)
45begin
46if(!Rst_n)
47seg_data<=0;
48else
49seg_data<={
50qianwei,//千位
51baiwei,//百位
52shiwei,//十位
53gewei,//个位
548'hFF//空闲
55};
56end
57
58endmodule
DIG_LED_DRIVE模块代码:
0/*数码管扫描模块,位选为外部74hc138译码器进行控制*/
1/*仿真时请将本文件设置为顶层,并在代码中根据相应注释中的内容选择cnt1_MAX = 24*/
2
3moduleDIG_LED_DRIVE(Clk,Rst_n,Data,Dig_Led_seg,Dig_Led_sel);
4
5inputClk;//系统时钟输入
6inputRst_n;//系统复位
7input[23:0]Data;//待显示数据
8
9output[7:0]Dig_Led_seg;//数码管段选
10output[2:0]Dig_Led_sel;//数码管位选
11
12parametersystem_clk=50_000_000;
13
14// localparam cnt1_MAX = 24;/*仿真的时候使用,板级验证时请注释掉*/
15localparamcnt1_MAX=system_clk/1000/2-1;/*板级验证的时候使用,仿真时请注释掉*/
16
17reg[14:0]cnt1;//分频计数器
18regclk_1K;//扫描时钟,1KHz
19reg[2:0]sel_r;//数码管位选
20reg[7:0]seg_r;//数码管段选
21reg[3:0]disp_data;//单位显示数据缓存
22
23//1KHz时钟分频计数器
24always@(posedgeClk)
25begin
26if(!Rst_n)cnt1<=0;
27elseif(cnt1==cnt1_MAX)cnt1<=0;
28elsecnt1<=cnt1+1'b1;
29end
30
31//得到1KHz时钟
32always@(posedgeClkornegedgeRst_n)
33begin
34if(!Rst_n)
35clk_1K<=0;
36elseif(cnt1==cnt1_MAX)
37clk_1K<=~clk_1K;
38end
39
40//位选信号控制
41always@(posedgeclk_1KornegedgeRst_n)
42begin
43if(!Rst_n)
44sel_r<=3'd0;
45elseif(sel_r==3'd3)
46sel_r<=3'd0;
47else
48sel_r<=sel_r+1'b1;
49end
50
51//根据不同的数码管位选择不同的待显示数据
52always@(*)
53begin
54if(!Rst_n)
55disp_data=4'd0;
56else
57begin
58case(sel_r)
593'd0:disp_data=Data[23:20];
603'd1:disp_data=Data[19:16];
613'd2:disp_data=Data[15:12];
623'd3:disp_data=Data[11:8];
633'd4:disp_data=Data[7:4];
643'd5:disp_data=Data[3:0];
65default:disp_data=4'd0;
66endcase
67end
68end
69
70//数据译码,将待显示数据翻译为符合数码管显示的编码
71always@(*)
72begin
73if(!Rst_n)
74seg_r=8'hff;
75else
76begin
77case(disp_data)
784'd0:seg_r=8'hc0;
794'd1:seg_r=8'hf9;
804'd2:seg_r=8'ha4;
814'd3:seg_r=8'hb0;
824'd4:seg_r=8'h99;
834'd5:seg_r=8'h92;
844'd6:seg_r=8'h82;
854'd7:seg_r=8'hf8;
864'd8:seg_r=8'h80;
874'd9:seg_r=8'h90;
884'd10: seg_r=8'h88;
894'd11: seg_r=8'h83;
904'd12: seg_r=8'hc6;
914'd13: seg_r=8'ha1;
924'd14: seg_r=8'h86;
934'd15: seg_r=8'h8e;
94default:seg_r=8'hff;
95endcase
96end
97end
98
99assignDig_Led_seg=seg_r;
100assignDig_Led_sel=sel_r;
101
102endmodule
AD_TLC549顶层模块代码:
0moduleAD_TLC549(Clk,Rst_n,ADC_Din,ADC_Clk,ADC_Cs_n,Dig_Led_sel,Dig_Led_seg);
1
2inputClk;
3inputRst_n;
4inputADC_Din;
5
6outputADC_Clk;
7outputADC_Cs_n;
8output[2:0]Dig_Led_sel;
9output[7:0]Dig_Led_seg;
10
11wireGet_Flag;
12wire[7:0]ADC_data;
13wire[23:0]seg_data;
14
15tlc549_Drivertlc549_Driver(
16.Clk(Clk),
17.Rst_n(Rst_n),
18.En(1'b1),
19.ADC_Din(ADC_Din),
20.ADC_Clk(ADC_Clk),
21.ADC_Cs_n(ADC_Cs_n),
22.Data(ADC_data),
23.Get_Flag(Get_Flag)
24);
25
26ControlControl(
27.Clk(Clk),
28.Rst_n(Rst_n),
29.Get_Flag(Get_Flag),
30.ADC_data(ADC_data),
31.seg_data(seg_data)
32);
33
34DIG_LED_DRIVEDIG_LED_DRIVE(
35.Clk(Clk),
36.Rst_n(Rst_n),
37.Data(seg_data),
38.Dig_Led_seg(Dig_Led_seg),
39.Dig_Led_sel(Dig_Led_sel)
40);
41
42endmodule
AD_TLC549_tb顶层测试代码如下:
0`timescale1ns/1ps
1
2moduleAD_TLC549_tb;
3
4regClk;
5regRst_n;
6regADC_Din;
7
8wireADC_Clk;
9wireADC_Cs_n;
10wire[2:0]Dig_Led_sel;
11wire[7:0]Dig_Led_seg;
12
13initialbegin
14Clk=1;
15Rst_n=0;
16ADC_Din=0;
17#200.1
18Rst_n=1;
19
20#1400ADC_Din=1;//aa
21#1000ADC_Din=0;
22#1000ADC_Din=1;
23#1000ADC_Din=0;
24#1000ADC_Din=1;
25#1000ADC_Din=0;
26#1000ADC_Din=1;
27#1000ADC_Din=0;
28
29#17000
30#1400ADC_Din=1;//98
31#1000ADC_Din=0;
32#1000ADC_Din=0;
33#1000ADC_Din=1;
34#1000ADC_Din=1;
35#1000ADC_Din=0;
36#1000ADC_Din=0;
37#1000ADC_Din=0;
38
39end
40
41AD_TLC549AD_TLC549_dut(
42.Clk(Clk),
43.Rst_n(Rst_n),
44.ADC_Din(ADC_Din),
45.ADC_Clk(ADC_Clk),
46.ADC_Cs_n(ADC_Cs_n),
47.Dig_Led_sel(Dig_Led_sel),
48.Dig_Led_seg(Dig_Led_seg)
49);
50
51always#10Clk=~Clk;
52
53endmodule
仿真图:
设计仿真图如下所示:
观察仿真图,实现了数据的采集,并正确显示,下板验证结果也达到了设计的预期效果。
-
FPGA
+关注
关注
1625文章
21664浏览量
601727
发布评论请先 登录
相关推荐
评论