搜索
您的当前位置:首页正文

基于FPGA的电压表设计报告

来源:知库网


基于VHDL的电压表的设计

报告

1、实验背景

传统的数字电压表设汁通常以大规模ASIC(专用集成电路)为核心器件,并辅以少量中规模集成电路及显示器件构成。ASIC完成从模拟量的输入到数字量的输出,是数字电压表的心脏。这种电压表设计简单、精确度高,但是这种设计方法由于采用了ASIC器件使得它欠缺灵活性,其系统功能固定,难以更新扩展。后来发展起来的用微处理器(单片机)控制通用A/D转换器件的数字电压表的设计的灵活性明显提高,系统功能的扩展变得简单,但是由于微处理器的引脚数量有限,其控制转换速度和灵活性还是不能满足日益发展的电子工业的需求。而应用EDA(电子设汁自动化)技术及FPGA(现场可编程门阵列),其集成度高、速度快、性能十分可靠、用户可自由编程且编程语言通俗易懂、系统功能扩展非常方便。采用FPGA芯片控制通用A/D转换器可使速度、灵活性大大优于由微处理器和通用A/D转换器构成的数字电压表。

2、实验目的

以8位A/D转换器ADC0809对模拟电压采样并转换为数字信号,以FPGA芯片为控制核心,以VHDL硬件语言编写电路实现硬件功能,对电压信号的转换结果进行准确实时的运算处理并送至数码管显示。系统的主要功能都集成在一块芯片(扣在FPGA芯片上)上,大大减少了系统的分立元件数量,降低了功耗,增加了可靠性,较好地实现了电压的精准测量。

3、实验内容

3.1、学习ADC0809芯片 3.2、熟悉状态机 3.3、学会制作电路 4、实验原理

本设计利用ADC0809作为电压采样及模数转换设备,FPGA作为系统的核心器件,用数码管进行数码显示。

采用Alterla公司EP1C12Q240C8 芯片FPGA作为系统的核心器件,负责ADC0809的A/D转换的启动、地址锁存、输入通道选择、数据读取。同时,把读取的8位二进制数据转换成便于输出显示的3位十进制BCD码送给数码管,以显示当前测量电压值。这些工作由ADC0809转换控制模块、数据转换模块、译码模块完成。系统原理框图如图1所示。

时序进程;组合控制锁存器 数据转换模 Current_State LOCK Q[7..0] 状态转换 模块 块 Next_State 状态机时钟clk1 转换后数据 分频模块 数码管动态扫描以及显示动态扫描clk3 译码控制模块 ADC时钟clk2 ADC0809 ALE START OE ADDA CLK EOC D[7..0] 48Mclk 数码管位选seg_com[2-0] 段选seg_data[7-0] 图1

4.1、A/D转换控制模块的设计思路:

本模块完成ADC0809的初始化、A/D转换的启动、地址锁存、通道选择、状态读取及数据读取、数据锁存等功能。此模块采用VHDL的多进程状态机完成。工作时序如下:

上电瞬间,FPGA初始化,A、B、C置成\"000\"(模拟信号从0通道输入),状态机处于第1个状态,此时ALE、START、OE、LOCK(数据锁存信号)均置0,初始化ADC0809。

第1个上升沿到来时,状态机由状态1转换到状态2,ALE、START置1,OE、LOCK为0,此时地址锁存信号有效,由ALE将A、B、C的\"000\"状态锁存到地址锁存器并译码,选择IN0即通道0作为模拟信号输入端,同时STRAT信号有效,启动采样。

第2个上升沿到来时,状态机由状态2转换到状态3,ALE、START返回到低电平,OE、LOCK继续为低电平,此时如果FPGA检测到ADC0809的EOC引脚由低电平变成高电平(A/D转换完成),则当时钟上升沿到来时,转换到状态3,否则继续保持在状态2,直到转换完成。

由状态2转换到状态3后,OE置高电平,允许转换数据输出,其余信号状态保持不变。

时钟上升沿再次到来时,状态机由状态3转换到状态4,LOCK置高电平,其余信号与状态3一样。当LOCK由低电平转换到高电

平的瞬问,稳定的数据锁存到锁存器。上升沿再次到来,则状态机返回状态0。控制器在时钟信号控制下完成状态转换,实现对ADC0809的控制。

4.2、数据转换模块的设计思路

本设计采用2.5 V参考电压,测量范围为0~5 V,由于转换器件为8位,则电压的最小分辨率为0.0098V,该实验中的译码电路调用conv_integer函数。用conv_integer(Q)*250/256这个变换,使得二进制转换为十进制的数字。 4.3、 数据显示模块的设计思路

