VHDL从TLC549中读取电压值
熟悉芯片
要从一块串行ADC芯片中读取数据,首先要看懂芯片的时序图。
TLC549时序:
从上图以及TLC549的数据手册可以得到一个完整的读取周期是这样的:
- 拉底片选信号nCS。经过两三个549的内部时钟周期(内部时钟4MHz)后,芯片确认变化。将上一个转换周期的结果的最高位(A7)输出到DATA OUT端。
- 从芯片的I/O CLK端收到连续八个脉冲。每个脉冲的下降沿的DATA OUT开始输出下一位的转换结果。
- 在第四个下降沿时启动新的一次转换过程的采样环节。
- 当第7个脉冲到来时上次上一次转换结果的最低位A0输出到DATA OUT上。
- 第八个脉冲下降沿后,把nCS拉高,否则失去同步。这时芯片会保持新转换周期的采样值。
等待36个内部周期的转换过程,之后可以拉低nCS开始读取周期。
- 这里需要注意的是I/O CLOCK的频率不能超过1.1MHz。不然会造成读取错误。
- 虽然再每个I/O CLOCK的下降沿时芯片会输出下一位的结果,但是DATA OUT 口上新的电平建立需要时间。这时电平会不稳定,因此应该在每个I/O CLOCK的上升沿读取数据。
读取芯片
注释很详细。代码说话。
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY ADC549 IS
PORT(
CLK : IN STD_LOGIC;
D : IN STD_LOGIC;
IOCLK : BUFFER STD_LOGIC;
CS : BUFFER STD_LOGIC;
DATA : OUT STD_LOGIC_VECTOR(7 DOWNTO 0));
END ENTITY ADC549;
--CLK时钟信号,需要小于1.1MHz 我的工程里是500K
--D ADC芯片的数据输出端
--CS 其实是nCS,反相片选端
--DATA 转换后的并行数据输出
ARCHITECTURE behav OF ADC549 IS
SIGNAL count : STD_LOGIC_VECTOR(7 DOWNTO 0) ;
SIGNAL Q : STD_LOGIC_VECTOR(7 DOWNTO 0) ;
BEGIN
IOCLK <= CLK; --IOCLK其实多余的,直接拿CLK接芯片就好
PROCESS(CLK) --这个进程用于产生正常工作的时序。
BEGIN
IF CLK'EVENT AND CLK='0' THEN
--count <= count + 1;
IF count < 8 THEN
CS <= '0' ;
ELSE
CS <= '1' ;
END IF; --产生八个有效的IOCLK,然后迅速拉高CS
count <= count + 1;
IF count >18 THEN
count <= (OTHERS => '0') ;
CS <= '0';
END IF; --保证经过36个内部时钟后才拉低CS 而且拉低CS要在第一个有效时钟到来之前
END IF;
END PROCESS;
PROCESS(CLK) --一个移位寄存器。把串行数据转换为并行
BEGIN
IF CLK'EVENT AND CLK='1' THEN
IF CS = '0' THEN
IF count <7 THEN
FOR i IN 7 DOWNTO 1 LOOP
Q(i) <= Q(i-1) ;
END LOOP;
END IF;
Q(0) <= D;
ELSE
DATA <= Q; --读取完成后,更新并行输出
END IF;
END IF;
END PROCESS;
END;
数据处理
上面得来的并行数据在此转换。TLC549是个8位ADC,因此实际电压值是:
Vfact=Vref×Data28−1
实验箱中 Vref=2.5V
为了方便数码管显示,用BCD码输出。
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY CONVERT IS
PORT(
BIN : IN STD_LOGIC_VECTOR(7 DOWNTO 0);
BCD0 : OUT STD_LOGIC_VECTOR(3 DOWNTO 0);
BCD1 : OUT STD_LOGIC_VECTOR(3 DOWNTO 0);
BCD2 : OUT STD_LOGIC_VECTOR(3 DOWNTO 0);
BCD3 : OUT STD_LOGIC_VECTOR(3 DOWNTO 0));
END ENTITY CONVERT;
ARCHITECTURE behav OF CONVERT IS
BEGIN
PROCESS(BIN)
VARIABLE vvar :INTEGER;
VARIABLE Hvar,Tvar,Ovar,TUvar :INTEGER RANGE 0 TO 9;
BEGIN
vvar := 2500*CONV_INTEGER(BIN)/255;
TUvar:= vvar / 1000;
Hvar := (vvar REM 1000) / 100 ;
Tvar := (vvar REM 100) / 10 ;
Ovar := vvar REM 10 ;
BCD0 <= CONV_STD_LOGIC_VECTOR(Ovar,4);
BCD1 <= CONV_STD_LOGIC_VECTOR(Tvar,4);
BCD2 <= CONV_STD_LOGIC_VECTOR(Hvar,4);
BCD3 <= CONV_STD_LOGIC_VECTOR(TUvar,4);
END PROCESS;
END;
显示结果
没什么好说的。一共四个进程:
- 一个进程计数
- 一个进程根据计数值选通不BCD码输入总线
- 一个进程对读入的BCD显示译码输出
- 一个进程根据计数值输出数码管的片选信号
扫描显示频率不宜太高也不宜太低,50Hz很合适。输入时钟应该为200Hz。
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY DISP IS
PORT(
CLK : IN STD_LOGIC;
A0 : IN STD_LOGIC_VECTOR(3 DOWNTO 0) ;
A1 : IN STD_LOGIC_VECTOR(3 DOWNTO 0) ;
A2 : IN STD_LOGIC_VECTOR(3 DOWNTO 0) ;
A3 : IN STD_LOGIC_VECTOR(3 DOWNTO 0) ;
SEG : OUT STD_LOGIC_VECTOR(7 DOWNTO 0);
DIG : OUT STD_LOGIC_VECTOR(3 DOWNTO 0));
END ENTITY DISP;
ARCHITECTURE behav OF DISP IS
SIGNAL SEL : STD_LOGIC_VECTOR(1 DOWNTO 0) ;
SIGNAL Yx : STD_LOGIC_VECTOR(3 DOWNTO 0) ;
BEGIN
PROCESS(CLK)
BEGIN
IF CLK'EVENT AND CLK='1' THEN
IF SEL < 3 THEN
SEL <= SEL + 1;
ELSE
SEL <= "00";
END IF;
END IF;
END PROCESS;
PROCESS (SEL) BEGIN
CASE SEL(1 DOWNTO 0) IS
WHEN "00" => Yx <= A0 ; -- 0
WHEN "01" => Yx <= A1 ; -- 1
WHEN "10" => Yx <= A2 ; -- 2
WHEN "11" => Yx <= A3 ; -- 3
WHEN OTHERS => NULL ;
END CASE ;
END PROCESS ;
PROCESS (SEL) BEGIN
CASE SEL(1 DOWNTO 0) IS
WHEN "00" => DIG<="1110" ; -- 0
WHEN "01" => DIG<="1101" ; -- 1
WHEN "10" => DIG<="1011" ; -- 2
WHEN "11" => DIG<="0111" ; -- 3
WHEN OTHERS => NULL ; -- NULL
END CASE ;
END PROCESS ;
PROCESS (Yx) BEGIN
CASE Yx(3 DOWNTO 0) IS
WHEN "0000" => SEG<=X"C0" ; -- 0
WHEN "0001" => SEG<=X"F9" ; -- 1
WHEN "0010" => SEG<=X"A4" ; -- 2
WHEN "0011" => SEG<=X"B0" ; -- 3
WHEN "0100" => SEG<=X"99" ; -- 4
WHEN "0101" => SEG<=X"92" ; -- 5
WHEN "0110" => SEG<=X"82" ; -- 6
WHEN "0111" => SEG<=X"F8" ; -- 7
WHEN "1000" => SEG<=X"80" ; -- 8
WHEN "1001" => SEG<=X"90" ; -- 9
WHEN OTHERS => SEG<=X"BF" ; -- -
END CASE ;
END PROCESS ;
END;