您好,欢迎来到世旅网。
搜索
您的当前位置:首页ADC0809采集与数值转换、10进制显示的VHDL实现

ADC0809采集与数值转换、10进制显示的VHDL实现

来源:世旅网


同ADC0809一路走来

采用VHDL语言控制ADC0809对模拟电压量进行采集不难,难在于将所得的数据进行转换,显示实际电压值(当然是10进制数),更难的是在转换方法上的运用,如何达到更高效率、资源占用率更低!

ADC0809对(0~5V)模拟量数值转换的公式为:Vo=data*5/255,即输出电压值Vo=data/51。在CPLD或FPGA上应用除法所占资源量较大。

个人在转换方式、方法上的认识与实践有如下例子! 例一:

----------------------有四舍五入,使用个176个logic elements------------------------------ --所用方法为:事先算好各数据对应实际电压值,采用查表方式得出数值,没有任何技术含量。 --不过很考验一个人的耐心、细心,对256个数据的计算、舍入、输入等,工作量还是(谁试谁知道)。 --较好的方法可以用 EXCEL计算,生成部分代码(推荐,还可以学习EXCEL的使用)。仿真波形如图1: --日期:2011-5-2 --作者:jungle library ieee;

use ieee.std_logic_1164.all; entity volt is

PORT(

Din VO2

: in std_logic_vector(7 downto 0); : out

integer range 0 to 5; integer range 0 to 9 );

VO1,VO0 : out

end volt;

architecture one of volt is

--显示数值寄存器,V0表示个位V1表示十位,V2表示百位 signal V1,V0: integer range 0 to 9; signal V2: integer range 0 to 5; VO2<=V2; VO1<=V1; VO0<=V0;

process(Din) --显示查表进程

begin

case Din is

WHEN\"00000000\"=>V2<=0;V1<=0;V0<=0; WHEN\"00000001\"=>V2<=0;V1<=0;V0<=2; WHEN\"00000010\"=>V2<=0;V1<=0;V0<=4; WHEN\"00000011\"=>V2<=0;V1<=0;V0<=6; ---------------4~252略------------ WHEN\"11111101\"=>V2<=4;V1<=9;V0<=6; WHEN\"11111110\"=>V2<=4;V1<=9;V0<=8; WHEN\"11111111\"=>V2<=5;V1<=0;V0<=0; WHEN OTHERS => NULL;

--253/51≈4.96

--3/51≈0.06

begin

end case;

end process;

end one;

图1 仿真波形

例二:

----------------------有四舍五入,使用个549个logic elements----------------

--方法说明:先将数据过大1000倍再除以51得到的数据就有4个有效数据,最低位数据来确定是否四舍五入(进位)。 --日期:2011-6-1 --作者:jungle LIBRARY ieee;

USE ieee.std_logic_1164.ALL; USE ieee.std_logic_arith.All; USE ieee.STD_LOGIC_UNSIGNED.ALL; ENTITY volt_data_change IS

PORT(

Din VO2

: in std_logic_vector(7 downto 0); : out std_logic_vector(2 downto 0);

);

--Vo0表示个位Vo1表示十位,Vo2表示百位 VO1,VO0 : out std_logic_vector(3 downto 0)

END volt_data_change;

ARCHITECTURE one OF volt_data_change IS

signal Dout_int : integer range 0 to 5000; signal Dout_int_div_10 : integer range 0 to 500;

signal Dout_vector_div_10 : std_logic_vector(8 downto 0); signal Dout_Lbit : integer range 0 to 9; signal Dout_round : integer range 0 to 500;

signal Dout_vector : std_logic_vector(10 downto 0); signal acc : std_logic;

-----------由16进制数得到10进制数的百位、十位、个位

function HEX2DEC(data_in : std_logic_vector(8 downto 0)) return std_logic_vector is

variable data : std_logic_vector(8 downto 0); variable data_out : std_logic_vector(10 downto 0); data := data_in; if data >499 then

data_out(10 downto 8) := \"101\"; data := data - 500;

data_out(10 downto 8) := \"100\"; data := data - 400;

data_out(10 downto 8) := \"011\"; data := data - 300;

begin

elsif data >399 then

elsif data >299 then

elsif data >199 then

data_out(10 downto 8) := \"010\"; data := data - 200;

data_out(10 downto 8) := \"001\"; data := data - 100;

data_out(10 downto 8) := \"000\"; data := data;

elsif data >99 then

else

end if;

if data >89 then

data_out(7 downto 4) := x\"9\"; data := data - 90;

data_out(7 downto 4) := x\"8\"; data := data - 80;

data_out(7 downto 4) := x\"7\"; data := data - 70;

data_out(7 downto 4) := x\"6\"; data := data - 60;