在此模块中我们将转换的3个十进制的数字进行BCD译码显示,此数据就是数码管显示的数据,因为在译码电路中输出来的数据中不含有小数,是三个十进制的数字,例如016,此时显示时需要在百位0数字后面加一个小数点。实现的方法就是在动态显示百位时,将显示百位的八段数码管的小数点点亮(该段置低电平),其余十位个位的八段数码管的小数点不点亮点亮(该段置高电平)。

电压的数据为H.HH,显然只需3个数码管显示就行。为了节省资源,采用扫描方式控制数码管的显示,扫描时钟由CK提供,其频率应大于100 Hz(否则会有闪烁现象)。例如当显示百位时(位选的数值为011),段选选择的数据位H3,之后显示十位时(位选的数值为101),段选选择的数据位H2,接着显示个位时(位选的数值为110),段选选择的数据位H1,然后又显示百位,依次循环进行。由于人的视觉停留效果,我们将看到每个数码管都被点亮。而

数码管的亮度由动态刷新数码管的时钟来决定。频率越大,亮度越亮。

5、实验步骤

5.1、学习0809的芯片资料

本次实验中,我们打算制作一个电压表,而A/D转换芯片我们采用并行输出数据的ADC0809,相对于我们以前实验所用的TLC549来说,它的转换速度更快一些,且其控制起来相对容易一些。该芯片我们在以前没有接触过,要想对其按照我们的要求来工作,需要对其的外部特性(引脚功能)进行了解。通过查阅资料我们得知各引脚功能和分布如下:

图2

IN0~IN7:8路模拟量输入端。 2-1~2-8:8位数字量输出端。

ADDA、ADDB、ADDC:3位地址输入线,用于选通8路模拟输入中的一路

ALE:地址锁存允许信号,输入,高电平有效。

START: A/D转换启动脉冲输入端,输入一个正脉冲(至少100ns宽)使其启动(脉冲上升沿使0809复位,下降沿启动A/D转换)。

EOC: A/D转换结束信号,输出,当A/D转换结束时,此端输出一个高电平(转换期间一直为低电平)。

OE:数据输出允许信号,输入,高电平有效。当A/D转换结束时,此端输入一个高电平,才能打开输出三态门,输出数字量。 CLK:时钟脉冲输入端。要求时钟频率不高于640KHZ。 REF(+)、REF(-):基准电压。 Vcc:电源,单一+5V。 GND:地。

我们选用了其0路模拟量输入端,即在INT0端输入需要转换的模拟量。

5.2、编写VHDL语言程序代码并且仿真 5.2.1、VHDL语言编写

根据实验原理部分,我们编写VHDL语言如下:

LIBRARY IEEE;

USE IEEE.STD_LOGIC_1164.ALL; USE IEEE.STD_LOGIC_UNSIGNED.ALL; USE IEEE.STD_LOGIC_ARITH.ALL;

ENTITY ADC08091 IS

PORT ( D:IN STD_LOGIC_VECTOR(7 DOWNTO 0); CLK:IN STD_LOGIC; EOC:IN STD_LOGIC;

ALE,START,OE,LOCK0:OUT STD_LOGIC; Q:OUT STD_LOGIC_VECTOR(7 DOWNTO 0);

ADDA:out std_logic_vector(2 downto 0);--select IN0-IN7 CLK1:OUT STD_LOGIC;

seg_data : OUT STD_LOGIC_VECTOR(7 downto 0); );

seg_com : OUT STD_LOGIC_VECTOR(3 downto 0)

END ENTITY ADC08091;

ARCHITECTURE BHV OF ADC08091 IS

signal DCLK_DIV : integer range 0 to 50000000:=0;

SIGNAL bcd_led : STD_LOGIC_VECTOR(3 DOWNTO 0); --

SIGNAL clkcnt : STD_LOGIC_VECTOR(16 DOWNTO 0):=(others=>'0'); -- SIGNAL writedata_r : integer range 0 to 50000000; SIGNAL datain : STD_LOGIC_VECTOR(15 DOWNTO 0); BEGIN

ADDA<=\"000\"; Q<=REGL; CLK1<=ad_clk_r; LOCK0<=LOCK;

-- --

TYPE states IS (st0,st1,st2,st3,st4); signal current_state,next_state:states:=st0; SIGNAL CLK_ST:STD_LOGIC;

