VHDL设计简单数字时钟

VHDL设计简单数字时钟

EDA实验要做一个数字时钟,很简单的那种,能跑就好。

时基模块

首先时钟嘛,总体来说肯定是时序电路。首先要做一个秒脉冲发送器。板子上有48MHz 的时钟输入,那就对它分频好了。

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

ENTITY DIV IS
    PORT(
        CLK     : IN STD_LOGIC;
        DCLK    : OUT STD_LOGIC);
END ENTITY DIV;

ARCHITECTURE behav OF DIV IS
SIGNAL count : STD_LOGIC_VECTOR(32 DOWNTO 0) ;
SIGNAL O : STD_LOGIC ;
BEGIN
    PROCESS(CLK)
    BEGIN
        IF CLK'EVENT AND CLK='1' THEN
            count <= count + 1 ;
            IF count = 23999999 THEN
                count <= (OTHERS => '0');
                O <= NOT O;
            END IF;
        END IF; 
    END PROCESS;
    DCLK <= O;
END;

很简单,48000000/((23999999+1)*2)=1
这个分频器是50%占空比的,因此只能偶数分频,分频比为(x+1)*2。

BCD码计数器

分频之后是计数。做成BCD码计数器主要是方便后面数码管显示,二进制计数的话中间转换也必将麻烦。HDL语言数值计算必将麻烦,又是信号又是变量的,赋值号不一样,也不能直接混着算。取模取余什么的限制较多。
时钟需要的24/60进制计数器代码:

60进制BCD码计数器实体说明

ENTITY CTR60 IS
    PORT(
        CLK : IN STD_LOGIC;
        Q   : OUT STD_LOGIC_VECTOR(7 DOWNTO 0);
        C   : OUT STD_LOGIC);
END ENTITY CTR60;

ARCHITECTURE behav OF CTR60 IS
BEGIN
    PROCESS(CLK)
    VARIABLE count :STD_LOGIC_VECTOR(7 DOWNTO 0);
    BEGIN
        IF CLK'EVENT AND CLK='1' THEN
            IF count(3 DOWNTO 0) < 9 THEN
                count(3 DOWNTO 0) := count(3 DOWNTO 0)+1;
            ELSE
                count(3 DOWNTO 0) := "0000";
                count(7 DOWNTO 4) := count(7 DOWNTO 4)+1;
            END IF;
            IF count(7 DOWNTO 4) > 5 THEN
                count(7 DOWNTO 0) := "00000000";
                C <= '1';
            ELSE
                C <= '0';
            END IF;     
        END IF;
        Q <= count;
    END PROCESS;
END;

24进制BCD码计数器实体说明

ENTITY CTR24 IS
    PORT(
        CLK : IN STD_LOGIC;
        Q   : OUT STD_LOGIC_VECTOR(7 DOWNTO 0);
        C   : OUT STD_LOGIC);
END ENTITY CTR24;

ARCHITECTURE behav OF CTR24 IS
BEGIN
    PROCESS(CLK)
    VARIABLE count :STD_LOGIC_VECTOR(7 DOWNTO 0);
    BEGIN
        IF CLK'EVENT AND CLK='1' THEN
            IF count(3 DOWNTO 0) < 9 THEN
                count(3 DOWNTO 0) := count(3 DOWNTO 0)+1;
            ELSE
                count(3 DOWNTO 0) := "0000";
                count(7 DOWNTO 4) := count(7 DOWNTO 4)+1;
            END IF;
            IF (count(7 DOWNTO 4) = 2) AND (count(3 DOWNTO 0) > 3) THEN
                count(7 DOWNTO 0) := "00000000";
                C <= '1';
            ELSE
                C <= '0';
            END IF; 
        END IF;
        Q <= count;
    END PROCESS;
END;

这时把他们串接起来,时钟的计数就完成了。就剩下显示了。

数码管扫描显示模块

既然是扫描显示那就需要一个时序控制咯。
跟上面的一样,做一个分频器。代码一样的不贴了。我是把输入时钟分频到了200Hz,扫描显示8个数码管。那么总体的刷新频率是50Hz,不闪。之前弄的20Hz闪瞎眼。没法看了。

8进制计数器

扫描显示一次点亮一个数码管,8个数码管一共16根线控制。那么需要对什么时候输出哪一位的段码之类的进行控制。不然显示会乱掉。很显然这是一个状态机一样的东西。那么计数器肯定少不了了。

ENTITY CTRB_8 IS
    PORT(
        CLK : IN STD_LOGIC;
        Q   : OUT STD_LOGIC_VECTOR(3 DOWNTO 0));
END ENTITY CTRB_8;