data_out(7 downto 4) := x\"5\"; data := data - 50;

data_out(7 downto 4) := x\"4\"; data := data - 40;

data_out(7 downto 4) := x\"3\"; data := data - 30;

data_out(7 downto 4) := x\"2\"; data := data - 20;

data_out(7 downto 4) := x\"1\"; data := data - 10;

data_out(7 downto 4) := x\"0\"; data := data;

elsif data >79 then

elsif data >69 then

elsif data >59 then

elsif data >49 then

elsif data >39 then

elsif data >29 then

elsif data >19 then

elsif data >9 then

else

end if;

data_out(3 downto 0) := data(3 downto 0); return data_out;

end HEX2DEC;

begin

Dout_int<=conv_integer(Din)*1000/51;

Dout_Lbit<=Dout_int-Dout_int/10*10;

Dout_int_div_10<=Dout_int/10;

Dout_vector_div_10<=conv_std_logic_vector(Dout_round,9); Dout_vector <= HEX2DEC(Dout_vector_div_10);

Vo2<=Dout_vector(10 downto 8); Vo1<=Dout_vector(7 downto 4); Vo0<=Dout_vector(3 downto 0);

--得出百位、十位、个位

--不管怎样只要前3位有效数据

Dout_round<= Dout_int_div_10+1 when acc='1' else Dout_int_div_10; --是否四舍五入

--得出Dout_int的个位数据

acc<='1' when Dout_Lbit > 4 and Dout_Lbit < 10 else '0'; --确定是否四舍五入

end one;

例三:

----------------------没有四舍五入,使用249个logic elements---------------- --方法说明:如例四所述 --日期:2011-6-1 --作者:jungle LIBRARY ieee;

USE ieee.std_logic_1164.ALL; USE ieee.std_logic_arith.All; USE ieee.STD_LOGIC_UNSIGNED.ALL; ENTITY volt_data_change IS

ARCHITECTURE an OF volt_data_change IS

PORT(

Din VO2 );

: in std_logic_vector(7 downto 0); : out integer range 0 to 5;

--Vo0表示个位Vo1表示十位,Vo2表示百位 VO1,VO0 : out integer range 0 to 9

END volt_data_change;

signal Dout_int : integer range 0 to 255;

signal buf100,buf10,buf1 : integer range 0 to 50; signal V2 : integer range 0 to 5; signal V1,V0 : integer range 0 to 9;

Dout_int<=conv_integer(Din); V2<=Dout_int/51;

begin

buf100<=(Dout_int-V2*51); V1<=buf100*10/51;

buf10<=(buf100*10-V1*51); V0<=buf10*10/51; Vo2<=V2; Vo1<=V1; Vo0<=V0;

end an;

例四:

---------------------没有四舍五入,使用96个logic elements---------------------------------- --在各种纠结、悲催之后,写出了让自己看得过去的代码。 --方法说明:例如230/51≈4.50。分三步计算得出每步的商。

被除数 230 26*10 5*10 除数 51 51 51 商 4 5 0 余数 26 5 50 --虽是除法思想,确不用除法来实现。由函数division()得到各步骤的商,以省资源为主要目的。 --不进行四舍五入计算了,留待后来学者学习研究。仿真波形如图2: --日期:2011-6-2 --作者:jungle LIBRARY ieee;

USE ieee.std_logic_1164.ALL; USE ieee.std_logic_arith.All; USE ieee.STD_LOGIC_UNSIGNED.ALL; ENTITY volt_data_change IS

ARCHITECTURE an OF volt_data_change IS

PORT(

Din VO2 );

: in std_logic_vector(7 downto 0); : out integer range 0 to 5;

--Vo0表示个位Vo1表示十位,Vo2表示百位 VO1,VO0 : out integer range 0 to 9

END volt_data_change;

signal Dout_int : integer range 0 to 255;

signal buf100,buf10,buf1 : integer range 0 to 500; signal V2 : integer range 0 to 5; signal V1,V0 : integer range 0 to 9;

function division(data_in : integer) return integer is

variable data : integer range 0 to 500; variable data_out : integer range 0 to 9:=0;

begin

data := data_in;

if data>458 then data_out := 9; elsif data>407 then data_out := 8; elsif data>356 then data_out := 7; elsif data>305 then data_out := 6; elsif data>254 then data_out := 5; elsif data>203 then data_out := 4; elsif data>152 then data_out := 3; elsif data>101 then data_out := 2; elsif data>50 then else data_out := 0; end if;

return data_out;

data_out := 1;

end division;

begin end an;

Vo2<=V2; Vo1<=V1; Vo0<=V0;

Dout_int<=conv_integer(Din); V2<=division(Dout_int);

buf100<=(Dout_int-V2*51)*10; V1<=division(buf100);

