FPGA控制的数字电压表电路设计
李培
(河南科技大学电子信息工程学院 河南洛阳 471003)
摘 要:介绍数字电压表的组成及工作原理,论述了基于VHDL语言和FPGA芯片的数字系统的设计思想和实现过程。
关键词:数字电压表;VHDL语言;FPGA
VHDL Realization of Digital Voltmeter
Abstract: The composition and working principle of digital voltm eter were introduced in this paper, the designing idea and implementation proces s based on VHDL and FPGA were also described.
Key words: digital voltmeter; VHDL; FPGA 引言
在硬件电子电路设计领域中,电子设计自动化(EDA)工具已成为主要的设计手段,而VHDL语言则是EDA的关键技术之一,它采用自顶向下的设计方法,即从系统总体要求出发,自上至下地将设计任务分解为不同的功能模块,最后将各功能模块连接形成顶层模块,完成系统硬件的整体设计。本文用FPGA芯片和VHDL语言设计了一个数字电压表,举例说明了利用VHDL语言实现数字系统的过程。
1.系统组成及工作原理
整个数字电压表的硬件结构如图1所示。
系统的核心电路由FPGA完成,本设计选用了Altera公司的EPlKl00QC208-3芯片,用VHDL语言对它进行设计,实现三大功能模块:(1)控制模块,激活A/D转换器动作、接收A/D转换器传递过来的数字转换值;(2)数据处理模块,将接收到的转换值调整成对应的数字信号;(3)扫描、显示模块,产生数码管的片选信号,并将数值处理模块输出的BCD码译成相应的7段数码驱动值。
工作时,系统按一定的速率采集输入的模拟电压,经ADC0804转换为8位数字量,此8位数字量经FPGA处理得到模拟电压的数字码,再输入数码管获得被测电压的数字显示。
此电压表的测量范围:0~5V,三位数码管显示。
2.FPGA功能模块的设计
数字电压表的三大模块都是用VHDL语言编程实现的。 2.1控制模块
用状态机作法,产生ADC0804的片选信号、读/写控制信号,通过状态信号INTR判断转换是否结束;转换结束后将转换数据锁存并输出。其状态转换图如图2所示。
State machine viewer
A/D模块如下:
2.2数据处理模块
ADC0804是8位模数转换器,它的输出状态共有28=256种,如果输入信号Vin为0~5V电压范围,则每两个状态值为5/(256-1),约为0.0196V,故测量分辨率为0.02V。常用测量方法是:当读取到DB7~DB0转换值是XXH时,电压测量值为U≈XXH×0.02V;考虑到直接使用乘法计算对应的电压值将耗用大量的FPGA内部组件,本设计用查表命令来得到正确的电压值。
在读取到ADC0804的转换数据后,先用查表指令算出高、低4位的两个电压值,并分别用12位BCD码表示;接着设计12位的BCD码加法,如果每4位相加结果超过9需进行加6调整。这样得到模拟电压的BCD码。
CBD模块如下:
本模块的功能仿真结果如图3所示;当转换数据为00010101,通过查表高4位0001是0.32V,而低4位0101是0.1V,最后的电压输出结果是0.32V+0.1V=0.42V,它的BCD码表示为000001000010,仿真结果正确。 2.3扫描、显示模块
如图4所示,CLK是扫描时钟,其频率为1kHz,由给定的40MHz时钟分频得到;DATAIN是数据处理模块输出的电压值的BCD码;SEL是数码管的片选信号;POINT是数码管小数点驱动;通过扫描分别输出3位电压值的BCD码DATAOUT,并通过DISP将BCD码译成相应的7段数码驱动值,送数码管显示。
2.4 3选1 数据选择器模块
下图是3选1 数据选择器模块,由sel来选择数据输出,sel的三个状态分别对应选中三个数据A,B,C,同时将选中的数据输出。
2.5位选信号产生器(3进制计数器)
位选信号产生器,实际上时一个3进制计数器,随着时钟的上升沿的到来,它始终在0,1,2之间来回的循环,它的输出作为3选1 数据选择器模块和小数点产生器的输入。以下是仿真和模块。
位选信号产生器的模块:
2.6 7段译码
将输入的数据通过译码电路在数码管上显示出来 7段译码的模块:
2.7小数点产生器
当if selDP=\"10\" then DPout
elsif
selDP=\"01\" then DPout
selDP=\"00\" then DPout
小数点产生器模块:
3.顶层文件的模块如下图:
4.仿真结果
在Quartus II 8.0中,仿真波形如图所示:
5.心得体会
从这次的课程设计中,我受益匪浅。电压表的设计,用EDA仿真工具Quartus II 8.0,用vhdl语言设计,这些对于我们初学者来说,并不是件容易的事情,但是同时巩固了我们对知识的深刻理解。为以后的FPGA设计打下了坚实的基础。所以,总的来说,过程是困难的,不容易的,结果却是很满意的,获得了很宝贵的知识和经验!
6.结束语
本文设计的VHDL语言程序已在Quartus II 8.0工具软件上进行了编译、仿真和调试。经过实验验证,本设计是正确的,其电压显示值误差没有超过量化台阶上限(0.02V)。本文给出的设计思想也适用于其他基于PLD芯片的系统设计。
参考文献
[1]潘松 EDA技术实用教程[M]。北京:科学出版社,2003.[2]卢毅 VHDL与数字电路设计[M]。北京:科学出版社,2001.[3]林敏 VHDL数字系统设计与高层次综合[M]。北京:电子工业出版社,2001.[ 4 ] http://www.edacn.net/bbs/index.php [5 ]齐洪喜,陆颖 VHDL电路设计实用教程[M]。 北京:清华大学出版社,2004 数字电压表设计 VHDL程序如下: A/D0809 LIBRARY ieee;
use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; use ieee.std_logic_unsigned.all; entity ad is
port(ST,eoc:in std_logic;
--控制端口
d:in std_logic_vector(7 downto 0);
oe,sta,ale,adda:out std_logic;
q:out std_logic_vector(7 downto 0)); end ad; architecture a of ad is type states is(st0,st1,st2,st3,st4,st5,st6);
--7个状态 signal c_state,n_state:states :=st0; signal regl:std_logic_vector(7 downto 0); signal lock:std_logic; begin adda
case c_state is
when st0=>ale
n_state
when st1=>ale
n_state
when st2=>ale
n_state
when st3=>ale
if(eoc=\'1\') then n_state
else n_state
――eoc为‘1’转换结束 进入下一状态
end if;
――否则 继续转换
when st4=>ale
n_state
when st5=>ale
n_state
when st6=>ale
n_state
when others=>n_state
end case; end proce com; reg:proce(st)
begin
if(st\'event and st=\'1\') then
c_state
end if; end proce reg; lo:proce(lock)
--锁存 begin
if(lock\'event and lock=\'1\') then
regl
end if; end proce lo;
q
end a;
BCD 8位转12 LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; USE IEEE.STD_LOGIC_ARITH.ALL; USE IEEE.STD_LOGIC_UNSIGNED.ALL; ENTITY BCD IS PORT (V:IN STD_LOGIC_VECTOR(7 DOWNTO 0);
HB,LB:BUFFER STD_LOGIC_VECTOR(11 DOWNTO 0);
BVALUE:BUFFER STD_LOGIC_VECTOR(11 DOWNTO 0);
BCD_L,BCD_M,BCD_H:OUT STD_LOGIC_VECTOR(3 DOWNTO 0)); END BCD; ARCHITECTURE A OF BCD IS BEGIN P1:PROCESS(V(7 DOWNTO 4))
BEGIN
--A/D输出高4位转换
分辨率0.32V
IF V(7 DOWNTO 4)=\"1111\" THEN HB
--4.80V
ELSIF V(7 DOWNTO 4)= \"1110\" THEN HB
ELSIF V(7 DOWNTO 4)= \"1101\" THEN HB
ELSIF V(7 DOWNTO 4)= \"1100\" THEN HB
ELSIF V(7 DOWNTO 4)= \"1011\" THEN HB
ELSIF V(7 DOWNTO 4)= \"1010\" THEN HB
ELSIF V(7 DOWNTO 4)= \"1001\" THEN HB
ELSIF V(7 DOWNTO 4)= \"1000\" THEN HB
ELSIF V(7 DOWNTO 4)= \"0111\" THEN HB
ELSIF V(7 DOWNTO 4)= \"0110\" THEN HB
ELSIF V(7 DOWNTO 4)= \"0101\" THEN HB
ELSIF V(7 DOWNTO 4)= \"0100\" THEN HB
ELSIF V(7 DOWNTO 4)= \"0011\" THEN HB
ELSIF V(7 DOWNTO 4)= \"0010\" THEN HB
ELSIF V(7 DOWNTO 4)= \"0001\" THEN HB
ELSIF V(7 DOWNTO 4)= \"0000\" THEN HB
ELSE HB
--0.00V
END IF;
END PROCESS P1; P2:PROCESS(V(3 DOWNTO 0))
BEGIN
--A/D输出低4位转换 分辨率0.02V
IF V(3 DOWNTO 0)= \"1111\" THEN LB
--0.30V
ELSIF V(3 DOWNTO 0)= \"1110\" THEN LB
ELSIF V(3 DOWNTO 0)= \"1101\" THEN LB
ELSIF V(3 DOWNTO 0)= \"1100\" THEN LB
ELSIF V(3 DOWNTO 0)= \"1011\" THEN LB
ELSIF V(3 DOWNTO 0)= \"1010\" THEN LB
ELSIF V(3 DOWNTO 0)= \"1001\" THEN LB
ELSIF V(3 DOWNTO 0)= \"1000\" THEN LB
ELSIF V(3 DOWNTO 0)= \"0111\" THEN LB
ELSIF V(3 DOWNTO 0)= \"0110\" THEN LB
ELSIF V(3 DOWNTO 0)= \"0101\" THEN LB
ELSIF V(3 DOWNTO 0)= \"0100\" THEN LB
ELSIF V(3 DOWNTO 0)= \"0011\" THEN LB
ELSIF V(3 DOWNTO 0)= \"0010\" THEN LB
ELSIF V(3 DOWNTO 0)= \"0001\" THEN LB
ELSIF V(3 DOWNTO 0)= \"0000\" THEN LB
ELSE LB
--0V
END IF; END PROCESS P2;
BVALUE
BEGIN
JJ:=BVALUE;
IF (JJ(3 DOWNTO 0)>\"1001\") THEN
――如果12位结果中,低4位
JJ:=JJ+\"000000000110\";
――大于9 则低4位加6
END IF;
IF(JJ(7 DOWNTO 4)>\"1001\") THEN
――如果中间的4位大于9
JJ:=JJ+\"000001100000\";
――则中4位加6
END IF; BCD_L
BCD_M
3选1 数据选择器
LIBRARY ieee; use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; use ieee.std_logic_unsigned.all; entity mux3_1 is port(sel:in std_logic_vector(1 downto 0); A,B,C:in std_logic_vector(3 downto 0); Mselout:out std_logic_vector(3 downto 0)); end mux3_1; architecture a of mux3_1 is begin
proce(sel) begin
if
sel=\"10\" then Mselout
elsif
sel=\"01\" then Mselout
elsif
sel=\"00\" then Mselout
else null;
end if; end proce; end a;
位选信号产生器(3进制计数器)
library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_unsigned.all; entity c3 is
port(clk,clr:in std_logic;
qout:buffer std_logic_vector(1 downto 0)
); end c3; architecture behave of c3 is begin
proce(clk,clr) begin if(clr=\'0\')then qout
qout
if(qout=2)then qout
end if; end if; end proce; end behave;
7段译码
LIBRARY ieee; USE ieee.std_logic_1164.all; USE ieee.std_logic_unsigned.all; ENTITY del7 IS PORT ( input : IN STD_LOGIC_vector(3 downto 0);
output : OUT
STD_LOGIC_vector(6 downto 0) ); END del7; ARCHITECTURE a OF del7 IS
BEGIN PROCESS (input) BEGIN
CASE input IS
WHEN \"0000\" =>output
WHEN \"0001\" =>output
WHEN \"0010\" =>output
WHEN \"0011\" =>output
WHEN \"0100\" =>output
WHEN \"0101\" =>output
WHEN \"0110\" =>output
WHEN \"0111\" =>output
WHEN \"1000\" =>output
WHEN \"1001\" =>output
WHEN OTHERS=>NULL;
END CASE; end proce;
END a;
小数点产生器
LIBRARY ieee; use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; use ieee.std_logic_unsigned.all; entity DP is port(SELDP:in std_logic_vector(1 downto 0);
DPout:out std_logic); end DP; architecture a of DP is begin
proce(selDP) begin
if
selDP=\"10\" then DPout
elsif
selDP=\"01\" then DPout
elsif
selDP=\"00\" then DPout
else null;
――小数点DP
end if; end proce; end a;
顶层文件
library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_unsigned.all; use ieee.std_logic_arith.all; entity V_WATCH is
port( clkK,EOCC:in std_logic;
DD:IN std_logic_vector(7 downto 0);
clk3,CLR3:IN STD_LOGIC;
OEE,START,ALEE,ADDAA:OUT STD_LOGIC;
DPOUT:OUT STD_LOGIC;
Qoutput:out std_logic_vector(6 downto 0);
Qselout:out std_logic_vector(1 downto 0)); end V_WATCH; architecture a of V_WATCH is
――元件例化 COMPONENT DP port(SELDP:in std_logic_vector(1 downto 0);
DPout:out std_logic); END COMPONENT; COMPONENT del7 PORT(input : IN STD_LOGIC_vector(3 downto 0);
output
: OUT STD_LOGIC_vector(6 downto 0)); END COMPONENT; COMPONENT mux3_1 port(sel:in std_logic_vector(1 downto 0); A,B,C:in std_logic_vector(3 downto 0); Mselout:out std_logic_vector(3 downto 0)); END COMPONENT; COMPONENT ad port(st,eoc:in std_logic;
d:in std_logic_vector(7 downto 0);
oe,sta,ale,adda:out std_logic;
q:out std_logic_vector(7 downto 0)); END COMPONENT; COMPONENT C3 PORT (clk,clr: IN STD_LOGIC;
qout: OUT std_logic_vector(1 downto 0)); END COMPONENT; COMPONENT BCD PORT (V:IN STD_LOGIC_VECTOR(7 DOWNTO 0);
HB,LB:BUFFER STD_LOGIC_VECTOR(11 DOWNTO 0);
BVALUE:BUFFER STD_LOGIC_VECTOR(11 DOWNTO 0);
BCD_L,BCD_M,BCD_H:OUT STD_LOGIC_VECTOR(3 DOWNTO 0)); END COMPONENT; signal a:
std_logic_vector(1 downto 0); SIGNAL SBCD_L,SBCD_M,SBCD_H: STD_LOGIC_VECTOR(3 DOWNTO 0); SIGNAL b:
STD_LOGIC_VECTOR(3 DOWNTO 0); SIGNAL q:
STD_LOGIC_VECTOR(7 DOWNTO 0); SIGNAL BBCD:
STD_LOGIC_VECTOR(11 DOWNTO 0);
BEGIN U1:AD
PORT MAP(CLKK,EOCC,DD,OEE,START,ALEE,ADDAA, q); U2:BCD
PORT MAP(q,BCD_L=>SBCD_L,BCD_M=>SBCD_M,BCD_H=>SBCD_H); U3:C3
PORT MAP(CLK3,CLR3,a);
U4:MUX3_1 PORT MAP(SELOUT,SBCD_L,SBCD_M,SBCD_H,DI); U5:DEL7
PORT MAP(b, Qoutput); U6:DP
PORT MAP(a,DPOUT); QSELOUT