VHDL数据采集

VHDL从TLC549中读取电压值

熟悉芯片

要从一块串行ADC芯片中读取数据,首先要看懂芯片的时序图。
TLC549时序:
TLC549时序
从上图以及TLC549的数据手册可以得到一个完整的读取周期是这样的:

  1. 拉底片选信号nCS。经过两三个549的内部时钟周期(内部时钟4MHz)后,芯片确认变化。将上一个转换周期的结果的最高位(A7)输出到DATA OUT端。
  2. 从芯片的I/O CLK端收到连续八个脉冲。每个脉冲的下降沿的DATA OUT开始输出下一位的转换结果。
  3. 在第四个下降沿时启动新的一次转换过程的采样环节。
  4. 当第7个脉冲到来时上次上一次转换结果的最低位A0输出到DATA OUT上。
  5. 第八个脉冲下降沿后,把nCS拉高,否则失去同步。这时芯片会保持新转换周期的采样值。
  6. 等待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×Data281

实验箱中 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;
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值