buf10<=(buf100-V1*51)*10; V0<=division(buf10);

--十位的余数 --个位

--百位的余数 --十位

--百位

图2 仿真波形

--------------------------------------------------------------------------------------------------

总结:一直以来都突破不了例一使用资源的下限,经过“胡思乱想”偶然想来例四解决方

案,才让自己看得过去!

没有做不到的,只有想不到的! 思想有多远,鱼儿就能游多远...我相信还有更好的方法来解决上述的问题。希望对学习VHDL的朋友有用,欢迎转载!

在此附上ADC0809的控制程序代码:

--------------------------------------------------------------------------------

--功能:基于VHDL语言,实现对ADC0809 简单控制

--说明:ADC0809 没有内部时钟,需外接采样时钟信号,这里由FPGA的系统 --时钟(50MHz)经96分频得到clk_adc(520.8KHz)作为ADC0809 转换工作时钟。 --

START

ALE OE LOCK B

0 0 0 0 0 1 0 0

1 0

初始态 启动转换

若测得 EOC=1,转ST3 输出转换后的数据

利用LOCK的上升沿锁存数据

-- ST0 0 0 0 -- ST1 1

-- ST2 0 0 0 -- ST3 0 0 1 -- ST4 0 library ieee;

use ieee.std_logic_1164.all; use ieee.std_logic_unsigned.all;

entity ADC0809 is

port ( ADC_Dout : in std_logic_vector(0 to 7);

CLK,EOC,EN : in std_logic;

ADDA : out std_logic_vector(2 downto 0);

0 1 1 0

-- START 正脉冲(至少100ns)=该模块时钟<10MHz,器件ADC0809时钟频率不高于640KHZ。

START,ALE,OE,AD_CLK : out std_logic;

ADC_DISPLY : out std_logic_vector(7 downto 0)); end ADC0809;

architecture behav of ADC0809 is

SIGNAL current_state,next_state:STD_LOGIC_VECTOR(4 DOWNTO 0); CONSTANT st0 : STD_LOGIC_VECTOR(4 DOWNTO 0):=\"00000\"; CONSTANT st1 : STD_LOGIC_VECTOR(4 DOWNTO 0):=\"11000\"; CONSTANT st2 : STD_LOGIC_VECTOR(4 DOWNTO 0):=\"00001\"; CONSTANT st3 : STD_LOGIC_VECTOR(4 DOWNTO 0):=\"00100\"; CONSTANT st4 : STD_LOGIC_VECTOR(4 DOWNTO 0):=\"00110\"; SIGNAL REGL : STD_LOGIC_VECTOR(7 DOWNTO 0); SIGNAL LOCK : STD_LOGIC;

SIGNAL clk_adc,clk_sys : STD_LOGIC; BEGIN

ADDA<=\"000\"; ADC_DISPLY<=REGL; LOCK<=current_state(1);

ALE<=current_state(3);

AD_CLK<=clk_adc;

OE<=current_state(2); START<=current_state(4);

COM : PROCESS(current_state,EOC) BEGIN

CASE current_state IS

when st0=> next_state<=st1; when st1=>next_state<=st2;

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

ELSE next_state<=st2; END IF;

when st3=>next_state<=st4; when st4=>next_state<=st0; when OTHERS => next_state<=st0;

END CASE; END PROCESS;

REG : PROCESS (clk_sys,en) BEGIN

if en='0' then

current_state<=st0; current_state<=next_state;

elsif(clk_sys'EVENT AND clk_sys='1') THEN END IF;

END PROCESS;

LATCH:PROCESS (LOCK) BEGIN

if en='0' then

REGL<=\"00000000\"; REGL<=ADC_Dout;

ELSIF LOCK='1' AND LOCK'EVENT THEN END IF;

variable cnt1 : integer range 0 to 3; if en='0' then

cnt1:=0; if cnt1=3 then

cnt1:=0;

clk_sys<=not clk_sys; cnt1:=cnt1+1;

elsif CLK'event and CLK='1' then

END PROCESS;

DIV_SYS : process(CLK,en) --clk_sys=6.25MHz<10MHz begin

else end if;

end if;

end process;

DIV : process(clk_sys,en) --clk_adc=520.8KHz<640KHz

variable cnt1 : integer range 0 to 7; if en='0' then begin

cnt1:=0; if cnt1=5 then

cnt1:=0;

clk_adc<=not clk_adc; cnt1:=cnt1+1;

elsif clk_sys'event and clk_sys='1' then

else end if;

end if;

end process;

END behav;

----------------------------------END-------------------------------------------

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

Copyright © 2019- esig.cn 版权所有

违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com

本站由北京市万商天勤律师事务所王兴未律师提供法律服务