signal REGL:STD_LOGIC_VECTOR(7 DOWNTO 0); signal LOCK: STD_LOGIC;

-- SIGNAL Q:STD_LOGIC_VECTOR(7 DOWNTO 0); signal ad_clk_r : std_logic:='0';

CLK_ST<=clkcnt(3);

process(CLK) --CLK counter.

begin

if(rising_edge(CLK))then clkcnt<= clkcnt+1; end if; end process;

COM:PROCESS(current_state,EOC)

BEGIN

CASE current_state IS

WHEN st0=>ALE<='0';START<='0';LOCK<='0';OE<='0';

WHEN st1=>ALE<='1';START<='1';LOCK<='0';OE<='0';

END CASE;

END PROCESS COM;

REG: PROCESS(CLK_ST) --

LATCH1:PROCESS(LOCK) BEGIN

IF RISING_EDGE(LOCK) THEN REGL<=D; END IF; BEGIN

IF rising_edge(CLK_ST) then current_state <=next_state;

end IF;

next_state <=st2;

IF(EOC='1') THEN next_state <=st3;

ELSE next_state<=st2; END IF;

next_state <=st4; next_state <=st0;

WHEN st2=>ALE<='0';START<='0';LOCK<='0';OE<='0';

next_state <=st1;

WHEN st3=>ALE<='0';START<='0';LOCK<='0';OE<='1'; WHEN st4=>ALE<='0';START<='0';LOCK<='1';OE<='1'; WHEN OTHERS=> next_state<= st0;

END PROCESS;

END PROCESS LATCH1;

CLK1_div:process (CLK) --GENERATE 0809'S clock ;0.75MHZ

process(REGL,writedata_r) begin

writedata_r <= conv_integer(REGL)*5000/256;

datain( 3 downto 0) <= conv_std_logic_vector(writedata_r rem 10,4); datain( 7 downto 4) <= conv_std_logic_vector(writedata_r/10 rem 10,4); datain(11 downto 8) <= conv_std_logic_vector(writedata_r/100 rem 10,4); datain(15 downto 12)<= conv_std_logic_vector(writedata_r/1000 rem 10,4); end process;

process(clkcnt(16 downto 15),datain) begin

case clkcnt(16 downto 15) is

when \"00\" =>bcd_led<=datain(3 downto 0);seg_com<=\"1110\" ; when \"01\" =>bcd_led<=datain(7 downto 4);seg_com<=\"1101\" ; when \"10\" =>bcd_led<=datain(11 downto 8);seg_com<=\"1011\" ; when \"11\" =>bcd_led<=datain(15 downto 12);seg_com<=\"0111\" ; when others => NULL; end case; end process;

process(bcd_led,clkcnt(16 downto 15))

begin

if clkcnt(16 downto 15)=\"11\"

then

case bcd_led is

begin

if rising_edge(clk) then

DCLK_DIV <= DCLK_DIV + 1; DCLK_DIV <= 0;

ad_clk_r <= not ad_clk_r;

if (DCLK_DIV < 31) then

else

end if ;

end if;

end process;

when \"0000\" => seg_data <= \"01000000\"; when \"0001\" => seg_data <= \"11110001\"; when \"0010\" => seg_data <= \"00100100\"; when \"0011\" => seg_data <= \"00110000\"; when \"0100\" => seg_data <= \"10010001\"; when \"0101\" => seg_data <= \"00010010\"; when \"0110\" => seg_data <= \"00000010\"; -- when \"0111\" => seg_data <= \"11110000\"; -- 7 when \"1000\" => seg_data <= \"00000000\"; -- 8 when \"1001\" => seg_data <= \"00010000\"; -- 9 when others => NULL;

end case;

case bcd_led is

when \"0000\" => seg_data <= \"01001000\"; when \"0001\" => seg_data <= \"11111001\"; when \"0010\" => seg_data <= \"00101100\"; when \"0011\" => seg_data <= \"00111000\"; when \"0100\" => seg_data <= \"10011001\"; when \"0101\" => seg_data <= \"00011010\"; when \"0110\" => seg_data <= \"00001010\"; -- when \"0111\" => seg_data <= \"11111000\"; -- 7 when \"1000\" => seg_data <= \"00001000\"; -- 8 when \"1001\" => seg_data <= \"00011000\"; -- 9 when others => NULL;

else

end case;

end if; end process;

END ARCHITECTURE BHV;

5.2.2、仿真测试

测试向量用来模拟实际类似输入信号的,用来察看是否能得到符合ADC0809时序图要求的控制信号。

