0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

FPGA学习系列:29. 数字电压表设计(AD)

FPGA学习交流 2018-08-15 14:07 次阅读

设计背景:

模数转换器,又称A/D转换器,简称ADC,通常是指一个将模拟信号转换为抗干扰性更强的数字信号电子器件。一般的ADC是将一个输入电压信号转换为一个输出的数字信号。由于数字信号本身不具有实际意义,仅仅表示一个相对大小,故任何一个ADC都需要一个参考模拟量作为转换标准。比较常见的参考标准为最大的可转换信号大小,而输出的数字量则表示输入信号相对于参考信号的大小。本设计则通过对模数转换芯片(TLC549)的采样控制,实现一个简易的数字电压表。

设计原理:

TLC549典型的配置电路如下图所示

image.png

TLC549的端口描述如下:

image.png

TLC549是一个8位的串行模数转换器,A/D转换时间最大为17us,最大转换速率为4MHz。下图为TLC549的访问时序,从图中可以看出,TLC549的使用只需对外接输入输出时钟I/O CLK芯片选择(/CS)、输入的模拟信号(ANALOG IN)的控制。

image.png


分析时序图可知:当片选信号(/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)作比较。设计的架构图如下:

image.png


设计架构图对应端口的功能描述表:

image.png


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~71Tsu

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
    +关注

    关注

    1629

    文章

    21738

    浏览量

    603460
收藏 人收藏

    评论

    相关推荐

    电压表测量电压是串联还是并联

    电压表是一种用于测量电路中两点之间电压差的仪器。在测量电压时,电压表需要与被测电路连接。根据连接方式的不同,电压表可以分为串联和并联两种方式
    的头像 发表于 07-13 10:46 6368次阅读

    电压表是根据什么原理工作的

    分组成: 1.1 测量电路:测量电路是电压表的核心部分,负责将被测电压转换为电压表可读的数值。测量电路通常由电阻、电容、二极管等元件组成。 1.2 显示装置:显示装置用于显示测量结果。常见的显示装置有指针式、
    的头像 发表于 07-13 10:44 3098次阅读

    数字电压表电路图 数字电压表的工作原理和作用

      数字电压表是一种将模拟电压信号转换为数字信号并以数字形式显示的电子测量仪器。它采用数字化测量
    的头像 发表于 06-27 16:17 3064次阅读
    <b class='flag-5'>数字</b><b class='flag-5'>电压表</b>电路图 <b class='flag-5'>数字</b><b class='flag-5'>电压表</b>的工作原理和作用

    源码系列:基于FPGA数字电压表(AD)设计

    今天给大侠带来基于FPGA数字电压表设计,附源码,获取源码,请在“FPGA技术江湖”公众号内回复“数字
    发表于 05-28 17:29

    数字电压表的应用场景

    数字电压表,作为现代电子测量技术的重要工具,已经广泛应用于各种电气测量领域。随着科技的不断进步和应用需求的不断提高,数字电压表的功能和性能也在不断完善,为各行各业提供了精确、可靠的
    的头像 发表于 05-21 17:13 839次阅读

    数字电压表的原理与特点

    数字电压表(DVM,也称为数字多用表或简称DMM)是现代电子测量领域中不可或缺的一种测量仪器。与传统的模拟电压表相比,数字
    的头像 发表于 05-21 16:54 2253次阅读

    电压表的读数方法 电压表的读数步骤是什么?

    电压表是一种用于测量电路中两点之间电压差的仪器。正确读取电压表的读数对于确保电路分析和故障诊断的准确性至关重要。
    的头像 发表于 05-09 16:23 3917次阅读

    电压表电压方法 电压表是如何测量电压

    电压表是用来测量电路中两点之间电压差的仪器,它在电气工程、实验室测试以及日常的电子设备维护中扮演着重要角色。
    的头像 发表于 05-07 17:16 4475次阅读

    电压表原理及使用方法 电压表串联在电路中会怎么样

    电压表是测量电路中电势差(电压)的一种电器仪器。它能够通过测量两个点之间的电势差来确定电路的电压。在以下文章中,我们将详细介绍电压表的原理和使用方法,并探讨
    的头像 发表于 02-02 13:39 8410次阅读

    电压表的使用方法及注意事项 电压表的电阻越大越好对吗

    电压表是一种用来测量电压的仪器,在电路实验和电器维修中起着重要的作用。正确选择和使用电压表不仅能提高测量的准确性,还能确保人身和设备的安全。以下是电压表的使用方法及注意事项。 一、
    的头像 发表于 02-02 11:13 7097次阅读

    电压表的使用方法 电压表的电阻有多大

    电压表是用来测量电路中电压的仪器,可以测量直流电压和交流电压。使用电压表需要注意一些注意事项,同时了解
    的头像 发表于 02-02 11:05 4221次阅读

    数字电压表测量的基本工作原理

    数字电压表是一种用于测量电压的仪器。它基于一些基本的工作原理来实现测量的准确性和可靠性。本文将详细介绍数字电压表的基本工作原理,以及其在测量
    的头像 发表于 01-25 13:55 1814次阅读

    数字电压表的固有误差由什么构成

    数字电压表的固有误差是指在一定条件下,由于仪器本身存在的不确定因素所导致的测量结果与待测量真值之间的偏差。数字电压表的固有误差主要由以下几个方面构成: 量程误差: 量程误差是指
    的头像 发表于 01-16 15:35 1538次阅读

    数字电压表测量的基本工作原理

    数字电压表是一种常用的测试仪器,它能够准确测量电路中的电压值。要了解数字电压表的工作原理,需要了解它是如何将输入信号转换为
    的头像 发表于 01-11 09:23 1446次阅读

    multism为什么电压表没识数

    Multism是一款常用的电路模拟软件,它在电路设计、仿真等领域广泛应用。然而,在使用Multism进行电路仿真时,有时可能会遇到电压表无法识数的情况。本文将对Multism电压表无法识数的原因进行
    的头像 发表于 01-04 16:46 1222次阅读