ARCHITECTURE behav OF CTRB_8 IS
BEGIN
    PROCESS(CLK)
    VARIABLE count :STD_LOGIC_VECTOR(3 DOWNTO 0);
    BEGIN
        IF CLK'EVENT AND CLK='1' THEN
            IF count(3 DOWNTO 0) < 7 THEN
                count := count + 1 ;
            ELSE
                count := "0000" ;
            END IF;
        END IF;
        Q <= count;
    END PROCESS;
END;

有了计数器,就知道目前是出于哪个状态。应该点亮哪个管点亮哪些段就有了依据。
有了依据怎么办?对计数器的输出译码决定:

38译码器

控制位码输出 !低电平选中!

ENTITY DECODER38 IS
    PORT(
        Ax : IN STD_LOGIC_VECTOR(3 DOWNTO 0) ;
        Yx : OUT STD_LOGIC_VECTOR(7 DOWNTO 0)) ;
END ENTITY DECODER38 ;

ARCHITECTURE behav OF DECODER38 IS
BEGIN
    PROCESS (Ax) BEGIN
        CASE Ax(3 DOWNTO 0) IS
            WHEN "0000" => Yx<="01111111" ; -- 0
            WHEN "0001" => Yx<="10111111" ; -- 1
            WHEN "0010" => Yx<="11011111" ; -- 2
            WHEN "0011" => Yx<="11101111" ; -- 3
            WHEN "0100" => Yx<="11110111" ; -- 4
            WHEN "0101" => Yx<="11111011" ; -- 5
            WHEN "0110" => Yx<="11111101" ; -- 6
            WHEN "0111" => Yx<="11111110" ; -- 7
            WHEN OTHERS => NULL ; -- NULL
        END CASE ;
    END PROCESS ;
END ARCHITECTURE behav ;

多路总线选择器

控制段码输出:

ENTITY BUSSELECTOR IS
    PORT(
        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) ;
        A4 : IN STD_LOGIC_VECTOR(3 DOWNTO 0) ;
        A5 : IN STD_LOGIC_VECTOR(3 DOWNTO 0) ;
        A6 : IN STD_LOGIC_VECTOR(3 DOWNTO 0) ;
        A7 : IN STD_LOGIC_VECTOR(3 DOWNTO 0) ;
        SEL: IN STD_LOGIC_VECTOR(3 DOWNTO 0) ;
        Yx : OUT STD_LOGIC_VECTOR(3 DOWNTO 0)) ;
END ENTITY BUSSELECTOR ;

ARCHITECTURE behav OF BUSSELECTOR IS
BEGIN
    PROCESS (SEL) BEGIN
        CASE SEL(3 DOWNTO 0) IS
            WHEN "0000" => Yx <= A0 ; -- 0
            WHEN "0001" => Yx <= A1 ; -- 1
            WHEN "0010" => Yx <= "1111" ; -- 2
            WHEN "0011" => Yx <= A3 ; -- 3
            WHEN "0100" => Yx <= A4 ; -- 4
            WHEN "0101" => Yx <= "1111" ; -- 5
            WHEN "0110" => Yx <= A6 ; -- 6
            WHEN "0111" => Yx <= A7 ; -- 7  
            WHEN OTHERS => NULL ;
        END CASE ;
    END PROCESS ;
END ARCHITECTURE behav ;

显示控制就已经做好了。
但是,段码不是天生有的。需要对计数器的输出显示译码。

BCD码显示译码器

这里的译码器是共阳的。低电平点亮。a,b,c,d,e,f,g,dp的顺序和连线管脚分配相关,具体情况具体改。

ENTITY leddecoder IS
    PORT(
        Ax : IN STD_LOGIC_VECTOR(3 DOWNTO 0) ;
        Yx : OUT STD_LOGIC_VECTOR(7 DOWNTO 0)) ;
END ENTITY leddecoder ;

ARCHITECTURE behav OF leddecoder IS
BEGIN
    PROCESS (Ax) BEGIN
        CASE Ax(3 DOWNTO 0) IS
            WHEN "0000" => Yx<=X"C0" ; -- 0
            WHEN "0001" => Yx<=X"F9" ; -- 1
            WHEN "0010" => Yx<=X"A4" ; -- 2
            WHEN "0011" => Yx<=X"B0" ; -- 3
            WHEN "0100" => Yx<=X"99" ; -- 4
            WHEN "0101" => Yx<=X"92" ; -- 5
            WHEN "0110" => Yx<=X"82" ; -- 6
            WHEN "0111" => Yx<=X"F8" ; -- 7
            WHEN "1000" => Yx<=X"80" ; -- 8
            WHEN "1001" => Yx<=X"90" ; -- 9 
            WHEN OTHERS => Yx<=X"BF" ; -- -
        END CASE ;
    END PROCESS ;
END ARCHITECTURE behav ;

到此所有电路模块都设计完了。

电路设计

Block Diagram设计。

Block Diagram

全编译一遍,烧板子上去正常运行。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值