利用modelsim仿真测试(测试向量见附表),得到0809控制相关的信号的波形图如下:

图3

图3仿真图ADC工作过程解释:start为转换启动控制信号,高电平有效;ale为模拟信号输入选通端口地址锁存信号,上升沿有效;一旦start有效后,状态信号eoc为低电平,进入转换状态,在此状态st2需要对eoc进行测试,如果为低表示转换没有结束,仍停留在st2状态等待,知道eoc变为高电平,才说明转换结束进入st3。转换结束之后,状态反馈信号eoc将变为高电平。此后,使oe变为高电平(输出有效),此时,0809的输出数据总线d【7..0】从高阻态变为有效输出数据。然后在下一状态st4,利用锁存信号(lock的上升沿),将0809输出的数据进行锁存。锁存的数据实际上是先保持在内部信号REGL中,再赋给输出端口Q。这个八位数据REGL,用于后续模块进行数值转换,进而进行数码管动态扫描,最终显示出电压值。

ADC0809的时序图如图4所示,时序图中ALE、START 变高的脉宽tws 、 twale都要求大于100ns。

图4

经分析、测量仿真波形图,各信号的脉宽等参数,符合0809的ADC0809的时序控制图要求。

利用modelsim仿真测试(测试向量见附表2),得到动态扫描管相关的信号的波形图5所示:

图5

工作过程解释:如图此时,采集到的八位数据=”01011101”,计算这

writedata_r

<=

conv_integer(REGL)*5000/256;。这样计算得到的电压值,保留了三位小数。计算得writedata_r=1816再将writedata_r各十进制位分离,转换成对应四个BCD码datain= 0001 1000 0001 0110,进译码电路再控制位选seg_com和段选信号seg_data,在数码管上动态显示出来1.816。

显然该数码管部分工作正常。

5.2.3、PCB版图的制作

通过上课老师的讲解EDA核心开发板的结构以及PETROL知识,我们画出的硬件电路原理图如图6所示:

图6

通过原理图进行转换,我们得到了硬件PCB如图7所示:

图7

6、实验成果

此次实验中,我们制作一个基于FPGA的电压表,该电压表具有集成度高、速度快、性能十分可靠、用户可自由编程进行功能扩展的特点。

该电压表实物图如图8所示:

图8

7、实验中的问题 7.1数码管工作不正常

当接上电路,数码管出现的数值不对,而当我们把ADC0809的8位数据输到核心板上的指示灯时,指示灯的值随着电压的变化而变化,说明ADC0809的工作是正常的。当我们使用开发系统自带的数码管时能正常的显示电压,这说明我们的数码管驱动有问题,通过分析,我们发现本应接+3.3V电源的三极管,接成了+5V,导致FPGA输出的位选无论为高还是低,数码管都全亮。因为+5V大于+3.3V,即便为+3.3V仍然有压降,仍然导通,故数码管被点亮。

还有就是数码管出现了乱码,分析得知是由于段选ABCDEFGH没有对

应接好从而导致七段译码显示不对。

8、实验感想 8.1、王晓明的感想

此次实验,我深入的学习了QuartusⅡ软件设计并仿真。在编写程序中,我对VHDL语言的语法等结构有了更深的了解。

在本次实验中出现了一些问题,这些问题来源都是由于我们在一开始没有注意细节,比如没有仔细的去研究核心板上的管脚排布,使得我们刚开始对EP1C12Q240C8所存错误,虽然这个管脚是可以变化的,但就是由于刚开始没有注意,使得后来又花了一些时间在更改管脚上面。其次是电路图中电阻使用错了,三级管射极加的电压不对,这些小的问题使得我们的实验并没有出现预期的效果。此次由于前面有过设计电压表的经验,软件方面并没有出现多大的问题,关键是硬件方面的细节问题出现得太多。在以后的设计电路中,我们应该更加重视硬件细节,不然的话就会做很多的无劳功。

此次实验虽出现了一些问题,但在问题中我也收获很多。这实验让我们明白我知识的贫乏和工作中的严谨重要性,让我有了追求知识的更多欲望。

在这感谢老师、同学、队友对我的帮助和支持! 8.2、杨俊的感想

这次实践中,我第一次初次遇到两种不同电平标准的器件的混合电压系统,电平兼容问题。搜索这一问题相关知识的过程,以及分析

具体解决方案的过程,让我学到了新的知识,积累了宝贵的实践经验,让我心中有电平转换的概念在以后的设计中定会倍加注意这个问题。在负责程序设计的过程中,让我再次巩固了状态机设计的相关知识,并且在显示部分设计中充分利用了以前设计的优秀代码实现同样功能,只要处理好衔接关系就能充分提高效率、节省时间。让我深深体会到,做工程设计,积累非常重要,如果我们做过很多设计,把所有优秀的设计保存起来,在某天另外的设计中或许就能发挥重要作用、节省很多时间。做好实物之后的调试,再次让我体会到作为一个设计者,耐心是非常的重要。调试的过程,总会出现一些不可预料的错误或失误,或是人为操作或是设计的失误,就会导致结果非常不解,自己感到非常困惑还可能影响心情烦躁郁闷,最后我们还是静下心来,一步步排查最后调试成功,充分锻炼了我们的耐心。另外,实践也再次锻炼了我们动手能力,分析并解决问题能力。做大的收获是锻炼了我与人相处、团队合作的能力,实验中小组也曾出现一些小分歧矛盾,还好我们几个队员性格都好,互相体谅,迅速化解矛盾平静了情绪,保证了实验的顺利完成。 8.3、白德立的感想

a、由于实验室只能用单面板和双面板,而为了节约资源,常常用单面板,这在绘制PCB电路的时候不得不花点心思去考虑如何尽可能在少使用飞线的情况下把PCB电路布局的更好。这是本人第一次做板子,没有什么实践经验,其中也遇到了不少问题,比如板子的PCB做好以后没有考虑到扣上FPGA核心板上是反过来的,还有设

计的时候布置得还不是很合理等。

b、在画好电路原理图的时候应该认真检查线路是否可行,原理上会达到什么效果等等,还有相应的元器件的封装一定要对上号等,本次也没有过多考虑这些问题,以至于在调试的时候,查找相关的参数的时候非常困难。还好是FPGA,锁定数据的方式灵活,要不然又得重新做了。

c、做学问必须得脚踏实地,不能想当然。在本次实践中,原来感觉做这个也挺简单的,但是真正去做的时候才发现了许多先前没有考虑到的事情,在巩固所学知识的同时积累了一些做板子的经验,学到了一些分析问题的方法。

d、遇到问题不能盲目乱搞。遇到问题就容易心烦气躁,在遇到问题的时候,必须保持冷静的头脑,认真想清楚再去处理,不能盲目或者冲动,有时错误可能就是一根小小的阴线或者一个让人不太注意的引脚。本次实践中,遇到数码管位选出错的情况就是其中一个三极管的管脚没有焊好。

e、团队合作非常重要。一个人的精力毕竟有限,学会团队合作非常重要,在合作的过程中,分工明确,认真负责,相互配合,是一个优秀团队的强大凝聚力。非常感谢我们队友给我的支持,真的,非常感谢!

附录一:

编写的测试向量如下:

LIBRARY IEEE;

USE IEEE.STD_LOGIC_1164.ALL; use ieee.std_logic_unsigned.all;

ENTITY test_adc0809 is end entity;

architecture bev of test_adc0809 is

signal D:STD_LOGIC_VECTOR(7 DOWNTO 0); signal CLK:STD_LOGIC; signal EOC:STD_LOGIC;

signal ALE,START,OE,LOCK0:STD_LOGIC; signal Q: STD_LOGIC_VECTOR(7 DOWNTO 0); signal ADDA: STD_LOGIC_VECTOR(2 downto 0); signal CLK1: STD_LOGIC;

signal seg_data : STD_LOGIC_VECTOR(7 downto 0); signal seg_com : STD_LOGIC_VECTOR(3 downto 0);

BEGIN

p0: entity work.adc0809(BHV) port map

(D,CLK,EOC,ALE,START,OE,LOCK0,Q,ADDA,CLK1,seg_data,seg_com);

clk48:process is begin

CLK <= '0'; wait for 10 NS; CLK <= '1'; wait for 10 NS; end process; PROCESS is begin

EOC<='0';

wait for 940 NS; EOC<='1'; wait for 560 NS; end PROCESS; process(OE) begin

if rising_edge(OE) then D <= \"01011101\"; else D <= (others=>'Z'); END IF; end process;

end architecture;

附录二: 实验器材清单 实验器材 EP1C12Q240C8 芯片 共阳4位数码管 ADC0809芯片 电阻22欧姆 电阻10k欧姆 三极管

数量 1片 1片 1片 8个 4个 4个

因篇幅问题不能全部显示,请点此查看更多更全内容

Top